From ffaab3e2bb13991bb3357e80f14bcae3745b2347 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Fri, 30 Jul 2010 00:29:29 +0000 Subject: [PATCH] Make macro weirdness in chained PCH work. This required changing the way PCHReader and PCHWriter are initialized to correctly pick up all initializer. On the upside, this means that there is far less repetition in the dependent PCH now. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109823 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTConsumer.h | 9 +++- include/clang/Basic/IdentifierTable.h | 48 +++++++++++-------- include/clang/Frontend/ASTConsumers.h | 3 +- include/clang/Frontend/CompilerInstance.h | 12 ++--- .../Frontend/PCHDeserializationListener.h | 4 ++ include/clang/Frontend/PCHReader.h | 11 +++-- include/clang/Frontend/PCHWriter.h | 3 +- lib/Basic/IdentifierTable.cpp | 1 + lib/Frontend/CompilerInstance.cpp | 15 +++--- lib/Frontend/FrontendAction.cpp | 13 +++-- lib/Frontend/FrontendActions.cpp | 6 +-- lib/Frontend/GeneratePCH.cpp | 19 +++++--- lib/Frontend/PCHReader.cpp | 29 ++++++++--- lib/Frontend/PCHWriter.cpp | 36 ++++++++------ test/PCH/Inputs/chain-macro-override1.h | 4 ++ test/PCH/Inputs/chain-macro-override2.h | 4 ++ test/PCH/chain-macro-override.c | 13 +++++ 17 files changed, 153 insertions(+), 77 deletions(-) create mode 100644 test/PCH/Inputs/chain-macro-override1.h create mode 100644 test/PCH/Inputs/chain-macro-override2.h create mode 100644 test/PCH/chain-macro-override.c diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index 06113954fc..b01f6c6001 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -18,9 +18,10 @@ namespace clang { class ASTContext; class CXXRecordDecl; class DeclGroupRef; - class TagDecl; class HandleTagDeclDefinition; + class PCHDeserializationListener; // layering violation because void* is ugly class SemaConsumer; // layering violation required for safe SemaConsumer + class TagDecl; class VarDecl; /// ASTConsumer - This is an abstract interface that should be implemented by @@ -80,6 +81,12 @@ public: /// it was actually used. virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {} + /// \brief If the consumer is interested in entities being deserialized from + /// PCH, it should return a pointer to a PCHDeserializationListener here. + /// + /// The return type is void* because PCHDS lives in Frontend. + virtual PCHDeserializationListener *GetPCHDeserializationListener() { return 0; } + /// PrintStats - If desired, print any statistics. virtual void PrintStats() {} diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 6b8bcdc52f..c8642a1ac5 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -59,7 +59,9 @@ class IdentifierInfo { bool IsPoisoned : 1; // True if identifier is poisoned. bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword. bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier". - // 9 bits left in 32-bit word. + bool IsFromPCH : 1; // True if identfier first appeared in a PCH + // and wasn't modified since. + // 8 bits left in 32-bit word. void *FETokenInfo; // Managed by the language front-end. llvm::StringMapEntry *Entry; @@ -125,6 +127,7 @@ public: NeedsHandleIdentifier = 1; else RecomputeNeedsHandleIdentifier(); + IsFromPCH = false; } /// get/setTokenID - If this is a source-language token (e.g. 'for'), this API @@ -186,6 +189,7 @@ public: NeedsHandleIdentifier = 1; else RecomputeNeedsHandleIdentifier(); + IsFromPCH = false; } /// isPoisoned - Return true if this token has been poisoned. @@ -213,6 +217,12 @@ public: /// know that HandleIdentifier will not affect the token. bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; } + /// isFromPCH - Return true if the identifier in its current state was loaded + /// from a PCH file. + bool isFromPCH() const { return IsFromPCH; } + + void setIsFromPCH(bool FromPCH = true) { IsFromPCH = FromPCH; } + private: /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does /// several special (but rare) things to identifiers of various sorts. For @@ -321,35 +331,33 @@ public: return get(llvm::StringRef(Name, NameLen)); } - /// \brief Creates a new IdentifierInfo from the given string. + /// \brief Gets an IdentifierInfo for the given name without consulting + /// external sources. /// - /// This is a lower-level version of get() that requires that this - /// identifier not be known previously and that does not consult an - /// external source for identifiers. In particular, external - /// identifier sources can use this routine to build IdentifierInfo - /// nodes and then introduce additional information about those - /// identifiers. - IdentifierInfo &CreateIdentifierInfo(const char *NameStart, - const char *NameEnd) { + /// This is a version of get() meant for external sources that want to + /// introduce or modify an identifier. If they called get(), they would + /// likely end up in a recursion. + IdentifierInfo &getOwn(const char *NameStart, const char *NameEnd) { llvm::StringMapEntry &Entry = HashTable.GetOrCreateValue(NameStart, NameEnd); IdentifierInfo *II = Entry.getValue(); - assert(!II && "IdentifierInfo already exists"); + if (!II) { - // Lookups failed, make a new IdentifierInfo. - void *Mem = getAllocator().Allocate(); - II = new (Mem) IdentifierInfo(); - Entry.setValue(II); + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate(); + II = new (Mem) IdentifierInfo(); + Entry.setValue(II); - // Make sure getName() knows how to find the IdentifierInfo - // contents. - II->Entry = &Entry; + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + } return *II; } - IdentifierInfo &CreateIdentifierInfo(llvm::StringRef Name) { - return CreateIdentifierInfo(Name.begin(), Name.end()); + IdentifierInfo &getOwn(llvm::StringRef Name) { + return getOwn(Name.begin(), Name.end()); } typedef HashTableTy::const_iterator iterator; diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 2d1df44cc9..0747290358 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -29,7 +29,6 @@ class CodeGenOptions; class Diagnostic; class FileManager; class LangOptions; -class PCHReader; class Preprocessor; class TargetOptions; @@ -63,7 +62,7 @@ ASTConsumer *CreateDeclContextPrinter(); // times. ASTConsumer *CreatePCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS, - PCHReader *Chain, + bool Chaining, const char *isysroot = 0); // Inheritance viewer: for C++ code, creates a graph of the inheritance diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 89df8f584b..4a4d5ae1d4 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -97,9 +97,6 @@ class CompilerInstance { /// The list of active output files. std::list< std::pair > OutputFiles; - /// The PCH reader. Not owned; the ASTContext owns this. - PCHReader *Reader; - void operator=(const CompilerInstance &); // DO NOT IMPLEMENT CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT public: @@ -503,7 +500,8 @@ public: /// Create an external AST source to read a PCH file and attach it to the AST /// context. void createPCHExternalASTSource(llvm::StringRef Path, - bool DisablePCHValidation); + bool DisablePCHValidation, + void *DeserializationListener); /// Create an external AST source to read a PCH file. /// @@ -511,10 +509,8 @@ public: static ExternalASTSource * createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, - Preprocessor &PP, ASTContext &Context); - - /// Get the PCH reader, if any. - PCHReader *getPCHReader() { return Reader; } + Preprocessor &PP, ASTContext &Context, + void *DeserializationListener); /// Create a code completion consumer using the invocation; note that this /// will cause the source manager to truncate the input source file at the diff --git a/include/clang/Frontend/PCHDeserializationListener.h b/include/clang/Frontend/PCHDeserializationListener.h index fe9c755605..52adda9f3f 100644 --- a/include/clang/Frontend/PCHDeserializationListener.h +++ b/include/clang/Frontend/PCHDeserializationListener.h @@ -20,6 +20,7 @@ namespace clang { class Decl; +class PCHReader; class QualType; class PCHDeserializationListener { @@ -27,6 +28,9 @@ protected: virtual ~PCHDeserializationListener() {} public: + /// \brief Tell the listener about the reader. + virtual void SetReader(PCHReader *Reader) = 0; + /// \brief An identifier was deserialized from the PCH. virtual void IdentifierRead(pch::IdentID ID, IdentifierInfo *II) = 0; /// \brief A type was deserialized from the PCH. The ID here has the qualifier diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 49579dc1b1..8e8cf25fb9 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -645,9 +645,8 @@ public: Listener.reset(listener); } - void setDeserializationListener(PCHDeserializationListener *Listener) { - DeserializationListener = Listener; - } + /// \brief Set the PCH deserialization listener. + void setDeserializationListener(PCHDeserializationListener *Listener); /// \brief Set the Preprocessor to use. void setPreprocessor(Preprocessor &pp); @@ -911,6 +910,12 @@ public: /// \brief Retrieve the macro definition with the given ID. MacroDefinition *getMacroDefinition(pch::IdentID ID); + + /// \brief Erase the macro that's bound to the given IdentifierInfo. + void EraseMacro(IdentifierInfo *II); + + /// \brief Check if the given macro identifier is built-in. + bool isBuiltinMacro(IdentifierInfo *II); /// \brief Retrieve the AST context that this PCH reader /// supplements. diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 90f59cfad9..c143cefccf 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -268,7 +268,7 @@ private: public: /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. - PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain); + PCHWriter(llvm::BitstreamWriter &Stream); /// \brief Write a precompiled header for the given semantic analysis. /// @@ -421,6 +421,7 @@ public: bool hasChain() const { return Chain; } // PCHDeserializationListener implementation + void SetReader(PCHReader *Reader); void IdentifierRead(pch::IdentID ID, IdentifierInfo *II); void TypeRead(pch::TypeID ID, QualType T); void DeclRead(pch::DeclID ID, const Decl *D); diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 8993e6713f..1f0c52bdc1 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -34,6 +34,7 @@ IdentifierInfo::IdentifierInfo() { IsPoisoned = false; IsCPPOperatorKeyword = false; NeedsHandleIdentifier = false; + IsFromPCH = false; FETokenInfo = 0; Entry = 0; } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ea295687aa..84e51837bc 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -37,7 +37,7 @@ using namespace clang; CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()), Reader(0) { + : Invocation(new CompilerInvocation()) { } CompilerInstance::~CompilerInstance() { @@ -251,13 +251,13 @@ void CompilerInstance::createASTContext() { // ExternalASTSource void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, - bool DisablePCHValidation) { + bool DisablePCHValidation, + void *DeserializationListener){ llvm::OwningPtr Source; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, - getPreprocessor(), getASTContext())); - // Remember the PCHReader, but in a non-owning way. - Reader = static_cast(Source.get()); + getPreprocessor(), getASTContext(), + DeserializationListener)); getASTContext().setExternalSource(Source); } @@ -266,12 +266,15 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, Preprocessor &PP, - ASTContext &Context) { + ASTContext &Context, + void *DeserializationListener) { llvm::OwningPtr Reader; Reader.reset(new PCHReader(PP, &Context, Sysroot.empty() ? 0 : Sysroot.c_str(), DisablePCHValidation)); + Reader->setDeserializationListener( + static_cast(DeserializationListener)); switch (Reader->ReadPCH(Path)) { case PCHReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 9efa8c61db..90b87864b8 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/FrontendAction.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -112,19 +113,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!usesPreprocessorOnly()) { CI.createASTContext(); - /// Use PCH? If so, we want the PCHReader active before the consumer - /// is created, because the consumer might be interested in the reader - /// (e.g. the PCH writer for chaining). + llvm::OwningPtr Consumer(CreateASTConsumer(CI, Filename)); + + /// Use PCH? if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { assert(hasPCHSupport() && "This action does not have PCH support!"); CI.createPCHExternalASTSource( CI.getPreprocessorOpts().ImplicitPCHInclude, - CI.getPreprocessorOpts().DisablePCHValidation); + CI.getPreprocessorOpts().DisablePCHValidation, + CI.getInvocation().getFrontendOpts().ChainedPCH? + Consumer->GetPCHDeserializationListener() : 0); if (!CI.getASTContext().getExternalSource()) goto failure; } - CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + CI.setASTConsumer(Consumer.take()); if (!CI.hasASTConsumer()) goto failure; } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 2d1287f85b..b0f85f1ad6 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -81,11 +81,11 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, if (!OS) return 0; - PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ? - CI.getPCHReader() : 0; + bool Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && + !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? Sysroot.c_str() : 0; - return CreatePCHGenerator(CI.getPreprocessor(), OS, Chain, isysroot); + return CreatePCHGenerator(CI.getPreprocessor(), OS, Chaining, isysroot); } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index 422a4b6264..561a68a6ef 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -37,19 +37,20 @@ namespace { PCHWriter Writer; public: - PCHGenerator(const Preprocessor &PP, PCHReader *Chain, + PCHGenerator(const Preprocessor &PP, bool Chaining, const char *isysroot, llvm::raw_ostream *Out); virtual void InitializeSema(Sema &S) { SemaPtr = &S; } virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual PCHDeserializationListener *GetPCHDeserializationListener(); }; } PCHGenerator::PCHGenerator(const Preprocessor &PP, - PCHReader *Chain, + bool Chaining, const char *isysroot, llvm::raw_ostream *OS) - : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0), - Stream(Buffer), Writer(Stream, Chain) { + : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), + StatCalls(0), Stream(Buffer), Writer(Stream) { // Install a stat() listener to keep track of all of the stat() // calls. @@ -57,7 +58,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, // If we have a chain, we want new stat calls only, so install the memorizer // *after* the already installed PCHReader's stat cache. PP.getFileManager().addStatCache(StatCalls, - /*AtBeginning=*/!Chain); + /*AtBeginning=*/!Chaining); } void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { @@ -78,9 +79,13 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Buffer.clear(); } +PCHDeserializationListener *PCHGenerator::GetPCHDeserializationListener() { + return &Writer; +} + ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS, - PCHReader *Chain, + bool Chaining, const char *isysroot) { - return new PCHGenerator(PP, Chain, isysroot, OS); + return new PCHGenerator(PP, Chaining, isysroot, OS); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 69922b0d0f..6fa7294f87 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -460,6 +460,13 @@ PCHReader::PerFileData::PerFileData() NumPreallocatedPreprocessingEntities(0) {} +void +PCHReader::setDeserializationListener(PCHDeserializationListener *Listener) { + DeserializationListener = Listener; + if (DeserializationListener) + DeserializationListener->SetReader(this); +} + namespace { class PCHMethodPoolLookupTrait { @@ -637,9 +644,9 @@ public: // and associate it with the persistent ID. IdentifierInfo *II = KnownII; if (!II) - II = &Reader.getIdentifierTable().CreateIdentifierInfo( - k.first, k.first + k.second); + II = &Reader.getIdentifierTable().getOwn(k.first, k.first + k.second); Reader.SetIdentifierInfo(ID, II); + II->setIsFromPCH(); return II; } @@ -662,8 +669,7 @@ public: // the new IdentifierInfo. IdentifierInfo *II = KnownII; if (!II) - II = &Reader.getIdentifierTable().CreateIdentifierInfo( - k.first, k.first + k.second); + II = &Reader.getIdentifierTable().getOwn(k.first, k.first + k.second); Reader.SetIdentifierInfo(ID, II); // Set or check the various bits in the IdentifierInfo structure. @@ -683,6 +689,9 @@ public: uint32_t Offset = ReadUnalignedLE32(d); Reader.ReadMacroRecord(Stream, Offset); DataLen -= 4; + } else if (II->hasMacroDefinition() && !Reader.isBuiltinMacro(II)) { + // A previous part of the chain added a macro, but this part #undefed it. + Reader.EraseMacro(II); } // Read all of the declarations visible at global scope with this @@ -695,6 +704,7 @@ public: Reader.SetGloballyVisibleDecls(II, DeclIDs); } + II->setIsFromPCH(); return II; } }; @@ -1379,6 +1389,15 @@ MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) { return MacroDefinitionsLoaded[ID]; } +void PCHReader::EraseMacro(IdentifierInfo *II) { + PP->setMacroInfo(II, 0); +} + +bool PCHReader::isBuiltinMacro(IdentifierInfo *II) { + assert(II->hasMacroDefinition() && "Identifier is not a macro"); + return PP->getMacroInfo(II)->isBuiltinMacro(); +} + /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. @@ -1797,8 +1816,6 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { Id != IdEnd; ++Id) Identifiers.push_back(Id->second); // We need to search the tables in all files. - // FIXME: What happens if this stuff changes between files, e.g. the - // dependent PCH undefs a macro from the core file? for (unsigned J = 0, M = Chain.size(); J != M; ++J) { PCHIdentifierLookupTable *IdTable = (PCHIdentifierLookupTable *)Chain[J]->IdentifierLookupTable; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index f475db5c5b..b574656bb6 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1810,7 +1810,8 @@ public: for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), DEnd = IdentifierResolver::end(); D != DEnd; ++D) - DataLen += sizeof(pch::DeclID); + if (!Writer.hasChain() || (*D)->getPCHLevel() == 0) + DataLen += sizeof(pch::DeclID); } clang::io::Emit16(Out, DataLen); // We emit the key length after the data length so that every @@ -1898,9 +1899,7 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end(); ID != IDEnd; ++ID) { assert(ID->first && "NULL identifier in identifier table"); - // FIXME: Right now, we only write identifiers that are new to this file. - // We need to write older identifiers that changed too, though. - if (ID->second >= FirstIdentID) + if (!Chain || !ID->first->isFromPCH()) Generator.insert(ID->first, ID->second); } @@ -2142,17 +2141,11 @@ void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { SelectorOffsets[ID - 1] = Offset; } -PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain) - : Stream(Stream), Chain(Chain), FirstDeclID(1), +PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream) + : Stream(Stream), Chain(0), FirstDeclID(1), FirstTypeID(pch::NUM_PREDEF_TYPE_IDS), FirstIdentID(1), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) { - if (Chain) { - Chain->setDeserializationListener(this); - FirstDeclID += Chain->getTotalNumDecls(); - FirstTypeID += Chain->getTotalNumTypes(); - FirstIdentID += Chain->getTotalNumIdentifiers(); - } NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; @@ -2335,6 +2328,13 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, const char *isysroot) { using namespace llvm; + FirstDeclID += Chain->getTotalNumDecls(); + FirstTypeID += Chain->getTotalNumTypes(); + FirstIdentID += Chain->getTotalNumIdentifiers(); + NextDeclID = FirstDeclID; + NextTypeID = FirstTypeID; + NextIdentID = FirstIdentID; + ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; @@ -2352,9 +2352,6 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // We don't start with the translation unit, but with its decls that // don't come from the other PCH. const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - // The TU was loaded before we managed to register ourselves as a listener. - // Thus we need to add it manually. - DeclIDs[TU] = 1; llvm::SmallVector NewGlobalDecls; for (DeclContext::decl_iterator I = TU->noload_decls_begin(), E = TU->noload_decls_end(); @@ -2868,6 +2865,15 @@ void PCHWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, AddSourceRange(Base.getSourceRange(), Record); } +void PCHWriter::SetReader(PCHReader *Reader) { + assert(Reader && "Cannot remove chain"); + assert(FirstDeclID == NextDeclID && + FirstTypeID == NextTypeID && + FirstIdentID == NextIdentID && + "Setting chain after writing has started."); + Chain = Reader; +} + void PCHWriter::IdentifierRead(pch::IdentID ID, IdentifierInfo *II) { IdentifierIDs[II] = ID; } diff --git a/test/PCH/Inputs/chain-macro-override1.h b/test/PCH/Inputs/chain-macro-override1.h new file mode 100644 index 0000000000..4f9321de93 --- /dev/null +++ b/test/PCH/Inputs/chain-macro-override1.h @@ -0,0 +1,4 @@ +void f() __attribute__((unavailable)); +void g(); +#define g() f() +#define h() f() diff --git a/test/PCH/Inputs/chain-macro-override2.h b/test/PCH/Inputs/chain-macro-override2.h new file mode 100644 index 0000000000..f279e2ad48 --- /dev/null +++ b/test/PCH/Inputs/chain-macro-override2.h @@ -0,0 +1,4 @@ +#define f() g() +#undef g +#undef h +#define h() g() diff --git a/test/PCH/chain-macro-override.c b/test/PCH/chain-macro-override.c new file mode 100644 index 0000000000..14478af35f --- /dev/null +++ b/test/PCH/chain-macro-override.c @@ -0,0 +1,13 @@ +// 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 + +// 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 -include-pch %t2 -fsyntax-only -verify %s + +void foo() { + f(); + g(); + h(); +} -- 2.40.0