================
@@ -191,39 +199,136 @@ void IncrementalParser::withdrawMostRecentTU(
C.TUDecl = Prev;
}
+/// The newest declaration of whatever D redeclares that still lives outside
+/// DiscardedTU
+static NamedDecl *findSurvivingPrevDecl(NamedDecl *D,
+ TranslationUnitDecl *DiscardedTU) {
+ for (Decl *Prev = D->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl())
+ if (Prev->getTranslationUnitDecl() != DiscardedTU)
+ return dyn_cast<NamedDecl>(Prev);
+ return nullptr;
+}
+
+/// Unlink everything a discarded re-opening of a namespace put into it.
Members
+/// are made visible in the namespace's primary context, which outlives the
+/// discarded PTU, so leaving them behind would keep half-parsed declarations
+/// reachable
+static void dropContainingMembers(NamespaceDecl *ND) {
+ llvm::SmallVector<Decl *, 8> Members(ND->decls());
+ for (Decl *M : Members)
+ ND->removeDecl(M);
+}
+
+bool IncrementalParser::withdrawRedecl(NamedDecl *D, NamedDecl *Prev,
+ TranslationUnitDecl *DiscardedTU) {
+ ASTContext &C = S.getASTContext();
+
+ auto Unlink = [&C](auto *Latest, NamedDecl *SurvivorND) {
+ using T = std::remove_pointer_t<decltype(Latest)>;
+ auto *Survivor = cast<T>(SurvivorND);
+
+ // Rebuild First -> ... -> Survivor -> ... -> Latest as
+ // First -> ... -> Survivor.
+ Latest->getFirstDecl()->RedeclLink.setLatest(Survivor);
+
+ // The chain is circular: a withdrawn declaration still linked into it can
+ // never walk back around to itself, so redecls() on one would not
+ // terminate. Give each a chain of its own.
+ for (T *Dead = Latest; Dead != Survivor;) {
+ T *Next = Dead->getPreviousDecl();
+ Dead->First = Dead;
+ Dead->RedeclLink = Redeclarable<T>::LatestDeclLink(C);
+ Dead = Next;
+ }
+ };
+
+ if (auto *TD = dyn_cast<TagDecl>(D)) {
+ Unlink(TD, Prev);
+ // A class keeps its definition outside the redeclaration chain, in the
+ // DefinitionData that startDefinition() hands to every redeclaration.
+ // Unlinking leaves the survivors pointing at the discarded definition, so
+ // drop it; a later definition allocates a fresh one for the whole chain.
+ if (auto *RD = dyn_cast<CXXRecordDecl>(Prev))
+ if (CXXRecordDecl *Def = RD->getDefinition();
+ Def && Def->getTranslationUnitDecl() == DiscardedTU)
+ for (auto *R : RD->redecls())
+ cast<CXXRecordDecl>(R)->DefinitionData = nullptr;
+ return true;
+ }
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ Unlink(FD, Prev);
+ return true;
+ }
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
+ Unlink(VD, Prev);
+ return true;
+ }
+ if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
+ dropContainingMembers(ND);
+ Unlink(ND, Prev);
+ return true;
+ }
+ if (auto *TND = dyn_cast<TypedefNameDecl>(D)) {
+ Unlink(TND, Prev);
+ return true;
----------------
Vipul-Cariappa wrote:
If this is regarding the duplication. I have tried fixing it.
Note that `dyn_cast<Redeclaration<Decl>(...)` is not possible; therefore, we
need the multiple `dyn_clas<Decl>(...)`s.
https://github.com/llvm/llvm-project/pull/218149
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits