diff --git a/clang/include/clang/Serialization/ASTDeserializationListener.h b/clang/include/clang/Serialization/ASTDeserializationListener.h index f8114de5f15a..3cccd0572c30 100644 --- a/clang/include/clang/Serialization/ASTDeserializationListener.h +++ b/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -22,7 +22,8 @@ namespace clang { class Decl; class ASTReader; class QualType; - +class MacroDefinition; + class ASTDeserializationListener { protected: virtual ~ASTDeserializationListener() {} @@ -42,6 +43,9 @@ public: virtual void DeclRead(serialization::DeclID ID, const Decl *D) = 0; /// \brief A selector was read from the AST file. virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) = 0; + /// \brief A macro definition was read from the AST file. + virtual void MacroDefinitionRead(serialization::MacroID, + MacroDefinition *MD) = 0; }; } diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index b2f08c183f27..5473b2d5da16 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -829,6 +829,11 @@ public: return static_cast(SelectorsLoaded.size()); } + /// \brief Returns the number of macro definitions found in the chain. + unsigned getTotalNumMacroDefinitions() const { + return static_cast(MacroDefinitionsLoaded.size()); + } + /// \brief Reads a TemplateArgumentLocInfo appropriate for the /// given TemplateArgument kind. TemplateArgumentLocInfo diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 95964e0ea557..528580ec03dc 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -163,7 +163,7 @@ private: /// \brief Offset of each selector within the method pool/selector /// table, indexed by the Selector ID (-1). std::vector SelectorOffsets; - + /// \brief Offsets of each of the macro identifiers into the /// bitstream. /// @@ -172,6 +172,12 @@ private: /// defined. llvm::DenseMap MacroOffsets; + /// \brief The first ID number we can use for our own macro definitions. + serialization::MacroID FirstMacroID; + + /// \brief The decl ID that will be assigned to the next new macro definition. + serialization::MacroID NextMacroID; + /// \brief Mapping from macro definitions (as they occur in the preprocessing /// record) to the macro IDs. llvm::DenseMap @@ -481,7 +487,8 @@ public: void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II); void TypeRead(serialization::TypeIdx Idx, QualType T); void DeclRead(serialization::DeclID ID, const Decl *D); - void SelectorRead(serialization::SelectorID iD, Selector Sel); + void SelectorRead(serialization::SelectorID ID, Selector Sel); + void MacroDefinitionRead(serialization::MacroID ID, MacroDefinition *MD); }; /// \brief AST and semantic-analysis consumer that generates a diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index adb233ac144a..35a8cc9fab23 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1493,19 +1493,29 @@ void ASTReader::ReadMacroRecord(llvm::BitstreamCursor &Stream, uint64_t Offset){ if (PPRec.getPreprocessedEntity(Record[0])) return; - if (Record[1] >= MacroDefinitionsLoaded.size()) { + if (Record[1] > MacroDefinitionsLoaded.size()) { Error("out-of-bounds macro definition record"); return; } - MacroDefinition *MD - = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]), + // Decode the identifier info and then check again; if the macro is + // still defined and associated with the identifier, + IdentifierInfo *II = DecodeIdentifierInfo(Record[4]); + if (!MacroDefinitionsLoaded[Record[1] - 1]) { + MacroDefinition *MD + = new (PPRec) MacroDefinition(II, SourceLocation::getFromRawEncoding(Record[5]), SourceRange( SourceLocation::getFromRawEncoding(Record[2]), SourceLocation::getFromRawEncoding(Record[3]))); - PPRec.SetPreallocatedEntity(Record[0], MD); - MacroDefinitionsLoaded[Record[1]] = MD; + + PPRec.SetPreallocatedEntity(Record[0], MD); + MacroDefinitionsLoaded[Record[1] - 1] = MD; + + if (DeserializationListener) + DeserializationListener->MacroDefinitionRead(Record[1], MD); + } + return; } } @@ -1582,23 +1592,23 @@ void ASTReader::ReadDefinedMacros() { } MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) { - if (ID == 0 || ID >= MacroDefinitionsLoaded.size()) + if (ID == 0 || ID > MacroDefinitionsLoaded.size()) return 0; - if (!MacroDefinitionsLoaded[ID]) { - unsigned Index = ID; + if (!MacroDefinitionsLoaded[ID - 1]) { + unsigned Index = ID - 1; for (unsigned I = 0, N = Chain.size(); I != N; ++I) { PerFileData &F = *Chain[N - I - 1]; if (Index < F.LocalNumMacroDefinitions) { - ReadMacroRecord(F.Stream, F.MacroDefinitionOffsets[Index]); + ReadMacroRecord(F.Stream, F.MacroDefinitionOffsets[Index]); break; } Index -= F.LocalNumMacroDefinitions; } - assert(MacroDefinitionsLoaded[ID] && "Broken chain"); + assert(MacroDefinitionsLoaded[ID - 1] && "Broken chain"); } - return MacroDefinitionsLoaded[ID]; + return MacroDefinitionsLoaded[ID - 1]; } /// \brief If we are loading a relocatable PCH file, and the filename is diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ef8c52f4be1c..c89680e2a6ec 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1360,11 +1360,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { if (MacroDefinition *MD = dyn_cast(*E)) { // Record this macro definition's location. MacroID ID = getMacroDefinitionID(MD); - if (ID != MacroDefinitionOffsets.size()) { - if (ID > MacroDefinitionOffsets.size()) - MacroDefinitionOffsets.resize(ID + 1); + + // Don't write the macro definition if it is from another AST file. + if (ID < FirstMacroID) + continue; + + unsigned Position = ID - FirstMacroID; + if (Position != MacroDefinitionOffsets.size()) { + if (Position > MacroDefinitionOffsets.size()) + MacroDefinitionOffsets.resize(Position + 1); - MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo(); + MacroDefinitionOffsets[Position] = Stream.GetCurrentBitNo(); } else MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); @@ -2206,7 +2212,8 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) : Stream(Stream), Chain(0), FirstDeclID(1), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), FirstIdentID(1), NextIdentID(FirstIdentID), FirstSelectorID(1), - NextSelectorID(FirstSelectorID), CollectedStmts(&StmtsToEmit), + NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID), + CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) { } @@ -2439,10 +2446,12 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, FirstTypeID += Chain->getTotalNumTypes(); FirstIdentID += Chain->getTotalNumIdentifiers(); FirstSelectorID += Chain->getTotalNumSelectors(); + FirstMacroID += Chain->getTotalNumMacroDefinitions(); NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; NextSelectorID = FirstSelectorID; + NextMacroID = FirstMacroID; ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; @@ -2733,7 +2742,7 @@ MacroID ASTWriter::getMacroDefinitionID(MacroDefinition *MD) { MacroID &ID = MacroDefinitions[MD]; if (ID == 0) - ID = MacroDefinitions.size(); + ID = NextMacroID++; return ID; } @@ -3106,6 +3115,7 @@ void ASTWriter::SetReader(ASTReader *Reader) { FirstTypeID == NextTypeID && FirstIdentID == NextIdentID && FirstSelectorID == NextSelectorID && + FirstMacroID == NextMacroID && "Setting chain after writing has started."); Chain = Reader; } @@ -3125,3 +3135,8 @@ void ASTWriter::DeclRead(DeclID ID, const Decl *D) { void ASTWriter::SelectorRead(SelectorID ID, Selector S) { SelectorIDs[S] = ID; } + +void ASTWriter::MacroDefinitionRead(serialization::MacroID ID, + MacroDefinition *MD) { + MacroDefinitions[MD] = ID; +} diff --git a/clang/test/PCH/chain-macro-override.c b/clang/test/PCH/chain-macro-override.c index 449ed8c7a0c4..8e208815fb26 100644 --- a/clang/test/PCH/chain-macro-override.c +++ b/clang/test/PCH/chain-macro-override.c @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: %clang_cc1 -include %S/Inputs/chain-macro-override1.h -include %S/Inputs/chain-macro-override2.h -fsyntax-only -verify %s +// RUN: %clang_cc1 -include %S/Inputs/chain-macro-override1.h -include %S/Inputs/chain-macro-override2.h -fsyntax-only -verify -detailed-preprocessing-record %s // Test with pch. -// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-macro-override1.h -// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-macro-override2.h -include-pch %t1 -chained-pch +// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-macro-override1.h -detailed-preprocessing-record +// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-macro-override2.h -include-pch %t1 -chained-pch -detailed-preprocessing-record // RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s int foo() { diff --git a/clang/test/PCH/chain-macro.c b/clang/test/PCH/chain-macro.c index b4dcdfe644d7..68b18deb0811 100644 --- a/clang/test/PCH/chain-macro.c +++ b/clang/test/PCH/chain-macro.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -emit-pch -o %t1 %S/Inputs/chain-macro1.h -// RUN: %clang_cc1 -emit-pch -o %t2 %S/Inputs/chain-macro2.h -include-pch %t1 -chained-pch +// RUN: %clang_cc1 -emit-pch -o %t1 -detailed-preprocessing-record %S/Inputs/chain-macro1.h +// RUN: %clang_cc1 -emit-pch -o %t2 -detailed-preprocessing-record %S/Inputs/chain-macro2.h -include-pch %t1 -chained-pch // RUN: %clang_cc1 -fsyntax-only -verify -include-pch %t2 %s // RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s