================
@@ -10475,6 +10468,12 @@ void ASTReader::finishPendingActions() {
   for (auto *ND : PendingMergedDefinitionsToDeduplicate)
     getContext().deduplicateMergedDefinitonsFor(ND);
   PendingMergedDefinitionsToDeduplicate.clear();
+
+  // For each decl chain that we wanted to complete while deserializing, mark
+  // it as "still needs to be completed".
+  for (Decl *D : PendingIncompleteDeclChains)
+    markIncompleteDeclChain(D);
+  PendingIncompleteDeclChains.clear();
----------------
mpark wrote:

> Sorry, I've been away from this code for a long time and have forgotten a lot 
> about how it's supposed to work.

Not a problem at all. In trying to dig through some of the history, I've seen 
that a bunch of this code is from 2015 😄

> We're just marking the chains as incomplete here, not actually completing 
> them, and we won't do the work to complete them until someone actually calls 
> `redecls()` or similar.

What I'm uncertain about is the expectation of the parts **within** 
`finishPendingActions` that call `redecls()` or similar. Because for those, we 
**still** won't do the work to complete them. More specifically, the parts 
within `finishPendingActions` that say "we require the redecl chain to be fully 
wired" seem to me like they wouldn't have the requirement guaranteed to be 
satisfied.

> I would expect that when we do go and wire up the redecl chains, we're 
> propagating the `Definition` value along the chain. Also, when chains aren't 
> wired up properly, each declaration still does correctly point to its 
> canonical declaration, so we will still detect things like multiple 
> definitions for an entity because each of those will try to update the 
> canonical declaration to have a different definition.

Ah, I see! This is great. Thanks for sharing. It's exactly this kind of 
high-level architectural understanding is what I'm needing more of.

> Moving the marking of pending incomplete decl chains as incomplete to the end 
> of the function makes sense to me.

This is exactly what I had done in #121245, but unfortunately it caused #126973 
so it got reverted. The reduced test case of #126973 is 
[pr129982.cpp](https://github.com/llvm/llvm-project/pull/129982/files#diff-972832d26c9b2be8952ac137e86510a1eaf0197f98df6245688b1c3b5303ad65).

My gathering of that situation so far is that `RD->addedMember(MD);` (near the 
end of `finishPendingActions`) effectively calls `RD->data()` which calls 
`RD->getMostRecentDecl()`. Anyway, for some reason leaving the `RD` in 
`PendingIncompleteDeclChains` as before is okay, but marking it incomplete 
caused another issue. The other issue in short:
1. There is a call to `getMostRecentDecl()` which calls `CompleteRedeclChain` 
which calls `DC->lookup(Name)`. During this process, the definition of `Name` 
is not found. 
[`Lookups[DC].Table[Name]`](https://github.com/llvm/llvm-project/blob/c6d95c441a29a45782ff72d6cb82839b86fd0e4a/clang/lib/Serialization/ASTReader.cpp#L8494-L8501)
 doesn't have the definition ID.
2. A pending update record populates `Lookups[DC].Table[Name]` with the 
definition ID.
3. Another call to `getMostRecentDecl()` which, if it were to call 
`CompleteRedeclChain` would call `DC->lookup(Name)` and find the definition. 
However, we updated the lazy ptr generation number in step (1), so we do not 
invoke `CompleteRedeclChain`, and we can't find the definition.

> Can we also add an assert that all of the other "pending" lists are still 
> empty at that point? (Or do we already have an assert for that somewhere?)

Yes, I can certainly do that. No, we don't have that assertion currently.

https://github.com/llvm/llvm-project/pull/129982
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to