From 464b0ca61a558d359795a3e4aa1ae5924ac571d5 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 22 Dec 2011 21:40:42 +0000 Subject: [PATCH] Serialize the AST reader's mapping from canonical declarations to the set of (previously-canonical) declaration IDs to the module file, so that future AST reader instances that load the module know which declarations are merged. This is important in the fairly tricky case where a declaration of an entity, e.g., @class X; occurs before the import of a module that also declares that entity. We merge the declarations, and record the fact that the declaration of X loaded from the module was merged into the (now canonical) declaration of X that we parsed. llvm-svn: 147181 --- .../include/clang/Serialization/ASTBitCodes.h | 5 ++- clang/include/clang/Serialization/ASTReader.h | 20 ++++++++++ clang/include/clang/Serialization/ASTWriter.h | 3 +- clang/lib/Serialization/ASTReader.cpp | 10 +++++ clang/lib/Serialization/ASTReaderDecl.cpp | 38 ++++++++++++++++--- clang/lib/Serialization/ASTWriter.cpp | 22 ++++++++++- .../test/Modules/Inputs/redecl-merge-bottom.h | 2 + clang/test/Modules/Inputs/redecl-merge-left.h | 2 + clang/test/Modules/redecl-merge.m | 7 +++- 9 files changed, 100 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index a4b6b8f45e7e..073ad80d7491 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -452,7 +452,10 @@ namespace clang { /// \brief Record code for an array of all of the (sub)modules that were /// imported by the AST file. - IMPORTED_MODULES = 51 + IMPORTED_MODULES = 51, + + /// \brief Record code for the set of merged declarations in an AST file. + MERGED_DECLARATIONS = 52 }; /// \brief Record types used within a source manager block. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 166ac6682104..1595a0ef61f0 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -690,6 +690,26 @@ private: /// that canonical declaration. MergedDeclsMap MergedDecls; + typedef llvm::DenseMap > + StoredMergedDeclsMap; + + /// \brief A mapping from canonical declaration IDs to the set of additional + /// declaration IDs that have been merged with that canonical declaration. + /// + /// This is the deserialized representation of the entries in MergedDecls. + /// When we query entries in MergedDecls, they will be augmented with entries + /// from StoredMergedDecls. + StoredMergedDeclsMap StoredMergedDecls; + + /// \brief Combine the stored merged declarations for the given canonical + /// declaration into the set of merged declarations. + /// + /// \returns An iterator into MergedDecls that corresponds to the position of + /// the given canonical declaration. + MergedDeclsMap::iterator + combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID); + /// \brief We delay loading the chain of objc categories after recursive /// loading of declarations is finished. std::vector > diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 8791d83d9369..ef2f1ada6f2b 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -415,7 +415,8 @@ private: void WriteDeclContextVisibleUpdate(const DeclContext *DC); void WriteFPPragmaOptions(const FPOptions &Opts); void WriteOpenCLExtensions(Sema &SemaRef); - + void WriteMergedDecls(); + unsigned DeclParmVarAbbrev; unsigned DeclContextLexicalAbbrev; unsigned DeclContextVisibleLookupAbbrev; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 2ac1908ee2fd..440474b587a9 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2407,6 +2407,16 @@ ASTReader::ReadASTBlock(ModuleFile &F) { F.RedeclarationsInfo = (const LocalRedeclarationsInfo *)BlobStart; break; } + + case MERGED_DECLARATIONS: { + for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) { + GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]); + SmallVectorImpl &Decls = StoredMergedDecls[CanonID]; + for (unsigned N = Record[Idx++]; N > 0; --N) + Decls.push_back(getGlobalDeclID(F, Record[Idx++])); + } + break; + } } } Error("premature end of bitstream in AST file"); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 2c8e6ea46634..cb816632bdd9 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -676,9 +676,14 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { } // If this declaration was the canonical declaration, make a note of - // that. - if (IDCanon == ID) - Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID()); + // that. We accept the linear algorithm here because the number of + // unique canonical declarations of an entity should always be tiny. + if (IDCanon == ID) { + SmallVectorImpl &Merged = Reader.MergedDecls[ExistingCanon]; + if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID()) + == Merged.end()) + Merged.push_back(Redecl.getFirstID()); + } } } } @@ -1725,6 +1730,29 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) { } } +ASTReader::MergedDeclsMap::iterator +ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) { + // If we don't have any stored merged declarations, just look in the + // merged declarations set. + StoredMergedDeclsMap::iterator StoredPos = StoredMergedDecls.find(CanonID); + if (StoredPos == StoredMergedDecls.end()) + return MergedDecls.find(Canon); + + // Append the stored merged declarations to the merged declarations set. + MergedDeclsMap::iterator Pos = MergedDecls.find(Canon); + if (Pos == MergedDecls.end()) + Pos = MergedDecls.insert(std::make_pair(Canon, + SmallVector())).first; + Pos->second.append(StoredPos->second.begin(), StoredPos->second.end()); + StoredMergedDecls.erase(StoredPos); + + // Sort and uniquify the set of merged declarations. + llvm::array_pod_sort(Pos->second.begin(), Pos->second.end()); + Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()), + Pos->second.end()); + return Pos; +} + void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) { Decl *previous = GetDecl(ID); ASTDeclReader::attachPreviousDecl(D, previous); @@ -2186,7 +2214,7 @@ static Decl *getMostRecentDecl(Decl *D) { void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) { Decl *D = GetDecl(ID); Decl *CanonDecl = D->getCanonicalDecl(); - + // Determine the set of declaration IDs we'll be searching for. llvm::SmallVector SearchDecls; GlobalDeclID CanonID = 0; @@ -2194,7 +2222,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) { SearchDecls.push_back(ID); // Always first. CanonID = ID; } - MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl); + MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID); if (MergedPos != MergedDecls.end()) SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 97c31b07a37b..feeb27f33892 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2903,6 +2903,25 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) { Stream.EmitRecord(OPENCL_EXTENSIONS, Record); } +void ASTWriter::WriteMergedDecls() { + if (!Chain || Chain->MergedDecls.empty()) + return; + + RecordData Record; + for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(), + IEnd = Chain->MergedDecls.end(); + I != IEnd; ++I) { + DeclID CanonID = I->first->isFromASTFile()? Chain->DeclToID[I->first] + : getDeclID(I->first); + assert(CanonID && "Merged declaration not known?"); + + Record.push_back(CanonID); + Record.push_back(I->second.size()); + Record.append(I->second.begin(), I->second.end()); + } + Stream.EmitRecord(MERGED_DECLARATIONS, Record); +} + //===----------------------------------------------------------------------===// // General Serialization Routines //===----------------------------------------------------------------------===// @@ -3401,7 +3420,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); WriteChainedObjCCategories(); - + WriteMergedDecls(); + if (!LocalRedeclarations.empty()) { // Sort the local redeclarations info by the first declaration ID, // since the reader will be perforing binary searches on this information. diff --git a/clang/test/Modules/Inputs/redecl-merge-bottom.h b/clang/test/Modules/Inputs/redecl-merge-bottom.h index ce4368d08a01..50c191c8b607 100644 --- a/clang/test/Modules/Inputs/redecl-merge-bottom.h +++ b/clang/test/Modules/Inputs/redecl-merge-bottom.h @@ -8,6 +8,8 @@ __import_module__ redecl_merge_right; @class A; +void refers_to_C4(C4*); + #ifdef __cplusplus template class Vector; diff --git a/clang/test/Modules/Inputs/redecl-merge-left.h b/clang/test/Modules/Inputs/redecl-merge-left.h index 7f355e8f9d68..c4789ad0c03b 100644 --- a/clang/test/Modules/Inputs/redecl-merge-left.h +++ b/clang/test/Modules/Inputs/redecl-merge-left.h @@ -22,6 +22,8 @@ void accept_a_C2(C2*); void accept_a_C3(C3*); @class C3; +@class C4; + @class Explicit; int *explicit_func(void); diff --git a/clang/test/Modules/redecl-merge.m b/clang/test/Modules/redecl-merge.m index 930e8df6b87f..ea04037707ed 100644 --- a/clang/test/Modules/redecl-merge.m +++ b/clang/test/Modules/redecl-merge.m @@ -58,13 +58,18 @@ void test_C3(C3 *c3) { C4 *global_C4; __import_module__ redecl_merge_left_left; -void test_C4(C4 *c4) { +void test_C4a(C4 *c4) { global_C4 = c4 = get_a_C4(); accept_a_C4(c4); } __import_module__ redecl_merge_bottom; +void test_C4b() { + if (&refers_to_C4) { + } +} + @implementation B + (B*)create_a_B { return 0; } @end