forked from OSchip/llvm-project
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.
llvm-svn: 109823
This commit is contained in:
parent
0c7476ad59
commit
07a89a83d4
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -34,6 +34,7 @@ IdentifierInfo::IdentifierInfo() {
|
|||
IsPoisoned = false;
|
||||
IsCPPOperatorKeyword = false;
|
||||
NeedsHandleIdentifier = false;
|
||||
IsFromPCH = false;
|
||||
FETokenInfo = 0;
|
||||
Entry = 0;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
void f() __attribute__((unavailable));
|
||||
void g();
|
||||
#define g() f()
|
||||
#define h() f()
|
|
@ -0,0 +1,4 @@
|
|||
#define f() g()
|
||||
#undef g
|
||||
#undef h
|
||||
#define h() g()
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue