]> granicus.if.org Git - clang/commitdiff
When reading the AST, delay loading of the redeclaration chain to avoid deeply nested...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 12 Feb 2011 07:50:47 +0000 (07:50 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 12 Feb 2011 07:50:47 +0000 (07:50 +0000)
Temporarily set the first (canonical) declaration as the previous one, which is the one that
matters, and mark the real previous DeclID to be loaded & attached later on.

Fixes rdar://8956193.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125434 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Serialization/ASTReader.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Index/c-index-redecls.c [new file with mode: 0644]

index 23701248d006d45a9bd419bcb5837628a8634a2c..015ccc9b3f87e0ca0959911ffc550a50a0ce4de5 100644 (file)
@@ -721,6 +721,13 @@ private:
   /// Objective-C protocols.
   std::deque<Decl *> InterestingDecls;
 
+  /// \brief We delay loading of the previous declaration chain to avoid
+  /// deeply nested calls when there are many redeclarations.
+  std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls;
+
+  /// \brief Ready to load the previous declaration of the given Decl.
+  void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID);
+
   /// \brief When reading a Stmt tree, Stmt operands are placed in this stack.
   llvm::SmallVector<Stmt *, 16> StmtStack;
 
index d2167376ff23037f0065eaf8d55b008d80be91f3..5e3fa132e6919fe67fc0e0b3b96ddd0ee551abf9 100644 (file)
@@ -4815,6 +4815,13 @@ void ASTReader::FinishedDeserializing() {
       PendingIdentifierInfos.pop_front();
     }
 
+    // Ready to load previous declarations of Decls that were delayed.
+    while (!PendingPreviousDecls.empty()) {
+      loadAndAttachPreviousDecl(PendingPreviousDecls.front().first,
+                                PendingPreviousDecls.front().second);
+      PendingPreviousDecls.pop_front();
+    }
+
     // We are not in recursive loading, so it's safe to pass the "interesting"
     // decls to the consumer.
     if (Consumer)
index 56c33ca913d27719b2ad427769561f9c7fca1ac0..279d081098f56b5cc3685d8b7519eb3408a22ce8 100644 (file)
@@ -75,6 +75,8 @@ namespace clang {
       : Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID),
         Record(Record), Idx(Idx), TypeIDForTypeDecl(0) { }
 
+    static void attachPreviousDecl(Decl *D, Decl *previous);
+
     void Visit(Decl *D);
 
     void UpdateDecl(Decl *D, const RecordData &Record);
@@ -981,13 +983,22 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   // can be used while this is still initializing.
 
   assert(D->CommonOrPrev.isNull() && "getCommonPtr was called earlier on this");
-  RedeclarableTemplateDecl *PrevDecl =
-      cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
-  assert((PrevDecl == 0 || PrevDecl->getKind() == D->getKind()) &&
-         "PrevDecl kind mismatch");
-  if (PrevDecl)
-    D->CommonOrPrev = PrevDecl;
-  if (PrevDecl == 0) {
+  DeclID PreviousDeclID = Record[Idx++];
+  DeclID FirstDeclID =  PreviousDeclID ? Record[Idx++] : 0;
+  // We delay loading of the redeclaration chain to avoid deeply nested calls.
+  // We temporarily set the first (canonical) declaration as the previous one
+  // which is the one that matters and mark the real previous DeclID to be
+  // loaded & attached later on.
+  RedeclarableTemplateDecl *FirstDecl =
+      cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(FirstDeclID));
+  assert((FirstDecl == 0 || FirstDecl->getKind() == D->getKind()) &&
+         "FirstDecl kind mismatch");
+  if (FirstDecl) {
+    D->CommonOrPrev = FirstDecl;
+    // Mark the real previous DeclID to be loaded & attached later on.
+    if (PreviousDeclID != FirstDeclID)
+      Reader.PendingPreviousDecls.push_back(std::make_pair(D, PreviousDeclID));
+  } else {
     D->CommonOrPrev = D->newCommon(*Reader.getContext());
     if (RedeclarableTemplateDecl *RTD
           = cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
@@ -1224,10 +1235,20 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
                 " reading");
   case NoRedeclaration:
     break;
-  case PointsToPrevious:
+  case PointsToPrevious: {
+    DeclID PreviousDeclID = Record[Idx++];
+    DeclID FirstDeclID = Record[Idx++];
+    // We delay loading of the redeclaration chain to avoid deeply nested calls.
+    // We temporarily set the first (canonical) declaration as the previous one
+    // which is the one that matters and mark the real previous DeclID to be
+    // loaded & attached later on.
     D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(
-                                cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+                                cast_or_null<T>(Reader.GetDecl(FirstDeclID)));
+    if (PreviousDeclID != FirstDeclID)
+      Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
+                                                           PreviousDeclID));
     break;
+  }
   case PointsToLatest:
     D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
                                 cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
@@ -1327,6 +1348,25 @@ ASTReader::DeclCursorForIndex(unsigned Index, DeclID ID) {
   return RecordLocation(F, F->DeclOffsets[Index]);
 }
 
+void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
+  assert(D && previous);
+  if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+    TD->RedeclLink.setPointer(cast<TagDecl>(previous));
+  } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    FD->RedeclLink.setPointer(cast<FunctionDecl>(previous));
+  } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    VD->RedeclLink.setPointer(cast<VarDecl>(previous));
+  } else {
+    RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
+    TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
+  }
+}
+
+void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
+  Decl *previous = GetDecl(ID);
+  ASTDeclReader::attachPreviousDecl(D, previous);
+}
+
 /// \brief Read the declaration at the given offset from the AST file.
 Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
   RecordLocation Loc = DeclCursorForIndex(Index, ID);
index b0ed8bc59f85e34e9b5bfbfa43c786950d318756..17ee85ad279d84c7a68bd01fd5daa4cffe8b8b72 100644 (file)
@@ -862,6 +862,9 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   // getCommonPtr() can be used while this is still initializing.
 
   Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+  if (D->getPreviousDeclaration())
+    Writer.AddDeclRef(D->getFirstDeclaration(), Record);
+
   if (D->getPreviousDeclaration() == 0) {
     // This TemplateDecl owns the CommonPtr; write it.
     assert(D->isCanonicalDecl());
@@ -1075,9 +1078,14 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
   if (D->RedeclLink.getNext() == D) {
     Record.push_back(NoRedeclaration);
   } else {
-    Record.push_back(D->RedeclLink.NextIsPrevious() ? PointsToPrevious
-                                                    : PointsToLatest);
-    Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
+    if (D->RedeclLink.NextIsPrevious()) {
+      Record.push_back(PointsToPrevious);
+      Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+      Writer.AddDeclRef(D->getFirstDeclaration(), Record);
+    } else {
+      Record.push_back(PointsToLatest);
+      Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
+    }
   }
 
   T *First = D->getFirstDeclaration();
diff --git a/test/Index/c-index-redecls.c b/test/Index/c-index-redecls.c
new file mode 100644 (file)
index 0000000..0cf2f03
--- /dev/null
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -emit-pch -o %t.ast %s
+// RUN: c-index-test -test-load-tu %t.ast all
+
+// rdar://8956193 - We would blow the thread stack because of nested calls due
+//                  to redeclarations.
+
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);
+void socrates(void);