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
/// 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() {}
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;
NeedsHandleIdentifier = 1;
else
RecomputeNeedsHandleIdentifier();
+ IsFromPCH = false;
}
/// get/setTokenID - If this is a source-language token (e.g. 'for'), this API
NeedsHandleIdentifier = 1;
else
RecomputeNeedsHandleIdentifier();
+ IsFromPCH = false;
}
/// isPoisoned - Return true if this token has been poisoned.
/// 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
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;
class Diagnostic;
class FileManager;
class LangOptions;
-class PCHReader;
class Preprocessor;
class TargetOptions;
// 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
/// 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:
/// 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.
///
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
namespace clang {
class Decl;
+class PCHReader;
class QualType;
class PCHDeserializationListener {
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
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);
/// \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.
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.
///
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);
IsPoisoned = false;
IsCPPOperatorKeyword = false;
NeedsHandleIdentifier = false;
+ IsFromPCH = false;
FETokenInfo = 0;
Entry = 0;
}
using namespace clang;
CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()), Reader(0) {
+ : Invocation(new CompilerInvocation()) {
}
CompilerInstance::~CompilerInstance() {
// 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);
}
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
//===----------------------------------------------------------------------===//
#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"
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;
}
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,
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.
// 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) {
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);
}
NumPreallocatedPreprocessingEntities(0)
{}
+void
+PCHReader::setDeserializationListener(PCHDeserializationListener *Listener) {
+ DeserializationListener = Listener;
+ if (DeserializationListener)
+ DeserializationListener->SetReader(this);
+}
+
namespace {
class PCHMethodPoolLookupTrait {
// 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;
}
// 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.
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
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}
+ II->setIsFromPCH();
return II;
}
};
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.
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;
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
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);
}
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;
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;
// 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();
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;
}
--- /dev/null
+void f() __attribute__((unavailable));
+void g();
+#define g() f()
+#define h() f()
--- /dev/null
+#define f() g()
+#undef g
+#undef h
+#define h() g()
--- /dev/null
+// 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();
+}