From e80b31f7f9be6a34fa8db3f3ca19f586b04b5a82 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 19 Dec 2011 19:00:47 +0000 Subject: [PATCH] Once we have fully deserialized a redeclaration chain for something with a definition pointer (e.g., C++ and Objective-C classes), zip through the redeclaration chain to make sure that all of the declarations point to the definition data. As part of this, realized again why the first redeclaration of an entity in a file is important, and brought back that idea. llvm-svn: 146886 --- clang/include/clang/AST/DeclObjC.h | 1 + clang/include/clang/Serialization/ASTReader.h | 5 ++- clang/lib/Serialization/ASTReader.cpp | 23 +++++++++++ clang/lib/Serialization/ASTReaderDecl.cpp | 38 +++++++++++++------ clang/lib/Serialization/ASTWriterDecl.cpp | 8 ++-- clang/test/Modules/redecl-merge.m | 4 +- 6 files changed, 61 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 7a5a715eab6d..6a0b6acc87dd 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/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/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 10ed5dceea5f..507b75f33cee 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/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/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fc49e88a50ad..2b417522bccb 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 35cd8478d5be..bd6a5a5e06d3 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/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/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index cb1c6f0476ea..7ae601810b92 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/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/clang/test/Modules/redecl-merge.m b/clang/test/Modules/redecl-merge.m index c5da754dfe0f..6497268c3840 100644 --- a/clang/test/Modules/redecl-merge.m +++ b/clang/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