]> granicus.if.org Git - clang/commitdiff
Make macro weirdness in chained PCH work. This required changing the way PCHReader...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 30 Jul 2010 00:29:29 +0000 (00:29 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 30 Jul 2010 00:29:29 +0000 (00:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109823 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
include/clang/AST/ASTConsumer.h
include/clang/Basic/IdentifierTable.h
include/clang/Frontend/ASTConsumers.h
include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/PCHDeserializationListener.h
include/clang/Frontend/PCHReader.h
include/clang/Frontend/PCHWriter.h
lib/Basic/IdentifierTable.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendAction.cpp
lib/Frontend/FrontendActions.cpp
lib/Frontend/GeneratePCH.cpp
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHWriter.cpp
test/PCH/Inputs/chain-macro-override1.h [new file with mode: 0644]
test/PCH/Inputs/chain-macro-override2.h [new file with mode: 0644]
test/PCH/chain-macro-override.c [new file with mode: 0644]

index 06113954fc48aed263542306a811a13585efe2ed..b01f6c6001742182b56697519ad57e93cdfa19b6 100644 (file)
@@ -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() {}
 
index 6b8bcdc52f6f5d9e30b6f46e73b23953e344542b..c8642a1ac5f75c57beb7eabdff4651f7a2645171 100644 (file)
@@ -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<IdentifierInfo*> *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<IdentifierInfo*> &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<IdentifierInfo>();
-    II = new (Mem) IdentifierInfo();
-    Entry.setValue(II);
+      // Lookups failed, make a new IdentifierInfo.
+      void *Mem = getAllocator().Allocate<IdentifierInfo>();
+      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;
index 2d1df44cc968afd6a97f7f5a7baa0ab37d21a3f2..0747290358457db51b22db952cf5b8e27e3c384f 100644 (file)
@@ -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
index 89df8f584bf229d0271eab2c04587876c42e4c09..4a4d5ae1d4f7ee7eeb073cf99c945a9f99b6f7b1 100644 (file)
@@ -97,9 +97,6 @@ class CompilerInstance {
   /// The list of active output files.
   std::list< std::pair<std::string, llvm::raw_ostream*> > 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
index fe9c75560538f11345dbb080257bb0fc39fdc005..52adda9f3f24e593baeb7a92f8b42713651fc6c6 100644 (file)
@@ -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
index 49579dc1b17e9c7e4473921e34c4283db63412af..8e8cf25fb965d3ed7c0c255c13c0092654f87c93 100644 (file)
@@ -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.
index 90f59cfad9890fdf3f2b6b9e1a8e57a68223a675..c143cefccfed02dac12df252987bc82328d42275 100644 (file)
@@ -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);
index 8993e6713fbebd324cf977ed0e9a7ba9d4dc8e96..1f0c52bdc19898f1073b51c3fd3a6f886b5bd1fb 100644 (file)
@@ -34,6 +34,7 @@ IdentifierInfo::IdentifierInfo() {
   IsPoisoned = false;
   IsCPPOperatorKeyword = false;
   NeedsHandleIdentifier = false;
+  IsFromPCH = false;
   FETokenInfo = 0;
   Entry = 0;
 }
index ea295687aa08fc849fa0a8d344dea13857e30107..84e51837bc80c36aed826ffc96b9afd068b7322b 100644 (file)
@@ -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<ExternalASTSource> Source;
   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
                                           DisablePCHValidation,
-                                          getPreprocessor(), getASTContext()));
-  // Remember the PCHReader, but in a non-owning way.
-  Reader = static_cast<PCHReader*>(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<PCHReader> Reader;
   Reader.reset(new PCHReader(PP, &Context,
                              Sysroot.empty() ? 0 : Sysroot.c_str(),
                              DisablePCHValidation));
 
+  Reader->setDeserializationListener(
+            static_cast<PCHDeserializationListener *>(DeserializationListener));
   switch (Reader->ReadPCH(Path)) {
   case PCHReader::Success:
     // Set the predefines buffer as suggested by the PCH reader. Typically, the
index 9efa8c61db8596a989e46233acd9fae5973c65b9..90b87864b83104070b16081fea9d22797186d714 100644 (file)
@@ -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<ASTConsumer> 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;
   }
index 2d1287f85b63b1f0483325a3fdf526363063ca3f..b0f85f1ad6d07c5fbb6b88e4c6f9d087277287f7 100644 (file)
@@ -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,
index 422a4b626472916e5d607b81b775b7871a240e0d..561a68a6ef6a0f372ec7c71008e721635e71e90f 100644 (file)
@@ -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);
 }
index 69922b0d0fad9919ee038fb58701e6402a4c16bf..6fa7294f870c1f1d369b39dfd7359b6db97c1bda 100644 (file)
@@ -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;
index f475db5c5bc15cb08a12c1f3fda22328c05342ff..b574656bb6d9a89f7839793815be66045d1a2ee5 100644 (file)
@@ -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<pch::DeclID, 64> 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 (file)
index 0000000..4f9321d
--- /dev/null
@@ -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 (file)
index 0000000..f279e2a
--- /dev/null
@@ -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 (file)
index 0000000..14478af
--- /dev/null
@@ -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();
+}