diff options
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 58 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 14 | ||||
-rw-r--r-- | test/Index/c-index-redecls.c | 107 |
5 files changed, 181 insertions, 12 deletions
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 23701248d0..015ccc9b3f 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -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; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index d2167376ff..5e3fa132e6 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 56c33ca913..279d081098 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index b0ed8bc59f..17ee85ad27 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -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 index 0000000000..0cf2f032a3 --- /dev/null +++ b/test/Index/c-index-redecls.c @@ -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); |