diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 7a5a715eab..6a0b6acc87 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -928,6 +928,7 @@ public: static bool classof(const ObjCInterfaceDecl *D) { return true; } static bool classofKind(Kind K) { return K == ObjCInterface; } + friend class ASTReader; friend class ASTDeclReader; friend class ASTDeclWriter; }; diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 10ed5dceea..507b75f33c 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -338,7 +338,10 @@ private: /// the DefinitionData pointer of all pending references. PendingForwardRefsMap PendingForwardRefs; - + /// \brief The set of C++ or Objective-C classes that have forward + /// declarations that have not yet been linked to their definitions. + llvm::SmallPtrSet PendingDefinitions; + typedef llvm::DenseMap FirstLatestDeclIDMap; /// \brief Map of first declarations from a chained PCH that point to the diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index fc49e88a50..2b417522bc 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6095,6 +6095,29 @@ void ASTReader::finishPendingActions() { } PendingChainedObjCCategories.clear(); } + + // If we deserialized any C++ or Objective-C class definitions, make sure + // that all redeclarations point to the definitions. Note that this can only + // happen now, after the redeclaration chains have been fully wired. + for (llvm::SmallPtrSet::iterator D = PendingDefinitions.begin(), + DEnd = PendingDefinitions.end(); + D != DEnd; ++D) { + if (CXXRecordDecl *RD = dyn_cast(*D)) { + for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(), + REnd = RD->redecls_end(); + R != REnd; ++R) + cast(*R)->DefinitionData = RD->DefinitionData; + + continue; + } + + ObjCInterfaceDecl *ID = cast(*D); + for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(), + REnd = ID->redecls_end(); + R != REnd; ++R) + R->Data = ID->Data; + } + PendingDefinitions.clear(); } void ASTReader::FinishedDeserializing() { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 35cd8478d5..bd6a5a5e06 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -630,6 +630,9 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { // pending references were linked. Reader.PendingForwardRefs.erase(ID); #endif + + // Note that we have deserialized a definition. + Reader.PendingDefinitions.insert(ID); } } else if (Def) { if (Def->Data) { @@ -1030,6 +1033,9 @@ void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D, Reader.PendingForwardRefs.erase(D); #endif } + + // Note that we have deserialized a definition. + Reader.PendingDefinitions.insert(D); } else if (DefinitionDecl) { if (DefinitionDecl->DefinitionData) { D->DefinitionData = DefinitionDecl->DefinitionData; @@ -1162,7 +1168,7 @@ void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // Initialize CommonOrPrev before VisitTemplateDecl so that getCommonPtr() // can be used while this is still initializing. - enum RedeclKind { FirstDeclaration, PointsToPrevious }; + enum RedeclKind { FirstDeclaration, FirstInFile, PointsToPrevious }; RedeclKind Kind = (RedeclKind)Record[Idx++]; // Determine the first declaration ID. @@ -1190,7 +1196,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { } break; } - + + case FirstInFile: case PointsToPrevious: { FirstDeclID = ReadDeclID(Record, Idx); DeclID PrevDeclID = ReadDeclID(Record, Idx); @@ -1204,9 +1211,13 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // loaded and attached later on. D->CommonOrPrev = FirstDecl; - // Make a note that we need to wire up this declaration to its - // previous declaration, later. - Reader.PendingPreviousDecls.push_back(std::make_pair(D, PrevDeclID)); + if (Kind == PointsToPrevious) { + // Make a note that we need to wire up this declaration to its + // previous declaration, later. We don't need to do this for the first + // declaration in any given module file, because those will be wired + // together later. + Reader.PendingPreviousDecls.push_back(std::make_pair(D, PrevDeclID)); + } break; } } @@ -1412,7 +1423,7 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) { template void ASTDeclReader::VisitRedeclarable(Redeclarable *D) { - enum RedeclKind { FirstDeclaration = 0, PointsToPrevious }; + enum RedeclKind { FirstDeclaration = 0, FirstInFile, PointsToPrevious }; RedeclKind Kind = (RedeclKind)Record[Idx++]; DeclID FirstDeclID; @@ -1420,7 +1431,8 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable *D) { case FirstDeclaration: FirstDeclID = ThisDeclID; break; - + + case FirstInFile: case PointsToPrevious: { FirstDeclID = ReadDeclID(Record, Idx); DeclID PrevDeclID = ReadDeclID(Record, Idx); @@ -1433,10 +1445,14 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable *D) { // loaded & attached later on. D->RedeclLink = typename Redeclarable::PreviousDeclLink(FirstDecl); - // Make a note that we need to wire up this declaration to its - // previous declaration, later. - Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast(D), - PrevDeclID)); + if (Kind == PointsToPrevious) { + // Make a note that we need to wire up this declaration to its + // previous declaration, later. We don't need to do this for the first + // declaration in any given module file, because those will be wired + // together later. + Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast(D), + PrevDeclID)); + } break; } } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index cb1c6f0476..7ae601810b 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1051,7 +1051,7 @@ void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) { void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // Emit data to initialize CommonOrPrev before VisitTemplateDecl so that // getCommonPtr() can be used while this is still initializing. - enum { FirstDeclaration, PointsToPrevious }; + enum { FirstDeclaration, FirstInFile, PointsToPrevious }; RedeclarableTemplateDecl *Prev = D->getPreviousDeclaration(); RedeclarableTemplateDecl *First = 0; if (!Prev) { @@ -1063,7 +1063,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { Record.push_back(D->isMemberSpecialization()); } else { First = D->getFirstDeclaration(); - Record.push_back(PointsToPrevious); + Record.push_back(Prev->isFromASTFile()? FirstInFile : PointsToPrevious); Writer.AddDeclRef(First, Record); Writer.AddDeclRef(Prev, Record); } @@ -1276,14 +1276,14 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, template void ASTDeclWriter::VisitRedeclarable(Redeclarable *D) { - enum { FirstDeclaration = 0, PointsToPrevious }; + enum { FirstDeclaration = 0, FirstInFile, PointsToPrevious }; T *Prev = D->getPreviousDeclaration(); T *First = D->getFirstDeclaration(); if (!Prev) { Record.push_back(FirstDeclaration); } else { - Record.push_back(PointsToPrevious); + Record.push_back(Prev->isFromASTFile()? FirstInFile : PointsToPrevious); Writer.AddDeclRef(First, Record); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); } diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m index c5da754dfe..6497268c38 100644 --- a/test/Modules/redecl-merge.m +++ b/test/Modules/redecl-merge.m @@ -32,7 +32,7 @@ void g(A *a) { #ifdef __cplusplus void testVector() { - Vector *vec_int; - // FIXME: vec_int.push_back(0); + Vector vec_int; + vec_int.push_back(0); } #endif