diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 41ef74ee0ab4f408fd05894d27a06b1943c96b04..cce6916b4e37c685e55e7ea471fcc947d28434cd 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -452,7 +452,11 @@ namespace clang { /// \brief Record code for an array of all of the (sub)modules that were /// imported by the AST file. - IMPORTED_MODULES + IMPORTED_MODULES, + + /// \brief Record code for the array describing the first/last local + /// redeclarations of each entity. + LOCAL_REDECLARATIONS }; /// \brief Record types used within a source manager block. @@ -1190,6 +1194,33 @@ namespace clang { CTOR_INITIALIZER_INDIRECT_MEMBER }; + /// \brief Describes the redeclarations of a declaration. + struct LocalRedeclarationsInfo { + DeclID FirstID; // The ID of the first declaration + DeclID FirstLocalID; // The ID of the first local declaration + DeclID LastLocalID; // The ID of the last local declaration + + friend bool operator<(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID < Y.FirstID; + } + + friend bool operator>(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID > Y.FirstID; + } + + friend bool operator<=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID <= Y.FirstID; + } + + friend bool operator>=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID >= Y.FirstID; + } + }; + /// @} } } // end namespace clang diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 0947dfc4eb758a4655bf6295ee70f16f17751496..10ed5dceea5fe82a7a5b2d926e1f3ca36e28fbbf 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -674,6 +674,17 @@ private: /// deeply nested calls when there are many redeclarations. std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls; + /// \brief The list of redeclaration chains that still need to be + /// reconstructed. + /// + /// Each element is the global declaration ID of the first declaration in + /// the chain. Elements in this vector should be unique; use + /// PendingDeclChainsKnown to ensure uniqueness. + llvm::SmallVector<serialization::DeclID, 16> PendingDeclChains; + + /// \brief Keeps track of the elements added to PendingDeclChains. + llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown; + /// \brief We delay loading the chain of objc categories after recursive /// loading of declarations is finished. std::vector<std::pair<ObjCInterfaceDecl *, serialization::DeclID> > @@ -759,6 +770,7 @@ private: RecordLocation DeclCursorForID(serialization::DeclID ID, unsigned &RawLocation); void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); + void loadPendingDeclChain(serialization::GlobalDeclID ID); void loadObjCChainedCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D); @@ -1028,6 +1040,15 @@ public: return cast_or_null<T>(GetLocalDecl(F, LocalID)); } + /// \brief Map a global declaration ID into the declaration ID used to + /// refer to this declaration within the given module fule. + /// + /// \returns the global ID of the given declaration as known in the given + /// module file. + serialization::DeclID + mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + serialization::DeclID GlobalID); + /// \brief Reads a declaration ID from the given position in a record in the /// given module. /// diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index ab0d1ef3d9fec0d7a4bd4fdc5df67b22989533a0..fd581bc4521ff6f382de696a6630998be0a99991 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -312,7 +312,11 @@ private: /// serialized again. In this case, it is registered here, so that the reader /// knows to read the updated version. SmallVector<ReplacedDeclInfo, 16> ReplacedDecls; - + + /// \brief The list of local redeclarations of entities that were + /// first declared non-locally. + SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclarations; + /// \brief Statements that we've encountered while serializing a /// declaration or type. SmallVector<Stmt *, 16> StmtsToEmit; diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index 16d9779e04deb32b158809293c6d0d9bc9272e61..cbac5cd148fd83ba0fbbb686a0db2d3059f65891 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -260,6 +260,15 @@ public: /// \brief Remapping table for declaration IDs in this module. ContinuousRangeMap<uint32_t, int, 2> DeclRemap; + /// \brief Mapping from the module files that this module file depends on + /// to the base declaration ID for that module as it is understood within this + /// module. + /// + /// This is effectively a reverse global-to-local mapping for declaration + /// IDs, so that we can interpret a true global ID (for this translation unit) + /// as a local ID (for this module file). + llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs; + /// \brief The number of C++ base specifier sets in this AST file. unsigned LocalNumCXXBaseSpecifiers; @@ -286,6 +295,13 @@ public: /// \brief Array of file-level DeclIDs sorted by file. const serialization::DeclID *FileSortedDecls; + /// \brief Array of redeclaration information within this module file, + /// sorted by the first declaration ID. + const serialization::LocalRedeclarationsInfo *RedeclarationsInfo; + + /// \brief The number of redeclaration info entries in RedeclarationsInfo. + unsigned LocalNumRedeclarationsInfos; + // === Types === /// \brief The number of types in this AST file. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a1713ee6850179f53f21ae167332feb254248430..bc1cb3fca63bd9db1b4f6493aa52c11f288fe65d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1063,6 +1063,8 @@ static NamedDecl *getPreviousDeclaration(NamedDecl *D) { return FD->getPreviousDeclaration(); if (RedeclarableTemplateDecl *RTD = dyn_cast<RedeclarableTemplateDecl>(D)) return RTD->getPreviousDeclaration(); + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + return TD->getPreviousDeclaration(); if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) return ID->getPreviousDeclaration(); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3af04c2bc8addc1825a624c106e6c80abf0650fe..64414c91675b53635227852a1adf9291a6870048 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1846,6 +1846,10 @@ ASTReader::ReadASTBlock(ModuleFile &F) { F.DeclRemap.insert(std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID)); + // Introduce the global -> local mapping for declarations within this + // module. + F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID; + DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); } break; @@ -2125,6 +2129,9 @@ ASTReader::ReadASTBlock(ModuleFile &F) { TypeRemap.insert(std::make_pair(TypeIndexOffset, OM->BaseTypeIndex - TypeIndexOffset)); + + // Global -> local mappings. + F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; } break; } @@ -2396,7 +2403,17 @@ ASTReader::ReadASTBlock(ModuleFile &F) { } } break; + } + + case LOCAL_REDECLARATIONS: { + if (F.LocalNumRedeclarationsInfos != 0) { + Error("duplicate LOCAL_REDECLARATIONS record in AST file"); + return Failure; + } + F.LocalNumRedeclarationsInfos = Record[0]; + F.RedeclarationsInfo = (const LocalRedeclarationsInfo *)BlobStart; + break; } } } @@ -4568,6 +4585,23 @@ Decl *ASTReader::GetDecl(DeclID ID) { return DeclsLoaded[Index]; } +DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + DeclID GlobalID) { + if (GlobalID < NUM_PREDEF_DECL_IDS) + return GlobalID; + + GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + ModuleFile *Owner = I->second; + + llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos + = M.GlobalToLocalDeclIDs.find(Owner); + if (Pos == M.GlobalToLocalDeclIDs.end()) + return 0; + + return GlobalID - Owner->BaseDeclID + Pos->second; +} + serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordData &Record, unsigned &Idx) { @@ -6027,6 +6061,7 @@ void ASTReader::ClearSwitchCaseIDs() { void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingPreviousDecls.empty() || + !PendingDeclChains.empty() || !PendingChainedObjCCategories.empty()) { // If any identifiers with corresponding top-level declarations have @@ -6044,6 +6079,12 @@ void ASTReader::finishPendingActions() { PendingPreviousDecls.pop_front(); } + // Load pending declaration chains. + for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { + loadPendingDeclChain(PendingDeclChains[I]); + } + PendingDeclChains.clear(); + for (std::vector<std::pair<ObjCInterfaceDecl *, serialization::DeclID> >::iterator I = PendingChainedObjCCategories.begin(), @@ -6082,6 +6123,7 @@ void ASTReader::FinishedDeserializing() { } finishPendingActions(); + PendingDeclChainsKnown.clear(); assert(PendingForwardRefs.size() == 0 && "Some forward refs did not get linked to the definition!"); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 5e5f1cb6fe6505e700b55fed5bfa6bca74083ccd..69f309aef0d0b99c4be2d626cad087ccb6c9cb53 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -114,6 +114,7 @@ namespace clang { TypeIDForTypeDecl(0) { } static void attachPreviousDecl(Decl *D, Decl *previous); + static void attachLatestDecl(Decl *D, Decl *latest); void Visit(Decl *D); @@ -307,11 +308,13 @@ void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { } void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) { + VisitRedeclarable(TD); VisitTypeDecl(TD); TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); } void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) { + VisitRedeclarable(TD); VisitTypeDecl(TD); TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); } @@ -1398,73 +1401,39 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) { template <typename T> void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { - enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest }; + enum RedeclKind { FirstInFile, PointsToPrevious }; RedeclKind Kind = (RedeclKind)Record[Idx++]; + + // Read the first declaration ID, and note that we need to reconstruct + // the redeclaration chain once we hit the top level. + DeclID FirstDeclID = ReadDeclID(Record, Idx); + if (Reader.PendingDeclChainsKnown.insert(FirstDeclID)) + Reader.PendingDeclChains.push_back(FirstDeclID); + + T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID)); + switch (Kind) { - default: - llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or" - " messed up reading"); - case NoRedeclaration: + case FirstInFile: + if (FirstDecl != D) + D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl); break; + case PointsToPrevious: { DeclID PreviousDeclID = ReadDeclID(Record, Idx); - DeclID FirstDeclID = ReadDeclID(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. - T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID)); D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl); - if (PreviousDeclID != FirstDeclID) - Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D), - PreviousDeclID)); - - // If the first declaration in the chain is in an inconsistent - // state where it thinks that it is the only declaration, fix its - // redeclaration link now to point at this declaration, so that we have a - // proper redeclaration chain. - if (FirstDecl->RedeclLink.getPointer() == FirstDecl) { - FirstDecl->RedeclLink - = typename Redeclarable<T>::LatestDeclLink(static_cast<T*>(D)); - } - break; - } - case PointsToLatest: { - T *LatestDecl = ReadDeclAs<T>(Record, Idx); - D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(LatestDecl); - // If the latest declaration in the chain is in an inconsistent - // state where it thinks that it is the only declaration, fix its - // redeclaration link now to point at this declaration, so that we have a - // proper redeclaration chain. - if (LatestDecl->RedeclLink.getPointer() == LatestDecl) { - LatestDecl->RedeclLink - = typename Redeclarable<T>::PreviousDeclLink(static_cast<T*>(D)); - } + // 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<T*>(D), + PreviousDeclID)); break; } } - - assert(!(Kind == PointsToPrevious && - Reader.FirstLatestDeclIDs.find(ThisDeclID) != - Reader.FirstLatestDeclIDs.end()) && - "This decl is not first, it should not be in the map"); - if (Kind == PointsToPrevious) - return; - - // This decl is a first one and the latest declaration that it points to is in - // the same AST file. However, if this actually needs to point to a - // redeclaration in another AST file, we need to update it by checking the - // FirstLatestDeclIDs map which tracks this kind of decls. - assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) && - "Invalid ThisDeclID ?"); - ASTReader::FirstLatestDeclIDMap::iterator I - = Reader.FirstLatestDeclIDs.find(ThisDeclID); - if (I != Reader.FirstLatestDeclIDs.end()) { - Decl *NewLatest = Reader.GetDecl(I->second); - D->RedeclLink - = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest)); - } } //===----------------------------------------------------------------------===// @@ -1564,7 +1533,9 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { FD->RedeclLink.setPointer(cast<FunctionDecl>(previous)); } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { VD->RedeclLink.setPointer(cast<VarDecl>(previous)); - } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(previous)) { + } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + TD->RedeclLink.setPointer(cast<TypedefNameDecl>(previous)); + } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous)); } else { RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D); @@ -1572,6 +1543,31 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { } } +void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) { + assert(D && Latest); + if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + TD->RedeclLink + = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest)); + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + FD->RedeclLink + = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest)); + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + VD->RedeclLink + = Redeclarable<VarDecl>::LatestDeclLink(cast<VarDecl>(Latest)); + } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + TD->RedeclLink + = Redeclarable<TypedefNameDecl>::LatestDeclLink( + cast<TypedefNameDecl>(Latest)); + } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + ID->RedeclLink + = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink( + cast<ObjCInterfaceDecl>(Latest)); + } else { + RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D); + TD->getCommonPtr()->Latest = cast<RedeclarableTemplateDecl>(Latest); + } +} + void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) { Decl *previous = GetDecl(ID); ASTDeclReader::attachPreviousDecl(D, previous); @@ -1903,6 +1899,152 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { } } +namespace { + struct CompareLocalRedeclarationsInfoToID { + bool operator()(const LocalRedeclarationsInfo &X, DeclID Y) { + return X.FirstID < Y; + } + + bool operator()(DeclID X, const LocalRedeclarationsInfo &Y) { + return X < Y.FirstID; + } + + bool operator()(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID < Y.FirstID; + } + bool operator()(DeclID X, DeclID Y) { + return X < Y; + } + }; + + class RedeclChainVisitor { + ASTReader &Reader; + DeclID GlobalFirstID; + llvm::SmallVector<std::pair<Decl *, Decl *>, 4> Chains; + + public: + RedeclChainVisitor(ASTReader &Reader, DeclID GlobalFirstID) + : Reader(Reader), GlobalFirstID(GlobalFirstID) { } + + static bool visit(ModuleFile &M, bool Preorder, void *UserData) { + if (Preorder) + return false; + + return static_cast<RedeclChainVisitor *>(UserData)->visit(M); + } + + bool visit(ModuleFile &M) { + // Map global ID of the first declaration down to the local ID + // used in this module file. + DeclID FirstID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalFirstID); + if (!FirstID) + return false; + + // Perform a binary search to find the local redeclarations for this + // declaration (if any). + const LocalRedeclarationsInfo *Result + = std::lower_bound(M.RedeclarationsInfo, + M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos, + FirstID, CompareLocalRedeclarationsInfoToID()); + if (Result == M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos || + Result->FirstID != FirstID) + return false; + + // Dig out the starting/ending declarations. + Decl *FirstLocalDecl = Reader.GetLocalDecl(M, Result->FirstLocalID); + Decl *LastLocalDecl = Reader.GetLocalDecl(M, Result->LastLocalID); + if (!FirstLocalDecl || !LastLocalDecl) + return false; + + // Append this redeclaration chain to the list. + Chains.push_back(std::make_pair(FirstLocalDecl, LastLocalDecl)); + return false; + } + + ArrayRef<std::pair<Decl *, Decl *> > getChains() const { + return Chains; + } + + void addParsed(Decl *FirstParsedDecl, Decl *LastParsedDecl) { + Chains.push_back(std::make_pair(FirstParsedDecl, LastParsedDecl)); + } + }; +} + +/// \brief Retrieve the previous declaration to D. +static Decl *getPreviousDecl(Decl *D) { + if (TagDecl *TD = dyn_cast<TagDecl>(D)) + return TD->getPreviousDeclaration(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getPreviousDeclaration(); + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->getPreviousDeclaration(); + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + return TD->getPreviousDeclaration(); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return ID->getPreviousDeclaration(); + + return cast<RedeclarableTemplateDecl>(D)->getPreviousDeclaration(); +} + +/// \brief Retrieve the most recent declaration of D. +static Decl *getMostRecentDecl(Decl *D) { + if (TagDecl *TD = dyn_cast<TagDecl>(D)) + return TD->getMostRecentDeclaration(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getMostRecentDeclaration(); + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->getMostRecentDeclaration(); + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + return TD->getMostRecentDeclaration(); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return ID->getMostRecentDeclaration(); + + return cast<RedeclarableTemplateDecl>(D)->getMostRecentDeclaration(); +} + +void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) { + // Build up the list of redeclaration chains. + RedeclChainVisitor Visitor(*this, ID); + ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor); + + // Retrieve the chains. + ArrayRef<std::pair<Decl *, Decl *> > Chains = Visitor.getChains(); + if (Chains.empty()) + return; + + // FIXME: Splice local (not from AST file) declarations into the list, + // rather than always re-ordering them. + Decl *CanonDecl = GetDecl(ID); + + // Capture all of the parsed declarations and put them at the end. + Decl *MostRecent = getMostRecentDecl(CanonDecl); + Decl *FirstParsed = MostRecent; + if (CanonDecl != MostRecent && !MostRecent->isFromASTFile()) { + Decl *Current = MostRecent; + while (Decl *Prev = getPreviousDecl(Current)) { + if (Prev->isFromASTFile()) { + Current = Prev; + continue; + } + + // Chain all of the parsed declarations together. + ASTDeclReader::attachPreviousDecl(FirstParsed, Prev); + FirstParsed = Prev; + Current = Prev; + } + + Visitor.addParsed(FirstParsed, MostRecent); + } + + // Hook up the separate chains. + Chains = Visitor.getChains(); + for (unsigned I = 1, N = Chains.size(); I != N; ++I) + ASTDeclReader::attachPreviousDecl(Chains[I].first, Chains[I-1].second); + ASTDeclReader::attachLatestDecl(CanonDecl, Chains.back().second); +} + namespace { /// \brief Given an ObjC interface, goes through the modules and links to the /// interface all the categories for it. diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index b3f76f749457c6e9e953f9734aa2ceb320c72c94..bb2b1cb5b082d5dde64809fc79fc9383ee524152 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -798,7 +798,8 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(KNOWN_NAMESPACES); RECORD(MODULE_OFFSET_MAP); RECORD(SOURCE_MANAGER_LINE_TABLE); - + RECORD(LOCAL_REDECLARATIONS); + // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); @@ -3411,6 +3412,25 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteDeclReplacementsBlock(); WriteChainedObjCCategories(); + if (!LocalRedeclarations.empty()) { + // Sort the local redeclarations info by the first declaration ID, + // since the reader will be perforing binary searches on this information. + llvm::array_pod_sort(LocalRedeclarations.begin(),LocalRedeclarations.end()); + + llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(LOCAL_REDECLARATIONS); + Record.push_back(LocalRedeclarations.size()); + Stream.EmitRecordWithBlob(AbbrevID, Record, + reinterpret_cast<char*>(LocalRedeclarations.data()), + LocalRedeclarations.size() * sizeof(LocalRedeclarationsInfo)); + } + // Some simple statistics Record.clear(); Record.push_back(NumStatements); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 9b74aaeae457e575d845cd43cee02823db7521e8..6c6428d55a806e94217785f334a43883b7f91489 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -125,6 +125,30 @@ namespace clang { }; } +static bool isFirstDeclInFile(Decl *D) { + // FIXME: There must be a better way to abstract Redeclarable<T> into a + // more-general "redeclarable type". + if (TagDecl *Tag = dyn_cast<TagDecl>(D)) + return !Tag->getPreviousDeclaration() || + Tag->getPreviousDeclaration()->isFromASTFile(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return !FD->getPreviousDeclaration() || + FD->getPreviousDeclaration()->isFromASTFile(); + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + return !VD->getPreviousDeclaration() || + VD->getPreviousDeclaration()->isFromASTFile(); + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + return !TD->getPreviousDeclaration() || + TD->getPreviousDeclaration()->isFromASTFile(); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return !ID->getPreviousDeclaration() || + ID->getPreviousDeclaration()->isFromASTFile(); + + RedeclarableTemplateDecl *RTD = cast<RedeclarableTemplateDecl>(D); + return !RTD->getPreviousDeclaration() || + RTD->getPreviousDeclaration()->isFromASTFile(); +} + void ASTDeclWriter::Visit(Decl *D) { DeclVisitor<ASTDeclWriter>::Visit(D); @@ -177,13 +201,14 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { } void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { + VisitRedeclarable(D); VisitTypeDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && - D->RedeclLink.getNext() == D && + isFirstDeclInFile(D) && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && @@ -196,6 +221,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { } void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) { + VisitRedeclarable(D); VisitTypeDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Code = serialization::DECL_TYPEALIAS; @@ -234,7 +260,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && - D->RedeclLink.getNext() == D && + isFirstDeclInFile(D) && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && @@ -258,7 +284,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && - D->RedeclLink.getNext() == D && + isFirstDeclInFile(D) && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && @@ -701,7 +727,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->isModulePrivate() && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && - D->RedeclLink.getNext() == D && + isFirstDeclInFile(D) && !D->hasCXXDirectInitializer() && D->getInit() == 0 && !isa<ParmVarDecl>(D) && @@ -1267,30 +1293,24 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, template <typename T> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { - enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest }; - if (D->RedeclLink.getNext() == D) { - Record.push_back(NoRedeclaration); - } else { - 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); - } - } - + enum { FirstInFile, PointsToPrevious }; T *First = D->getFirstDeclaration(); - T *ThisDecl = static_cast<T*>(D); - // If this is a most recent redeclaration that is pointed to by a first decl - // in a chained PCH, keep track of the association with the map so we can - // update the first decl during AST reading. - if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl && - First->isFromASTFile() && !ThisDecl->isFromASTFile()) { - assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end() - && "The latest is already set"); - Writer.FirstLatestDecls[First] = ThisDecl; + if (!D->getPreviousDeclaration() || + D->getPreviousDeclaration()->isFromASTFile()) { + Record.push_back(FirstInFile); + Writer.AddDeclRef(First, Record); + + // Capture the set of redeclarations in this file. + LocalRedeclarationsInfo LocalInfo = { + Writer.GetDeclRef(First), + Writer.GetDeclRef(static_cast<T*>(D)), + Writer.GetDeclRef(D->getMostRecentDeclaration()) + }; + Writer.LocalRedeclarations.push_back(LocalInfo); + } else { + Record.push_back(PointsToPrevious); + Writer.AddDeclRef(First, Record); + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); } } @@ -1374,7 +1394,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM)); // Redeclarable - Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + Abv->Add(BitCodeAbbrevOp(0)); // First in file + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext @@ -1421,7 +1442,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD)); // Redeclarable - Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + Abv->Add(BitCodeAbbrevOp(0)); // First in file + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext @@ -1462,7 +1484,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR)); // Redeclarable - Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + Abv->Add(BitCodeAbbrevOp(0)); // First in file + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext @@ -1511,6 +1534,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { // Abbreviation for DECL_TYPEDEF Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF)); + // Redeclarable + Abv->Add(BitCodeAbbrevOp(0)); // First in file + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext @@ -1538,7 +1564,8 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR)); // Redeclarable - Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + Abv->Add(BitCodeAbbrevOp(0)); // First in file + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index 11e7243cd51ba7fe8e9242ec2bf1b1e6e336f694..1298714dd068e3e635a4c233d7147fa9ef679b8b 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -35,7 +35,7 @@ ModuleFile::ModuleFile(ModuleKind Kind) SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), DeclOffsets(0), BaseDeclID(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), - FileSortedDecls(0), + FileSortedDecls(0), RedeclarationsInfo(0), LocalNumRedeclarationsInfos(0), LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0) {} diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index f7cc7d4b515381ce80632d38b5c273312e2519b6..b101c01567d694db6282262e44ca93683b4e6ab2 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -41,4 +41,20 @@ module decldef { explicit module Decl { header "decl.h" } explicit module Decl2 { header "decl2.h" } explicit module Def { header "def.h" } -} \ No newline at end of file +} + +module redecl_merge_top { + header "redecl-merge-top.h" +} +module redecl_merge_left { + header "redecl-merge-left.h" + export * +} +module redecl_merge_right { + header "redecl-merge-right.h" + export * +} +module redecl_merge_bottom { + header "redecl-merge-bottom.h" + export * +} diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h new file mode 100644 index 0000000000000000000000000000000000000000..e45e0dea0477ec1f1d3672533e6dc31b0257e357 --- /dev/null +++ b/test/Modules/Inputs/redecl-merge-bottom.h @@ -0,0 +1,4 @@ +__import_module__ redecl_merge_left; +__import_module__ redecl_merge_right; + +@class A; diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h new file mode 100644 index 0000000000000000000000000000000000000000..085892234818cd04796988109c5d45c4fef7335a --- /dev/null +++ b/test/Modules/Inputs/redecl-merge-left.h @@ -0,0 +1,7 @@ +__import_module__ redecl_merge_top; + +@class A; + +@class A; + +@class A; diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h new file mode 100644 index 0000000000000000000000000000000000000000..266146c9953e8fff73a29738377314daa056bfe8 --- /dev/null +++ b/test/Modules/Inputs/redecl-merge-right.h @@ -0,0 +1,9 @@ +__import_module__ redecl_merge_top; + +@interface Super +@end + +@interface A : Super +- (Super*)init; +@end + diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h new file mode 100644 index 0000000000000000000000000000000000000000..886436cdda8670d59a7aec93dbb4b0055ba7e683 --- /dev/null +++ b/test/Modules/Inputs/redecl-merge-top.h @@ -0,0 +1,5 @@ +@class A; + +@class A; + +@class A; diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m new file mode 100644 index 0000000000000000000000000000000000000000..40c6aaf0fffa49a2fbef6f9b5fb0932d8d430637 --- /dev/null +++ b/test/Modules/redecl-merge.m @@ -0,0 +1,20 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodule-cache-path %t -I %S/Inputs %s -verify +__import_module__ redecl_merge_left; +__import_module__ redecl_merge_right; + +@implementation A +- (Super*)init { return self; } +@end + +void f(A *a) { + [a init]; +} + +@class A; + +__import_module__ redecl_merge_bottom; + +void g(A *a) { + [a init]; +} diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp index af0a23afea9f1b06519b26ff1937a038e0040ff5..c42ee7d39eeb8012bf44fce285062d6a96199388 100644 --- a/test/PCH/chain-cxx.cpp +++ b/test/PCH/chain-cxx.cpp @@ -44,6 +44,8 @@ const int TS3<T>::value; // Instantiate struct, but not value. struct instantiate : TS3<int> {}; +// Typedef +typedef int Integer; //===----------------------------------------------------------------------===// #elif not defined(HEADER2) @@ -97,6 +99,9 @@ struct B : A { }; // Instantiate TS3's member. static const int ts3m1 = TS3<int>::value; +// Redefinition of typedef +typedef int Integer; + //===----------------------------------------------------------------------===// #else //===----------------------------------------------------------------------===// @@ -122,6 +127,7 @@ void test() { TS2int ts2; B b; + Integer i = 17; } // Should have remembered that there is a definition.