blob: 834917de1d468b8705f8103adfb16816e9282cd6 [file] [log] [blame]
//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the ASTReader class, which reads AST files.
//
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "clang/Serialization/SerializationDiagnostic.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstdio>
#include <iterator>
using namespace clang;
using namespace clang::serialization;
using namespace clang::serialization::reader;
using llvm::BitstreamCursor;
//===----------------------------------------------------------------------===//
// ChainedASTReaderListener implementation
//===----------------------------------------------------------------------===//
bool
ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) {
return First->ReadFullVersionInformation(FullVersion) ||
Second->ReadFullVersionInformation(FullVersion);
}
void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) {
First->ReadModuleName(ModuleName);
Second->ReadModuleName(ModuleName);
}
void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) {
First->ReadModuleMapFile(ModuleMapPath);
Second->ReadModuleMapFile(ModuleMapPath);
}
bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain) {
return First->ReadLanguageOptions(LangOpts, Complain) ||
Second->ReadLanguageOptions(LangOpts, Complain);
}
bool
ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) {
return First->ReadTargetOptions(TargetOpts, Complain) ||
Second->ReadTargetOptions(TargetOpts, Complain);
}
bool ChainedASTReaderListener::ReadDiagnosticOptions(
const DiagnosticOptions &DiagOpts, bool Complain) {
return First->ReadDiagnosticOptions(DiagOpts, Complain) ||
Second->ReadDiagnosticOptions(DiagOpts, Complain);
}
bool
ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts,
bool Complain) {
return First->ReadFileSystemOptions(FSOpts, Complain) ||
Second->ReadFileSystemOptions(FSOpts, Complain);
}
bool ChainedASTReaderListener::ReadHeaderSearchOptions(
const HeaderSearchOptions &HSOpts, bool Complain) {
return First->ReadHeaderSearchOptions(HSOpts, Complain) ||
Second->ReadHeaderSearchOptions(HSOpts, Complain);
}
bool ChainedASTReaderListener::ReadPreprocessorOptions(
const PreprocessorOptions &PPOpts, bool Complain,
std::string &SuggestedPredefines) {
return First->ReadPreprocessorOptions(PPOpts, Complain,
SuggestedPredefines) ||
Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines);
}
void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M,
unsigned Value) {
First->ReadCounter(M, Value);
Second->ReadCounter(M, Value);
}
bool ChainedASTReaderListener::needsInputFileVisitation() {
return First->needsInputFileVisitation() ||
Second->needsInputFileVisitation();
}
bool ChainedASTReaderListener::needsSystemInputFileVisitation() {
return First->needsSystemInputFileVisitation() ||
Second->needsSystemInputFileVisitation();
}
void ChainedASTReaderListener::visitModuleFile(StringRef Filename) {
First->visitModuleFile(Filename);
Second->visitModuleFile(Filename);
}
bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
bool isSystem,
bool isOverridden) {
return First->visitInputFile(Filename, isSystem, isOverridden) ||
Second->visitInputFile(Filename, isSystem, isOverridden);
}
//===----------------------------------------------------------------------===//
// PCH validator implementation
//===----------------------------------------------------------------------===//
ASTReaderListener::~ASTReaderListener() {}
/// \brief Compare the given set of language options against an existing set of
/// language options.
///
/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
///
/// \returns true if the languagae options mis-match, false otherwise.
static bool checkLanguageOptions(const LangOptions &LangOpts,
const LangOptions &ExistingLangOpts,
DiagnosticsEngine *Diags) {
#define LANGOPT(Name, Bits, Default, Description) \
if (ExistingLangOpts.Name != LangOpts.Name) { \
if (Diags) \
Diags->Report(diag::err_pch_langopt_mismatch) \
<< Description << LangOpts.Name << ExistingLangOpts.Name; \
return true; \
}
#define VALUE_LANGOPT(Name, Bits, Default, Description) \
if (ExistingLangOpts.Name != LangOpts.Name) { \
if (Diags) \
Diags->Report(diag::err_pch_langopt_value_mismatch) \
<< Description; \
return true; \
}
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
if (Diags) \
Diags->Report(diag::err_pch_langopt_value_mismatch) \
<< Description; \
return true; \
}
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
if (Diags)
Diags->Report(diag::err_pch_langopt_value_mismatch)
<< "target Objective-C runtime";
return true;
}
if (ExistingLangOpts.CommentOpts.BlockCommandNames !=
LangOpts.CommentOpts.BlockCommandNames) {
if (Diags)
Diags->Report(diag::err_pch_langopt_value_mismatch)
<< "block command names";
return true;
}
return false;
}
/// \brief Compare the given set of target options against an existing set of
/// target options.
///
/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
///
/// \returns true if the target options mis-match, false otherwise.
static bool checkTargetOptions(const TargetOptions &TargetOpts,
const TargetOptions &ExistingTargetOpts,
DiagnosticsEngine *Diags) {
#define CHECK_TARGET_OPT(Field, Name) \
if (TargetOpts.Field != ExistingTargetOpts.Field) { \
if (Diags) \
Diags->Report(diag::err_pch_targetopt_mismatch) \
<< Name << TargetOpts.Field << ExistingTargetOpts.Field; \
return true; \
}
CHECK_TARGET_OPT(Triple, "target");
CHECK_TARGET_OPT(CPU, "target CPU");
CHECK_TARGET_OPT(ABI, "target ABI");
CHECK_TARGET_OPT(LinkerVersion, "target linker version");
#undef CHECK_TARGET_OPT
// Compare feature sets.
SmallVector<StringRef, 4> ExistingFeatures(
ExistingTargetOpts.FeaturesAsWritten.begin(),
ExistingTargetOpts.FeaturesAsWritten.end());
SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
TargetOpts.FeaturesAsWritten.end());
std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
std::sort(ReadFeatures.begin(), ReadFeatures.end());
unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
++ExistingIdx;
++ReadIdx;
continue;
}
if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
if (Diags)
Diags->Report(diag::err_pch_targetopt_feature_mismatch)
<< false << ReadFeatures[ReadIdx];
return true;
}
if (Diags)
Diags->Report(diag::err_pch_targetopt_feature_mismatch)
<< true << ExistingFeatures[ExistingIdx];
return true;
}
if (ExistingIdx < ExistingN) {
if (Diags)
Diags->Report(diag::err_pch_targetopt_feature_mismatch)
<< true << ExistingFeatures[ExistingIdx];
return true;
}
if (ReadIdx < ReadN) {
if (Diags)
Diags->Report(diag::err_pch_targetopt_feature_mismatch)
<< false << ReadFeatures[ReadIdx];
return true;
}
return false;
}
bool
PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain) {
const LangOptions &ExistingLangOpts = PP.getLangOpts();
return checkLanguageOptions(LangOpts, ExistingLangOpts,
Complain? &Reader.Diags : 0);
}
bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) {
const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
return checkTargetOptions(TargetOpts, ExistingTargetOpts,
Complain? &Reader.Diags : 0);
}
namespace {
typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
MacroDefinitionsMap;
typedef llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> >
DeclsMap;
}
/// \brief Collect the macro definitions provided by the given preprocessor
/// options.
static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
MacroDefinitionsMap &Macros,
SmallVectorImpl<StringRef> *MacroNames = 0){
for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
StringRef Macro = PPOpts.Macros[I].first;
bool IsUndef = PPOpts.Macros[I].second;
std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
StringRef MacroName = MacroPair.first;
StringRef MacroBody = MacroPair.second;
// For an #undef'd macro, we only care about the name.
if (IsUndef) {
if (MacroNames && !Macros.count(MacroName))
MacroNames->push_back(MacroName);
Macros[MacroName] = std::make_pair("", true);
continue;
}
// For a #define'd macro, figure out the actual definition.
if (MacroName.size() == Macro.size())
MacroBody = "1";
else {
// Note: GCC drops anything following an end-of-line character.
StringRef::size_type End = MacroBody.find_first_of("\n\r");
MacroBody = MacroBody.substr(0, End);
}
if (MacroNames && !Macros.count(MacroName))
MacroNames->push_back(MacroName);
Macros[MacroName] = std::make_pair(MacroBody, false);
}
}
/// \brief Check the preprocessor options deserialized from the control block
/// against the preprocessor options in an existing preprocessor.
///
/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
const PreprocessorOptions &ExistingPPOpts,
DiagnosticsEngine *Diags,
FileManager &FileMgr,
std::string &SuggestedPredefines,
const LangOptions &LangOpts) {
// Check macro definitions.
MacroDefinitionsMap ASTFileMacros;
collectMacroDefinitions(PPOpts, ASTFileMacros);
MacroDefinitionsMap ExistingMacros;
SmallVector<StringRef, 4> ExistingMacroNames;
collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
// Dig out the macro definition in the existing preprocessor options.
StringRef MacroName = ExistingMacroNames[I];
std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
// Check whether we know anything about this macro name or not.
llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
= ASTFileMacros.find(MacroName);
if (Known == ASTFileMacros.end()) {
// FIXME: Check whether this identifier was referenced anywhere in the
// AST file. If so, we should reject the AST file. Unfortunately, this
// information isn't in the control block. What shall we do about it?
if (Existing.second) {
SuggestedPredefines += "#undef ";
SuggestedPredefines += MacroName.str();
SuggestedPredefines += '\n';
} else {
SuggestedPredefines += "#define ";
SuggestedPredefines += MacroName.str();
SuggestedPredefines += ' ';
SuggestedPredefines += Existing.first.str();
SuggestedPredefines += '\n';
}
continue;
}
// If the macro was defined in one but undef'd in the other, we have a
// conflict.
if (Existing.second != Known->second.second) {
if (Diags) {
Diags->Report(diag::err_pch_macro_def_undef)
<< MacroName << Known->second.second;
}
return true;
}
// If the macro was #undef'd in both, or if the macro bodies are identical,
// it's fine.
if (Existing.second || Existing.first == Known->second.first)
continue;
// The macro bodies differ; complain.
if (Diags) {
Diags->Report(diag::err_pch_macro_def_conflict)
<< MacroName << Known->second.first << Existing.first;
}
return true;
}
// Check whether we're using predefines.
if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
if (Diags) {
Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
}
return true;
}
// Detailed record is important since it is used for the module cache hash.
if (LangOpts.Modules &&
PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord) {
if (Diags) {
Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord;
}
return true;
}
// Compute the #include and #include_macros lines we need.
for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
StringRef File = ExistingPPOpts.Includes[I];
if (File == ExistingPPOpts.ImplicitPCHInclude)
continue;
if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
!= PPOpts.Includes.end())
continue;
SuggestedPredefines += "#include \"";
SuggestedPredefines +=
HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
SuggestedPredefines += "\"\n";
}
for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
StringRef File = ExistingPPOpts.MacroIncludes[I];
if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
File)
!= PPOpts.MacroIncludes.end())
continue;
SuggestedPredefines += "#__include_macros \"";
SuggestedPredefines +=
HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
SuggestedPredefines += "\"\n##\n";
}
return false;
}
bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool Complain,
std::string &SuggestedPredefines) {
const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
Complain? &Reader.Diags : 0,
PP.getFileManager(),
SuggestedPredefines,
PP.getLangOpts());
}
void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
PP.setCounterValue(Value);
}
//===----------------------------------------------------------------------===//
// AST reader implementation
//===----------------------------------------------------------------------===//
void
ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
DeserializationListener = Listener;
}
unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
return serialization::ComputeHash(Sel);
}
std::pair<unsigned, unsigned>
ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
ASTSelectorLookupTrait::internal_key_type
ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
using namespace llvm::support;
SelectorTable &SelTable = Reader.getContext().Selectors;
unsigned N = endian::readNext<uint16_t, little, unaligned>(d);
IdentifierInfo *FirstII = Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
if (N == 0)
return SelTable.getNullarySelector(FirstII);
else if (N == 1)
return SelTable.getUnarySelector(FirstII);
SmallVector<IdentifierInfo *, 16> Args;
Args.push_back(FirstII);
for (unsigned I = 1; I != N; ++I)
Args.push_back(Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d)));
return SelTable.getSelector(N, Args.data());
}
ASTSelectorLookupTrait::data_type
ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
unsigned DataLen) {
using namespace llvm::support;
data_type Result;
Result.ID = Reader.getGlobalSelectorID(
F, endian::readNext<uint32_t, little, unaligned>(d));
unsigned NumInstanceMethodsAndBits =
endian::readNext<uint16_t, little, unaligned>(d);
unsigned NumFactoryMethodsAndBits =
endian::readNext<uint16_t, little, unaligned>(d);
Result.InstanceBits = NumInstanceMethodsAndBits & 0x3;
Result.FactoryBits = NumFactoryMethodsAndBits & 0x3;
unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2;
unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2;
// Load instance methods
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F, endian::readNext<uint32_t, little, unaligned>(d)))
Result.Instance.push_back(Method);
}
// Load factory methods
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F, endian::readNext<uint32_t, little, unaligned>(d)))
Result.Factory.push_back(Method);
}
return Result;
}
unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
return llvm::HashString(a);
}
std::pair<unsigned, unsigned>
ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
ASTIdentifierLookupTraitBase::internal_key_type
ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
assert(n >= 2 && d[n-1] == '\0');
return StringRef((const char*) d, n-1);
}
/// \brief Whether the given identifier is "interesting".
static bool isInterestingIdentifier(IdentifierInfo &II) {
return II.isPoisoned() ||
II.isExtensionToken() ||
II.getObjCOrBuiltinID() ||
II.hasRevertedTokenIDToIdentifier() ||
II.hadMacroDefinition() ||
II.getFETokenInfo<void>();
}
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen) {
using namespace llvm::support;
unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
bool IsInteresting = RawID & 0x01;
// Wipe out the "is interesting" bit.
RawID = RawID >> 1;
IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
if (!IsInteresting) {
// For uninteresting identifiers, just build the IdentifierInfo
// and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
if (!II) {
II = &Reader.getIdentifierTable().getOwn(k);
KnownII = II;
}
Reader.SetIdentifierInfo(ID, II);
if (!II->isFromAST()) {
bool WasInteresting = isInterestingIdentifier(*II);
II->setIsFromAST();
if (WasInteresting)
II->setChangedSinceDeserialization();
}
Reader.markIdentifierUpToDate(II);
return II;
}
unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d);
unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d);
bool CPlusPlusOperatorKeyword = Bits & 0x01;
Bits >>= 1;
bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
Bits >>= 1;
bool Poisoned = Bits & 0x01;
Bits >>= 1;
bool ExtensionToken = Bits & 0x01;
Bits >>= 1;
bool hasSubmoduleMacros = Bits & 0x01;
Bits >>= 1;
bool hadMacroDefinition = Bits & 0x01;
Bits >>= 1;
assert(Bits == 0 && "Extra bits in the identifier?");
DataLen -= 8;
// Build the IdentifierInfo itself and link the identifier ID with
// the new IdentifierInfo.
IdentifierInfo *II = KnownII;
if (!II) {
II = &Reader.getIdentifierTable().getOwn(StringRef(k));
KnownII = II;
}
Reader.markIdentifierUpToDate(II);
if (!II->isFromAST()) {
bool WasInteresting = isInterestingIdentifier(*II);
II->setIsFromAST();
if (WasInteresting)
II->setChangedSinceDeserialization();
}
// Set or check the various bits in the IdentifierInfo structure.
// Token IDs are read-only.
if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier)
II->RevertTokenIDToIdentifier();
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
assert(II->isExtensionToken() == ExtensionToken &&
"Incorrect extension token flag");
(void)ExtensionToken;
if (Poisoned)
II->setIsPoisoned(true);
assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
"Incorrect C++ operator keyword flag");
(void)CPlusPlusOperatorKeyword;
// If this identifier is a macro, deserialize the macro
// definition.
if (hadMacroDefinition) {
uint32_t MacroDirectivesOffset =
endian::readNext<uint32_t, little, unaligned>(d);
DataLen -= 4;
SmallVector<uint32_t, 8> LocalMacroIDs;
if (hasSubmoduleMacros) {
while (uint32_t LocalMacroID =
endian::readNext<uint32_t, little, unaligned>(d)) {
DataLen -= 4;
LocalMacroIDs.push_back(LocalMacroID);
}
DataLen -= 4;
}
if (F.Kind == MK_Module) {
// Macro definitions are stored from newest to oldest, so reverse them
// before registering them.
llvm::SmallVector<unsigned, 8> MacroSizes;
for (SmallVectorImpl<uint32_t>::iterator
I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; /**/) {
unsigned Size = 1;
static const uint32_t HasOverridesFlag = 0x80000000U;
if (I + 1 != E && (I[1] & HasOverridesFlag))
Size += 1 + (I[1] & ~HasOverridesFlag);
MacroSizes.push_back(Size);
I += Size;
}
SmallVectorImpl<uint32_t>::iterator I = LocalMacroIDs.end();
for (SmallVectorImpl<unsigned>::reverse_iterator SI = MacroSizes.rbegin(),
SE = MacroSizes.rend();
SI != SE; ++SI) {
I -= *SI;
uint32_t LocalMacroID = *I;
llvm::ArrayRef<uint32_t> Overrides;
if (*SI != 1)
Overrides = llvm::makeArrayRef(&I[2], *SI - 2);
Reader.addPendingMacroFromModule(II, &F, LocalMacroID, Overrides);
}
assert(I == LocalMacroIDs.begin());
} else {
Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset);
}
}
Reader.SetIdentifierInfo(ID, II);
// Read all of the declarations visible at global scope with this
// name.
if (DataLen > 0) {
SmallVector<uint32_t, 4> DeclIDs;
for (; DataLen > 0; DataLen -= 4)
DeclIDs.push_back(Reader.getGlobalDeclID(
F, endian::readNext<uint32_t, little, unaligned>(d)));
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}
return II;
}
unsigned
ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const {
llvm::FoldingSetNodeID ID;
ID.AddInteger(Key.Kind);
switch (Key.Kind) {
case DeclarationName::Identifier:
case DeclarationName::CXXLiteralOperatorName:
ID.AddString(((IdentifierInfo*)Key.Data)->getName());
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
break;
case DeclarationName::CXXOperatorName:
ID.AddInteger((OverloadedOperatorKind)Key.Data);
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
break;
}
return ID.ComputeHash();
}
ASTDeclContextNameLookupTrait::internal_key_type
ASTDeclContextNameLookupTrait::GetInternalKey(
const external_key_type& Name) const {
DeclNameKey Key;
Key.Kind = Name.getNameKind();
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
Key.Data = (uint64_t)Name.getAsIdentifierInfo();
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
Key.Data = Name.getCXXOverloadedOperator();
break;
case DeclarationName::CXXLiteralOperatorName:
Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
Key.Data = 0;
break;
}
return Key;
}
std::pair<unsigned, unsigned>
ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
ASTDeclContextNameLookupTrait::internal_key_type
ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
using namespace llvm::support;
DeclNameKey Key;
Key.Kind = (DeclarationName::NameKind)*d++;
switch (Key.Kind) {
case DeclarationName::Identifier:
Key.Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Key.Data =
(uint64_t)Reader.getLocalSelector(
F, endian::readNext<uint32_t, little, unaligned>(
d)).getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
Key.Data = *d++; // OverloadedOperatorKind
break;
case DeclarationName::CXXLiteralOperatorName:
Key.Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
Key.Data = 0;
break;
}
return Key;
}
ASTDeclContextNameLookupTrait::data_type
ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
const unsigned char* d,
unsigned DataLen) {
using namespace llvm::support;
unsigned NumDecls = endian::readNext<uint16_t, little, unaligned>(d);
LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
const_cast<unsigned char *>(d));
return std::make_pair(Start, Start + NumDecls);
}
bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
DeclContextInfo &Info) {
SavedStreamPosition SavedPosition(Cursor);
// First the lexical decls.
if (Offsets.first != 0) {
Cursor.JumpToBit(Offsets.first);
RecordData Record;
StringRef Blob;
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_LEXICAL) {
Error("Expected lexical block");
return true;
}
Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
}
// Now the lookup table.
if (Offsets.second != 0) {
Cursor.JumpToBit(Offsets.second);
RecordData Record;
StringRef Blob;
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_VISIBLE) {
Error("Expected visible lookup table block");
return true;
}
Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create(
(const unsigned char *)Blob.data() + Record[0],
(const unsigned char *)Blob.data() + sizeof(uint32_t),
(const unsigned char *)Blob.data(),
ASTDeclContextNameLookupTrait(*this, M));
}
return false;
}
void ASTReader::Error(StringRef Msg) {
Error(diag::err_fe_pch_malformed, Msg);
if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
Diag(diag::note_module_cache_path)
<< PP.getHeaderSearchInfo().getModuleCachePath();
}
}
void ASTReader::Error(unsigned DiagID,
StringRef Arg1, StringRef Arg2) {
if (Diags.isDiagnosticInFlight())
Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
else
Diag(DiagID) << Arg1 << Arg2;
}
//===----------------------------------------------------------------------===//
// Source Manager Deserialization
//===----------------------------------------------------------------------===//
/// \brief Read the line table in the source manager block.
/// \returns true if there was an error.
bool ASTReader::ParseLineTable(ModuleFile &F,
SmallVectorImpl<uint64_t> &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
// Parse the file names
std::map<int, int> FileIDs;
for (int I = 0, N = Record[Idx++]; I != N; ++I) {
// Extract the file name
unsigned FilenameLen = Record[Idx++];
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
MaybeAddSystemRootToFilename(F, Filename);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
// Parse the line entries
std::vector<LineEntry> Entries;
while (Idx < Record.size()) {
int FID = Record[Idx++];
assert(FID >= 0 && "Serialized line entries for non-local file.");
// Remap FileID from 1-based old view.
FID += F.SLocEntryBaseID - 1;
// Extract the line entries
unsigned NumEntries = Record[Idx++];
assert(NumEntries && "Numentries is 00000");
Entries.clear();
Entries.reserve(NumEntries);
for (unsigned I = 0; I != NumEntries; ++I) {
unsigned FileOffset = Record[Idx++];
unsigned LineNo = Record[Idx++];
int FilenameID = FileIDs[Record[Idx++]];
SrcMgr::CharacteristicKind FileKind
= (SrcMgr::CharacteristicKind)Record[Idx++];
unsigned IncludeOffset = Record[Idx++];
Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
FileKind, IncludeOffset));
}
LineTable.AddEntry(FileID::get(FID), Entries);
}
return false;
}
/// \brief Read a source manager block
bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
// Set the source-location entry cursor to the current position in
// the stream. This cursor will be used to read the contents of the
// source manager block initially, and then lazily read
// source-location entries as needed.
SLocEntryCursor = F.Stream;
// The stream itself is going to skip over the source manager block.
if (F.Stream.SkipBlock()) {
Error("malformed block record in AST file");
return true;
}
// Enter the source manager block.
if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
Error("malformed source manager block record in AST file");
return true;
}
RecordData Record;
while (true) {
llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks();
switch (E.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return true;
case llvm::BitstreamEntry::EndBlock:
return false;
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
}
// Read a record.
Record.clear();
StringRef Blob;
switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
case SM_SLOC_FILE_ENTRY:
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
// Once we hit one of the source location entries, we're done.
return false;
}
}
}
/// \brief If a header file is not found at the path that we expect it to be
/// and the PCH file was moved from its original location, try to resolve the
/// file by assuming that header+PCH were moved together and the header is in
/// the same place relative to the PCH.
static std::string
resolveFileRelativeToOriginalDir(const std::string &Filename,
const std::string &OriginalDir,
const std::string &CurrDir) {
assert(OriginalDir != CurrDir &&
"No point trying to resolve the file if the PCH dir didn't change");
using namespace llvm::sys;
SmallString<128> filePath(Filename);
fs::make_absolute(filePath);
assert(path::is_absolute(OriginalDir));
SmallString<128> currPCHPath(CurrDir);
path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
fileDirE = path::end(path::parent_path(filePath));
path::const_iterator origDirI = path::begin(OriginalDir),
origDirE = path::end(OriginalDir);
// Skip the common path components from filePath and OriginalDir.
while (fileDirI != fileDirE && origDirI != origDirE &&
*fileDirI == *origDirI) {
++fileDirI;
++origDirI;
}
for (; origDirI != origDirE; ++origDirI)
path::append(currPCHPath, "..");
path::append(currPCHPath, fileDirI, fileDirE);
path::append(currPCHPath, path::filename(Filename));
return currPCHPath.str();
}
bool ASTReader::ReadSLocEntry(int ID) {
if (ID == 0)
return false;
if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
return true;
}
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
unsigned BaseOffset = F->SLocEntryBaseOffset;
++NumSLocEntriesRead;
llvm::BitstreamEntry Entry = SLocEntryCursor.advance();
if (Entry.Kind != llvm::BitstreamEntry::Record) {
Error("incorrectly-formatted source location entry in AST file");
return true;
}
RecordData Record;
StringRef Blob;
switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) {
default:
Error("incorrectly-formatted source location entry in AST file");
return true;
case SM_SLOC_FILE_ENTRY: {
// We will detect whether a file changed and return 'Failure' for it, but
// we will also try to fail gracefully by setting up the SLocEntry.
unsigned InputID = Record[4];
InputFile IF = getInputFile(*F, InputID);
const FileEntry *File = IF.getFile();
bool OverriddenBuffer = IF.isOverridden();
// Note that we only check if a File was returned. If it was out-of-date
// we have complained but we will continue creating a FileID to recover
// gracefully.
if (!File)
return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
// This is the module's main file.
IncludeLoc = getImportLocation(F);
}
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
FileInfo.NumCreatedFIDs = Record[5];
if (Record[3])
FileInfo.setHasLineDirectives();
const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
unsigned NumFileDecls = Record[7];
if (NumFileDecls) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
NumFileDecls));
}
const SrcMgr::ContentCache *ContentCache
= SourceMgr.getOrCreateContentCache(File,
/*isSystemFile=*/FileCharacter != SrcMgr::C_User);
if (OverriddenBuffer && !ContentCache->BufferOverridden &&
ContentCache->ContentsEntry == ContentCache->OrigEntry) {
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
SourceMgr.overrideFileContents(File, Buffer);
}
break;
}
case SM_SLOC_BUFFER_ENTRY: {
const char *Name = Blob.data();
unsigned Offset = Record[0];
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
IncludeLoc = getImportLocation(F);
}
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode
= SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
BaseOffset + Offset, IncludeLoc);
break;
}
case SM_SLOC_EXPANSION_ENTRY: {
SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
SourceMgr.createExpansionLoc(SpellingLoc,
ReadSourceLocation(*F, Record[2]),
ReadSourceLocation(*F, Record[3]),
Record[4],
ID,
BaseOffset + Record[0]);
break;
}
}
return false;
}
std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
if (ID == 0)
return std::make_pair(SourceLocation(), "");
if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
return std::make_pair(SourceLocation(), "");
}
// Find which module file this entry lands in.
ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
if (M->Kind != MK_Module)
return std::make_pair(SourceLocation(), "");
// FIXME: Can we map this down to a particular submodule? That would be
// ideal.
return std::make_pair(M->ImportLoc, StringRef(M->ModuleName));
}
/// \brief Find the location where the module F is imported.
SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
if (F->ImportLoc.isValid())
return F->ImportLoc;
// Otherwise we have a PCH. It's considered to be "imported" at the first
// location of its includer.
if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
// Main file is the importer.
assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file");
return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
}
return F->ImportedBy[0]->FirstLoc;
}
/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
/// specified cursor. Read the abbreviations that are at the top of the block
/// and then leave the cursor pointing into the block.
bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
if (Cursor.EnterSubBlock(BlockID)) {
Error("malformed block record in AST file");
return Failure;
}
while (true) {
uint64_t Offset = Cursor.GetCurrentBitNo();
unsigned Code = Cursor.ReadCode();
// We expect all abbrevs to be at the start of the block.
if (Code != llvm::bitc::DEFINE_ABBREV) {
Cursor.JumpToBit(Offset);
return false;
}
Cursor.ReadAbbrevRecord();
}
}
Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
unsigned &Idx) {
Token Tok;
Tok.startToken();
Tok.setLocation(ReadSourceLocation(F, Record, Idx));
Tok.setLength(Record[Idx++]);
if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
Tok.setIdentifierInfo(II);
Tok.setKind((tok::TokenKind)Record[Idx++]);
Tok.setFlag((Token::TokenFlags)Record[Idx++]);
return Tok;
}
MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this macro.
SavedStreamPosition SavedPosition(Stream);
Stream.JumpToBit(Offset);
RecordData Record;
SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
while (true) {
// Advance to the next record, but if we get to the end of the block, don't
// pop it (removing all the abbreviations from the cursor) since we want to
// be able to reseek within the block and read entries.
unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd;
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags);
switch (Entry.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return Macro;
case llvm::BitstreamEntry::EndBlock:
return Macro;
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
}
// Read a record.
Record.clear();
PreprocessorRecordTypes RecType =
(PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record);
switch (RecType) {
case PP_MACRO_DIRECTIVE_HISTORY:
return Macro;
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE: {
// If we already have a macro, that means that we've hit the end
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
return Macro;
unsigned NextIndex = 1; // Skip identifier ID.
SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
MI->setUsedForHeaderGuard(Record[NextIndex++]);
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
bool isC99VarArgs = Record[NextIndex++];
bool isGNUVarArgs = Record[NextIndex++];
bool hasCommaPasting = Record[NextIndex++];
MacroArgs.clear();
unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
// Install function-like macro info.
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
if (hasCommaPasting) MI->setHasCommaPasting();
MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
PP.getPreprocessorAllocator());
}
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
Macro = MI;
if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() &&
Record[NextIndex]) {
// We have a macro definition. Register the association
PreprocessedEntityID
GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
PreprocessingRecord::PPEntityID
PPID = PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true);
MacroDefinition *PPDef =
cast_or_null<MacroDefinition>(PPRec.getPreprocessedEntity(PPID));
if (PPDef)
PPRec.RegisterMacroDefinition(Macro, PPDef);
}
++NumMacrosRead;
break;
}
case PP_TOKEN: {
// If we see a TOKEN before a PP_MACRO_*, then the file is
// erroneous, just pretend we didn't see this.
if (Macro == 0) break;
unsigned Idx = 0;
Token Tok = ReadToken(F, Record, Idx);
Macro->AddTokenToBody(Tok);
break;
}
}
}
}
PreprocessedEntityID
ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
ContinuousRangeMap<uint32_t, int, 2>::const_iterator
I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
assert(I != M.PreprocessedEntityRemap.end()
&& "Invalid index into preprocessed entity index remap");
return LocalID + I->second;
}
unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
FE->getName() };
return ikey;
}
bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
if (strcmp(a.Filename, b.Filename) == 0)
return true;
// Determine whether the actual files are equivalent.
FileManager &FileMgr = Reader.getFileManager();
const FileEntry *FEA = FileMgr.getFile(a.Filename);
const FileEntry *FEB = FileMgr.getFile(b.Filename);
return (FEA && FEA == FEB);
}
std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned KeyLen = (unsigned) endian::readNext<uint16_t, little, unaligned>(d);
unsigned DataLen = (unsigned) *d++;
return std::make_pair(KeyLen, DataLen);
}
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;
internal_key_type ikey;
ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d));
ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d));
ikey.Filename = (const char *)d;
return ikey;
}
HeaderFileInfoTrait::data_type
HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
using namespace llvm::support;
HeaderFileInfo HFI;
unsigned Flags = *d++;
HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
((Flags >> 6) & 0x03);
HFI.isImport = (Flags >> 5) & 0x01;
HFI.isPragmaOnce = (Flags >> 4) & 0x01;
HFI.DirInfo = (Flags >> 2) & 0x03;
HFI.Resolved = (Flags >> 1) & 0x01;
HFI.IndexHeaderMapHeader = Flags & 0x01;
HFI.NumIncludes = endian::readNext<uint16_t, little, unaligned>(d);
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
M, endian::readNext<uint32_t, little, unaligned>(d));
if (unsigned FrameworkOffset =
endian::readNext<uint32_t, little, unaligned>(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
}
if (d != End) {
uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d);
if (LocalSMID) {
// This header is part of a module. Associate it with the module to enable
// implicit module import.
SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
Module *Mod = Reader.getSubmodule(GlobalSMID);
HFI.isModuleHeader = true;
FileManager &FileMgr = Reader.getFileManager();
ModuleMap &ModMap =
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole());
}
}
assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
(void)End;
// This HeaderFileInfo was externally loaded.
HFI.External = true;
return HFI;
}
void
ASTReader::addPendingMacroFromModule(IdentifierInfo *II, ModuleFile *M,
GlobalMacroID GMacID,
llvm::ArrayRef<SubmoduleID> Overrides) {
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
SubmoduleID *OverrideData = 0;
if (!Overrides.empty()) {
OverrideData = new (Context) SubmoduleID[Overrides.size() + 1];
OverrideData[0] = Overrides.size();
for (unsigned I = 0; I != Overrides.size(); ++I)
OverrideData[I + 1] = getGlobalSubmoduleID(*M, Overrides[I]);
}
PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, OverrideData));
}
void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II,
ModuleFile *M,
uint64_t MacroDirectivesOffset) {
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset));
}
void ASTReader::ReadDefinedMacros() {
// Note that we are loading defined macros.
Deserializing Macros(this);
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
E = ModuleMgr.rend(); I != E; ++I) {
BitstreamCursor &MacroCursor = (*I)->MacroCursor;
// If there was no preprocessor block, skip this file.
if (!MacroCursor.getBitStreamReader())
continue;
BitstreamCursor Cursor = MacroCursor;
Cursor.JumpToBit((*I)->MacroStartOffset);
RecordData Record;
while (true) {
llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks();
switch (E.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return;
case llvm::BitstreamEntry::EndBlock:
goto NextCursor;
case llvm::BitstreamEntry::Record:
Record.clear();
switch (Cursor.readRecord(E.ID, Record)) {
default: // Default behavior: ignore.
break;
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE:
getLocalIdentifier(**I, Record[0]);
break;
case PP_TOKEN:
// Ignore tokens.
break;
}
break;
}
}
NextCursor: ;
}
}
namespace {
/// \brief Visitor class used to look up identifirs in an AST file.
class IdentifierLookupVisitor {
StringRef Name;
unsigned PriorGeneration;
unsigned &NumIdentifierLookups;
unsigned &NumIdentifierLookupHits;
IdentifierInfo *Found;
public:
IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration,
unsigned &NumIdentifierLookups,
unsigned &NumIdentifierLookupHits)
: Name(Name), PriorGeneration(PriorGeneration),
NumIdentifierLookups(NumIdentifierLookups),
NumIdentifierLookupHits(NumIdentifierLookupHits),
Found()
{
}
static bool visit(ModuleFile &M, void *UserData) {
IdentifierLookupVisitor *This
= static_cast<IdentifierLookupVisitor *>(UserData);
// If we've already searched this module file, skip it now.
if (M.Generation <= This->PriorGeneration)
return true;
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
return false;
ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
M, This->Found);
++This->NumIdentifierLookups;
ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait);
if (Pos == IdTable->end())
return false;
// Dereferencing the iterator has the effect of building the
// IdentifierInfo node and populating it with the various
// declarations it needs.
++This->NumIdentifierLookupHits;
This->Found = *Pos;
return true;
}
// \brief Retrieve the identifier info found within the module
// files.
IdentifierInfo *getIdentifierInfo() const { return Found; }
};
}
void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
// Note that we are loading an identifier.
Deserializing AnIdentifier(this);
unsigned PriorGeneration = 0;
if (getContext().getLangOpts().Modules)
PriorGeneration = IdentifierGeneration[&II];
// If there is a global index, look there first to determine which modules
// provably do not have any results for this identifier.
GlobalModuleIndex::HitSet Hits;
GlobalModuleIndex::HitSet *HitsPtr = 0;
if (!loadGlobalIndex()) {
if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
HitsPtr = &Hits;
}
}
IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
NumIdentifierLookups,
NumIdentifierLookupHits);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
markIdentifierUpToDate(&II);
}
void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
if (!II)
return;
II->setOutOfDate(false);
// Update the generation for this identifier.
if (getContext().getLangOpts().Modules)
IdentifierGeneration[II] = CurrentGeneration;
}
struct ASTReader::ModuleMacroInfo {
SubmoduleID SubModID;
MacroInfo *MI;
SubmoduleID *Overrides;
// FIXME: Remove this.
ModuleFile *F;
bool isDefine() const { return MI; }
SubmoduleID getSubmoduleID() const { return SubModID; }
llvm::ArrayRef<SubmoduleID> getOverriddenSubmodules() const {
if (!Overrides)
return llvm::ArrayRef<SubmoduleID>();
return llvm::makeArrayRef(Overrides + 1, *Overrides);
}
DefMacroDirective *import(Preprocessor &PP, SourceLocation ImportLoc) const {
if (!MI)
return 0;
return PP.AllocateDefMacroDirective(MI, ImportLoc, /*isImported=*/true);
}
};
ASTReader::ModuleMacroInfo *
ASTReader::getModuleMacro(const PendingMacroInfo &PMInfo) {
ModuleMacroInfo Info;
uint32_t ID = PMInfo.ModuleMacroData.MacID;
if (ID & 1) {
// Macro undefinition.
Info.SubModID = getGlobalSubmoduleID(*PMInfo.M, ID >> 1);
Info.MI = 0;
} else {
// Macro definition.
GlobalMacroID GMacID = getGlobalMacroID(*PMInfo.M, ID >> 1);
assert(GMacID);
// If this macro has already been loaded, don't do so again.
// FIXME: This is highly dubious. Multiple macro definitions can have the
// same MacroInfo (and hence the same GMacID) due to #pragma push_macro etc.
if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS])
return 0;
Info.MI = getMacro(GMacID);
Info.SubModID = Info.MI->getOwningModuleID();
}
Info.Overrides = PMInfo.ModuleMacroData.Overrides;
Info.F = PMInfo.M;
return new (Context) ModuleMacroInfo(Info);
}
void ASTReader::resolvePendingMacro(IdentifierInfo *II,
const PendingMacroInfo &PMInfo) {
assert(II);
if (PMInfo.M->Kind != MK_Module) {
installPCHMacroDirectives(II, *PMInfo.M,
PMInfo.PCHMacroData.MacroDirectivesOffset);
return;
}
// Module Macro.
ModuleMacroInfo *MMI = getModuleMacro(PMInfo);
if (!MMI)
return;
Module *Owner = getSubmodule(MMI->getSubmoduleID());
if (Owner && Owner->NameVisibility == Module::Hidden) {
// Macros in the owning module are hidden. Just remember this macro to
// install if we make this module visible.
HiddenNamesMap[Owner].HiddenMacros.insert(std::make_pair(II, MMI));
} else {
installImportedMacro(II, MMI, Owner);
}
}
void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
ModuleFile &M, uint64_t Offset) {
assert(M.Kind != MK_Module);
BitstreamCursor &Cursor = M.MacroCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(Offset);
llvm::BitstreamEntry Entry =
Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
if (Entry.Kind != llvm::BitstreamEntry::Record) {
Error("malformed block record in AST file");
return;
}
RecordData Record;
PreprocessorRecordTypes RecType =
(PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record);
if (RecType != PP_MACRO_DIRECTIVE_HISTORY) {
Error("malformed block record in AST file");
return;
}
// Deserialize the macro directives history in reverse source-order.
MacroDirective *Latest = 0, *Earliest = 0;
unsigned Idx = 0, N = Record.size();
while (Idx < N) {
MacroDirective *MD = 0;
SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++];
switch (K) {
case MacroDirective::MD_Define: {
GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]);
MacroInfo *MI = getMacro(GMacID);
bool isImported = Record[Idx++];
bool isAmbiguous = Record[Idx++];
DefMacroDirective *DefMD =
PP.AllocateDefMacroDirective(MI, Loc, isImported);
DefMD->setAmbiguous(isAmbiguous);
MD = DefMD;
break;
}
case MacroDirective::MD_Undefine:
MD = PP.AllocateUndefMacroDirective(Loc);
break;
case MacroDirective::MD_Visibility: {
bool isPublic = Record[Idx++];
MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic);
break;
}
}
if (!Latest)
Latest = MD;
if (Earliest)
Earliest->setPrevious(MD);
Earliest = MD;
}
PP.setLoadedMacroDirective(II, Latest);
}
/// \brief For the given macro definitions, check if they are both in system
/// modules.
static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
Module *NewOwner, ASTReader &Reader) {
assert(PrevMI && NewMI);
Module *PrevOwner = 0;
if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
PrevOwner = Reader.getSubmodule(PrevModID);
SourceManager &SrcMgr = Reader.getSourceManager();
bool PrevInSystem
= PrevOwner? PrevOwner->IsSystem
: SrcMgr.isInSystemHeader(PrevMI->getDefinitionLoc());
bool NewInSystem
= NewOwner? NewOwner->IsSystem
: SrcMgr.isInSystemHeader(NewMI->getDefinitionLoc());
if (PrevOwner && PrevOwner == NewOwner)
return false;
return PrevInSystem && NewInSystem;
}
void ASTReader::removeOverriddenMacros(IdentifierInfo *II,
AmbiguousMacros &Ambig,
llvm::ArrayRef<SubmoduleID> Overrides) {
for (unsigned OI = 0, ON = Overrides.size(); OI != ON; ++OI) {
SubmoduleID OwnerID = Overrides[OI];
// If this macro is not yet visible, remove it from the hidden names list.
Module *Owner = getSubmodule(OwnerID);
HiddenNames &Hidden = HiddenNamesMap[Owner];
HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
if (HI != Hidden.HiddenMacros.end()) {
auto SubOverrides = HI->second->getOverriddenSubmodules();
Hidden.HiddenMacros.erase(HI);
removeOverriddenMacros(II, Ambig, SubOverrides);
}
// If this macro is already in our list of conflicts, remove it from there.
Ambig.erase(
std::remove_if(Ambig.begin(), Ambig.end(), [&](DefMacroDirective *MD) {
return MD->getInfo()->getOwningModuleID() == OwnerID;
}),
Ambig.end());
}
}
ASTReader::AmbiguousMacros *
ASTReader::removeOverriddenMacros(IdentifierInfo *II,
llvm::ArrayRef<SubmoduleID> Overrides) {
MacroDirective *Prev = PP.getMacroDirective(II);
if (!Prev && Overrides.empty())
return 0;
DefMacroDirective *PrevDef = Prev ? Prev->getDefinition().getDirective() : 0;
if (PrevDef && PrevDef->isAmbiguous()) {
// We had a prior ambiguity. Check whether we resolve it (or make it worse).
AmbiguousMacros &Ambig = AmbiguousMacroDefs[II];
Ambig.push_back(PrevDef);
removeOverriddenMacros(II, Ambig, Overrides);
if (!Ambig.empty())
return &Ambig;
AmbiguousMacroDefs.erase(II);
} else {
// There's no ambiguity yet. Maybe we're introducing one.
llvm::SmallVector<DefMacroDirective*, 1> Ambig;
if (PrevDef)
Ambig.push_back(PrevDef);
removeOverriddenMacros(II, Ambig, Overrides);
if (!Ambig.empty()) {
AmbiguousMacros &Result = AmbiguousMacroDefs[II];
Result.swap(Ambig);
return &Result;
}
}
// We ended up with no ambiguity.
return 0;
}
void ASTReader::installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
Module *Owner) {
assert(II && Owner);
SourceLocation ImportLoc = Owner->MacroVisibilityLoc;
if (ImportLoc.isInvalid()) {
// FIXME: If we made macros from this module visible but didn't provide a
// source location for the import, we don't have a location for the macro.
// Use the location at which the containing module file was first imported
// for now.
ImportLoc = MMI->F->DirectImportLoc;
assert(ImportLoc.isValid() && "no import location for a visible macro?");
}
llvm::SmallVectorImpl<DefMacroDirective*> *Prev =
removeOverriddenMacros(II, MMI->getOverriddenSubmodules());
// Create a synthetic macro definition corresponding to the import (or null
// if this was an undefinition of the macro).
DefMacroDirective *MD = MMI->import(PP, ImportLoc);
// If there's no ambiguity, just install the macro.
if (!Prev) {
if (MD)
PP.appendMacroDirective(II, MD);
else
PP.appendMacroDirective(II, PP.AllocateUndefMacroDirective(ImportLoc));
return;
}
assert(!Prev->empty());
if (!MD) {
// We imported a #undef that didn't remove all prior definitions. The most
// recent prior definition remains, and we install it in the place of the
// imported directive.
MacroInfo *NewMI = Prev->back()->getInfo();
Prev->pop_back();
MD = PP.AllocateDefMacroDirective(NewMI, ImportLoc, /*Imported*/true);
}
// We're introducing a macro definition that creates or adds to an ambiguity.
// We can resolve that ambiguity if this macro is token-for-token identical to
// all of the existing definitions.
MacroInfo *NewMI = MD->getInfo();
assert(NewMI && "macro definition with no MacroInfo?");
while (!Prev->empty()) {
MacroInfo *PrevMI = Prev->back()->getInfo();
assert(PrevMI && "macro definition with no MacroInfo?");
// Before marking the macros as ambiguous, check if this is a case where
// both macros are in system headers. If so, we trust that the system
// did not get it wrong. This also handles cases where Clang's own
// headers have a different spelling of certain system macros:
// #define LONG_MAX __LONG_MAX__ (clang's limits.h)
// #define LONG_MAX 0x7fffffffffffffffL (system's limits.h)
//
// FIXME: Remove the defined-in-system-headers check. clang's limits.h
// overrides the system limits.h's macros, so there's no conflict here.
if (NewMI != PrevMI &&
!PrevMI->isIdenticalTo(*NewMI, PP, /*Syntactically=*/true) &&
!areDefinedInSystemModules(PrevMI, NewMI, Owner, *this))
break;
// The previous definition is the same as this one (or both are defined in
// system modules so we can assume they're equivalent); we don't need to
// track it any more.
Prev->pop_back();
}
if (!Prev->empty())
MD->setAmbiguous(true);
PP.appendMacroDirective(II, MD);
}
ASTReader::InputFileInfo
ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
// Go find this input file.
BitstreamCursor &Cursor = F.InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
unsigned Code = Cursor.ReadCode();
RecordData Record;
StringRef Blob;
unsigned Result = Cursor.readRecord(Code, Record, &Blob);
assert(static_cast<InputFileRecordTypes>(Result) == INPUT_FILE &&
"invalid record type for input file");
(void)Result;
std::string Filename;
off_t StoredSize;
time_t StoredTime;
bool Overridden;
assert(Record[0] == ID && "Bogus stored ID or offset");
StoredSize = static_cast<off_t>(Record[1]);
StoredTime = static_cast<time_t>(Record[2]);
Overridden = static_cast<bool>(Record[3]);
Filename = Blob;
MaybeAddSystemRootToFilename(F, Filename);
InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
return R;
}
std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) {
return readInputFileInfo(F, ID).Filename;
}
InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// If this ID is bogus, just return an empty input file.
if (ID == 0 || ID > F.InputFilesLoaded.size())
return InputFile();
// If we've already loaded this input file, return it.
if (F.InputFilesLoaded[ID-1].getFile())
return F.InputFilesLoaded[ID-1];
if (F.InputFilesLoaded[ID-1].isNotFound())
return InputFile();
// Go find this input file.
BitstreamCursor &Cursor = F.InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
InputFileInfo FI = readInputFileInfo(F, ID);
off_t StoredSize = FI.StoredSize;
time_t StoredTime = FI.StoredTime;
bool Overridden = FI.Overridden;
StringRef Filename = FI.Filename;
const FileEntry *File
= Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
: FileMgr.getFile(Filename, /*OpenFile=*/false);
// If we didn't find the file, resolve it relative to the
// original directory from which this AST file was created.
if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
F.OriginalDir != CurrentDir) {
std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
F.OriginalDir,
CurrentDir);
if (!Resolved.empty())
File = FileMgr.getFile(Resolved);
}
// For an overridden file, create a virtual file with the stored
// size/timestamp.
if (Overridden && File == 0) {
File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
}
if (File == 0) {
if (Complain) {
std::string ErrorStr = "could not find file '";
ErrorStr += Filename;
ErrorStr += "' referenced by AST file";
Error(ErrorStr.c_str());
}
// Record that we didn't find the file.
F.InputFilesLoaded[ID-1] = InputFile::getNotFound();
return InputFile();
}
// Check if there was a request to override the contents of the file
// that was part of the precompiled header. Overridding such a file
// can lead to problems when lexing using the source locations from the
// PCH.
SourceManager &SM = getSourceManager();
if (!Overridden && SM.isFileOverridden(File)) {
if (Complain)
Error(diag::err_fe_pch_file_overridden, Filename);
// After emitting the diagnostic, recover by disabling the override so
// that the original file will be used.
SM.disableFileContentsOverride(File);
// The FileEntry is a virtual file entry with the size of the contents
// that would override the original contents. Set it to the original's
// size/time.
FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
StoredSize, StoredTime);
}
bool IsOutOfDate = false;
// For an overridden file, there is nothing to validate.
if (!Overridden && (StoredSize != File->getSize()
#if !defined(LLVM_ON_WIN32)
// In our regression testing, the Windows file system seems to
// have inconsistent modification times that sometimes
// erroneously trigger this error-handling path.
|| StoredTime != File->getModificationTime()
#endif
)) {
if (Complain) {
// Build a list of the PCH imports that got us here (in reverse).
SmallVector<ModuleFile *, 4> ImportStack(1, &F);
while (ImportStack.back()->ImportedBy.size() > 0)
ImportStack.push_back(ImportStack.back()->ImportedBy[0]);
// The top-level PCH is stale.
StringRef TopLevelPCHName(ImportStack.back()->FileName);
Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName);
// Print the import stack.
if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) {
Diag(diag::note_pch_required_by)
<< Filename << ImportStack[0]->FileName;
for (unsigned I = 1; I < ImportStack.size(); ++I)
Diag(diag::note_pch_required_by)
<< ImportStack[I-1]->FileName << ImportStack[I]->FileName;
}
if (!Diags.isDiagnosticInFlight())
Diag(diag::note_pch_rebuild_required) << TopLevelPCHName;
}
IsOutOfDate = true;
}
InputFile IF = InputFile(File, Overridden, IsOutOfDate);
// Note that we've loaded this input file.
F.InputFilesLoaded[ID-1] = IF;
return IF;
}
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
ModuleFile &M = ModuleMgr.getPrimaryModule();
std::string Filename = filenameStrRef;
MaybeAddSystemRootToFilename(M, Filename);
const FileEntry *File = FileMgr.getFile(Filename);
if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
M.OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
M.OriginalDir,
CurrentDir);
if (!resolved.empty())
File = FileMgr.getFile(resolved);
}
return File;
}
/// \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.
void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
std::string &Filename) {
// If this is not a relocatable PCH file, there's nothing to do.
if (!M.RelocatablePCH)
return;
if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
return;
if (isysroot.empty()) {
// If no system root was given, default to '/'
Filename.insert(Filename.begin(), '/');
return;
}
unsigned Length = isysroot.size();
if (isysroot[Length - 1] != '/')
Filename.insert(Filename.begin(), '/');
Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
}
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
// Read all of the records and blocks in the control block.
RecordData Record;
while (1) {
llvm::BitstreamEntry Entry = Stream.advance();
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return Failure;
case llvm::BitstreamEntry::EndBlock: {
// Validate input files.
const HeaderSearchOptions &HSOpts =
PP.getHeaderSearchInfo().getHeaderSearchOpts();
// All user input files reside at the index range [0, Record[1]), and
// system input files reside at [Record[1], Record[0]).
// Record is the one from INPUT_FILE_OFFSETS.
unsigned NumInputs = Record[0];
unsigned NumUserInputs = Record[1];
if (!DisableValidation &&
(ValidateSystemInputs || !HSOpts.ModulesValidateOncePerBuildSession ||
F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// If we are reading a module, we will create a verification timestamp,
// so we verify all input files. Otherwise, verify only user input
// files.
unsigned N = NumUserInputs;
if (ValidateSystemInputs ||
(HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module))
N = NumInputs;
for (unsigned I = 0; I < N; ++I) {
InputFile IF = getInputFile(F, I+1, Complain);
if (!IF.getFile() || IF.isOutOfDate())
return OutOfDate;
}
}
if (Listener)
Listener->visitModuleFile(F.FileName);
if (Listener && Listener->needsInputFileVisitation()) {
unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs
: NumUserInputs;
for (unsigned I = 0; I < N; ++I) {
bool IsSystem = I >= NumUserInputs;
InputFileInfo FI = readInputFileInfo(F, I+1);
Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden);
}
}
return Success;
}
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
F.InputFilesCursor = Stream;
if (Stream.SkipBlock() || // Skip with the main cursor
// Read the abbreviations
ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
continue;
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
return Failure;
}
continue;
}
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
}
// Read and process a record.
Record.clear();
StringRef Blob;
switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
case METADATA: {
if (Record[0] != VERSION_MAJOR && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old
: diag::err_pch_version_too_new);
return VersionMismatch;
}
bool hasErrors = Record[5];
if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
Diag(diag::err_pch_with_compiler_errors);
return HadErrors;
}
F.RelocatablePCH = Record[4];
const std::string &CurBranch = getClangFullRepositoryVersion();
StringRef ASTBranch = Blob;
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch;
return VersionMismatch;
}
break;
}
case IMPORTS: {
// Load each of the imported PCH files.
unsigned Idx = 0, N = Record.size();
while (Idx < N) {
// Read information about the AST file.
ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
// The import location will be the local one for now; we will adjust
// all import locations of module imports after the global source
// location info are setup.
SourceLocation ImportLoc =
SourceLocation::getFromRawEncoding(Record[Idx++]);
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
unsigned Length = Record[Idx++];
SmallString<128> ImportedFile(Record.begin() + Idx,
Record.begin() + Idx + Length);
Idx += Length;
// Load the AST file.
switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
StoredSize, StoredModTime,
ClientLoadCapabilities)) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
case Missing:
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
case HadErrors: return HadErrors;
case Success: break;
}
}
break;
}
case LANGUAGE_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseLanguageOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case TARGET_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseTargetOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case DIAGNOSTIC_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseDiagnosticOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case FILE_SYSTEM_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseFileSystemOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case HEADER_SEARCH_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseHeaderSearchOptions(Record, Complain, *Listener) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case PREPROCESSOR_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParsePreprocessorOptions(Record, Complain, *Listener,
SuggestedPredefines) &&
!DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case ORIGINAL_FILE:
F.OriginalSourceFileID = FileID::get(Record[0]);
F.ActualOriginalSourceFileName = Blob;
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
break;
case ORIGINAL_FILE_ID:
F.OriginalSourceFileID = FileID::get(Record[0]);
break;
case ORIGINAL_PCH_DIR:
F.OriginalDir = Blob;
break;
case MODULE_NAME:
F.ModuleName = Blob;
if (Listener)
Listener->ReadModuleName(F.ModuleName);
break;
case MODULE_MAP_FILE:
F.ModuleMapPath = Blob;
// Try to resolve ModuleName in the current header search context and
// verify that it is found in the same module map file as we saved. If the
// top-level AST file is a main file, skip this check because there is no
// usable header search context.
assert(!F.ModuleName.empty() &&
"MODULE_NAME should come before MOUDLE_MAP_FILE");
if (F.Kind == MK_Module &&
(*ModuleMgr.begin())->Kind != MK_MainFile) {
Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
if (!M) {
assert(ImportedBy && "top-level import should be verified");
if ((ClientLoadCapabilities & ARR_Missing) == 0)
Diag(diag::err_imported_module_not_found)
<< F.ModuleName << ImportedBy->FileName;
return Missing;
}
const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
if (StoredModMap == nullptr || StoredModMap != M->ModuleMap) {
assert(M->ModuleMap && "found module is missing module map file");
assert(M->Name == F.ModuleName && "found module with different name");
assert(ImportedBy && "top-level import should be verified");
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Diag(diag::err_imported_module_modmap_changed)
<< F.ModuleName << ImportedBy->FileName
<< M->ModuleMap->getName() << F.ModuleMapPath;
return OutOfDate;
}
}
if (Listener)
Listener->ReadModuleMapFile(F.ModuleMapPath);
break;
case INPUT_FILE_OFFSETS:
F.InputFileOffsets = (const uint32_t *)Blob.data();
F.InputFilesLoaded.resize(Record[0]);
break;
}
}
}
ASTReader::ASTReadResult
ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
// Read all of the records and blocks for the AST file.
RecordData Record;
while (1) {
llvm::BitstreamEntry Entry = Stream.advance();
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
Error("error at end of module block in AST file");
return Failure;
case llvm::BitstreamEntry::EndBlock: {
// Outside of C++, we do not store a lookup map for the translation unit.
// Instead, mark it as needing a lookup map to be built if this module
// contains any declarations lexically within it (which it always does!).
// This usually has no cost, since we very rarely need the lookup map for
// the translation unit outside C++.
DeclContext *DC = Context.getTranslationUnitDecl();
if (DC->hasExternalLexicalStorage() &&
!getContext().getLangOpts().CPlusPlus)
DC->setMustBuildLookupTable();
return Success;
}
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case DECLTYPES_BLOCK_ID:
// We lazily load the decls block, but we want to set up the
// DeclsCursor cursor to point into it. Clone our current bitcode
// cursor to it, enter the block and read the abbrevs in that block.
// With the main cursor, we just skip over it.
F.DeclsCursor = Stream;
if (Stream.SkipBlock() || // Skip with the main cursor.
// Read the abbrevs.
ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
break;
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
if (!PP.getExternalSource())
PP.setExternalSource(this);
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
case PREPROCESSOR_DETAIL_BLOCK_ID:
F.PreprocessorDetailCursor = Stream;
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID))