diff --git a/clang/include/clang/AST/ASTConsumer.h b/clang/include/clang/AST/ASTConsumer.h index 06113954fc48..b01f6c600174 100644 --- a/clang/include/clang/AST/ASTConsumer.h +++ b/clang/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/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 6b8bcdc52f6f..c8642a1ac5f7 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/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/clang/include/clang/Frontend/ASTConsumers.h b/clang/include/clang/Frontend/ASTConsumers.h index 2d1df44cc968..074729035845 100644 --- a/clang/include/clang/Frontend/ASTConsumers.h +++ b/clang/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/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 89df8f584bf2..4a4d5ae1d4f7 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/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/clang/include/clang/Frontend/PCHDeserializationListener.h b/clang/include/clang/Frontend/PCHDeserializationListener.h index fe9c75560538..52adda9f3f24 100644 --- a/clang/include/clang/Frontend/PCHDeserializationListener.h +++ b/clang/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/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 49579dc1b17e..8e8cf25fb965 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/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/clang/include/clang/Frontend/PCHWriter.h b/clang/include/clang/Frontend/PCHWriter.h index 90f59cfad989..c143cefccfed 100644 --- a/clang/include/clang/Frontend/PCHWriter.h +++ b/clang/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/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 8993e6713fbe..1f0c52bdc198 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/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/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ea295687aa08..84e51837bc80 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/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/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 9efa8c61db85..90b87864b831 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/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/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 2d1287f85b63..b0f85f1ad6d0 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/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/clang/lib/Frontend/GeneratePCH.cpp b/clang/lib/Frontend/GeneratePCH.cpp index 422a4b626472..561a68a6ef6a 100644 --- a/clang/lib/Frontend/GeneratePCH.cpp +++ b/clang/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/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 69922b0d0fad..6fa7294f870c 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/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/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index f475db5c5bc1..b574656bb6d9 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/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/clang/test/PCH/Inputs/chain-macro-override1.h b/clang/test/PCH/Inputs/chain-macro-override1.h new file mode 100644 index 000000000000..4f9321de93b1 --- /dev/null +++ b/clang/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/clang/test/PCH/Inputs/chain-macro-override2.h b/clang/test/PCH/Inputs/chain-macro-override2.h new file mode 100644 index 000000000000..f279e2ad48c0 --- /dev/null +++ b/clang/test/PCH/Inputs/chain-macro-override2.h @@ -0,0 +1,4 @@ +#define f() g() +#undef g +#undef h +#define h() g() diff --git a/clang/test/PCH/chain-macro-override.c b/clang/test/PCH/chain-macro-override.c new file mode 100644 index 000000000000..14478af35f19 --- /dev/null +++ b/clang/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(); +}