2013-01-31 11:23:57 +08:00
|
|
|
//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
|
2012-12-18 22:30:41 +08:00
|
|
|
//
|
|
|
|
// 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"
|
2013-01-25 09:03:03 +08:00
|
|
|
#include "clang/Serialization/GlobalModuleIndex.h"
|
2012-12-18 22:30:41 +08:00
|
|
|
#include "clang/Serialization/ModuleManager.h"
|
|
|
|
#include "clang/Serialization/SerializationDiagnostic.h"
|
2013-03-07 02:12:47 +08:00
|
|
|
#include "llvm/ADT/Hashing.h"
|
2012-12-18 22:30:41 +08:00
|
|
|
#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"
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-18 22:30:41 +08:00
|
|
|
#include "llvm/Support/system_error.h"
|
|
|
|
#include <algorithm>
|
2013-01-20 08:57:52 +08:00
|
|
|
#include <cstdio>
|
2012-12-18 22:30:41 +08:00
|
|
|
#include <iterator>
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace clang::serialization;
|
|
|
|
using namespace clang::serialization::reader;
|
2013-01-20 08:56:42 +08:00
|
|
|
using llvm::BitstreamCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2014-03-07 14:40:32 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ChainedASTReaderListener implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
bool
|
|
|
|
ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) {
|
|
|
|
return First->ReadFullVersionInformation(FullVersion) ||
|
|
|
|
Second->ReadFullVersionInformation(FullVersion);
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
2014-03-14 11:07:38 +08:00
|
|
|
void ChainedASTReaderListener::visitModuleFile(StringRef Filename) {
|
|
|
|
First->visitModuleFile(Filename);
|
|
|
|
Second->visitModuleFile(Filename);
|
|
|
|
}
|
2014-03-07 14:40:32 +08:00
|
|
|
bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
|
2014-03-14 10:26:31 +08:00
|
|
|
bool isSystem,
|
|
|
|
bool isOverridden) {
|
|
|
|
return First->visitInputFile(Filename, isSystem, isOverridden) ||
|
|
|
|
Second->visitInputFile(Filename, isSystem, isOverridden);
|
2014-03-07 14:40:32 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2013-02-22 22:21:27 +08:00
|
|
|
if (ExistingLangOpts.CommentOpts.BlockCommandNames !=
|
|
|
|
LangOpts.CommentOpts.BlockCommandNames) {
|
|
|
|
if (Diags)
|
|
|
|
Diags->Report(diag::err_pch_langopt_value_mismatch)
|
|
|
|
<< "block command names";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
2013-07-05 12:43:31 +08:00
|
|
|
typedef llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> >
|
|
|
|
DeclsMap;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \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,
|
2013-04-27 05:33:40 +08:00
|
|
|
std::string &SuggestedPredefines,
|
|
|
|
const LangOptions &LangOpts) {
|
2012-12-18 22:30:41 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2013-04-27 05:33:40 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// 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(),
|
2013-04-27 05:33:40 +08:00
|
|
|
SuggestedPredefines,
|
|
|
|
PP.getLangOpts());
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 clang::io;
|
|
|
|
unsigned KeyLen = ReadUnalignedLE16(d);
|
|
|
|
unsigned DataLen = ReadUnalignedLE16(d);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTSelectorLookupTrait::internal_key_type
|
|
|
|
ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
|
|
|
|
using namespace clang::io;
|
|
|
|
SelectorTable &SelTable = Reader.getContext().Selectors;
|
|
|
|
unsigned N = ReadUnalignedLE16(d);
|
|
|
|
IdentifierInfo *FirstII
|
2013-01-22 00:52:34 +08:00
|
|
|
= Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
|
2012-12-18 22:30:41 +08:00
|
|
|
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)
|
2013-01-22 00:52:34 +08:00
|
|
|
Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)));
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
return SelTable.getSelector(N, Args.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTSelectorLookupTrait::data_type
|
|
|
|
ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
|
|
|
|
unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
|
|
|
|
data_type Result;
|
|
|
|
|
|
|
|
Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d));
|
2013-04-17 08:08:58 +08:00
|
|
|
unsigned NumInstanceMethodsAndBits = ReadUnalignedLE16(d);
|
|
|
|
unsigned NumFactoryMethodsAndBits = ReadUnalignedLE16(d);
|
|
|
|
Result.InstanceBits = NumInstanceMethodsAndBits & 0x3;
|
|
|
|
Result.FactoryBits = NumFactoryMethodsAndBits & 0x3;
|
|
|
|
unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2;
|
|
|
|
unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// Load instance methods
|
|
|
|
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
|
|
|
|
if (ObjCMethodDecl *Method
|
|
|
|
= Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
|
|
|
|
Result.Instance.push_back(Method);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load factory methods
|
|
|
|
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
|
|
|
|
if (ObjCMethodDecl *Method
|
|
|
|
= Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
|
|
|
|
Result.Factory.push_back(Method);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2013-01-24 02:53:14 +08:00
|
|
|
unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
|
|
|
|
return llvm::HashString(a);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned, unsigned>
|
2013-01-24 02:53:14 +08:00
|
|
|
ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
|
2012-12-18 22:30:41 +08:00
|
|
|
using namespace clang::io;
|
|
|
|
unsigned DataLen = ReadUnalignedLE16(d);
|
|
|
|
unsigned KeyLen = ReadUnalignedLE16(d);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
2013-01-24 02:53:14 +08:00
|
|
|
ASTIdentifierLookupTraitBase::internal_key_type
|
|
|
|
ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
|
2012-12-18 22:30:41 +08:00
|
|
|
assert(n >= 2 && d[n-1] == '\0');
|
2013-01-24 02:53:14 +08:00
|
|
|
return StringRef((const char*) d, n-1);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2013-02-12 02:16:18 +08:00
|
|
|
/// \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>();
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
|
|
|
|
const unsigned char* d,
|
|
|
|
unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
unsigned RawID = ReadUnalignedLE32(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) {
|
2013-01-24 02:53:14 +08:00
|
|
|
II = &Reader.getIdentifierTable().getOwn(k);
|
2012-12-18 22:30:41 +08:00
|
|
|
KnownII = II;
|
|
|
|
}
|
|
|
|
Reader.SetIdentifierInfo(ID, II);
|
2013-02-12 02:16:18 +08:00
|
|
|
if (!II->isFromAST()) {
|
|
|
|
bool WasInteresting = isInterestingIdentifier(*II);
|
|
|
|
II->setIsFromAST();
|
|
|
|
if (WasInteresting)
|
|
|
|
II->setChangedSinceDeserialization();
|
|
|
|
}
|
|
|
|
Reader.markIdentifierUpToDate(II);
|
2012-12-18 22:30:41 +08:00
|
|
|
return II;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
|
|
|
|
unsigned Bits = ReadUnalignedLE16(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;
|
2013-03-23 05:12:57 +08:00
|
|
|
bool hasSubmoduleMacros = Bits & 0x01;
|
|
|
|
Bits >>= 1;
|
2012-12-18 22:30:41 +08:00
|
|
|
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) {
|
2013-01-24 02:53:14 +08:00
|
|
|
II = &Reader.getIdentifierTable().getOwn(StringRef(k));
|
2012-12-18 22:30:41 +08:00
|
|
|
KnownII = II;
|
|
|
|
}
|
|
|
|
Reader.markIdentifierUpToDate(II);
|
2013-02-12 02:16:18 +08:00
|
|
|
if (!II->isFromAST()) {
|
|
|
|
bool WasInteresting = isInterestingIdentifier(*II);
|
|
|
|
II->setIsFromAST();
|
|
|
|
if (WasInteresting)
|
|
|
|
II->setChangedSinceDeserialization();
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// Set or check the various bits in the IdentifierInfo structure.
|
|
|
|
// Token IDs are read-only.
|
2013-02-27 09:13:51 +08:00
|
|
|
if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier)
|
2012-12-18 22:30:41 +08:00
|
|
|
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) {
|
2013-03-23 05:12:57 +08:00
|
|
|
uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d);
|
|
|
|
DataLen -= 4;
|
|
|
|
SmallVector<uint32_t, 8> LocalMacroIDs;
|
|
|
|
if (hasSubmoduleMacros) {
|
|
|
|
while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) {
|
|
|
|
DataLen -= 4;
|
|
|
|
LocalMacroIDs.push_back(LocalMacroID);
|
|
|
|
}
|
2013-01-19 11:14:56 +08:00
|
|
|
DataLen -= 4;
|
|
|
|
}
|
2013-03-23 05:12:57 +08:00
|
|
|
|
|
|
|
if (F.Kind == MK_Module) {
|
2014-03-01 08:08:04 +08:00
|
|
|
// Macro definitions are stored from newest to oldest, so reverse them
|
|
|
|
// before registering them.
|
|
|
|
llvm::SmallVector<unsigned, 8> MacroSizes;
|
2013-03-23 05:12:57 +08:00
|
|
|
for (SmallVectorImpl<uint32_t>::iterator
|
2014-03-01 08:08:04 +08:00
|
|
|
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;
|
2013-03-23 05:12:57 +08:00
|
|
|
}
|
2014-03-01 08:08:04 +08:00
|
|
|
|
|
|
|
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());
|
2013-03-23 05:12:57 +08:00
|
|
|
} else {
|
|
|
|
Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset);
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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, ReadUnalignedLE32(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 clang::io;
|
|
|
|
unsigned KeyLen = ReadUnalignedLE16(d);
|
|
|
|
unsigned DataLen = ReadUnalignedLE16(d);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTDeclContextNameLookupTrait::internal_key_type
|
|
|
|
ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
|
|
|
|
using namespace clang::io;
|
|
|
|
|
|
|
|
DeclNameKey Key;
|
|
|
|
Key.Kind = (DeclarationName::NameKind)*d++;
|
|
|
|
switch (Key.Kind) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
|
|
|
|
break;
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
Key.Data =
|
|
|
|
(uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d))
|
|
|
|
.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
Key.Data = *d++; // OverloadedOperatorKind
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(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 clang::io;
|
|
|
|
unsigned NumDecls = ReadUnalignedLE16(d);
|
2013-01-12 06:29:49 +08:00
|
|
|
LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
|
|
|
|
const_cast<unsigned char *>(d));
|
2012-12-18 22:30:41 +08:00
|
|
|
return std::make_pair(Start, Start + NumDecls);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Cursor,
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned Code = Cursor.ReadCode();
|
2013-01-20 10:38:54 +08:00
|
|
|
unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
if (RecCode != DECL_CONTEXT_LEXICAL) {
|
|
|
|
Error("Expected lexical block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-01-20 10:38:54 +08:00
|
|
|
Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
|
|
|
|
Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now the lookup table.
|
|
|
|
if (Offsets.second != 0) {
|
|
|
|
Cursor.JumpToBit(Offsets.second);
|
|
|
|
|
|
|
|
RecordData Record;
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned Code = Cursor.ReadCode();
|
2013-01-20 10:38:54 +08:00
|
|
|
unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
if (RecCode != DECL_CONTEXT_VISIBLE) {
|
|
|
|
Error("Expected visible lookup table block");
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-11 15:17:35 +08:00
|
|
|
Info.NameLookupTableData
|
|
|
|
= ASTDeclContextNameLookupTable::Create(
|
|
|
|
(const unsigned char *)Blob.data() + Record[0],
|
|
|
|
(const unsigned char *)Blob.data(),
|
|
|
|
ASTDeclContextNameLookupTrait(*this, M));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::Error(StringRef Msg) {
|
|
|
|
Error(diag::err_fe_pch_malformed, Msg);
|
2013-05-11 06:15:13 +08:00
|
|
|
if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
|
|
|
|
Diag(diag::note_module_cache_path)
|
|
|
|
<< PP.getHeaderSearchInfo().getModuleCachePath();
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// 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) {
|
2013-01-20 05:39:22 +08:00
|
|
|
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:
|
2012-12-18 22:30:41 +08:00
|
|
|
return false;
|
2013-01-20 05:39:22 +08:00
|
|
|
case llvm::BitstreamEntry::Record:
|
|
|
|
// The interesting case.
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Read a record.
|
|
|
|
Record.clear();
|
2013-01-22 02:28:26 +08:00
|
|
|
StringRef Blob;
|
|
|
|
switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
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]);
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned BaseOffset = F->SLocEntryBaseOffset;
|
|
|
|
|
|
|
|
++NumSLocEntriesRead;
|
2013-01-20 05:39:22 +08:00
|
|
|
llvm::BitstreamEntry Entry = SLocEntryCursor.advance();
|
|
|
|
if (Entry.Kind != llvm::BitstreamEntry::Record) {
|
2012-12-18 22:30:41 +08:00
|
|
|
Error("incorrectly-formatted source location entry in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
RecordData Record;
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
|
|
|
switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
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);
|
2013-03-01 11:26:04 +08:00
|
|
|
const FileEntry *File = IF.getFile();
|
|
|
|
bool OverriddenBuffer = IF.isOverridden();
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-03-01 11:26:04 +08:00
|
|
|
// 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)
|
2012-12-18 22:30:41 +08:00
|
|
|
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();
|
2013-01-20 10:38:54 +08:00
|
|
|
unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
if (RecCode != SM_SLOC_BUFFER_BLOB) {
|
|
|
|
Error("AST record has invalid code");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::MemoryBuffer *Buffer
|
2013-01-20 10:38:54 +08:00
|
|
|
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
|
2012-12-18 22:30:41 +08:00
|
|
|
SourceMgr.overrideFileContents(File, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SM_SLOC_BUFFER_ENTRY: {
|
2013-01-20 10:38:54 +08:00
|
|
|
const char *Name = Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
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
|
2013-01-20 10:38:54 +08:00
|
|
|
= SLocEntryCursor.readRecord(Code, Record, &Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
if (RecCode != SM_SLOC_BUFFER_BLOB) {
|
|
|
|
Error("AST record has invalid code");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::MemoryBuffer *Buffer
|
2013-01-20 10:38:54 +08:00
|
|
|
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
|
2012-12-18 22:30:41 +08:00
|
|
|
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, llvm::sys::path::stem(M->FileName));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \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. We assume that it is the first entry in the
|
|
|
|
// entry table. We can't ask the manager, because at the time of PCH loading
|
|
|
|
// the main file entry doesn't exist yet.
|
|
|
|
// The very first entry is the invalid instantiation loc, which takes up
|
|
|
|
// offsets 0 and 1.
|
|
|
|
return SourceLocation::getFromRawEncoding(2U);
|
|
|
|
}
|
|
|
|
//return F->Loaders[0]->FirstLoc;
|
|
|
|
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.
|
2013-01-20 08:56:42 +08:00
|
|
|
bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:41:30 +08:00
|
|
|
Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
|
2013-05-03 08:10:13 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-03-23 05:12:57 +08:00
|
|
|
MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Stream = F.MacroCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// 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) {
|
2013-01-20 08:00:22 +08:00
|
|
|
// 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.
|
2013-01-20 08:56:42 +08:00
|
|
|
unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd;
|
2013-01-20 08:00:22 +08:00
|
|
|
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");
|
2013-03-23 05:12:57 +08:00
|
|
|
return Macro;
|
2013-01-20 08:00:22 +08:00
|
|
|
case llvm::BitstreamEntry::EndBlock:
|
2013-03-23 05:12:57 +08:00
|
|
|
return Macro;
|
2013-01-20 08:00:22 +08:00
|
|
|
case llvm::BitstreamEntry::Record:
|
|
|
|
// The interesting case.
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read a record.
|
|
|
|
Record.clear();
|
|
|
|
PreprocessorRecordTypes RecType =
|
2013-01-20 10:38:54 +08:00
|
|
|
(PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record);
|
2012-12-18 22:30:41 +08:00
|
|
|
switch (RecType) {
|
2013-03-23 05:12:57 +08:00
|
|
|
case PP_MACRO_DIRECTIVE_HISTORY:
|
|
|
|
return Macro;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
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)
|
2013-03-23 05:12:57 +08:00
|
|
|
return Macro;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-03-23 05:12:57 +08:00
|
|
|
unsigned NextIndex = 1; // Skip identifier ID.
|
|
|
|
SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
|
2012-12-18 22:30:41 +08:00
|
|
|
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
|
2013-03-23 05:12:57 +08:00
|
|
|
MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
|
2013-01-08 03:16:23 +08:00
|
|
|
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
|
2012-12-18 22:30:41 +08:00
|
|
|
MI->setIsUsed(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();
|
2013-02-23 02:35:59 +08:00
|
|
|
PreprocessingRecord::PPEntityID
|
|
|
|
PPID = PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true);
|
|
|
|
MacroDefinition *PPDef =
|
|
|
|
cast_or_null<MacroDefinition>(PPRec.getPreprocessedEntity(PPID));
|
|
|
|
if (PPDef)
|
|
|
|
PPRec.RegisterMacroDefinition(Macro, PPDef);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
++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;
|
|
|
|
|
2013-05-03 08:10:13 +08:00
|
|
|
unsigned Idx = 0;
|
|
|
|
Token Tok = ReadToken(F, Record, Idx);
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-03-07 02:12:47 +08:00
|
|
|
unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
|
|
|
|
return llvm::hash_combine(ikey.Size, ikey.ModTime);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
HeaderFileInfoTrait::internal_key_type
|
2013-03-07 02:12:47 +08:00
|
|
|
HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
|
|
|
|
internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
|
|
|
|
FE->getName() };
|
|
|
|
return ikey;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-03-07 02:12:47 +08:00
|
|
|
bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
|
|
|
|
if (a.Size != b.Size || a.ModTime != b.ModTime)
|
2012-12-18 22:30:41 +08:00
|
|
|
return false;
|
|
|
|
|
2013-03-07 02:12:47 +08:00
|
|
|
if (strcmp(a.Filename, b.Filename) == 0)
|
|
|
|
return true;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Determine whether the actual files are equivalent.
|
2013-03-05 04:33:40 +08:00
|
|
|
FileManager &FileMgr = Reader.getFileManager();
|
2013-03-07 02:12:47 +08:00
|
|
|
const FileEntry *FEA = FileMgr.getFile(a.Filename);
|
|
|
|
const FileEntry *FEB = FileMgr.getFile(b.Filename);
|
2013-03-05 04:33:40 +08:00
|
|
|
return (FEA && FEA == FEB);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned, unsigned>
|
|
|
|
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
|
|
|
|
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
|
|
|
|
unsigned DataLen = (unsigned) *d++;
|
2013-03-07 02:12:47 +08:00
|
|
|
return std::make_pair(KeyLen, DataLen);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-03-07 02:12:47 +08:00
|
|
|
|
|
|
|
HeaderFileInfoTrait::internal_key_type
|
|
|
|
HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
|
|
|
|
internal_key_type ikey;
|
|
|
|
ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
|
|
|
|
ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
|
|
|
|
ikey.Filename = (const char *)d;
|
|
|
|
return ikey;
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
HeaderFileInfoTrait::data_type
|
2013-03-14 05:13:51 +08:00
|
|
|
HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned DataLen) {
|
|
|
|
const unsigned char *End = d + DataLen;
|
|
|
|
using namespace clang::io;
|
|
|
|
HeaderFileInfo HFI;
|
|
|
|
unsigned Flags = *d++;
|
2013-06-21 05:14:14 +08:00
|
|
|
HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
|
|
|
|
((Flags >> 6) & 0x03);
|
2012-12-18 22:30:41 +08:00
|
|
|
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 = ReadUnalignedLE16(d);
|
|
|
|
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M,
|
|
|
|
ReadUnalignedLE32(d));
|
|
|
|
if (unsigned FrameworkOffset = ReadUnalignedLE32(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);
|
|
|
|
}
|
|
|
|
|
2013-03-14 05:13:51 +08:00
|
|
|
if (d != End) {
|
|
|
|
uint32_t LocalSMID = ReadUnalignedLE32(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();
|
2013-06-21 05:14:14 +08:00
|
|
|
ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole());
|
2013-03-14 05:13:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
|
|
|
|
(void)End;
|
|
|
|
|
|
|
|
// This HeaderFileInfo was externally loaded.
|
|
|
|
HFI.External = true;
|
|
|
|
return HFI;
|
|
|
|
}
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
void
|
|
|
|
ASTReader::addPendingMacroFromModule(IdentifierInfo *II, ModuleFile *M,
|
|
|
|
GlobalMacroID GMacID,
|
|
|
|
llvm::ArrayRef<SubmoduleID> Overrides) {
|
2013-03-23 05:12:57 +08:00
|
|
|
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
|
2014-03-01 08:08:04 +08:00
|
|
|
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));
|
2013-03-23 05:12:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II,
|
|
|
|
ModuleFile *M,
|
|
|
|
uint64_t MacroDirectivesOffset) {
|
2012-12-18 22:30:41 +08:00
|
|
|
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
|
2013-03-23 05:12:57 +08:00
|
|
|
PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadDefinedMacros() {
|
|
|
|
// Note that we are loading defined macros.
|
|
|
|
Deserializing Macros(this);
|
|
|
|
|
|
|
|
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
|
|
|
|
E = ModuleMgr.rend(); I != E; ++I) {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &MacroCursor = (*I)->MacroCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// If there was no preprocessor block, skip this file.
|
|
|
|
if (!MacroCursor.getBitStreamReader())
|
|
|
|
continue;
|
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor Cursor = MacroCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
Cursor.JumpToBit((*I)->MacroStartOffset);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
while (true) {
|
2013-01-20 05:39:22 +08:00
|
|
|
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();
|
2013-01-20 10:38:54 +08:00
|
|
|
switch (Cursor.readRecord(E.ID, Record)) {
|
2013-01-20 05:39:22 +08:00
|
|
|
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;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
NextCursor: ;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief Visitor class used to look up identifirs in an AST file.
|
|
|
|
class IdentifierLookupVisitor {
|
|
|
|
StringRef Name;
|
|
|
|
unsigned PriorGeneration;
|
2013-01-25 08:38:33 +08:00
|
|
|
unsigned &NumIdentifierLookups;
|
|
|
|
unsigned &NumIdentifierLookupHits;
|
2012-12-18 22:30:41 +08:00
|
|
|
IdentifierInfo *Found;
|
2013-01-25 08:38:33 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
public:
|
2013-01-25 08:38:33 +08:00
|
|
|
IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration,
|
|
|
|
unsigned &NumIdentifierLookups,
|
|
|
|
unsigned &NumIdentifierLookupHits)
|
2013-01-26 07:32:03 +08:00
|
|
|
: Name(Name), PriorGeneration(PriorGeneration),
|
2013-01-25 08:38:33 +08:00
|
|
|
NumIdentifierLookups(NumIdentifierLookups),
|
|
|
|
NumIdentifierLookupHits(NumIdentifierLookupHits),
|
|
|
|
Found()
|
|
|
|
{
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
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;
|
2013-01-25 09:03:03 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTIdentifierLookupTable *IdTable
|
|
|
|
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
|
|
|
|
if (!IdTable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
|
|
|
|
M, This->Found);
|
2013-01-25 08:38:33 +08:00
|
|
|
++This->NumIdentifierLookups;
|
|
|
|
ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait);
|
2012-12-18 22:30:41 +08:00
|
|
|
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.
|
2013-01-25 08:38:33 +08:00
|
|
|
++This->NumIdentifierLookupHits;
|
2012-12-18 22:30:41 +08:00
|
|
|
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];
|
2013-01-25 09:03:03 +08:00
|
|
|
|
|
|
|
// If there is a global index, look there first to determine which modules
|
|
|
|
// provably do not have any results for this identifier.
|
2013-01-26 07:32:03 +08:00
|
|
|
GlobalModuleIndex::HitSet Hits;
|
|
|
|
GlobalModuleIndex::HitSet *HitsPtr = 0;
|
2013-01-25 09:03:03 +08:00
|
|
|
if (!loadGlobalIndex()) {
|
2013-01-26 07:32:03 +08:00
|
|
|
if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
|
|
|
|
HitsPtr = &Hits;
|
2013-01-25 09:03:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-26 07:32:03 +08:00
|
|
|
IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
|
2013-01-25 08:38:33 +08:00
|
|
|
NumIdentifierLookups,
|
|
|
|
NumIdentifierLookupHits);
|
2013-01-26 07:32:03 +08:00
|
|
|
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-03-23 05:12:57 +08:00
|
|
|
void ASTReader::resolvePendingMacro(IdentifierInfo *II,
|
|
|
|
const PendingMacroInfo &PMInfo) {
|
|
|
|
assert(II);
|
|
|
|
|
|
|
|
if (PMInfo.M->Kind != MK_Module) {
|
|
|
|
installPCHMacroDirectives(II, *PMInfo.M,
|
|
|
|
PMInfo.PCHMacroData.MacroDirectivesOffset);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
// Module Macro.
|
2013-03-23 05:12:57 +08:00
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
ModuleMacroInfo *MMI = getModuleMacro(PMInfo);
|
|
|
|
if (!MMI)
|
2013-03-23 05:12:57 +08:00
|
|
|
return;
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
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);
|
2013-03-23 05:12:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2013-03-27 01:17:01 +08:00
|
|
|
MacroDirective *MD = 0;
|
2013-03-23 05:12:57 +08:00
|
|
|
SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
|
2013-03-27 01:17:01 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2013-03-23 05:12:57 +08:00
|
|
|
|
|
|
|
if (!Latest)
|
|
|
|
Latest = MD;
|
|
|
|
if (Earliest)
|
|
|
|
Earliest->setPrevious(MD);
|
|
|
|
Earliest = MD;
|
|
|
|
}
|
|
|
|
|
|
|
|
PP.setLoadedMacroDirective(II, Latest);
|
|
|
|
}
|
|
|
|
|
2013-03-27 09:25:34 +08:00
|
|
|
/// \brief For the given macro definitions, check if they are both in system
|
2013-04-13 05:00:54 +08:00
|
|
|
/// modules.
|
|
|
|
static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
|
2013-06-08 06:56:11 +08:00
|
|
|
Module *NewOwner, ASTReader &Reader) {
|
2013-03-27 09:25:34 +08:00
|
|
|
assert(PrevMI && NewMI);
|
|
|
|
Module *PrevOwner = 0;
|
|
|
|
if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
|
|
|
|
PrevOwner = Reader.getSubmodule(PrevModID);
|
2013-06-08 06:56:11 +08:00
|
|
|
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)
|
2013-03-27 09:25:34 +08:00
|
|
|
return false;
|
2013-06-08 06:56:11 +08:00
|
|
|
return PrevInSystem && NewInSystem;
|
2013-03-27 09:25:34 +08:00
|
|
|
}
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
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];
|
2013-03-23 05:12:57 +08:00
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
// 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()) {
|
2014-03-06 11:16:27 +08:00
|
|
|
auto SubOverrides = HI->second->getOverriddenSubmodules();
|
2014-03-01 08:08:04 +08:00
|
|
|
Hidden.HiddenMacros.erase(HI);
|
2014-03-06 11:16:27 +08:00
|
|
|
removeOverriddenMacros(II, Ambig, SubOverrides);
|
2014-03-01 08:08:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this macro is already in our list of conflicts, remove it from there.
|
2014-03-06 08:33:23 +08:00
|
|
|
Ambig.erase(
|
|
|
|
std::remove_if(Ambig.begin(), Ambig.end(), [&](DefMacroDirective *MD) {
|
|
|
|
return MD->getInfo()->getOwningModuleID() == OwnerID;
|
|
|
|
}),
|
|
|
|
Ambig.end());
|
2014-03-01 08:08:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTReader::AmbiguousMacros *
|
|
|
|
ASTReader::removeOverriddenMacros(IdentifierInfo *II,
|
|
|
|
llvm::ArrayRef<SubmoduleID> Overrides) {
|
2013-03-23 05:12:57 +08:00
|
|
|
MacroDirective *Prev = PP.getMacroDirective(II);
|
2014-03-01 08:08:04 +08:00
|
|
|
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;
|
2013-03-27 01:17:01 +08:00
|
|
|
}
|
2013-03-23 05:12:57 +08:00
|
|
|
}
|
2014-03-01 08:08:04 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-03-27 01:17:01 +08:00
|
|
|
PP.appendMacroDirective(II, MD);
|
2013-03-23 05:12:57 +08:00
|
|
|
}
|
|
|
|
|
2014-03-14 10:26:27 +08:00
|
|
|
ASTReader::InputFileInfo
|
|
|
|
ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
|
2014-03-07 15:27:49 +08:00
|
|
|
// 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;
|
|
|
|
|
2014-03-14 10:26:27 +08:00
|
|
|
std::string Filename;
|
|
|
|
off_t StoredSize;
|
|
|
|
time_t StoredTime;
|
|
|
|
bool Overridden;
|
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
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);
|
2014-03-14 10:26:27 +08:00
|
|
|
|
2014-03-15 01:45:06 +08:00
|
|
|
InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
|
|
|
|
return R;
|
2014-03-07 15:27:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) {
|
2014-03-14 10:26:27 +08:00
|
|
|
return readInputFileInfo(F, ID).Filename;
|
2014-03-07 15:27:49 +08:00
|
|
|
}
|
|
|
|
|
2013-03-01 11:26:04 +08:00
|
|
|
InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
|
2012-12-18 22:30:41 +08:00
|
|
|
// 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.
|
2013-03-01 11:26:04 +08:00
|
|
|
if (F.InputFilesLoaded[ID-1].getFile())
|
2012-12-18 22:30:41 +08:00
|
|
|
return F.InputFilesLoaded[ID-1];
|
|
|
|
|
2014-01-09 03:13:34 +08:00
|
|
|
if (F.InputFilesLoaded[ID-1].isNotFound())
|
|
|
|
return InputFile();
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Go find this input file.
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Cursor = F.InputFilesCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
SavedStreamPosition SavedPosition(Cursor);
|
|
|
|
Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
|
|
|
|
|
2014-03-14 10:26:27 +08:00
|
|
|
InputFileInfo FI = readInputFileInfo(F, ID);
|
|
|
|
off_t StoredSize = FI.StoredSize;
|
|
|
|
time_t StoredTime = FI.StoredTime;
|
|
|
|
bool Overridden = FI.Overridden;
|
|
|
|
StringRef Filename = FI.Filename;
|
2014-03-07 15:27:49 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2013-03-01 11:26:04 +08:00
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
// For an overridden file, create a virtual file with the stored
|
|
|
|
// size/timestamp.
|
|
|
|
if (Overridden && File == 0) {
|
|
|
|
File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
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();
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
// 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()
|
2012-12-18 22:30:41 +08:00
|
|
|
#if !defined(LLVM_ON_WIN32)
|
2014-03-07 15:27:49 +08:00
|
|
|
// 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()
|
2012-12-18 22:30:41 +08:00
|
|
|
#endif
|
2014-03-07 15:27:49 +08:00
|
|
|
)) {
|
|
|
|
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)
|
2014-01-17 08:19:09 +08:00
|
|
|
Diag(diag::note_pch_required_by)
|
2014-03-07 15:27:49 +08:00
|
|
|
<< ImportStack[I-1]->FileName << ImportStack[I]->FileName;
|
2013-03-19 08:28:20 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
if (!Diags.isDiagnosticInFlight())
|
|
|
|
Diag(diag::note_pch_rebuild_required) << TopLevelPCHName;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
IsOutOfDate = true;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 15:27:49 +08:00
|
|
|
InputFile IF = InputFile(File, Overridden, IsOutOfDate);
|
|
|
|
|
|
|
|
// Note that we've loaded this input file.
|
|
|
|
F.InputFilesLoaded[ID-1] = IF;
|
|
|
|
return IF;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVectorImpl<ImportedModule> &Loaded,
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned ClientLoadCapabilities) {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Stream = F.Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
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;
|
2013-01-20 05:39:22 +08:00
|
|
|
while (1) {
|
|
|
|
llvm::BitstreamEntry Entry = Stream.advance();
|
|
|
|
|
|
|
|
switch (Entry.Kind) {
|
|
|
|
case llvm::BitstreamEntry::Error:
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return Failure;
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
case llvm::BitstreamEntry::EndBlock: {
|
|
|
|
// Validate input files.
|
|
|
|
const HeaderSearchOptions &HSOpts =
|
|
|
|
PP.getHeaderSearchInfo().getHeaderSearchOpts();
|
2014-03-07 14:40:32 +08:00
|
|
|
|
|
|
|
// 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];
|
|
|
|
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
if (!DisableValidation &&
|
|
|
|
(!HSOpts.ModulesValidateOncePerBuildSession ||
|
|
|
|
F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
|
2014-03-07 14:40:32 +08:00
|
|
|
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
// If we are reading a module, we will create a verification timestamp,
|
|
|
|
// so we verify all input files. Otherwise, verify only user input
|
|
|
|
// files.
|
2014-03-07 14:40:32 +08:00
|
|
|
|
|
|
|
unsigned N = NumUserInputs;
|
|
|
|
if (ValidateSystemInputs ||
|
|
|
|
(HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module))
|
|
|
|
N = NumInputs;
|
|
|
|
|
2014-02-08 01:31:11 +08:00
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
2013-03-01 11:26:04 +08:00
|
|
|
InputFile IF = getInputFile(F, I+1, Complain);
|
|
|
|
if (!IF.getFile() || IF.isOutOfDate())
|
2012-12-18 22:30:41 +08:00
|
|
|
return OutOfDate;
|
2013-03-01 11:26:04 +08:00
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2014-03-07 14:40:32 +08:00
|
|
|
|
2014-03-14 11:07:38 +08:00
|
|
|
if (Listener)
|
|
|
|
Listener->visitModuleFile(F.FileName);
|
|
|
|
|
2014-03-07 14:40:32 +08:00
|
|
|
if (Listener && Listener->needsInputFileVisitation()) {
|
|
|
|
unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs
|
|
|
|
: NumUserInputs;
|
2014-03-14 10:26:31 +08:00
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
|
|
|
bool IsSystem = I >= NumUserInputs;
|
|
|
|
InputFileInfo FI = readInputFileInfo(F, I+1);
|
|
|
|
Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden);
|
|
|
|
}
|
2014-03-07 14:40:32 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
return Success;
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
}
|
|
|
|
|
2013-01-20 05:39:22 +08:00
|
|
|
case llvm::BitstreamEntry::SubBlock:
|
|
|
|
switch (Entry.ID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
default:
|
2013-01-20 05:39:22 +08:00
|
|
|
if (Stream.SkipBlock()) {
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
continue;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
|
|
|
|
case llvm::BitstreamEntry::Record:
|
|
|
|
// The interesting case.
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read and process a record.
|
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
|
|
|
switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
case METADATA: {
|
|
|
|
if (Record[0] != VERSION_MAJOR && !DisableValidation) {
|
|
|
|
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
|
2014-02-11 23:40:09 +08:00
|
|
|
Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old
|
|
|
|
: diag::err_pch_version_too_new);
|
2012-12-18 22:30:41 +08:00
|
|
|
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();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef ASTBranch = Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
|
|
|
|
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
|
2014-02-11 23:40:09 +08:00
|
|
|
Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch;
|
2012-12-18 22:30:41 +08:00
|
|
|
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++]);
|
2013-03-19 08:28:20 +08:00
|
|
|
off_t StoredSize = (off_t)Record[Idx++];
|
|
|
|
time_t StoredModTime = (time_t)Record[Idx++];
|
2012-12-18 22:30:41 +08:00
|
|
|
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,
|
2013-03-19 08:28:20 +08:00
|
|
|
StoredSize, StoredModTime,
|
2012-12-18 22:30:41 +08:00
|
|
|
ClientLoadCapabilities)) {
|
|
|
|
case Failure: return Failure;
|
|
|
|
// If we have to ignore the dependency, we'll have to ignore this too.
|
2013-03-19 08:38:50 +08:00
|
|
|
case Missing:
|
2012-12-18 22:30:41 +08:00
|
|
|
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) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TARGET_OPTIONS: {
|
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
|
ParseTargetOptions(Record, Complain, *Listener) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DIAGNOSTIC_OPTIONS: {
|
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
|
ParseDiagnosticOptions(Record, Complain, *Listener) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FILE_SYSTEM_OPTIONS: {
|
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
|
ParseFileSystemOptions(Record, Complain, *Listener) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case HEADER_SEARCH_OPTIONS: {
|
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
|
ParseHeaderSearchOptions(Record, Complain, *Listener) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PREPROCESSOR_OPTIONS: {
|
|
|
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
|
ParsePreprocessorOptions(Record, Complain, *Listener,
|
|
|
|
SuggestedPredefines) &&
|
2014-02-06 06:21:15 +08:00
|
|
|
!DisableValidation && !AllowConfigurationMismatch)
|
2012-12-18 22:30:41 +08:00
|
|
|
return ConfigurationMismatch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ORIGINAL_FILE:
|
|
|
|
F.OriginalSourceFileID = FileID::get(Record[0]);
|
2013-01-20 10:38:54 +08:00
|
|
|
F.ActualOriginalSourceFileName = Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
|
|
|
|
MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORIGINAL_FILE_ID:
|
|
|
|
F.OriginalSourceFileID = FileID::get(Record[0]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORIGINAL_PCH_DIR:
|
2013-01-20 10:38:54 +08:00
|
|
|
F.OriginalDir = Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INPUT_FILE_OFFSETS:
|
2013-01-20 10:38:54 +08:00
|
|
|
F.InputFileOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.InputFilesLoaded.resize(Record[0]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ReadASTBlock(ModuleFile &F) {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Stream = F.Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read all of the records and blocks for the AST file.
|
|
|
|
RecordData Record;
|
2013-01-20 05:39:22 +08:00
|
|
|
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 true;
|
|
|
|
case llvm::BitstreamEntry::EndBlock: {
|
2013-04-04 06:49:41 +08:00
|
|
|
// 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++.
|
2012-12-18 22:30:41 +08:00
|
|
|
DeclContext *DC = Context.getTranslationUnitDecl();
|
2013-04-04 06:49:41 +08:00
|
|
|
if (DC->hasExternalLexicalStorage() &&
|
|
|
|
!getContext().getLangOpts().CPlusPlus)
|
2012-12-18 22:30:41 +08:00
|
|
|
DC->setMustBuildLookupTable();
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
case llvm::BitstreamEntry::SubBlock:
|
|
|
|
switch (Entry.ID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
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 true;
|
|
|
|
}
|
|
|
|
break;
|
2014-03-21 03:44:17 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case PREPROCESSOR_BLOCK_ID:
|
|
|
|
F.MacroCursor = Stream;
|
|
|
|
if (!PP.getExternalSource())
|
|
|
|
PP.setExternalSource(this);
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Stream.SkipBlock() ||
|
|
|
|
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
|
|
|
|
break;
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case PREPROCESSOR_DETAIL_BLOCK_ID:
|
|
|
|
F.PreprocessorDetailCursor = Stream;
|
|
|
|
if (Stream.SkipBlock() ||
|
2013-01-20 05:39:22 +08:00
|
|
|
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
|
2012-12-18 22:30:41 +08:00
|
|
|
PREPROCESSOR_DETAIL_BLOCK_ID)) {
|
2013-01-20 05:39:22 +08:00
|
|
|
Error("malformed preprocessor detail record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
F.PreprocessorDetailStartOffset
|
2013-01-20 05:39:22 +08:00
|
|
|
= F.PreprocessorDetailCursor.GetCurrentBitNo();
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!PP.getPreprocessingRecord())
|
|
|
|
PP.createPreprocessingRecord();
|
|
|
|
if (!PP.getPreprocessingRecord()->getExternalSource())
|
|
|
|
PP.getPreprocessingRecord()->SetExternalSource(*this);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOURCE_MANAGER_BLOCK_ID:
|
|
|
|
if (ReadSourceManagerBlock(F))
|
|
|
|
return true;
|
|
|
|
break;
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case SUBMODULE_BLOCK_ID:
|
|
|
|
if (ReadSubmoduleBlock(F))
|
|
|
|
return true;
|
|
|
|
break;
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case COMMENTS_BLOCK_ID: {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor C = Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Stream.SkipBlock() ||
|
|
|
|
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
|
|
|
|
Error("malformed comments block in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
CommentsCursors.push_back(std::make_pair(C, &F));
|
|
|
|
break;
|
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
default:
|
2013-01-20 05:39:22 +08:00
|
|
|
if (Stream.SkipBlock()) {
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
continue;
|
2013-01-20 05:39:22 +08:00
|
|
|
|
|
|
|
case llvm::BitstreamEntry::Record:
|
|
|
|
// The interesting case.
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read and process a record.
|
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
|
|
|
switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
default: // Default behavior: ignore.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TYPE_OFFSET: {
|
|
|
|
if (F.LocalNumTypes != 0) {
|
|
|
|
Error("duplicate TYPE_OFFSET record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-20 10:38:54 +08:00
|
|
|
F.TypeOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumTypes = Record[0];
|
|
|
|
unsigned LocalBaseTypeIndex = Record[1];
|
|
|
|
F.BaseTypeIndex = getTotalNumTypes();
|
|
|
|
|
|
|
|
if (F.LocalNumTypes > 0) {
|
|
|
|
// Introduce the global -> local mapping for types within this module.
|
|
|
|
GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for types within this module.
|
|
|
|
F.TypeRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseTypeIndex,
|
|
|
|
F.BaseTypeIndex - LocalBaseTypeIndex));
|
|
|
|
|
|
|
|
TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DECL_OFFSET: {
|
|
|
|
if (F.LocalNumDecls != 0) {
|
|
|
|
Error("duplicate DECL_OFFSET record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-20 10:38:54 +08:00
|
|
|
F.DeclOffsets = (const DeclOffset *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumDecls = Record[0];
|
|
|
|
unsigned LocalBaseDeclID = Record[1];
|
|
|
|
F.BaseDeclID = getTotalNumDecls();
|
|
|
|
|
|
|
|
if (F.LocalNumDecls > 0) {
|
|
|
|
// Introduce the global -> local mapping for declarations within this
|
|
|
|
// module.
|
|
|
|
GlobalDeclMap.insert(
|
|
|
|
std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for declarations within this
|
|
|
|
// module.
|
|
|
|
F.DeclRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
|
|
|
|
|
|
|
|
// Introduce the global -> local mapping for declarations within this
|
|
|
|
// module.
|
|
|
|
F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
|
|
|
|
|
|
|
|
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TU_UPDATE_LEXICAL: {
|
|
|
|
DeclContext *TU = Context.getTranslationUnitDecl();
|
|
|
|
DeclContextInfo &Info = F.DeclContextInfos[TU];
|
2013-01-20 10:38:54 +08:00
|
|
|
Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data());
|
2012-12-18 22:30:41 +08:00
|
|
|
Info.NumLexicalDecls
|
2013-01-20 10:38:54 +08:00
|
|
|
= static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair));
|
2012-12-18 22:30:41 +08:00
|
|
|
TU->setHasExternalLexicalStorage(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case UPDATE_VISIBLE: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
|
|
|
|
ASTDeclContextNameLookupTable *Table =
|
|
|
|
ASTDeclContextNameLookupTable::Create(
|
2013-01-20 10:38:54 +08:00
|
|
|
(const unsigned char *)Blob.data() + Record[Idx++],
|
|
|
|
(const unsigned char *)Blob.data(),
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTDeclContextNameLookupTrait(*this, F));
|
|
|
|
if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
|
|
|
|
DeclContext *TU = Context.getTranslationUnitDecl();
|
2014-03-11 15:17:35 +08:00
|
|
|
F.DeclContextInfos[TU].NameLookupTableData = Table;
|
2012-12-18 22:30:41 +08:00
|
|
|
TU->setHasExternalVisibleStorage(true);
|
2014-03-11 11:10:46 +08:00
|
|
|
} else if (Decl *D = DeclsLoaded[ID - NUM_PREDEF_DECL_IDS]) {
|
|
|
|
auto *DC = cast<DeclContext>(D);
|
|
|
|
DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
|
2014-03-11 15:17:35 +08:00
|
|
|
auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
|
|
|
|
delete LookupTable;
|
|
|
|
LookupTable = Table;
|
2012-12-18 22:30:41 +08:00
|
|
|
} else
|
|
|
|
PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IDENTIFIER_TABLE:
|
2013-01-20 10:38:54 +08:00
|
|
|
F.IdentifierTableData = Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Record[0]) {
|
|
|
|
F.IdentifierLookupTable
|
|
|
|
= ASTIdentifierLookupTable::Create(
|
|
|
|
(const unsigned char *)F.IdentifierTableData + Record[0],
|
|
|
|
(const unsigned char *)F.IdentifierTableData,
|
|
|
|
ASTIdentifierLookupTrait(*this, F));
|
|
|
|
|
|
|
|
PP.getIdentifierTable().setExternalIdentifierLookup(this);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IDENTIFIER_OFFSET: {
|
|
|
|
if (F.LocalNumIdentifiers != 0) {
|
|
|
|
Error("duplicate IDENTIFIER_OFFSET record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-20 10:38:54 +08:00
|
|
|
F.IdentifierOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumIdentifiers = Record[0];
|
|
|
|
unsigned LocalBaseIdentifierID = Record[1];
|
|
|
|
F.BaseIdentifierID = getTotalNumIdentifiers();
|
|
|
|
|
|
|
|
if (F.LocalNumIdentifiers > 0) {
|
|
|
|
// Introduce the global -> local mapping for identifiers within this
|
|
|
|
// module.
|
|
|
|
GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1,
|
|
|
|
&F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for identifiers within this
|
|
|
|
// module.
|
|
|
|
F.IdentifierRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseIdentifierID,
|
|
|
|
F.BaseIdentifierID - LocalBaseIdentifierID));
|
|
|
|
|
|
|
|
IdentifiersLoaded.resize(IdentifiersLoaded.size()
|
|
|
|
+ F.LocalNumIdentifiers);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-01-31 09:06:56 +08:00
|
|
|
case EAGERLY_DESERIALIZED_DECLS:
|
2012-12-18 22:30:41 +08:00
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
2014-01-31 09:06:56 +08:00
|
|
|
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SPECIAL_TYPES:
|
2013-02-02 07:45:03 +08:00
|
|
|
if (SpecialTypes.empty()) {
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SpecialTypes.size() != Record.size()) {
|
|
|
|
Error("invalid special-types record");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
|
|
|
|
serialization::TypeID ID = getGlobalTypeID(F, Record[I]);
|
|
|
|
if (!SpecialTypes[I])
|
|
|
|
SpecialTypes[I] = ID;
|
|
|
|
// FIXME: If ID && SpecialTypes[I] != ID, do we need a separate
|
|
|
|
// merge step?
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case STATISTICS:
|
|
|
|
TotalNumStatements += Record[0];
|
|
|
|
TotalNumMacros += Record[1];
|
|
|
|
TotalLexicalDeclContexts += Record[2];
|
|
|
|
TotalVisibleDeclContexts += Record[3];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UNUSED_FILESCOPED_DECLS:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DELEGATING_CTORS:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEAK_UNDECLARED_IDENTIFIERS:
|
|
|
|
if (Record.size() % 4 != 0) {
|
|
|
|
Error("invalid weak identifiers record");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Ignore weak undeclared identifiers from non-original PCH
|
|
|
|
// files. This isn't the way to do it :)
|
|
|
|
WeakUndeclaredIdentifiers.clear();
|
|
|
|
|
|
|
|
// Translate the weak, undeclared identifiers into global IDs.
|
|
|
|
for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
|
|
|
|
WeakUndeclaredIdentifiers.push_back(
|
|
|
|
getGlobalIdentifierID(F, Record[I++]));
|
|
|
|
WeakUndeclaredIdentifiers.push_back(
|
|
|
|
getGlobalIdentifierID(F, Record[I++]));
|
|
|
|
WeakUndeclaredIdentifiers.push_back(
|
|
|
|
ReadSourceLocation(F, Record, I).getRawEncoding());
|
|
|
|
WeakUndeclaredIdentifiers.push_back(Record[I++]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-01-11 07:43:47 +08:00
|
|
|
case LOCALLY_SCOPED_EXTERN_C_DECLS:
|
2012-12-18 22:30:41 +08:00
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
2013-01-11 07:43:47 +08:00
|
|
|
LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I]));
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SELECTOR_OFFSETS: {
|
2013-01-20 10:38:54 +08:00
|
|
|
F.SelectorOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumSelectors = Record[0];
|
|
|
|
unsigned LocalBaseSelectorID = Record[1];
|
|
|
|
F.BaseSelectorID = getTotalNumSelectors();
|
|
|
|
|
|
|
|
if (F.LocalNumSelectors > 0) {
|
|
|
|
// Introduce the global -> local mapping for selectors within this
|
|
|
|
// module.
|
|
|
|
GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for selectors within this
|
|
|
|
// module.
|
|
|
|
F.SelectorRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseSelectorID,
|
|
|
|
F.BaseSelectorID - LocalBaseSelectorID));
|
|
|
|
|
|
|
|
SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case METHOD_POOL:
|
2013-01-20 10:38:54 +08:00
|
|
|
F.SelectorLookupTableData = (const unsigned char *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Record[0])
|
|
|
|
F.SelectorLookupTable
|
|
|
|
= ASTSelectorLookupTable::Create(
|
|
|
|
F.SelectorLookupTableData + Record[0],
|
|
|
|
F.SelectorLookupTableData,
|
|
|
|
ASTSelectorLookupTrait(*this, F));
|
|
|
|
TotalNumMethodPoolEntries += Record[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REFERENCED_SELECTOR_POOL:
|
|
|
|
if (!Record.empty()) {
|
|
|
|
for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
|
|
|
|
ReferencedSelectorsData.push_back(getGlobalSelectorID(F,
|
|
|
|
Record[Idx++]));
|
|
|
|
ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx).
|
|
|
|
getRawEncoding());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PP_COUNTER_VALUE:
|
|
|
|
if (!Record.empty() && Listener)
|
|
|
|
Listener->ReadCounter(F, Record[0]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FILE_SORTED_DECLS:
|
2013-01-20 10:38:54 +08:00
|
|
|
F.FileSortedDecls = (const DeclID *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.NumFileSortedDecls = Record[0];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOURCE_LOCATION_OFFSETS: {
|
2013-01-20 10:38:54 +08:00
|
|
|
F.SLocEntryOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumSLocEntries = Record[0];
|
|
|
|
unsigned SLocSpaceSize = Record[1];
|
2014-03-02 21:01:17 +08:00
|
|
|
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
|
2012-12-18 22:30:41 +08:00
|
|
|
SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
|
|
|
|
SLocSpaceSize);
|
|
|
|
// Make our entry in the range map. BaseID is negative and growing, so
|
|
|
|
// we invert it. Because we invert it, though, we need the other end of
|
|
|
|
// the range.
|
|
|
|
unsigned RangeStart =
|
|
|
|
unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
|
|
|
|
GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
|
|
|
|
F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
|
|
|
|
|
|
|
|
// SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
|
|
|
|
assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0);
|
|
|
|
GlobalSLocOffsetMap.insert(
|
|
|
|
std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
|
|
|
|
- SLocSpaceSize,&F));
|
|
|
|
|
|
|
|
// Initialize the remapping table.
|
|
|
|
// Invalid stays invalid.
|
2014-03-21 03:44:17 +08:00
|
|
|
F.SLocRemap.insertOrReplace(std::make_pair(0U, 0));
|
2012-12-18 22:30:41 +08:00
|
|
|
// This module. Base was 2 when being compiled.
|
2014-03-21 03:44:17 +08:00
|
|
|
F.SLocRemap.insertOrReplace(std::make_pair(2U,
|
2012-12-18 22:30:41 +08:00
|
|
|
static_cast<int>(F.SLocEntryBaseOffset - 2)));
|
|
|
|
|
|
|
|
TotalNumSLocEntries += F.LocalNumSLocEntries;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MODULE_OFFSET_MAP: {
|
|
|
|
// Additional remapping information.
|
2013-01-20 10:38:54 +08:00
|
|
|
const unsigned char *Data = (const unsigned char*)Blob.data();
|
|
|
|
const unsigned char *DataEnd = Data + Blob.size();
|
2014-03-21 03:44:17 +08:00
|
|
|
|
|
|
|
// If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders.
|
|
|
|
if (F.SLocRemap.find(0) == F.SLocRemap.end()) {
|
|
|
|
F.SLocRemap.insert(std::make_pair(0U, 0));
|
|
|
|
F.SLocRemap.insert(std::make_pair(2U, 1));
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Continuous range maps we may be updating in our module.
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder
|
|
|
|
IdentifierRemap(F.IdentifierRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder
|
|
|
|
MacroRemap(F.MacroRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder
|
|
|
|
PreprocessedEntityRemap(F.PreprocessedEntityRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder
|
|
|
|
SubmoduleRemap(F.SubmoduleRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder
|
|
|
|
SelectorRemap(F.SelectorRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
|
|
|
|
|
|
|
|
while(Data < DataEnd) {
|
|
|
|
uint16_t Len = io::ReadUnalignedLE16(Data);
|
|
|
|
StringRef Name = StringRef((const char*)Data, Len);
|
|
|
|
Data += Len;
|
|
|
|
ModuleFile *OM = ModuleMgr.lookup(Name);
|
|
|
|
if (!OM) {
|
|
|
|
Error("SourceLocation remap refers to unknown module");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
|
|
|
|
|
|
|
|
// Source location offset is mapped to OM->SLocEntryBaseOffset.
|
|
|
|
SLocRemap.insert(std::make_pair(SLocOffset,
|
|
|
|
static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
|
|
|
|
IdentifierRemap.insert(
|
|
|
|
std::make_pair(IdentifierIDOffset,
|
|
|
|
OM->BaseIdentifierID - IdentifierIDOffset));
|
|
|
|
MacroRemap.insert(std::make_pair(MacroIDOffset,
|
|
|
|
OM->BaseMacroID - MacroIDOffset));
|
|
|
|
PreprocessedEntityRemap.insert(
|
|
|
|
std::make_pair(PreprocessedEntityIDOffset,
|
|
|
|
OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
|
|
|
|
SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset,
|
|
|
|
OM->BaseSubmoduleID - SubmoduleIDOffset));
|
|
|
|
SelectorRemap.insert(std::make_pair(SelectorIDOffset,
|
|
|
|
OM->BaseSelectorID - SelectorIDOffset));
|
|
|
|
DeclRemap.insert(std::make_pair(DeclIDOffset,
|
|
|
|
OM->BaseDeclID - DeclIDOffset));
|
|
|
|
|
|
|
|
TypeRemap.insert(std::make_pair(TypeIndexOffset,
|
|
|
|
OM->BaseTypeIndex - TypeIndexOffset));
|
|
|
|
|
|
|
|
// Global -> local mappings.
|
|
|
|
F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SOURCE_MANAGER_LINE_TABLE:
|
|
|
|
if (ParseLineTable(F, Record))
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOURCE_LOCATION_PRELOADS: {
|
|
|
|
// Need to transform from the local view (1-based IDs) to the global view,
|
|
|
|
// which is based off F.SLocEntryBaseID.
|
|
|
|
if (!F.PreloadSLocEntries.empty()) {
|
|
|
|
Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
F.PreloadSLocEntries.swap(Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EXT_VECTOR_DECLS:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VTABLE_USES:
|
|
|
|
if (Record.size() % 3 != 0) {
|
|
|
|
Error("Invalid VTABLE_USES record");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Later tables overwrite earlier ones.
|
|
|
|
// FIXME: Modules will have some trouble with this. This is clearly not
|
|
|
|
// the right way to do this.
|
|
|
|
VTableUses.clear();
|
|
|
|
|
|
|
|
for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) {
|
|
|
|
VTableUses.push_back(getGlobalDeclID(F, Record[Idx++]));
|
|
|
|
VTableUses.push_back(
|
|
|
|
ReadSourceLocation(F, Record, Idx).getRawEncoding());
|
|
|
|
VTableUses.push_back(Record[Idx++]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DYNAMIC_CLASSES:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
DynamicClasses.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PENDING_IMPLICIT_INSTANTIATIONS:
|
|
|
|
if (PendingInstantiations.size() % 2 != 0) {
|
|
|
|
Error("Invalid existing PendingInstantiations");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Record.size() % 2 != 0) {
|
|
|
|
Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
|
|
|
|
PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
|
|
|
|
PendingInstantiations.push_back(
|
|
|
|
ReadSourceLocation(F, Record, I).getRawEncoding());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEMA_DECL_REFS:
|
2013-10-18 14:54:39 +08:00
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("Invalid SEMA_DECL_REFS block");
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PPD_ENTITIES_OFFSETS: {
|
2013-01-20 10:38:54 +08:00
|
|
|
F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data();
|
|
|
|
assert(Blob.size() % sizeof(PPEntityOffset) == 0);
|
|
|
|
F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset);
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
unsigned LocalBasePreprocessedEntityID = Record[0];
|
|
|
|
|
|
|
|
unsigned StartingID;
|
|
|
|
if (!PP.getPreprocessingRecord())
|
|
|
|
PP.createPreprocessingRecord();
|
|
|
|
if (!PP.getPreprocessingRecord()->getExternalSource())
|
|
|
|
PP.getPreprocessingRecord()->SetExternalSource(*this);
|
|
|
|
StartingID
|
|
|
|
= PP.getPreprocessingRecord()
|
|
|
|
->allocateLoadedEntities(F.NumPreprocessedEntities);
|
|
|
|
F.BasePreprocessedEntityID = StartingID;
|
|
|
|
|
|
|
|
if (F.NumPreprocessedEntities > 0) {
|
|
|
|
// Introduce the global -> local mapping for preprocessed entities in
|
|
|
|
// this module.
|
|
|
|
GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for preprocessed entities in
|
|
|
|
// this module.
|
|
|
|
F.PreprocessedEntityRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBasePreprocessedEntityID,
|
|
|
|
F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DECL_UPDATE_OFFSETS: {
|
|
|
|
if (Record.size() % 2 != 0) {
|
|
|
|
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; I += 2)
|
|
|
|
DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
|
|
|
|
.push_back(std::make_pair(&F, Record[I+1]));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DECL_REPLACEMENTS: {
|
|
|
|
if (Record.size() % 3 != 0) {
|
|
|
|
Error("invalid DECL_REPLACEMENTS block in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; I += 3)
|
|
|
|
ReplacedDecls[getGlobalDeclID(F, Record[I])]
|
|
|
|
= ReplacedDeclInfo(&F, Record[I+1], Record[I+2]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OBJC_CATEGORIES_MAP: {
|
|
|
|
if (F.LocalNumObjCCategoriesInMap != 0) {
|
|
|
|
Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
F.LocalNumObjCCategoriesInMap = Record[0];
|
2013-01-20 10:38:54 +08:00
|
|
|
F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OBJC_CATEGORIES:
|
|
|
|
F.ObjCCategories.swap(Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CXX_BASE_SPECIFIER_OFFSETS: {
|
|
|
|
if (F.LocalNumCXXBaseSpecifiers != 0) {
|
|
|
|
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
F.LocalNumCXXBaseSpecifiers = Record[0];
|
2013-01-20 10:38:54 +08:00
|
|
|
F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DIAG_PRAGMA_MAPPINGS:
|
|
|
|
if (F.PragmaDiagMappings.empty())
|
|
|
|
F.PragmaDiagMappings.swap(Record);
|
|
|
|
else
|
|
|
|
F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
|
|
|
|
Record.begin(), Record.end());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CUDA_SPECIAL_DECL_REFS:
|
|
|
|
// Later tables overwrite earlier ones.
|
|
|
|
// FIXME: Modules will have trouble with this.
|
|
|
|
CUDASpecialDeclRefs.clear();
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HEADER_SEARCH_TABLE: {
|
2013-01-20 10:38:54 +08:00
|
|
|
F.HeaderFileInfoTableData = Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumHeaderFileInfos = Record[1];
|
|
|
|
if (Record[0]) {
|
|
|
|
F.HeaderFileInfoTable
|
|
|
|
= HeaderFileInfoLookupTable::Create(
|
|
|
|
(const unsigned char *)F.HeaderFileInfoTableData + Record[0],
|
|
|
|
(const unsigned char *)F.HeaderFileInfoTableData,
|
|
|
|
HeaderFileInfoTrait(*this, F,
|
|
|
|
&PP.getHeaderSearchInfo(),
|
2013-01-20 10:38:54 +08:00
|
|
|
Blob.data() + Record[2]));
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
PP.getHeaderSearchInfo().SetExternalSource(this);
|
|
|
|
if (!PP.getHeaderSearchInfo().getExternalLookup())
|
|
|
|
PP.getHeaderSearchInfo().SetExternalLookup(this);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FP_PRAGMA_OPTIONS:
|
|
|
|
// Later tables overwrite earlier ones.
|
|
|
|
FPPragmaOptions.swap(Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENCL_EXTENSIONS:
|
|
|
|
// Later tables overwrite earlier ones.
|
|
|
|
OpenCLExtensions.swap(Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TENTATIVE_DEFINITIONS:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KNOWN_NAMESPACES:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
|
|
|
KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
|
|
|
|
break;
|
2013-01-26 08:35:08 +08:00
|
|
|
|
2013-02-01 16:13:20 +08:00
|
|
|
case UNDEFINED_BUT_USED:
|
|
|
|
if (UndefinedButUsed.size() % 2 != 0) {
|
|
|
|
Error("Invalid existing UndefinedButUsed");
|
2013-01-26 08:35:08 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Record.size() % 2 != 0) {
|
2013-02-01 16:13:20 +08:00
|
|
|
Error("invalid undefined-but-used record");
|
2013-01-26 08:35:08 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
|
2013-02-01 16:13:20 +08:00
|
|
|
UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
|
|
|
|
UndefinedButUsed.push_back(
|
2013-01-26 08:35:08 +08:00
|
|
|
ReadSourceLocation(F, Record, I).getRawEncoding());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case IMPORTED_MODULES: {
|
|
|
|
if (F.Kind != MK_Module) {
|
|
|
|
// If we aren't loading a module (which has its own exports), make
|
|
|
|
// all of the imported modules visible.
|
|
|
|
// FIXME: Deal with macros-only imports.
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
|
|
|
|
if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I]))
|
|
|
|
ImportedModules.push_back(GlobalID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case LOCAL_REDECLARATIONS: {
|
|
|
|
F.RedeclarationChains.swap(Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case LOCAL_REDECLARATIONS_MAP: {
|
|
|
|
if (F.LocalNumRedeclarationsInMap != 0) {
|
|
|
|
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
F.LocalNumRedeclarationsInMap = Record[0];
|
2013-01-20 10:38:54 +08:00
|
|
|
F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MERGED_DECLARATIONS: {
|
|
|
|
for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
|
|
|
|
GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
|
|
|
|
SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
|
|
|
|
for (unsigned N = Record[Idx++]; N > 0; --N)
|
|
|
|
Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MACRO_OFFSET: {
|
|
|
|
if (F.LocalNumMacros != 0) {
|
|
|
|
Error("duplicate MACRO_OFFSET record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-20 10:38:54 +08:00
|
|
|
F.MacroOffsets = (const uint32_t *)Blob.data();
|
2012-12-18 22:30:41 +08:00
|
|
|
F.LocalNumMacros = Record[0];
|
|
|
|
unsigned LocalBaseMacroID = Record[1];
|
|
|
|
F.BaseMacroID = getTotalNumMacros();
|
|
|
|
|
|
|
|
if (F.LocalNumMacros > 0) {
|
|
|
|
// Introduce the global -> local mapping for macros within this module.
|
|
|
|
GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for macros within this module.
|
|
|
|
F.MacroRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseMacroID,
|
|
|
|
F.BaseMacroID - LocalBaseMacroID));
|
|
|
|
|
|
|
|
MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-03-23 05:12:57 +08:00
|
|
|
case MACRO_TABLE: {
|
|
|
|
// FIXME: Not used yet.
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-08-08 05:41:30 +08:00
|
|
|
|
|
|
|
case LATE_PARSED_TEMPLATE: {
|
|
|
|
LateParsedTemplates.append(Record.begin(), Record.end());
|
|
|
|
break;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-13 07:36:21 +08:00
|
|
|
/// \brief Move the given method to the back of the global list of methods.
|
|
|
|
static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
|
|
|
|
// Find the entry for this selector in the method pool.
|
|
|
|
Sema::GlobalMethodPool::iterator Known
|
|
|
|
= S.MethodPool.find(Method->getSelector());
|
|
|
|
if (Known == S.MethodPool.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Retrieve the appropriate method list.
|
|
|
|
ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first
|
|
|
|
: Known->second.second;
|
|
|
|
bool Found = false;
|
2013-04-17 08:08:58 +08:00
|
|
|
for (ObjCMethodList *List = &Start; List; List = List->getNext()) {
|
2013-02-13 07:36:21 +08:00
|
|
|
if (!Found) {
|
|
|
|
if (List->Method == Method) {
|
|
|
|
Found = true;
|
|
|
|
} else {
|
|
|
|
// Keep searching.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-17 08:08:58 +08:00
|
|
|
if (List->getNext())
|
|
|
|
List->Method = List->getNext()->Method;
|
2013-02-13 07:36:21 +08:00
|
|
|
else
|
|
|
|
List->Method = Method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-27 09:25:34 +08:00
|
|
|
void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
|
2014-03-01 08:08:04 +08:00
|
|
|
for (unsigned I = 0, N = Names.HiddenDecls.size(); I != N; ++I) {
|
|
|
|
Decl *D = Names.HiddenDecls[I];
|
|
|
|
bool wasHidden = D->Hidden;
|
|
|
|
D->Hidden = false;
|
|
|
|
|
|
|
|
if (wasHidden && SemaObj) {
|
|
|
|
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
|
|
|
|
moveMethodToBackOfGlobalList(*SemaObj, Method);
|
2013-02-13 07:36:21 +08:00
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
2014-03-01 08:08:04 +08:00
|
|
|
|
|
|
|
for (HiddenMacrosMap::const_iterator I = Names.HiddenMacros.begin(),
|
|
|
|
E = Names.HiddenMacros.end();
|
|
|
|
I != E; ++I)
|
|
|
|
installImportedMacro(I->first, I->second, Owner);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2014-03-01 08:08:04 +08:00
|
|
|
void ASTReader::makeModuleVisible(Module *Mod,
|
2013-02-02 00:36:12 +08:00
|
|
|
Module::NameVisibilityKind NameVisibility,
|
2013-03-21 05:10:35 +08:00
|
|
|
SourceLocation ImportLoc,
|
|
|
|
bool Complain) {
|
2012-12-18 22:30:41 +08:00
|
|
|
llvm::SmallPtrSet<Module *, 4> Visited;
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<Module *, 4> Stack;
|
2013-08-24 00:11:15 +08:00
|
|
|
Stack.push_back(Mod);
|
2012-12-18 22:30:41 +08:00
|
|
|
while (!Stack.empty()) {
|
2013-08-24 00:11:15 +08:00
|
|
|
Mod = Stack.pop_back_val();
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
if (NameVisibility <= Mod->NameVisibility) {
|
2013-08-24 00:11:15 +08:00
|
|
|
// This module already has this level of visibility (or greater), so
|
2012-12-18 22:30:41 +08:00
|
|
|
// there is nothing more to do.
|
|
|
|
continue;
|
|
|
|
}
|
2014-03-01 08:08:04 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!Mod->isAvailable()) {
|
|
|
|
// Modules that aren't available cannot be made visible.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the module's name visibility.
|
2014-03-01 08:08:04 +08:00
|
|
|
if (NameVisibility >= Module::MacrosVisible &&
|
|
|
|
Mod->NameVisibility < Module::MacrosVisible)
|
|
|
|
Mod->MacroVisibilityLoc = ImportLoc;
|
2012-12-18 22:30:41 +08:00
|
|
|
Mod->NameVisibility = NameVisibility;
|
2014-03-01 08:08:04 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// If we've already deserialized any names from this module,
|
|
|
|
// mark them as visible.
|
|
|
|
HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
|
|
|
|
if (Hidden != HiddenNamesMap.end()) {
|
2013-03-27 09:25:34 +08:00
|
|
|
makeNamesVisible(Hidden->second, Hidden->first);
|
2012-12-18 22:30:41 +08:00
|
|
|
HiddenNamesMap.erase(Hidden);
|
|
|
|
}
|
2013-11-05 05:51:33 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Push any exported modules onto the stack to be marked as visible.
|
2013-02-20 03:34:40 +08:00
|
|
|
SmallVector<Module *, 16> Exports;
|
|
|
|
Mod->getExportedModules(Exports);
|
|
|
|
for (SmallVectorImpl<Module *>::iterator
|
|
|
|
I = Exports.begin(), E = Exports.end(); I != E; ++I) {
|
|
|
|
Module *Exported = *I;
|
|
|
|
if (Visited.insert(Exported))
|
|
|
|
Stack.push_back(Exported);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-03-21 05:10:35 +08:00
|
|
|
|
|
|
|
// Detect any conflicts.
|
|
|
|
if (Complain) {
|
|
|
|
assert(ImportLoc.isValid() && "Missing import location");
|
|
|
|
for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
|
|
|
|
if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) {
|
|
|
|
Diag(ImportLoc, diag::warn_module_conflict)
|
|
|
|
<< Mod->getFullModuleName()
|
|
|
|
<< Mod->Conflicts[I].Other->getFullModuleName()
|
|
|
|
<< Mod->Conflicts[I].Message;
|
|
|
|
// FIXME: Need note where the other module was imported.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 09:03:03 +08:00
|
|
|
bool ASTReader::loadGlobalIndex() {
|
|
|
|
if (GlobalIndex)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
|
|
|
|
!Context.getLangOpts().Modules)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Try to load the global index.
|
|
|
|
TriedLoadingGlobalIndex = true;
|
|
|
|
StringRef ModuleCachePath
|
|
|
|
= getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
|
|
|
|
std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result
|
2013-03-19 08:28:20 +08:00
|
|
|
= GlobalModuleIndex::readIndex(ModuleCachePath);
|
2013-01-25 09:03:03 +08:00
|
|
|
if (!Result.first)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
GlobalIndex.reset(Result.first);
|
2013-01-26 07:32:03 +08:00
|
|
|
ModuleMgr.setGlobalIndex(GlobalIndex.get());
|
2013-01-25 09:03:03 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::isGlobalIndexUnavailable() const {
|
|
|
|
return Context.getLangOpts().Modules && UseGlobalIndex &&
|
|
|
|
!hasGlobalIndex() && TriedLoadingGlobalIndex;
|
|
|
|
}
|
|
|
|
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
static void updateModuleTimestamp(ModuleFile &MF) {
|
|
|
|
// Overwrite the timestamp file contents so that file's mtime changes.
|
|
|
|
std::string TimestampFilename = MF.getTimestampFilename();
|
|
|
|
std::string ErrorInfo;
|
2014-02-24 23:06:52 +08:00
|
|
|
llvm::raw_fd_ostream OS(TimestampFilename.c_str(), ErrorInfo,
|
2014-02-25 02:20:21 +08:00
|
|
|
llvm::sys::fs::F_Text);
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
if (!ErrorInfo.empty())
|
|
|
|
return;
|
|
|
|
OS << "Timestamp file\n";
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
|
|
|
|
ModuleKind Type,
|
|
|
|
SourceLocation ImportLoc,
|
|
|
|
unsigned ClientLoadCapabilities) {
|
2013-05-24 13:44:08 +08:00
|
|
|
llvm::SaveAndRestore<SourceLocation>
|
|
|
|
SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Bump the generation number.
|
|
|
|
unsigned PreviousGeneration = CurrentGeneration++;
|
|
|
|
|
|
|
|
unsigned NumModules = ModuleMgr.size();
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<ImportedModule, 4> Loaded;
|
2012-12-18 22:30:41 +08:00
|
|
|
switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
|
|
|
|
/*ImportedBy=*/0, Loaded,
|
2013-03-19 08:28:20 +08:00
|
|
|
0, 0,
|
2012-12-18 22:30:41 +08:00
|
|
|
ClientLoadCapabilities)) {
|
|
|
|
case Failure:
|
2013-03-19 08:28:20 +08:00
|
|
|
case Missing:
|
2012-12-18 22:30:41 +08:00
|
|
|
case OutOfDate:
|
|
|
|
case VersionMismatch:
|
|
|
|
case ConfigurationMismatch:
|
|
|
|
case HadErrors:
|
2013-03-19 08:28:20 +08:00
|
|
|
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
|
|
|
|
Context.getLangOpts().Modules
|
|
|
|
? &PP.getHeaderSearchInfo().getModuleMap()
|
|
|
|
: 0);
|
2013-01-25 09:03:03 +08:00
|
|
|
|
|
|
|
// If we find that any modules are unusable, the global index is going
|
|
|
|
// to be out-of-date. Just remove it.
|
|
|
|
GlobalIndex.reset();
|
2013-01-26 07:32:03 +08:00
|
|
|
ModuleMgr.setGlobalIndex(0);
|
2012-12-18 22:30:41 +08:00
|
|
|
return ReadResult;
|
|
|
|
|
|
|
|
case Success:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here comes stuff that we only do once the entire chain is loaded.
|
|
|
|
|
|
|
|
// Load the AST blocks of all of the modules that we loaded.
|
2013-01-13 03:30:44 +08:00
|
|
|
for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
|
|
|
|
MEnd = Loaded.end();
|
2012-12-18 22:30:41 +08:00
|
|
|
M != MEnd; ++M) {
|
|
|
|
ModuleFile &F = *M->Mod;
|
|
|
|
|
|
|
|
// Read the AST block.
|
|
|
|
if (ReadASTBlock(F))
|
|
|
|
return Failure;
|
|
|
|
|
|
|
|
// Once read, set the ModuleFile bit base offset and update the size in
|
|
|
|
// bits of all files we've seen.
|
|
|
|
F.GlobalBitOffset = TotalModulesSizeInBits;
|
|
|
|
TotalModulesSizeInBits += F.SizeInBits;
|
|
|
|
GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
|
|
|
|
|
|
|
|
// Preload SLocEntries.
|
|
|
|
for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
|
|
|
|
int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
|
|
|
|
// Load it through the SourceManager and don't call ReadSLocEntry()
|
|
|
|
// directly because the entry may have already been loaded in which case
|
|
|
|
// calling ReadSLocEntry() directly would trigger an assertion in
|
|
|
|
// SourceManager.
|
|
|
|
SourceMgr.getLoadedSLocEntryByID(Index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-23 02:50:14 +08:00
|
|
|
// Setup the import locations and notify the module manager that we've
|
|
|
|
// committed to these module files.
|
2013-01-13 03:30:44 +08:00
|
|
|
for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
|
|
|
|
MEnd = Loaded.end();
|
2012-12-18 22:30:41 +08:00
|
|
|
M != MEnd; ++M) {
|
|
|
|
ModuleFile &F = *M->Mod;
|
2013-03-23 02:50:14 +08:00
|
|
|
|
|
|
|
ModuleMgr.moduleFileAccepted(&F);
|
|
|
|
|
|
|
|
// Set the import location.
|
2013-02-02 00:36:14 +08:00
|
|
|
F.DirectImportLoc = ImportLoc;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!M->ImportedBy)
|
|
|
|
F.ImportLoc = M->ImportLoc;
|
|
|
|
else
|
|
|
|
F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
|
|
|
|
M->ImportLoc.getRawEncoding());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark all of the identifiers in the identifier table as being out of date,
|
|
|
|
// so that various accessors know to check the loaded modules when the
|
|
|
|
// identifier is used.
|
|
|
|
for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
|
|
|
|
IdEnd = PP.getIdentifierTable().end();
|
|
|
|
Id != IdEnd; ++Id)
|
|
|
|
Id->second->setOutOfDate(true);
|
|
|
|
|
|
|
|
// Resolve any unresolved module exports.
|
2013-03-21 05:10:35 +08:00
|
|
|
for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
|
|
|
|
UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I];
|
2012-12-18 22:30:41 +08:00
|
|
|
SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
|
|
|
|
Module *ResolvedMod = getSubmodule(GlobalID);
|
2013-03-21 05:10:35 +08:00
|
|
|
|
|
|
|
switch (Unresolved.Kind) {
|
|
|
|
case UnresolvedModuleRef::Conflict:
|
|
|
|
if (ResolvedMod) {
|
|
|
|
Module::Conflict Conflict;
|
|
|
|
Conflict.Other = ResolvedMod;
|
|
|
|
Conflict.Message = Unresolved.String.str();
|
|
|
|
Unresolved.Mod->Conflicts.push_back(Conflict);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case UnresolvedModuleRef::Import:
|
2012-12-18 22:30:41 +08:00
|
|
|
if (ResolvedMod)
|
|
|
|
Unresolved.Mod->Imports.push_back(ResolvedMod);
|
|
|
|
continue;
|
|
|
|
|
2013-03-21 05:10:35 +08:00
|
|
|
case UnresolvedModuleRef::Export:
|
|
|
|
if (ResolvedMod || Unresolved.IsWildcard)
|
|
|
|
Unresolved.Mod->Exports.push_back(
|
|
|
|
Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
|
|
|
|
continue;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-03-21 05:10:35 +08:00
|
|
|
UnresolvedModuleRefs.clear();
|
2013-09-24 17:14:14 +08:00
|
|
|
|
|
|
|
// FIXME: How do we load the 'use'd modules? They may not be submodules.
|
|
|
|
// Might be unnecessary as use declarations are only used to build the
|
|
|
|
// module itself.
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
InitializeContext();
|
|
|
|
|
2013-10-18 14:54:39 +08:00
|
|
|
if (SemaObj)
|
|
|
|
UpdateSema();
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->ReaderInitialized(this);
|
|
|
|
|
|
|
|
ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
|
|
|
|
if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
|
|
|
|
PrimaryModule.OriginalSourceFileID
|
|
|
|
= FileID::get(PrimaryModule.SLocEntryBaseID
|
|
|
|
+ PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
|
|
|
|
|
|
|
|
// If this AST file is a precompiled preamble, then set the
|
|
|
|
// preamble file ID of the source manager to the file source file
|
|
|
|
// from which the preamble was built.
|
|
|
|
if (Type == MK_Preamble) {
|
|
|
|
SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
|
|
|
|
} else if (Type == MK_MainFile) {
|
|
|
|
SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For any Objective-C class definitions we have already loaded, make sure
|
|
|
|
// that we load any additional categories.
|
|
|
|
for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
|
|
|
|
loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
|
|
|
|
ObjCClassesLoaded[I],
|
|
|
|
PreviousGeneration);
|
|
|
|
}
|
2013-01-25 09:03:03 +08:00
|
|
|
|
Add an option to allow Clang verify source files for a module only once during
the build
When Clang loads the module, it verifies the user source files that the module
was built from. If any file was changed, the module is rebuilt. There are two
problems with this:
1. correctness: we don't verify system files (there are too many of them, and
stat'ing all of them would take a lot of time);
2. performance: the same module file is verified again and again during a
single build.
This change allows the build system to optimize source file verification. The
idea is based on the fact that while the project is being built, the source
files don't change. This allows us to verify the module only once during a
single build session. The build system passes a flag,
-fbuild-session-timestamp=, to inform Clang of the time when the build started.
The build system also requests to enable this feature by passing
-fmodules-validate-once-per-build-session. If these flags are not passed, the
behavior is not changed. When Clang verifies the module the first time, it
writes out a timestamp file. Then, when Clang loads the module the second
time, it finds a timestamp file, so it can compare the verification timestamp
of the module with the time when the build started. If the verification
timestamp is too old, the module is verified again, and the timestamp file is
updated.
llvm-svn: 201224
2014-02-12 18:33:14 +08:00
|
|
|
if (PP.getHeaderSearchInfo()
|
|
|
|
.getHeaderSearchOpts()
|
|
|
|
.ModulesValidateOncePerBuildSession) {
|
|
|
|
// Now we are certain that the module and all modules it depends on are
|
|
|
|
// up to date. Create or update timestamp files for modules that are
|
|
|
|
// located in the module cache (not for PCH files that could be anywhere
|
|
|
|
// in the filesystem).
|
|
|
|
for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
|
|
|
|
ImportedModule &M = Loaded[I];
|
|
|
|
if (M.Mod->Kind == MK_Module) {
|
|
|
|
updateModuleTimestamp(*M.Mod);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTReader::ASTReadResult
|
|
|
|
ASTReader::ReadASTCore(StringRef FileName,
|
|
|
|
ModuleKind Type,
|
|
|
|
SourceLocation ImportLoc,
|
|
|
|
ModuleFile *ImportedBy,
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVectorImpl<ImportedModule> &Loaded,
|
2013-03-19 08:28:20 +08:00
|
|
|
off_t ExpectedSize, time_t ExpectedModTime,
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned ClientLoadCapabilities) {
|
|
|
|
ModuleFile *M;
|
|
|
|
std::string ErrorStr;
|
2013-03-19 08:28:20 +08:00
|
|
|
ModuleManager::AddModuleResult AddResult
|
|
|
|
= ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
|
|
|
|
CurrentGeneration, ExpectedSize, ExpectedModTime,
|
|
|
|
M, ErrorStr);
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-03-19 08:28:20 +08:00
|
|
|
switch (AddResult) {
|
|
|
|
case ModuleManager::AlreadyLoaded:
|
2012-12-18 22:30:41 +08:00
|
|
|
return Success;
|
2013-03-19 08:28:20 +08:00
|
|
|
|
|
|
|
case ModuleManager::NewlyLoaded:
|
|
|
|
// Load module file below.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ModuleManager::Missing:
|
|
|
|
// The module file was missing; if the client handle handle, that, return
|
|
|
|
// it.
|
|
|
|
if (ClientLoadCapabilities & ARR_Missing)
|
|
|
|
return Missing;
|
|
|
|
|
|
|
|
// Otherwise, return an error.
|
|
|
|
{
|
|
|
|
std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
|
|
|
|
+ ErrorStr;
|
|
|
|
Error(Msg);
|
|
|
|
}
|
|
|
|
return Failure;
|
|
|
|
|
|
|
|
case ModuleManager::OutOfDate:
|
|
|
|
// We couldn't load the module file because it is out-of-date. If the
|
|
|
|
// client can handle out-of-date, return it.
|
|
|
|
if (ClientLoadCapabilities & ARR_OutOfDate)
|
|
|
|
return OutOfDate;
|
|
|
|
|
|
|
|
// Otherwise, return an error.
|
|
|
|
{
|
|
|
|
std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
|
|
|
|
+ ErrorStr;
|
|
|
|
Error(Msg);
|
|
|
|
}
|
|
|
|
return Failure;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2013-03-19 08:28:20 +08:00
|
|
|
assert(M && "Missing module file");
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// FIXME: This seems rather a hack. Should CurrentDir be part of the
|
|
|
|
// module?
|
|
|
|
if (FileName != "-") {
|
|
|
|
CurrentDir = llvm::sys::path::parent_path(FileName);
|
|
|
|
if (CurrentDir.empty()) CurrentDir = ".";
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleFile &F = *M;
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Stream = F.Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
Stream.init(F.StreamFile);
|
|
|
|
F.SizeInBits = F.Buffer->getBufferSize() * 8;
|
|
|
|
|
|
|
|
// Sniff for the signature.
|
|
|
|
if (Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'P' ||
|
|
|
|
Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'H') {
|
|
|
|
Diag(diag::err_not_a_pch_file) << FileName;
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is used for compatibility with older PCH formats.
|
|
|
|
bool HaveReadControlBlock = false;
|
|
|
|
|
2013-01-20 08:00:22 +08:00
|
|
|
while (1) {
|
|
|
|
llvm::BitstreamEntry Entry = Stream.advance();
|
|
|
|
|
|
|
|
switch (Entry.Kind) {
|
|
|
|
case llvm::BitstreamEntry::Error:
|
|
|
|
case llvm::BitstreamEntry::EndBlock:
|
|
|
|
case llvm::BitstreamEntry::Record:
|
2012-12-18 22:30:41 +08:00
|
|
|
Error("invalid record at top-level of AST file");
|
|
|
|
return Failure;
|
2013-01-20 08:00:22 +08:00
|
|
|
|
|
|
|
case llvm::BitstreamEntry::SubBlock:
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We only know the control subblock ID.
|
2013-01-20 08:00:22 +08:00
|
|
|
switch (Entry.ID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
case llvm::bitc::BLOCKINFO_BLOCK_ID:
|
|
|
|
if (Stream.ReadBlockInfoBlock()) {
|
|
|
|
Error("malformed BlockInfoBlock in AST file");
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONTROL_BLOCK_ID:
|
|
|
|
HaveReadControlBlock = true;
|
|
|
|
switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
|
|
|
|
case Success:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Failure: return Failure;
|
2013-03-19 08:28:20 +08:00
|
|
|
case Missing: return Missing;
|
2012-12-18 22:30:41 +08:00
|
|
|
case OutOfDate: return OutOfDate;
|
|
|
|
case VersionMismatch: return VersionMismatch;
|
|
|
|
case ConfigurationMismatch: return ConfigurationMismatch;
|
|
|
|
case HadErrors: return HadErrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AST_BLOCK_ID:
|
|
|
|
if (!HaveReadControlBlock) {
|
|
|
|
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
|
2014-02-11 23:40:09 +08:00
|
|
|
Diag(diag::err_pch_version_too_old);
|
2012-12-18 22:30:41 +08:00
|
|
|
return VersionMismatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Record that we've loaded this module.
|
|
|
|
Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
|
|
|
|
return Success;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (Stream.SkipBlock()) {
|
|
|
|
Error("malformed block record in AST file");
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::InitializeContext() {
|
|
|
|
// If there's a listener, notify them that we "read" the translation unit.
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
|
|
|
|
Context.getTranslationUnitDecl());
|
|
|
|
|
|
|
|
// Make sure we load the declaration update records for the translation unit,
|
|
|
|
// if there are any.
|
|
|
|
loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
|
|
|
|
Context.getTranslationUnitDecl());
|
|
|
|
|
|
|
|
// FIXME: Find a better way to deal with collisions between these
|
|
|
|
// built-in types. Right now, we just ignore the problem.
|
|
|
|
|
|
|
|
// Load the special types.
|
|
|
|
if (SpecialTypes.size() >= NumSpecialTypeIDs) {
|
|
|
|
if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
|
|
|
|
if (!Context.CFConstantStringTypeDecl)
|
|
|
|
Context.setCFConstantStringType(GetType(String));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
|
|
|
|
QualType FileType = GetType(File);
|
|
|
|
if (FileType.isNull()) {
|
|
|
|
Error("FILE type is NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Context.FILEDecl) {
|
|
|
|
if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
|
|
|
|
Context.setFILEDecl(Typedef->getDecl());
|
|
|
|
else {
|
|
|
|
const TagType *Tag = FileType->getAs<TagType>();
|
|
|
|
if (!Tag) {
|
|
|
|
Error("Invalid FILE type in AST file");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Context.setFILEDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) {
|
|
|
|
QualType Jmp_bufType = GetType(Jmp_buf);
|
|
|
|
if (Jmp_bufType.isNull()) {
|
|
|
|
Error("jmp_buf type is NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Context.jmp_bufDecl) {
|
|
|
|
if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
|
|
|
|
Context.setjmp_bufDecl(Typedef->getDecl());
|
|
|
|
else {
|
|
|
|
const TagType *Tag = Jmp_bufType->getAs<TagType>();
|
|
|
|
if (!Tag) {
|
|
|
|
Error("Invalid jmp_buf type in AST file");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Context.setjmp_bufDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) {
|
|
|
|
QualType Sigjmp_bufType = GetType(Sigjmp_buf);
|
|
|
|
if (Sigjmp_bufType.isNull()) {
|
|
|
|
Error("sigjmp_buf type is NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Context.sigjmp_bufDecl) {
|
|
|
|
if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
|
|
|
|
Context.setsigjmp_bufDecl(Typedef->getDecl());
|
|
|
|
else {
|
|
|
|
const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
|
|
|
|
assert(Tag && "Invalid sigjmp_buf type in AST file");
|
|
|
|
Context.setsigjmp_bufDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned ObjCIdRedef
|
|
|
|
= SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) {
|
|
|
|
if (Context.ObjCIdRedefinitionType.isNull())
|
|
|
|
Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned ObjCClassRedef
|
|
|
|
= SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) {
|
|
|
|
if (Context.ObjCClassRedefinitionType.isNull())
|
|
|
|
Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned ObjCSelRedef
|
|
|
|
= SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) {
|
|
|
|
if (Context.ObjCSelRedefinitionType.isNull())
|
|
|
|
Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) {
|
|
|
|
QualType Ucontext_tType = GetType(Ucontext_t);
|
|
|
|
if (Ucontext_tType.isNull()) {
|
|
|
|
Error("ucontext_t type is NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Context.ucontext_tDecl) {
|
|
|
|
if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>())
|
|
|
|
Context.setucontext_tDecl(Typedef->getDecl());
|
|
|
|
else {
|
|
|
|
const TagType *Tag = Ucontext_tType->getAs<TagType>();
|
|
|
|
assert(Tag && "Invalid ucontext_t type in AST file");
|
|
|
|
Context.setucontext_tDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReadPragmaDiagnosticMappings(Context.getDiagnostics());
|
|
|
|
|
|
|
|
// If there were any CUDA special declarations, deserialize them.
|
|
|
|
if (!CUDASpecialDeclRefs.empty()) {
|
|
|
|
assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!");
|
|
|
|
Context.setcudaConfigureCallDecl(
|
|
|
|
cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-export any modules that were imported by a non-module AST file.
|
|
|
|
for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
|
|
|
|
if (Module *Imported = getSubmodule(ImportedModules[I]))
|
2013-02-02 00:36:12 +08:00
|
|
|
makeModuleVisible(Imported, Module::AllVisible,
|
2013-03-21 05:10:35 +08:00
|
|
|
/*ImportLoc=*/SourceLocation(),
|
|
|
|
/*Complain=*/false);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
ImportedModules.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::finalizeForWriting() {
|
|
|
|
for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
|
|
|
|
HiddenEnd = HiddenNamesMap.end();
|
|
|
|
Hidden != HiddenEnd; ++Hidden) {
|
2013-03-27 09:25:34 +08:00
|
|
|
makeNamesVisible(Hidden->second, Hidden->first);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
HiddenNamesMap.clear();
|
|
|
|
}
|
|
|
|
|
2013-05-07 03:23:40 +08:00
|
|
|
/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
|
|
|
|
/// cursor into the start of the given block ID, returning false on success and
|
|
|
|
/// true on failure.
|
|
|
|
static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) {
|
2013-01-20 08:56:42 +08:00
|
|
|
while (1) {
|
|
|
|
llvm::BitstreamEntry Entry = Cursor.advance();
|
|
|
|
switch (Entry.Kind) {
|
|
|
|
case llvm::BitstreamEntry::Error:
|
|
|
|
case llvm::BitstreamEntry::EndBlock:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case llvm::BitstreamEntry::Record:
|
|
|
|
// Ignore top-level records.
|
|
|
|
Cursor.skipRecord(Entry.ID);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case llvm::BitstreamEntry::SubBlock:
|
2013-05-07 03:23:40 +08:00
|
|
|
if (Entry.ID == BlockID) {
|
|
|
|
if (Cursor.EnterSubBlock(BlockID))
|
2013-01-20 08:56:42 +08:00
|
|
|
return true;
|
|
|
|
// Found it!
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Cursor.SkipBlock())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
/// \brief Retrieve the name of the original source file name
|
|
|
|
/// directly from the AST file, without actually loading the AST
|
|
|
|
/// file.
|
|
|
|
std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
|
|
|
|
FileManager &FileMgr,
|
|
|
|
DiagnosticsEngine &Diags) {
|
|
|
|
// Open the AST file.
|
|
|
|
std::string ErrStr;
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer;
|
2012-12-18 22:30:41 +08:00
|
|
|
Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
|
|
|
|
if (!Buffer) {
|
|
|
|
Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr;
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the stream
|
|
|
|
llvm::BitstreamReader StreamFile;
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
|
|
|
|
(const unsigned char *)Buffer->getBufferEnd());
|
|
|
|
Stream.init(StreamFile);
|
|
|
|
|
|
|
|
// Sniff for the signature.
|
|
|
|
if (Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'P' ||
|
|
|
|
Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'H') {
|
|
|
|
Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
|
|
|
|
return std::string();
|
|
|
|
}
|
2013-01-20 08:56:42 +08:00
|
|
|
|
2013-01-20 05:39:22 +08:00
|
|
|
// Scan for the CONTROL_BLOCK_ID block.
|
2013-05-07 03:23:40 +08:00
|
|
|
if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) {
|
2013-01-20 08:56:42 +08:00
|
|
|
Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
|
|
|
|
return std::string();
|
2013-01-20 05:39:22 +08:00
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
// Scan for ORIGINAL_FILE inside the control block.
|
|
|
|
RecordData Record;
|
2013-01-20 05:39:22 +08:00
|
|
|
while (1) {
|
2013-01-20 08:56:42 +08:00
|
|
|
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
2013-01-20 05:39:22 +08:00
|
|
|
if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
|
|
|
|
return std::string();
|
|
|
|
|
|
|
|
if (Entry.Kind != llvm::BitstreamEntry::Record) {
|
|
|
|
Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
|
|
|
|
return std::string();
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-01-20 05:39:22 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
|
|
|
if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE)
|
|
|
|
return Blob.str();
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class SimplePCHValidator : public ASTReaderListener {
|
|
|
|
const LangOptions &ExistingLangOpts;
|
|
|
|
const TargetOptions &ExistingTargetOpts;
|
|
|
|
const PreprocessorOptions &ExistingPPOpts;
|
|
|
|
FileManager &FileMgr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
SimplePCHValidator(const LangOptions &ExistingLangOpts,
|
|
|
|
const TargetOptions &ExistingTargetOpts,
|
|
|
|
const PreprocessorOptions &ExistingPPOpts,
|
|
|
|
FileManager &FileMgr)
|
|
|
|
: ExistingLangOpts(ExistingLangOpts),
|
|
|
|
ExistingTargetOpts(ExistingTargetOpts),
|
|
|
|
ExistingPPOpts(ExistingPPOpts),
|
|
|
|
FileMgr(FileMgr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-13 10:13:41 +08:00
|
|
|
bool ReadLanguageOptions(const LangOptions &LangOpts,
|
|
|
|
bool Complain) override {
|
2012-12-18 22:30:41 +08:00
|
|
|
return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
|
|
|
|
}
|
2014-03-13 10:13:41 +08:00
|
|
|
bool ReadTargetOptions(const TargetOptions &TargetOpts,
|
|
|
|
bool Complain) override {
|
2012-12-18 22:30:41 +08:00
|
|
|
return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
|
|
|
|
}
|
2014-03-13 10:13:41 +08:00
|
|
|
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
|
|
|
|
bool Complain,
|
|
|
|
std::string &SuggestedPredefines) override {
|
2012-12-18 22:30:41 +08:00
|
|
|
return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
|
2013-04-27 05:33:40 +08:00
|
|
|
SuggestedPredefines, ExistingLangOpts);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::readASTFileControlBlock(StringRef Filename,
|
|
|
|
FileManager &FileMgr,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
// Open the AST file.
|
|
|
|
std::string ErrStr;
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer;
|
2012-12-18 22:30:41 +08:00
|
|
|
Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
|
|
|
|
if (!Buffer) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the stream
|
|
|
|
llvm::BitstreamReader StreamFile;
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor Stream;
|
2012-12-18 22:30:41 +08:00
|
|
|
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
|
|
|
|
(const unsigned char *)Buffer->getBufferEnd());
|
|
|
|
Stream.init(StreamFile);
|
|
|
|
|
|
|
|
// Sniff for the signature.
|
|
|
|
if (Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'P' ||
|
|
|
|
Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'H') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
// Scan for the CONTROL_BLOCK_ID block.
|
2013-05-07 03:23:40 +08:00
|
|
|
if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
|
2013-01-20 08:56:42 +08:00
|
|
|
return true;
|
2013-05-07 03:23:40 +08:00
|
|
|
|
|
|
|
bool NeedsInputFiles = Listener.needsInputFileVisitation();
|
2014-03-07 14:40:32 +08:00
|
|
|
bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation();
|
2013-05-07 03:23:40 +08:00
|
|
|
BitstreamCursor InputFilesCursor;
|
|
|
|
if (NeedsInputFiles) {
|
|
|
|
InputFilesCursor = Stream;
|
|
|
|
if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Read the abbreviations
|
|
|
|
while (true) {
|
|
|
|
uint64_t Offset = InputFilesCursor.GetCurrentBitNo();
|
|
|
|
unsigned Code = InputFilesCursor.ReadCode();
|
|
|
|
|
|
|
|
// We expect all abbrevs to be at the start of the block.
|
|
|
|
if (Code != llvm::bitc::DEFINE_ABBREV) {
|
|
|
|
InputFilesCursor.JumpToBit(Offset);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
InputFilesCursor.ReadAbbrevRecord();
|
|
|
|
}
|
|
|
|
}
|
2013-01-20 08:56:42 +08:00
|
|
|
|
|
|
|
// Scan for ORIGINAL_FILE inside the control block.
|
2012-12-18 22:30:41 +08:00
|
|
|
RecordData Record;
|
2013-01-20 08:56:42 +08:00
|
|
|
while (1) {
|
|
|
|
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
|
|
|
if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Entry.Kind != llvm::BitstreamEntry::Record)
|
|
|
|
return true;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
|
|
|
unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
|
2013-01-20 08:56:42 +08:00
|
|
|
switch ((ControlRecordTypes)RecCode) {
|
|
|
|
case METADATA: {
|
|
|
|
if (Record[0] != VERSION_MAJOR)
|
|
|
|
return true;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-03-28 00:47:18 +08:00
|
|
|
if (Listener.ReadFullVersionInformation(Blob))
|
2013-01-20 08:56:42 +08:00
|
|
|
return true;
|
2013-03-28 00:47:18 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LANGUAGE_OPTIONS:
|
|
|
|
if (ParseLanguageOptions(Record, false, Listener))
|
|
|
|
return true;
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
case TARGET_OPTIONS:
|
|
|
|
if (ParseTargetOptions(Record, false, Listener))
|
|
|
|
return true;
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
case DIAGNOSTIC_OPTIONS:
|
|
|
|
if (ParseDiagnosticOptions(Record, false, Listener))
|
|
|
|
return true;
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
case FILE_SYSTEM_OPTIONS:
|
|
|
|
if (ParseFileSystemOptions(Record, false, Listener))
|
|
|
|
return true;
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
case HEADER_SEARCH_OPTIONS:
|
|
|
|
if (ParseHeaderSearchOptions(Record, false, Listener))
|
|
|
|
return true;
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
case PREPROCESSOR_OPTIONS: {
|
|
|
|
std::string IgnoredSuggestedPredefines;
|
|
|
|
if (ParsePreprocessorOptions(Record, false, Listener,
|
|
|
|
IgnoredSuggestedPredefines))
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-05-07 03:23:40 +08:00
|
|
|
case INPUT_FILE_OFFSETS: {
|
|
|
|
if (!NeedsInputFiles)
|
|
|
|
break;
|
|
|
|
|
|
|
|
unsigned NumInputFiles = Record[0];
|
|
|
|
unsigned NumUserFiles = Record[1];
|
|
|
|
const uint32_t *InputFileOffs = (const uint32_t *)Blob.data();
|
|
|
|
for (unsigned I = 0; I != NumInputFiles; ++I) {
|
|
|
|
// Go find this input file.
|
|
|
|
bool isSystemFile = I >= NumUserFiles;
|
2014-03-07 14:40:32 +08:00
|
|
|
|
|
|
|
if (isSystemFile && !NeedsSystemInputFiles)
|
|
|
|
break; // the rest are system input files
|
|
|
|
|
2013-05-07 03:23:40 +08:00
|
|
|
BitstreamCursor &Cursor = InputFilesCursor;
|
|
|
|
SavedStreamPosition SavedPosition(Cursor);
|
|
|
|
Cursor.JumpToBit(InputFileOffs[I]);
|
|
|
|
|
|
|
|
unsigned Code = Cursor.ReadCode();
|
|
|
|
RecordData Record;
|
|
|
|
StringRef Blob;
|
|
|
|
bool shouldContinue = false;
|
|
|
|
switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
|
|
|
|
case INPUT_FILE:
|
2014-03-14 10:26:31 +08:00
|
|
|
bool Overridden = static_cast<bool>(Record[3]);
|
|
|
|
shouldContinue = Listener.visitInputFile(Blob, isSystemFile, Overridden);
|
2013-05-07 03:23:40 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!shouldContinue)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
default:
|
|
|
|
// No other validation to perform.
|
|
|
|
break;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ASTReader::isAcceptableASTFile(StringRef Filename,
|
|
|
|
FileManager &FileMgr,
|
|
|
|
const LangOptions &LangOpts,
|
|
|
|
const TargetOptions &TargetOpts,
|
|
|
|
const PreprocessorOptions &PPOpts) {
|
|
|
|
SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr);
|
|
|
|
return !readASTFileControlBlock(Filename, FileMgr, validator);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
|
|
|
|
// Enter the submodule block.
|
|
|
|
if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
|
|
|
|
Error("malformed submodule block record in AST file");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
|
|
|
|
bool First = true;
|
|
|
|
Module *CurrentModule = 0;
|
|
|
|
RecordData Record;
|
|
|
|
while (true) {
|
2013-01-20 08:56:42 +08:00
|
|
|
llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
|
2012-12-18 22:30:41 +08:00
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
switch (Entry.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;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2013-01-20 08:56:42 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Read a record.
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
switch (F.Stream.readRecord(Entry.ID, Record, &Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
default: // Default behavior: ignore.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SUBMODULE_DEFINITION: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-20 11:59:18 +08:00
|
|
|
if (Record.size() < 8) {
|
2012-12-18 22:30:41 +08:00
|
|
|
Error("malformed module definition");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Name = Blob;
|
2014-03-08 08:03:56 +08:00
|
|
|
unsigned Idx = 0;
|
|
|
|
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]);
|
|
|
|
SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]);
|
|
|
|
bool IsFramework = Record[Idx++];
|
|
|
|
bool IsExplicit = Record[Idx++];
|
|
|
|
bool IsSystem = Record[Idx++];
|
|
|
|
bool IsExternC = Record[Idx++];
|
|
|
|
bool InferSubmodules = Record[Idx++];
|
|
|
|
bool InferExplicitSubmodules = Record[Idx++];
|
|
|
|
bool InferExportWildcard = Record[Idx++];
|
|
|
|
bool ConfigMacrosExhaustive = Record[Idx++];
|
2013-03-20 11:59:18 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
Module *ParentModule = 0;
|
|
|
|
if (Parent)
|
|
|
|
ParentModule = getSubmodule(Parent);
|
|
|
|
|
|
|
|
// Retrieve this (sub)module from the module map, creating it if
|
|
|
|
// necessary.
|
|
|
|
CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
|
|
|
|
IsFramework,
|
|
|
|
IsExplicit).first;
|
|
|
|
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
|
|
|
|
if (GlobalIndex >= SubmodulesLoaded.size() ||
|
|
|
|
SubmodulesLoaded[GlobalIndex]) {
|
|
|
|
Error("too many submodules");
|
|
|
|
return true;
|
|
|
|
}
|
2013-02-07 06:40:31 +08:00
|
|
|
|
2013-03-19 08:28:20 +08:00
|
|
|
if (!ParentModule) {
|
|
|
|
if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
|
|
|
|
if (CurFile != F.File) {
|
|
|
|
if (!Diags.isDiagnosticInFlight()) {
|
|
|
|
Diag(diag::err_module_file_conflict)
|
|
|
|
<< CurrentModule->getTopLevelModuleName()
|
|
|
|
<< CurFile->getName()
|
|
|
|
<< F.File->getName();
|
|
|
|
}
|
|
|
|
return true;
|
2013-02-07 06:40:31 +08:00
|
|
|
}
|
|
|
|
}
|
2013-03-19 08:28:20 +08:00
|
|
|
|
|
|
|
CurrentModule->setASTFile(F.File);
|
2013-02-07 06:40:31 +08:00
|
|
|
}
|
2013-03-19 08:28:20 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
CurrentModule->IsFromModuleFile = true;
|
|
|
|
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
|
2014-03-08 08:03:56 +08:00
|
|
|
CurrentModule->IsExternC = IsExternC;
|
2012-12-18 22:30:41 +08:00
|
|
|
CurrentModule->InferSubmodules = InferSubmodules;
|
|
|
|
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
|
|
|
|
CurrentModule->InferExportWildcard = InferExportWildcard;
|
2013-03-20 11:59:18 +08:00
|
|
|
CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
|
|
|
|
|
|
|
|
SubmodulesLoaded[GlobalIndex] = CurrentModule;
|
2013-01-15 01:21:00 +08:00
|
|
|
|
2013-03-21 05:10:35 +08:00
|
|
|
// Clear out data that will be replaced by what is the module file.
|
2013-01-15 01:21:00 +08:00
|
|
|
CurrentModule->LinkLibraries.clear();
|
2013-03-20 11:59:18 +08:00
|
|
|
CurrentModule->ConfigMacros.clear();
|
2013-03-21 05:10:35 +08:00
|
|
|
CurrentModule->UnresolvedConflicts.clear();
|
|
|
|
CurrentModule->Conflicts.clear();
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_UMBRELLA_HEADER: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
2013-01-20 10:38:54 +08:00
|
|
|
if (const FileEntry *Umbrella = PP.getFileManager().getFile(Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!CurrentModule->getUmbrellaHeader())
|
|
|
|
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
|
|
|
|
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
|
|
|
|
Error("mismatched umbrella headers in submodule");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_HEADER: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
2013-03-14 05:13:51 +08:00
|
|
|
// We lazily associate headers with their modules via the HeaderInfoTable.
|
|
|
|
// FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
|
|
|
|
// of complete filenames or remove it entirely.
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_EXCLUDED_HEADER: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
2013-03-14 05:13:51 +08:00
|
|
|
// We lazily associate headers with their modules via the HeaderInfoTable.
|
|
|
|
// FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
|
|
|
|
// of complete filenames or remove it entirely.
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-06-21 05:14:14 +08:00
|
|
|
case SUBMODULE_PRIVATE_HEADER: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// We lazily associate headers with their modules via the HeaderInfoTable.
|
|
|
|
// FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
|
|
|
|
// of complete filenames or remove it entirely.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case SUBMODULE_TOPHEADER: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
2013-03-14 05:13:43 +08:00
|
|
|
CurrentModule->addTopHeaderFilename(Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_UMBRELLA_DIR: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (const DirectoryEntry *Umbrella
|
2013-01-20 10:38:54 +08:00
|
|
|
= PP.getFileManager().getDirectory(Blob)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!CurrentModule->getUmbrellaDir())
|
|
|
|
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
|
|
|
|
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
|
|
|
|
Error("mismatched umbrella directories in submodule");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_METADATA: {
|
|
|
|
if (!First) {
|
|
|
|
Error("submodule metadata record not at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
First = false;
|
|
|
|
|
|
|
|
F.BaseSubmoduleID = getTotalNumSubmodules();
|
|
|
|
F.LocalNumSubmodules = Record[0];
|
|
|
|
unsigned LocalBaseSubmoduleID = Record[1];
|
|
|
|
if (F.LocalNumSubmodules > 0) {
|
|
|
|
// Introduce the global -> local mapping for submodules within this
|
|
|
|
// module.
|
|
|
|
GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F));
|
|
|
|
|
|
|
|
// Introduce the local -> global mapping for submodules within this
|
|
|
|
// module.
|
|
|
|
F.SubmoduleRemap.insertOrReplace(
|
|
|
|
std::make_pair(LocalBaseSubmoduleID,
|
|
|
|
F.BaseSubmoduleID - LocalBaseSubmoduleID));
|
|
|
|
|
|
|
|
SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_IMPORTS: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
|
2013-03-21 05:10:35 +08:00
|
|
|
UnresolvedModuleRef Unresolved;
|
2012-12-18 22:30:41 +08:00
|
|
|
Unresolved.File = &F;
|
|
|
|
Unresolved.Mod = CurrentModule;
|
|
|
|
Unresolved.ID = Record[Idx];
|
2013-03-21 05:10:35 +08:00
|
|
|
Unresolved.Kind = UnresolvedModuleRef::Import;
|
2012-12-18 22:30:41 +08:00
|
|
|
Unresolved.IsWildcard = false;
|
2013-03-21 05:10:35 +08:00
|
|
|
UnresolvedModuleRefs.push_back(Unresolved);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SUBMODULE_EXPORTS: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
|
2013-03-21 05:10:35 +08:00
|
|
|
UnresolvedModuleRef Unresolved;
|
2012-12-18 22:30:41 +08:00
|
|
|
Unresolved.File = &F;
|
|
|
|
Unresolved.Mod = CurrentModule;
|
|
|
|
Unresolved.ID = Record[Idx];
|
2013-03-21 05:10:35 +08:00
|
|
|
Unresolved.Kind = UnresolvedModuleRef::Export;
|
2012-12-18 22:30:41 +08:00
|
|
|
Unresolved.IsWildcard = Record[Idx + 1];
|
2013-03-21 05:10:35 +08:00
|
|
|
UnresolvedModuleRefs.push_back(Unresolved);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Once we've loaded the set of exports, there's no reason to keep
|
|
|
|
// the parsed, unresolved exports around.
|
|
|
|
CurrentModule->UnresolvedExports.clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SUBMODULE_REQUIRES: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
2013-10-29 06:18:19 +08:00
|
|
|
CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
|
2012-12-18 22:30:41 +08:00
|
|
|
Context.getTargetInfo());
|
|
|
|
break;
|
|
|
|
}
|
2013-01-15 01:21:00 +08:00
|
|
|
|
|
|
|
case SUBMODULE_LINK_LIBRARY:
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
CurrentModule->LinkLibraries.push_back(
|
2013-01-20 10:38:54 +08:00
|
|
|
Module::LinkLibrary(Blob, Record[0]));
|
2013-01-15 01:21:00 +08:00
|
|
|
break;
|
2013-03-20 08:22:05 +08:00
|
|
|
|
|
|
|
case SUBMODULE_CONFIG_MACRO:
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
CurrentModule->ConfigMacros.push_back(Blob.str());
|
|
|
|
break;
|
2013-03-21 05:10:35 +08:00
|
|
|
|
|
|
|
case SUBMODULE_CONFLICT: {
|
|
|
|
if (First) {
|
|
|
|
Error("missing submodule metadata record at beginning of block");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrentModule)
|
|
|
|
break;
|
|
|
|
|
|
|
|
UnresolvedModuleRef Unresolved;
|
|
|
|
Unresolved.File = &F;
|
|
|
|
Unresolved.Mod = CurrentModule;
|
|
|
|
Unresolved.ID = Record[0];
|
|
|
|
Unresolved.Kind = UnresolvedModuleRef::Conflict;
|
|
|
|
Unresolved.IsWildcard = false;
|
|
|
|
Unresolved.String = Blob;
|
|
|
|
UnresolvedModuleRefs.push_back(Unresolved);
|
|
|
|
break;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse the record that corresponds to a LangOptions data
|
|
|
|
/// structure.
|
|
|
|
///
|
|
|
|
/// This routine parses the language options from the AST file and then gives
|
|
|
|
/// them to the AST listener if one is set.
|
|
|
|
///
|
|
|
|
/// \returns true if the listener deems the file unacceptable, false otherwise.
|
|
|
|
bool ASTReader::ParseLanguageOptions(const RecordData &Record,
|
|
|
|
bool Complain,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
LangOptions LangOpts;
|
|
|
|
unsigned Idx = 0;
|
|
|
|
#define LANGOPT(Name, Bits, Default, Description) \
|
|
|
|
LangOpts.Name = Record[Idx++];
|
|
|
|
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
|
|
|
|
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
|
|
|
|
#include "clang/Basic/LangOptions.def"
|
2013-01-18 19:30:38 +08:00
|
|
|
#define SANITIZER(NAME, ID) LangOpts.Sanitize.ID = Record[Idx++];
|
|
|
|
#include "clang/Basic/Sanitizers.def"
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
|
|
|
|
VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
|
|
|
|
LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
|
|
|
|
|
|
|
|
unsigned Length = Record[Idx++];
|
|
|
|
LangOpts.CurrentModule.assign(Record.begin() + Idx,
|
|
|
|
Record.begin() + Idx + Length);
|
2013-02-22 22:21:27 +08:00
|
|
|
|
|
|
|
Idx += Length;
|
|
|
|
|
|
|
|
// Comment options.
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
LangOpts.CommentOpts.BlockCommandNames.push_back(
|
|
|
|
ReadString(Record, Idx));
|
|
|
|
}
|
2013-04-10 23:35:17 +08:00
|
|
|
LangOpts.CommentOpts.ParseAllComments = Record[Idx++];
|
2013-02-22 22:21:27 +08:00
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
return Listener.ReadLanguageOptions(LangOpts, Complain);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ParseTargetOptions(const RecordData &Record,
|
|
|
|
bool Complain,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
TargetOptions TargetOpts;
|
|
|
|
TargetOpts.Triple = ReadString(Record, Idx);
|
|
|
|
TargetOpts.CPU = ReadString(Record, Idx);
|
|
|
|
TargetOpts.ABI = ReadString(Record, Idx);
|
|
|
|
TargetOpts.LinkerVersion = ReadString(Record, Idx);
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
|
|
|
|
}
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
TargetOpts.Features.push_back(ReadString(Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Listener.ReadTargetOptions(TargetOpts, Complain);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
DiagnosticOptions DiagOpts;
|
|
|
|
unsigned Idx = 0;
|
|
|
|
#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
|
|
|
|
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
|
|
|
|
DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
|
|
|
|
#include "clang/Basic/DiagnosticOptions.def"
|
|
|
|
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
DiagOpts.Warnings.push_back(ReadString(Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
FileSystemOptions FSOpts;
|
|
|
|
unsigned Idx = 0;
|
|
|
|
FSOpts.WorkingDir = ReadString(Record, Idx);
|
|
|
|
return Listener.ReadFileSystemOptions(FSOpts, Complain);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
|
|
|
|
bool Complain,
|
|
|
|
ASTReaderListener &Listener) {
|
|
|
|
HeaderSearchOptions HSOpts;
|
|
|
|
unsigned Idx = 0;
|
|
|
|
HSOpts.Sysroot = ReadString(Record, Idx);
|
|
|
|
|
|
|
|
// Include entries.
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
std::string Path = ReadString(Record, Idx);
|
|
|
|
frontend::IncludeDirGroup Group
|
|
|
|
= static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
|
|
|
|
bool IsFramework = Record[Idx++];
|
|
|
|
bool IgnoreSysRoot = Record[Idx++];
|
|
|
|
HSOpts.UserEntries.push_back(
|
2013-01-30 08:34:26 +08:00
|
|
|
HeaderSearchOptions::Entry(Path, Group, IsFramework, IgnoreSysRoot));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// System header prefixes.
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
std::string Prefix = ReadString(Record, Idx);
|
|
|
|
bool IsSystemHeader = Record[Idx++];
|
|
|
|
HSOpts.SystemHeaderPrefixes.push_back(
|
|
|
|
HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader));
|
|
|
|
}
|
|
|
|
|
|
|
|
HSOpts.ResourceDir = ReadString(Record, Idx);
|
|
|
|
HSOpts.ModuleCachePath = ReadString(Record, Idx);
|
2014-03-03 16:12:05 +08:00
|
|
|
HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
|
2012-12-18 22:30:41 +08:00
|
|
|
HSOpts.DisableModuleHash = Record[Idx++];
|
|
|
|
HSOpts.UseBuiltinIncludes = Record[Idx++];
|
|
|
|
HSOpts.UseStandardSystemIncludes = Record[Idx++];
|
|
|
|
HSOpts.UseStandardCXXIncludes = Record[Idx++];
|
|
|
|
HSOpts.UseLibcxx = Record[Idx++];
|
|
|
|
|
|
|
|
return Listener.ReadHeaderSearchOptions(HSOpts, Complain);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
|
|
|
|
bool Complain,
|
|
|
|
ASTReaderListener &Listener,
|
|
|
|
std::string &SuggestedPredefines) {
|
|
|
|
PreprocessorOptions PPOpts;
|
|
|
|
unsigned Idx = 0;
|
|
|
|
|
|
|
|
// Macro definitions/undefs
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
std::string Macro = ReadString(Record, Idx);
|
|
|
|
bool IsUndef = Record[Idx++];
|
|
|
|
PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Includes
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
PPOpts.Includes.push_back(ReadString(Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Macro Includes
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
|
PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
PPOpts.UsePredefines = Record[Idx++];
|
2013-04-27 05:33:40 +08:00
|
|
|
PPOpts.DetailedRecord = Record[Idx++];
|
2012-12-18 22:30:41 +08:00
|
|
|
PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
|
|
|
|
PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
|
|
|
|
PPOpts.ObjCXXARCStandardLibrary =
|
|
|
|
static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
|
|
|
|
SuggestedPredefines.clear();
|
|
|
|
return Listener.ReadPreprocessorOptions(PPOpts, Complain,
|
|
|
|
SuggestedPredefines);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<ModuleFile *, unsigned>
|
|
|
|
ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
|
|
|
|
GlobalPreprocessedEntityMapType::iterator
|
|
|
|
I = GlobalPreprocessedEntityMap.find(GlobalIndex);
|
|
|
|
assert(I != GlobalPreprocessedEntityMap.end() &&
|
|
|
|
"Corrupted global preprocessed entity map");
|
|
|
|
ModuleFile *M = I->second;
|
|
|
|
unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID;
|
|
|
|
return std::make_pair(M, LocalIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
|
|
|
|
ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
|
|
|
|
if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
|
|
|
|
return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
|
|
|
|
Mod.NumPreprocessedEntities);
|
|
|
|
|
|
|
|
return std::make_pair(PreprocessingRecord::iterator(),
|
|
|
|
PreprocessingRecord::iterator());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator>
|
|
|
|
ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
|
|
|
|
return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
|
|
|
|
ModuleDeclIterator(this, &Mod,
|
|
|
|
Mod.FileSortedDecls + Mod.NumFileSortedDecls));
|
|
|
|
}
|
|
|
|
|
|
|
|
PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
|
|
|
|
PreprocessedEntityID PPID = Index+1;
|
|
|
|
std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
|
|
|
|
ModuleFile &M = *PPInfo.first;
|
|
|
|
unsigned LocalIndex = PPInfo.second;
|
|
|
|
const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
|
|
|
|
|
|
|
|
if (!PP.getPreprocessingRecord()) {
|
|
|
|
Error("no preprocessing record");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-20 08:56:42 +08:00
|
|
|
SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
|
|
|
|
M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
|
|
|
|
|
|
|
|
llvm::BitstreamEntry Entry =
|
|
|
|
M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
|
|
|
|
if (Entry.Kind != llvm::BitstreamEntry::Record)
|
|
|
|
return 0;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Read the record.
|
|
|
|
SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
|
|
|
|
ReadSourceLocation(M, PPOffs.End));
|
|
|
|
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef Blob;
|
2012-12-18 22:30:41 +08:00
|
|
|
RecordData Record;
|
|
|
|
PreprocessorDetailRecordTypes RecType =
|
2013-01-20 10:38:54 +08:00
|
|
|
(PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord(
|
|
|
|
Entry.ID, Record, &Blob);
|
2012-12-18 22:30:41 +08:00
|
|
|
switch (RecType) {
|
|
|
|
case PPD_MACRO_EXPANSION: {
|
|
|
|
bool isBuiltin = Record[0];
|
|
|
|
IdentifierInfo *Name = 0;
|
|
|
|
MacroDefinition *Def = 0;
|
|
|
|
if (isBuiltin)
|
|
|
|
Name = getLocalIdentifier(M, Record[1]);
|
|
|
|
else {
|
|
|
|
PreprocessedEntityID
|
|
|
|
GlobalID = getGlobalPreprocessedEntityID(M, Record[1]);
|
|
|
|
Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1));
|
|
|
|
}
|
|
|
|
|
|
|
|
MacroExpansion *ME;
|
|
|
|
if (isBuiltin)
|
|
|
|
ME = new (PPRec) MacroExpansion(Name, Range);
|
|
|
|
else
|
|
|
|
ME = new (PPRec) MacroExpansion(Def, Range);
|
|
|
|
|
|
|
|
return ME;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PPD_MACRO_DEFINITION: {
|
|
|
|
// Decode the identifier info and then check again; if the macro is
|
|
|
|
// still defined and associated with the identifier,
|
|
|
|
IdentifierInfo *II = getLocalIdentifier(M, Record[0]);
|
|
|
|
MacroDefinition *MD
|
|
|
|
= new (PPRec) MacroDefinition(II, Range);
|
|
|
|
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->MacroDefinitionRead(PPID, MD);
|
|
|
|
|
|
|
|
return MD;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PPD_INCLUSION_DIRECTIVE: {
|
2013-01-20 10:38:54 +08:00
|
|
|
const char *FullFileNameStart = Blob.data() + Record[0];
|
|
|
|
StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
|
2012-12-18 22:30:41 +08:00
|
|
|
const FileEntry *File = 0;
|
|
|
|
if (!FullFileName.empty())
|
|
|
|
File = PP.getFileManager().getFile(FullFileName);
|
|
|
|
|
|
|
|
// FIXME: Stable encoding
|
|
|
|
InclusionDirective::InclusionKind Kind
|
|
|
|
= static_cast<InclusionDirective::InclusionKind>(Record[2]);
|
|
|
|
InclusionDirective *ID
|
|
|
|
= new (PPRec) InclusionDirective(PPRec, Kind,
|
2013-01-20 10:38:54 +08:00
|
|
|
StringRef(Blob.data(), Record[0]),
|
2012-12-18 22:30:41 +08:00
|
|
|
Record[1], Record[3],
|
|
|
|
File,
|
|
|
|
Range);
|
|
|
|
return ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief \arg SLocMapI points at a chunk of a module that contains no
|
|
|
|
/// preprocessed entities or the entities it contains are not the ones we are
|
|
|
|
/// looking for. Find the next module that contains entities and return the ID
|
|
|
|
/// of the first entry.
|
|
|
|
PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
|
|
|
|
GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
|
|
|
|
++SLocMapI;
|
|
|
|
for (GlobalSLocOffsetMapType::const_iterator
|
|
|
|
EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
|
|
|
|
ModuleFile &M = *SLocMapI->second;
|
|
|
|
if (M.NumPreprocessedEntities)
|
|
|
|
return M.BasePreprocessedEntityID;
|
|
|
|
}
|
|
|
|
|
|
|
|
return getTotalNumPreprocessedEntities();
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <unsigned PPEntityOffset::*PPLoc>
|
|
|
|
struct PPEntityComp {
|
|
|
|
const ASTReader &Reader;
|
|
|
|
ModuleFile &M;
|
|
|
|
|
|
|
|
PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { }
|
|
|
|
|
|
|
|
bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
|
|
|
|
SourceLocation LHS = getLoc(L);
|
|
|
|
SourceLocation RHS = getLoc(R);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const PPEntityOffset &L, SourceLocation RHS) const {
|
|
|
|
SourceLocation LHS = getLoc(L);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(SourceLocation LHS, const PPEntityOffset &R) const {
|
|
|
|
SourceLocation RHS = getLoc(R);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation getLoc(const PPEntityOffset &PPE) const {
|
|
|
|
return Reader.ReadSourceLocation(M, PPE.*PPLoc);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
|
|
|
|
PreprocessedEntityID
|
|
|
|
ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
|
|
|
|
if (SourceMgr.isLocalSourceLocation(BLoc))
|
|
|
|
return getTotalNumPreprocessedEntities();
|
|
|
|
|
|
|
|
GlobalSLocOffsetMapType::const_iterator
|
|
|
|
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
|
2013-03-08 10:32:34 +08:00
|
|
|
BLoc.getOffset() - 1);
|
2012-12-18 22:30:41 +08:00
|
|
|
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
|
|
|
|
"Corrupted global sloc offset map");
|
|
|
|
|
|
|
|
if (SLocMapI->second->NumPreprocessedEntities == 0)
|
|
|
|
return findNextPreprocessedEntity(SLocMapI);
|
|
|
|
|
|
|
|
ModuleFile &M = *SLocMapI->second;
|
|
|
|
typedef const PPEntityOffset *pp_iterator;
|
|
|
|
pp_iterator pp_begin = M.PreprocessedEntityOffsets;
|
|
|
|
pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
|
|
|
|
|
|
|
|
size_t Count = M.NumPreprocessedEntities;
|
|
|
|
size_t Half;
|
|
|
|
pp_iterator First = pp_begin;
|
|
|
|
pp_iterator PPI;
|
|
|
|
|
|
|
|
// Do a binary search manually instead of using std::lower_bound because
|
|
|
|
// The end locations of entities may be unordered (when a macro expansion
|
|
|
|
// is inside another macro argument), but for this case it is not important
|
|
|
|
// whether we get the first macro expansion or its containing macro.
|
|
|
|
while (Count > 0) {
|
|
|
|
Half = Count/2;
|
|
|
|
PPI = First;
|
|
|
|
std::advance(PPI, Half);
|
|
|
|
if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
|
|
|
|
BLoc)){
|
|
|
|
First = PPI;
|
|
|
|
++First;
|
|
|
|
Count = Count - Half - 1;
|
|
|
|
} else
|
|
|
|
Count = Half;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PPI == pp_end)
|
|
|
|
return findNextPreprocessedEntity(SLocMapI);
|
|
|
|
|
|
|
|
return M.BasePreprocessedEntityID + (PPI - pp_begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
|
|
|
|
PreprocessedEntityID
|
|
|
|
ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
|
|
|
|
if (SourceMgr.isLocalSourceLocation(ELoc))
|
|
|
|
return getTotalNumPreprocessedEntities();
|
|
|
|
|
|
|
|
GlobalSLocOffsetMapType::const_iterator
|
|
|
|
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
|
2013-03-08 10:32:34 +08:00
|
|
|
ELoc.getOffset() - 1);
|
2012-12-18 22:30:41 +08:00
|
|
|
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
|
|
|
|
"Corrupted global sloc offset map");
|
|
|
|
|
|
|
|
if (SLocMapI->second->NumPreprocessedEntities == 0)
|
|
|
|
return findNextPreprocessedEntity(SLocMapI);
|
|
|
|
|
|
|
|
ModuleFile &M = *SLocMapI->second;
|
|
|
|
typedef const PPEntityOffset *pp_iterator;
|
|
|
|
pp_iterator pp_begin = M.PreprocessedEntityOffsets;
|
|
|
|
pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
|
|
|
|
pp_iterator PPI =
|
|
|
|
std::upper_bound(pp_begin, pp_end, ELoc,
|
|
|
|
PPEntityComp<&PPEntityOffset::Begin>(*this, M));
|
|
|
|
|
|
|
|
if (PPI == pp_end)
|
|
|
|
return findNextPreprocessedEntity(SLocMapI);
|
|
|
|
|
|
|
|
return M.BasePreprocessedEntityID + (PPI - pp_begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Returns a pair of [Begin, End) indices of preallocated
|
|
|
|
/// preprocessed entities that \arg Range encompasses.
|
|
|
|
std::pair<unsigned, unsigned>
|
|
|
|
ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) {
|
|
|
|
if (Range.isInvalid())
|
|
|
|
return std::make_pair(0,0);
|
|
|
|
assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
|
|
|
|
|
|
|
|
PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin());
|
|
|
|
PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd());
|
|
|
|
return std::make_pair(BeginID, EndID);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Optionally returns true or false if the preallocated preprocessed
|
|
|
|
/// entity with index \arg Index came from file \arg FID.
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
|
2012-12-18 22:30:41 +08:00
|
|
|
FileID FID) {
|
|
|
|
if (FID.isInvalid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
|
|
|
|
ModuleFile &M = *PPInfo.first;
|
|
|
|
unsigned LocalIndex = PPInfo.second;
|
|
|
|
const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
|
|
|
|
|
|
|
|
SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin);
|
|
|
|
if (Loc.isInvalid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief Visitor used to search for information about a header file.
|
|
|
|
class HeaderFileInfoVisitor {
|
|
|
|
const FileEntry *FE;
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<HeaderFileInfo> HFI;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
public:
|
2013-03-07 02:12:44 +08:00
|
|
|
explicit HeaderFileInfoVisitor(const FileEntry *FE)
|
|
|
|
: FE(FE) { }
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
static bool visit(ModuleFile &M, void *UserData) {
|
|
|
|
HeaderFileInfoVisitor *This
|
|
|
|
= static_cast<HeaderFileInfoVisitor *>(UserData);
|
|
|
|
|
|
|
|
HeaderFileInfoLookupTable *Table
|
|
|
|
= static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
|
|
|
|
if (!Table)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Look in the on-disk hash table for an entry for this file name.
|
2013-03-07 02:12:47 +08:00
|
|
|
HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Pos == Table->end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
This->HFI = *Pos;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
|
2012-12-18 22:30:41 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
|
2013-03-07 02:12:44 +08:00
|
|
|
HeaderFileInfoVisitor Visitor(FE);
|
2012-12-18 22:30:41 +08:00
|
|
|
ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
|
2013-05-09 07:46:55 +08:00
|
|
|
if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
|
2012-12-18 22:30:41 +08:00
|
|
|
return *HFI;
|
|
|
|
|
|
|
|
return HeaderFileInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
|
|
|
|
// FIXME: Make it work properly with modules.
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
|
2012-12-18 22:30:41 +08:00
|
|
|
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
|
|
|
|
ModuleFile &F = *(*I);
|
|
|
|
unsigned Idx = 0;
|
|
|
|
DiagStates.clear();
|
|
|
|
assert(!Diag.DiagStates.empty());
|
|
|
|
DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
|
|
|
|
while (Idx < F.PragmaDiagMappings.size()) {
|
|
|
|
SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
|
|
|
|
unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
|
|
|
|
if (DiagStateID != 0) {
|
|
|
|
Diag.DiagStatePoints.push_back(
|
|
|
|
DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
|
|
|
|
FullSourceLoc(Loc, SourceMgr)));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(DiagStateID == 0);
|
|
|
|
// A new DiagState was created here.
|
|
|
|
Diag.DiagStates.push_back(*Diag.GetCurDiagState());
|
|
|
|
DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
|
|
|
|
DiagStates.push_back(NewState);
|
|
|
|
Diag.DiagStatePoints.push_back(
|
|
|
|
DiagnosticsEngine::DiagStatePoint(NewState,
|
|
|
|
FullSourceLoc(Loc, SourceMgr)));
|
|
|
|
while (1) {
|
|
|
|
assert(Idx < F.PragmaDiagMappings.size() &&
|
|
|
|
"Invalid data, didn't find '-1' marking end of diag/map pairs");
|
|
|
|
if (Idx >= F.PragmaDiagMappings.size()) {
|
|
|
|
break; // Something is messed up but at least avoid infinite loop in
|
|
|
|
// release build.
|
|
|
|
}
|
|
|
|
unsigned DiagID = F.PragmaDiagMappings[Idx++];
|
|
|
|
if (DiagID == (unsigned)-1) {
|
|
|
|
break; // no more diag/map pairs for this location.
|
|
|
|
}
|
|
|
|
diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
|
|
|
|
DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc);
|
|
|
|
Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Get the correct cursor and offset for loading a type.
|
|
|
|
ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
|
|
|
|
GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
|
|
|
|
assert(I != GlobalTypeMap.end() && "Corrupted global type map");
|
|
|
|
ModuleFile *M = I->second;
|
|
|
|
return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Read and return the type with the given index..
|
|
|
|
///
|
|
|
|
/// The index is the type ID, shifted and minus the number of predefs. This
|
|
|
|
/// routine actually reads the record corresponding to the type at the given
|
|
|
|
/// location. It is a helper routine for GetType, which deals with reading type
|
|
|
|
/// IDs.
|
|
|
|
QualType ASTReader::readTypeRecord(unsigned Index) {
|
|
|
|
RecordLocation Loc = TypeCursorForIndex(Index);
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// Keep track of where we are in the stream, then jump back there
|
|
|
|
// after reading this type.
|
|
|
|
SavedStreamPosition SavedPosition(DeclsCursor);
|
|
|
|
|
|
|
|
ReadingKindTracker ReadingKind(Read_Type, *this);
|
|
|
|
|
|
|
|
// Note that we are loading a type record.
|
|
|
|
Deserializing AType(this);
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
DeclsCursor.JumpToBit(Loc.Offset);
|
|
|
|
RecordData Record;
|
|
|
|
unsigned Code = DeclsCursor.ReadCode();
|
2013-01-20 10:38:54 +08:00
|
|
|
switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
case TYPE_EXT_QUAL: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("Incorrect encoding of extended qualifier type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType Base = readType(*Loc.F, Record, Idx);
|
|
|
|
Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]);
|
|
|
|
return Context.getQualifiedType(Base, Quals);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_COMPLEX: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of complex type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType ElemType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getComplexType(ElemType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_POINTER: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of pointer type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType PointeeType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getPointerType(PointeeType);
|
|
|
|
}
|
|
|
|
|
2013-06-25 01:51:48 +08:00
|
|
|
case TYPE_DECAYED: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of decayed type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType OriginalType = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType DT = Context.getAdjustedParameterType(OriginalType);
|
|
|
|
if (!isa<DecayedType>(DT))
|
|
|
|
Error("Decayed type does not decay");
|
|
|
|
return DT;
|
|
|
|
}
|
|
|
|
|
2013-12-05 09:23:43 +08:00
|
|
|
case TYPE_ADJUSTED: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("Incorrect encoding of adjusted type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType OriginalTy = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType AdjustedTy = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getAdjustedType(OriginalTy, AdjustedTy);
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
case TYPE_BLOCK_POINTER: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of block pointer type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType PointeeType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getBlockPointerType(PointeeType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_LVALUE_REFERENCE: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("Incorrect encoding of lvalue reference type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType PointeeType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getLValueReferenceType(PointeeType, Record[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_RVALUE_REFERENCE: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of rvalue reference type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType PointeeType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getRValueReferenceType(PointeeType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_MEMBER_POINTER: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("Incorrect encoding of member pointer type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType PointeeType = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType ClassType = readType(*Loc.F, Record, Idx);
|
|
|
|
if (PointeeType.isNull() || ClassType.isNull())
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_CONSTANT_ARRAY: {
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
|
|
|
unsigned Idx = 3;
|
|
|
|
llvm::APInt Size = ReadAPInt(Record, Idx);
|
|
|
|
return Context.getConstantArrayType(ElementType, Size,
|
|
|
|
ASM, IndexTypeQuals);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_INCOMPLETE_ARRAY: {
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
|
|
|
return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_VARIABLE_ARRAY: {
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
|
|
|
SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
|
|
|
|
SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
|
|
|
|
return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
|
|
|
|
ASM, IndexTypeQuals,
|
|
|
|
SourceRange(LBLoc, RBLoc));
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_VECTOR: {
|
|
|
|
if (Record.size() != 3) {
|
|
|
|
Error("incorrect encoding of vector type in AST file");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
unsigned NumElements = Record[1];
|
|
|
|
unsigned VecKind = Record[2];
|
|
|
|
return Context.getVectorType(ElementType, NumElements,
|
|
|
|
(VectorType::VectorKind)VecKind);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_EXT_VECTOR: {
|
|
|
|
if (Record.size() != 3) {
|
|
|
|
Error("incorrect encoding of extended vector type in AST file");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
unsigned NumElements = Record[1];
|
|
|
|
return Context.getExtVectorType(ElementType, NumElements);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_FUNCTION_NO_PROTO: {
|
|
|
|
if (Record.size() != 6) {
|
|
|
|
Error("incorrect encoding of no-proto function type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType ResultType = readType(*Loc.F, Record, Idx);
|
|
|
|
FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
|
|
|
|
(CallingConv)Record[4], Record[5]);
|
|
|
|
return Context.getFunctionNoProtoType(ResultType, Info);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_FUNCTION_PROTO: {
|
|
|
|
QualType ResultType = readType(*Loc.F, Record, Idx);
|
|
|
|
|
|
|
|
FunctionProtoType::ExtProtoInfo EPI;
|
|
|
|
EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
|
|
|
|
/*hasregparm*/ Record[2],
|
|
|
|
/*regparm*/ Record[3],
|
|
|
|
static_cast<CallingConv>(Record[4]),
|
|
|
|
/*produces*/ Record[5]);
|
|
|
|
|
|
|
|
unsigned Idx = 6;
|
|
|
|
unsigned NumParams = Record[Idx++];
|
|
|
|
SmallVector<QualType, 16> ParamTypes;
|
|
|
|
for (unsigned I = 0; I != NumParams; ++I)
|
|
|
|
ParamTypes.push_back(readType(*Loc.F, Record, Idx));
|
|
|
|
|
|
|
|
EPI.Variadic = Record[Idx++];
|
|
|
|
EPI.HasTrailingReturn = Record[Idx++];
|
|
|
|
EPI.TypeQuals = Record[Idx++];
|
|
|
|
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
|
2014-03-21 05:47:22 +08:00
|
|
|
SmallVector<QualType, 8> ExceptionStorage;
|
|
|
|
readExceptionSpec(*Loc.F, ExceptionStorage, EPI, Record, Idx);
|
2013-03-09 05:51:21 +08:00
|
|
|
return Context.getFunctionType(ResultType, ParamTypes, EPI);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_UNRESOLVED_USING: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
return Context.getTypeDeclType(
|
|
|
|
ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_TYPEDEF: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("incorrect encoding of typedef type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
unsigned Idx = 0;
|
|
|
|
TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx);
|
|
|
|
QualType Canonical = readType(*Loc.F, Record, Idx);
|
|
|
|
if (!Canonical.isNull())
|
|
|
|
Canonical = Context.getCanonicalType(Canonical);
|
|
|
|
return Context.getTypedefType(Decl, Canonical);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_TYPEOF_EXPR:
|
|
|
|
return Context.getTypeOfExprType(ReadExpr(*Loc.F));
|
|
|
|
|
|
|
|
case TYPE_TYPEOF: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("incorrect encoding of typeof(type) in AST file");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType UnderlyingType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getTypeOfType(UnderlyingType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_DECLTYPE: {
|
|
|
|
QualType UnderlyingType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_UNARY_TRANSFORM: {
|
|
|
|
QualType BaseType = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType UnderlyingType = readType(*Loc.F, Record, Idx);
|
|
|
|
UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
|
|
|
|
return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
|
|
|
|
}
|
|
|
|
|
2013-04-27 00:15:35 +08:00
|
|
|
case TYPE_AUTO: {
|
|
|
|
QualType Deduced = readType(*Loc.F, Record, Idx);
|
|
|
|
bool IsDecltypeAuto = Record[Idx++];
|
2013-04-30 21:56:41 +08:00
|
|
|
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
|
2013-08-22 20:12:24 +08:00
|
|
|
return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
|
2013-04-27 00:15:35 +08:00
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
case TYPE_RECORD: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("incorrect encoding of record type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
unsigned Idx = 0;
|
|
|
|
bool IsDependent = Record[Idx++];
|
|
|
|
RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
|
|
|
|
RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
|
|
|
|
QualType T = Context.getRecordType(RD);
|
|
|
|
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_ENUM: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("incorrect encoding of enum type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
unsigned Idx = 0;
|
|
|
|
bool IsDependent = Record[Idx++];
|
|
|
|
QualType T
|
|
|
|
= Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx));
|
|
|
|
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_ATTRIBUTED: {
|
|
|
|
if (Record.size() != 3) {
|
|
|
|
Error("incorrect encoding of attributed type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType modifiedType = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType equivalentType = readType(*Loc.F, Record, Idx);
|
|
|
|
AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
|
|
|
|
return Context.getAttributedType(kind, modifiedType, equivalentType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_PAREN: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("incorrect encoding of paren type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType InnerType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getParenType(InnerType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_PACK_EXPANSION: {
|
|
|
|
if (Record.size() != 2) {
|
|
|
|
Error("incorrect encoding of pack expansion type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType Pattern = readType(*Loc.F, Record, Idx);
|
|
|
|
if (Pattern.isNull())
|
|
|
|
return QualType();
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<unsigned> NumExpansions;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (Record[1])
|
|
|
|
NumExpansions = Record[1] - 1;
|
|
|
|
return Context.getPackExpansionType(Pattern, NumExpansions);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_ELABORATED: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
|
|
|
|
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
|
|
|
|
QualType NamedType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getElaboratedType(Keyword, NNS, NamedType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_OBJC_INTERFACE: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
ObjCInterfaceDecl *ItfD
|
|
|
|
= ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
|
|
|
|
return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_OBJC_OBJECT: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
QualType Base = readType(*Loc.F, Record, Idx);
|
|
|
|
unsigned NumProtos = Record[Idx++];
|
|
|
|
SmallVector<ObjCProtocolDecl*, 4> Protos;
|
|
|
|
for (unsigned I = 0; I != NumProtos; ++I)
|
|
|
|
Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
|
|
|
|
return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_OBJC_OBJECT_POINTER: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
QualType Pointee = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getObjCObjectPointerType(Pointee);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
QualType Parm = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType Replacement = readType(*Loc.F, Record, Idx);
|
2014-03-15 18:23:27 +08:00
|
|
|
return Context.getSubstTemplateTypeParmType(
|
|
|
|
cast<TemplateTypeParmType>(Parm),
|
|
|
|
Context.getCanonicalType(Replacement));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
QualType Parm = readType(*Loc.F, Record, Idx);
|
|
|
|
TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
|
|
|
|
return Context.getSubstTemplateTypeParmPackType(
|
|
|
|
cast<TemplateTypeParmType>(Parm),
|
|
|
|
ArgPack);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_INJECTED_CLASS_NAME: {
|
|
|
|
CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx);
|
|
|
|
QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
|
|
|
|
// FIXME: ASTContext::getInjectedClassNameType is not currently suitable
|
|
|
|
// for AST reading, too much interdependencies.
|
|
|
|
return
|
|
|
|
QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_TEMPLATE_TYPE_PARM: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
unsigned Depth = Record[Idx++];
|
|
|
|
unsigned Index = Record[Idx++];
|
|
|
|
bool Pack = Record[Idx++];
|
|
|
|
TemplateTypeParmDecl *D
|
|
|
|
= ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
|
|
|
|
return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_DEPENDENT_NAME: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
|
|
|
|
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
|
|
|
|
const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
|
|
|
|
QualType Canon = readType(*Loc.F, Record, Idx);
|
|
|
|
if (!Canon.isNull())
|
|
|
|
Canon = Context.getCanonicalType(Canon);
|
|
|
|
return Context.getDependentNameType(Keyword, NNS, Name, Canon);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
|
|
|
|
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
|
|
|
|
const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
|
|
|
|
unsigned NumArgs = Record[Idx++];
|
|
|
|
SmallVector<TemplateArgument, 8> Args;
|
|
|
|
Args.reserve(NumArgs);
|
|
|
|
while (NumArgs--)
|
|
|
|
Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
|
|
|
|
return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
|
|
|
|
Args.size(), Args.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_DEPENDENT_SIZED_ARRAY: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
|
|
|
|
// ArrayType
|
|
|
|
QualType ElementType = readType(*Loc.F, Record, Idx);
|
|
|
|
ArrayType::ArraySizeModifier ASM
|
|
|
|
= (ArrayType::ArraySizeModifier)Record[Idx++];
|
|
|
|
unsigned IndexTypeQuals = Record[Idx++];
|
|
|
|
|
|
|
|
// DependentSizedArrayType
|
|
|
|
Expr *NumElts = ReadExpr(*Loc.F);
|
|
|
|
SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
|
|
|
|
|
|
|
|
return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
|
|
|
|
IndexTypeQuals, Brackets);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_TEMPLATE_SPECIALIZATION: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
bool IsDependent = Record[Idx++];
|
|
|
|
TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
|
|
|
|
SmallVector<TemplateArgument, 8> Args;
|
|
|
|
ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
|
|
|
|
QualType Underlying = readType(*Loc.F, Record, Idx);
|
|
|
|
QualType T;
|
|
|
|
if (Underlying.isNull())
|
|
|
|
T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(),
|
|
|
|
Args.size());
|
|
|
|
else
|
|
|
|
T = Context.getTemplateSpecializationType(Name, Args.data(),
|
|
|
|
Args.size(), Underlying);
|
|
|
|
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TYPE_ATOMIC: {
|
|
|
|
if (Record.size() != 1) {
|
|
|
|
Error("Incorrect encoding of atomic type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType ValueType = readType(*Loc.F, Record, Idx);
|
|
|
|
return Context.getAtomicType(ValueType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm_unreachable("Invalid TypeCode!");
|
|
|
|
}
|
|
|
|
|
2014-03-21 05:47:22 +08:00
|
|
|
void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
|
|
|
|
SmallVectorImpl<QualType> &Exceptions,
|
|
|
|
FunctionProtoType::ExtProtoInfo &EPI,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
ExceptionSpecificationType EST =
|
|
|
|
static_cast<ExceptionSpecificationType>(Record[Idx++]);
|
|
|
|
EPI.ExceptionSpecType = EST;
|
|
|
|
if (EST == EST_Dynamic) {
|
|
|
|
EPI.NumExceptions = Record[Idx++];
|
|
|
|
for (unsigned I = 0; I != EPI.NumExceptions; ++I)
|
|
|
|
Exceptions.push_back(readType(ModuleFile, Record, Idx));
|
|
|
|
EPI.Exceptions = Exceptions.data();
|
|
|
|
} else if (EST == EST_ComputedNoexcept) {
|
|
|
|
EPI.NoexceptExpr = ReadExpr(ModuleFile);
|
|
|
|
} else if (EST == EST_Uninstantiated) {
|
|
|
|
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
|
|
|
|
EPI.ExceptionSpecTemplate =
|
|
|
|
ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
|
|
|
|
} else if (EST == EST_Unevaluated) {
|
|
|
|
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
|
|
|
|
ASTReader &Reader;
|
|
|
|
ModuleFile &F;
|
|
|
|
const ASTReader::RecordData &Record;
|
|
|
|
unsigned &Idx;
|
|
|
|
|
|
|
|
SourceLocation ReadSourceLocation(const ASTReader::RecordData &R,
|
|
|
|
unsigned &I) {
|
|
|
|
return Reader.ReadSourceLocation(F, R, I);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) {
|
|
|
|
return Reader.ReadDeclAs<T>(F, Record, Idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
TypeLocReader(ASTReader &Reader, ModuleFile &F,
|
|
|
|
const ASTReader::RecordData &Record, unsigned &Idx)
|
|
|
|
: Reader(Reader), F(F), Record(Record), Idx(Idx)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
// We want compile-time assurance that we've enumerated all of
|
|
|
|
// these, so unfortunately we have to declare them first, then
|
|
|
|
// define them out-of-line.
|
|
|
|
#define ABSTRACT_TYPELOC(CLASS, PARENT)
|
|
|
|
#define TYPELOC(CLASS, PARENT) \
|
|
|
|
void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
|
|
|
|
#include "clang/AST/TypeLocNodes.def"
|
|
|
|
|
|
|
|
void VisitFunctionTypeLoc(FunctionTypeLoc);
|
|
|
|
void VisitArrayTypeLoc(ArrayTypeLoc);
|
|
|
|
};
|
|
|
|
|
|
|
|
void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
|
|
|
|
TL.setBuiltinLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
if (TL.needsExtraLocalData()) {
|
|
|
|
TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
|
|
|
|
TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
|
|
|
|
TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
|
|
|
|
TL.setModeAttr(Record[Idx++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
2013-06-25 01:51:48 +08:00
|
|
|
void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
2013-12-05 09:23:43 +08:00
|
|
|
void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
|
|
|
TL.setCaretLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
|
|
|
|
TL.setAmpLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
|
|
|
|
TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
|
|
|
|
TL.setLBracketLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRBracketLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
if (Record[Idx++])
|
|
|
|
TL.setSizeExpr(Reader.ReadExpr(F));
|
|
|
|
else
|
|
|
|
TL.setSizeExpr(0);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDependentSizedArrayTypeLoc(
|
|
|
|
DependentSizedArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
|
|
|
|
DependentSizedExtVectorTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
|
|
|
|
TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
|
2014-01-21 08:32:38 +08:00
|
|
|
for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) {
|
|
|
|
TL.setParam(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
|
|
|
|
TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
|
|
|
TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
|
|
|
|
TL.setKWLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
|
|
|
TL.setAttrNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
if (TL.hasAttrOperand()) {
|
|
|
|
SourceRange range;
|
|
|
|
range.setBegin(ReadSourceLocation(Record, Idx));
|
|
|
|
range.setEnd(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setAttrOperandParensRange(range);
|
|
|
|
}
|
|
|
|
if (TL.hasAttrExprOperand()) {
|
|
|
|
if (Record[Idx++])
|
|
|
|
TL.setAttrExprOperand(Reader.ReadExpr(F));
|
|
|
|
else
|
|
|
|
TL.setAttrExprOperand(0);
|
|
|
|
} else if (TL.hasAttrEnumOperand())
|
|
|
|
TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
|
|
|
|
SubstTemplateTypeParmTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
|
|
|
|
SubstTemplateTypeParmPackTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
|
|
|
|
TemplateSpecializationTypeLoc TL) {
|
|
|
|
TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
|
|
|
TL.setArgLocInfo(i,
|
|
|
|
Reader.GetTemplateArgumentLocInfo(F,
|
|
|
|
TL.getTypePtr()->getArg(i).getKind(),
|
|
|
|
Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
|
|
|
TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
|
|
|
|
TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
|
|
|
|
DependentTemplateSpecializationTypeLoc TL) {
|
|
|
|
TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
|
|
|
|
TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
|
|
|
|
TL.setArgLocInfo(I,
|
|
|
|
Reader.GetTemplateArgumentLocInfo(F,
|
|
|
|
TL.getTypePtr()->getArg(I).getKind(),
|
|
|
|
Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
|
|
|
|
TL.setEllipsisLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
|
|
|
|
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
|
|
|
|
TL.setHasBaseTypeAsWritten(Record[Idx++]);
|
|
|
|
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
|
|
|
|
TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
|
|
|
|
TL.setKWLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
QualType InfoTy = readType(F, Record, Idx);
|
|
|
|
if (InfoTy.isNull())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
|
|
|
|
TypeLocReader TLR(*this, F, Record, Idx);
|
|
|
|
for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
|
|
|
|
TLR.Visit(TL);
|
|
|
|
return TInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTReader::GetType(TypeID ID) {
|
|
|
|
unsigned FastQuals = ID & Qualifiers::FastMask;
|
|
|
|
unsigned Index = ID >> Qualifiers::FastWidth;
|
|
|
|
|
|
|
|
if (Index < NUM_PREDEF_TYPE_IDS) {
|
|
|
|
QualType T;
|
|
|
|
switch ((PredefinedTypeIDs)Index) {
|
|
|
|
case PREDEF_TYPE_NULL_ID: return QualType();
|
|
|
|
case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
|
|
|
|
case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_CHAR_U_ID:
|
|
|
|
case PREDEF_TYPE_CHAR_S_ID:
|
|
|
|
// FIXME: Check that the signedness of CharTy is correct!
|
|
|
|
T = Context.CharTy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
|
|
|
|
case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
|
|
|
|
case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
|
|
|
|
case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
|
|
|
|
case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
|
|
|
|
case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
|
|
|
|
case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
|
|
|
|
case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
|
|
|
|
case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
|
|
|
|
case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
|
|
|
|
case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
|
|
|
|
case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
|
|
|
|
case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
|
|
|
|
case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
|
|
|
|
case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
|
|
|
|
case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
|
|
|
|
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
|
|
|
|
case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
|
|
|
|
case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
|
|
|
|
case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
|
|
|
|
case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
|
|
|
|
case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
|
|
|
|
case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
|
|
|
|
case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
|
|
|
|
case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
|
|
|
|
case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
|
|
|
|
case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
|
|
|
|
case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
|
2012-12-18 22:38:23 +08:00
|
|
|
case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
|
|
|
|
case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
|
|
|
|
case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
|
|
|
|
case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
|
|
|
|
case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
|
|
|
|
case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
|
2013-02-07 18:55:47 +08:00
|
|
|
case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break;
|
2013-01-20 20:31:11 +08:00
|
|
|
case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break;
|
2012-12-18 22:30:41 +08:00
|
|
|
case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_AUTO_RREF_DEDUCT:
|
|
|
|
T = Context.getAutoRRefDeductType();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
|
|
|
|
T = Context.ARCUnbridgedCastTy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_VA_LIST_TAG:
|
|
|
|
T = Context.getVaListTagType();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PREDEF_TYPE_BUILTIN_FN:
|
|
|
|
T = Context.BuiltinFnTy;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!T.isNull() && "Unknown predefined type");
|
|
|
|
return T.withFastQualifiers(FastQuals);
|
|
|
|
}
|
|
|
|
|
|
|
|
Index -= NUM_PREDEF_TYPE_IDS;
|
|
|
|
assert(Index < TypesLoaded.size() && "Type index out-of-range");
|
|
|
|
if (TypesLoaded[Index].isNull()) {
|
|
|
|
TypesLoaded[Index] = readTypeRecord(Index);
|
|
|
|
if (TypesLoaded[Index].isNull())
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
TypesLoaded[Index]->setFromAST();
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
|
|
|
|
TypesLoaded[Index]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TypesLoaded[Index].withFastQualifiers(FastQuals);
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) {
|
|
|
|
return GetType(getGlobalTypeID(F, LocalID));
|
|
|
|
}
|
|
|
|
|
|
|
|
serialization::TypeID
|
|
|
|
ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
|
|
|
|
unsigned FastQuals = LocalID & Qualifiers::FastMask;
|
|
|
|
unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
|
|
|
|
|
|
|
|
if (LocalIndex < NUM_PREDEF_TYPE_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
|
|
|
|
assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
|
|
|
|
|
|
|
|
unsigned GlobalIndex = LocalIndex + I->second;
|
|
|
|
return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateArgumentLocInfo
|
|
|
|
ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
|
|
|
|
TemplateArgument::ArgKind Kind,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Index) {
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
return ReadExpr(F);
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
return GetTypeSourceInfo(F, Record, Index);
|
|
|
|
case TemplateArgument::Template: {
|
|
|
|
NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
|
|
|
|
Index);
|
|
|
|
SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
|
|
|
|
return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
|
|
|
|
SourceLocation());
|
|
|
|
}
|
|
|
|
case TemplateArgument::TemplateExpansion: {
|
|
|
|
NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
|
|
|
|
Index);
|
|
|
|
SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
|
|
|
|
SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
|
|
|
|
return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
|
|
|
|
EllipsisLoc);
|
|
|
|
}
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
// FIXME: Is this right?
|
|
|
|
return TemplateArgumentLocInfo();
|
|
|
|
}
|
|
|
|
llvm_unreachable("unexpected template argument loc");
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateArgumentLoc
|
|
|
|
ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Index) {
|
|
|
|
TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
|
|
|
|
|
|
|
|
if (Arg.getKind() == TemplateArgument::Expression) {
|
|
|
|
if (Record[Index++]) // bool InfoHasSameExpr.
|
|
|
|
return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
|
|
|
|
}
|
|
|
|
return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(),
|
|
|
|
Record, Index));
|
|
|
|
}
|
|
|
|
|
2013-08-10 15:24:53 +08:00
|
|
|
const ASTTemplateArgumentListInfo*
|
|
|
|
ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Index) {
|
|
|
|
SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index);
|
|
|
|
SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index);
|
|
|
|
unsigned NumArgsAsWritten = Record[Index++];
|
|
|
|
TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
|
|
|
|
for (unsigned i = 0; i != NumArgsAsWritten; ++i)
|
|
|
|
TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index));
|
|
|
|
return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
Decl *ASTReader::GetExternalDecl(uint32_t ID) {
|
|
|
|
return GetDecl(ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
|
|
|
|
unsigned &Idx){
|
|
|
|
if (Idx >= Record.size())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned LocalID = Record[Idx++];
|
|
|
|
return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
|
|
|
|
RecordLocation Loc = getLocalBitOffset(Offset);
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Cursor = Loc.F->DeclsCursor;
|
2012-12-18 22:30:41 +08:00
|
|
|
SavedStreamPosition SavedPosition(Cursor);
|
|
|
|
Cursor.JumpToBit(Loc.Offset);
|
|
|
|
ReadingKindTracker ReadingKind(Read_Decl, *this);
|
|
|
|
RecordData Record;
|
|
|
|
unsigned Code = Cursor.ReadCode();
|
2013-01-20 10:38:54 +08:00
|
|
|
unsigned RecCode = Cursor.readRecord(Code, Record);
|
2012-12-18 22:30:41 +08:00
|
|
|
if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
|
|
|
|
Error("Malformed AST file: missing C++ base specifiers");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
unsigned NumBases = Record[Idx++];
|
|
|
|
void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
|
|
|
|
CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
|
|
|
|
for (unsigned I = 0; I != NumBases; ++I)
|
|
|
|
Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
|
|
|
|
return Bases;
|
|
|
|
}
|
|
|
|
|
|
|
|
serialization::DeclID
|
|
|
|
ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
|
|
|
|
if (LocalID < NUM_PREDEF_DECL_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
|
|
|
|
assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
|
|
|
|
|
|
|
|
return LocalID + I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
|
|
|
|
ModuleFile &M) const {
|
|
|
|
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
|
|
|
|
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
|
|
|
|
return &M == I->second;
|
|
|
|
}
|
|
|
|
|
2013-01-21 23:25:38 +08:00
|
|
|
ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!D->isFromASTFile())
|
|
|
|
return 0;
|
|
|
|
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
|
|
|
|
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
|
|
|
|
return I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
|
|
|
|
if (ID < NUM_PREDEF_DECL_IDS)
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
|
|
|
|
|
|
|
|
if (Index > DeclsLoaded.size()) {
|
|
|
|
Error("declaration ID out-of-range for AST file");
|
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Decl *D = DeclsLoaded[Index])
|
|
|
|
return D->getLocation();
|
|
|
|
|
|
|
|
unsigned RawLocation = 0;
|
|
|
|
RecordLocation Rec = DeclCursorForID(ID, RawLocation);
|
|
|
|
return ReadSourceLocation(*Rec.F, RawLocation);
|
|
|
|
}
|
|
|
|
|
|
|
|
Decl *ASTReader::GetDecl(DeclID ID) {
|
|
|
|
if (ID < NUM_PREDEF_DECL_IDS) {
|
|
|
|
switch ((PredefinedDeclIDs)ID) {
|
|
|
|
case PREDEF_DECL_NULL_ID:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case PREDEF_DECL_TRANSLATION_UNIT_ID:
|
|
|
|
return Context.getTranslationUnitDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_OBJC_ID_ID:
|
|
|
|
return Context.getObjCIdDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_OBJC_SEL_ID:
|
|
|
|
return Context.getObjCSelDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_OBJC_CLASS_ID:
|
|
|
|
return Context.getObjCClassDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_OBJC_PROTOCOL_ID:
|
|
|
|
return Context.getObjCProtocolDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_INT_128_ID:
|
|
|
|
return Context.getInt128Decl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_UNSIGNED_INT_128_ID:
|
|
|
|
return Context.getUInt128Decl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
|
|
|
|
return Context.getObjCInstanceTypeDecl();
|
|
|
|
|
|
|
|
case PREDEF_DECL_BUILTIN_VA_LIST_ID:
|
|
|
|
return Context.getBuiltinVaListDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
|
|
|
|
|
|
|
|
if (Index >= DeclsLoaded.size()) {
|
|
|
|
assert(0 && "declaration ID out-of-range for AST file");
|
|
|
|
Error("declaration ID out-of-range for AST file");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DeclsLoaded[Index]) {
|
|
|
|
ReadDeclRecord(ID);
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DeclsLoaded[Index];
|
|
|
|
}
|
|
|
|
|
|
|
|
DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
|
|
|
|
DeclID GlobalID) {
|
|
|
|
if (GlobalID < NUM_PREDEF_DECL_IDS)
|
|
|
|
return GlobalID;
|
|
|
|
|
|
|
|
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
|
|
|
|
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
|
|
|
|
ModuleFile *Owner = I->second;
|
|
|
|
|
|
|
|
llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
|
|
|
|
= M.GlobalToLocalDeclIDs.find(Owner);
|
|
|
|
if (Pos == M.GlobalToLocalDeclIDs.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return GlobalID - Owner->BaseDeclID + Pos->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
if (Idx >= Record.size()) {
|
|
|
|
Error("Corrupted AST file");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return getGlobalDeclID(F, Record[Idx++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Resolve the offset of a statement into a statement.
|
|
|
|
///
|
|
|
|
/// This operation will read a new statement from the external
|
|
|
|
/// source each time it is called, and is meant to be used via a
|
|
|
|
/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
|
|
|
|
Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
|
|
|
|
// Switch case IDs are per Decl.
|
|
|
|
ClearSwitchCaseIDs();
|
|
|
|
|
|
|
|
// Offset here is a global offset across the entire chain.
|
|
|
|
RecordLocation Loc = getLocalBitOffset(Offset);
|
|
|
|
Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
|
|
|
|
return ReadStmtFromStream(*Loc.F);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class FindExternalLexicalDeclsVisitor {
|
|
|
|
ASTReader &Reader;
|
|
|
|
const DeclContext *DC;
|
|
|
|
bool (*isKindWeWant)(Decl::Kind);
|
|
|
|
|
|
|
|
SmallVectorImpl<Decl*> &Decls;
|
|
|
|
bool PredefsVisited[NUM_PREDEF_DECL_IDS];
|
|
|
|
|
|
|
|
public:
|
|
|
|
FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
|
|
|
|
bool (*isKindWeWant)(Decl::Kind),
|
|
|
|
SmallVectorImpl<Decl*> &Decls)
|
|
|
|
: Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
|
|
|
|
{
|
|
|
|
for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
|
|
|
|
PredefsVisited[I] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
|
|
|
|
if (Preorder)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
FindExternalLexicalDeclsVisitor *This
|
|
|
|
= static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
|
|
|
|
|
|
|
|
ModuleFile::DeclContextInfosMap::iterator Info
|
|
|
|
= M.DeclContextInfos.find(This->DC);
|
|
|
|
if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Load all of the declaration IDs
|
|
|
|
for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
|
|
|
|
*IDE = ID + Info->second.NumLexicalDecls;
|
|
|
|
ID != IDE; ++ID) {
|
|
|
|
if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't add predefined declarations to the lexical context more
|
|
|
|
// than once.
|
|
|
|
if (ID->second < NUM_PREDEF_DECL_IDS) {
|
|
|
|
if (This->PredefsVisited[ID->second])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
This->PredefsVisited[ID->second] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
|
|
|
|
if (!This->DC->isDeclInLexicalTraversal(D))
|
|
|
|
This->Decls.push_back(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
|
|
|
|
bool (*isKindWeWant)(Decl::Kind),
|
|
|
|
SmallVectorImpl<Decl*> &Decls) {
|
|
|
|
// There might be lexical decls in multiple modules, for the TU at
|
|
|
|
// least. Walk all of the modules in the order they were loaded.
|
|
|
|
FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
|
|
|
|
ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
|
|
|
|
++NumLexicalDeclContextsRead;
|
|
|
|
return ELR_Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class DeclIDComp {
|
|
|
|
ASTReader &Reader;
|
|
|
|
ModuleFile &Mod;
|
|
|
|
|
|
|
|
public:
|
|
|
|
DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
|
|
|
|
|
|
|
|
bool operator()(LocalDeclID L, LocalDeclID R) const {
|
|
|
|
SourceLocation LHS = getLocation(L);
|
|
|
|
SourceLocation RHS = getLocation(R);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(SourceLocation LHS, LocalDeclID R) const {
|
|
|
|
SourceLocation RHS = getLocation(R);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(LocalDeclID L, SourceLocation RHS) const {
|
|
|
|
SourceLocation LHS = getLocation(L);
|
|
|
|
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation getLocation(LocalDeclID ID) const {
|
|
|
|
return Reader.getSourceManager().getFileLoc(
|
|
|
|
Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::FindFileRegionDecls(FileID File,
|
|
|
|
unsigned Offset, unsigned Length,
|
|
|
|
SmallVectorImpl<Decl *> &Decls) {
|
|
|
|
SourceManager &SM = getSourceManager();
|
|
|
|
|
|
|
|
llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File);
|
|
|
|
if (I == FileDeclIDs.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
FileDeclsInfo &DInfo = I->second;
|
|
|
|
if (DInfo.Decls.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
SourceLocation
|
|
|
|
BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
|
|
|
|
SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
|
|
|
|
|
|
|
|
DeclIDComp DIDComp(*this, *DInfo.Mod);
|
|
|
|
ArrayRef<serialization::LocalDeclID>::iterator
|
|
|
|
BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
|
|
|
|
BeginLoc, DIDComp);
|
|
|
|
if (BeginIt != DInfo.Decls.begin())
|
|
|
|
--BeginIt;
|
|
|
|
|
|
|
|
// If we are pointing at a top-level decl inside an objc container, we need
|
|
|
|
// to backtrack until we find it otherwise we will fail to report that the
|
|
|
|
// region overlaps with an objc container.
|
|
|
|
while (BeginIt != DInfo.Decls.begin() &&
|
|
|
|
GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
|
|
|
|
->isTopLevelDeclInObjCContainer())
|
|
|
|
--BeginIt;
|
|
|
|
|
|
|
|
ArrayRef<serialization::LocalDeclID>::iterator
|
|
|
|
EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
|
|
|
|
EndLoc, DIDComp);
|
|
|
|
if (EndIt != DInfo.Decls.end())
|
|
|
|
++EndIt;
|
|
|
|
|
|
|
|
for (ArrayRef<serialization::LocalDeclID>::iterator
|
|
|
|
DIt = BeginIt; DIt != EndIt; ++DIt)
|
|
|
|
Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief ModuleFile visitor used to perform name lookup into a
|
|
|
|
/// declaration context.
|
|
|
|
class DeclContextNameLookupVisitor {
|
|
|
|
ASTReader &Reader;
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVectorImpl<const DeclContext *> &Contexts;
|
2012-12-18 22:30:41 +08:00
|
|
|
DeclarationName Name;
|
|
|
|
SmallVectorImpl<NamedDecl *> &Decls;
|
|
|
|
|
|
|
|
public:
|
|
|
|
DeclContextNameLookupVisitor(ASTReader &Reader,
|
|
|
|
SmallVectorImpl<const DeclContext *> &Contexts,
|
|
|
|
DeclarationName Name,
|
|
|
|
SmallVectorImpl<NamedDecl *> &Decls)
|
|
|
|
: Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
|
|
|
|
|
|
|
|
static bool visit(ModuleFile &M, void *UserData) {
|
|
|
|
DeclContextNameLookupVisitor *This
|
|
|
|
= static_cast<DeclContextNameLookupVisitor *>(UserData);
|
|
|
|
|
|
|
|
// Check whether we have any visible declaration information for
|
|
|
|
// this context in this module.
|
|
|
|
ModuleFile::DeclContextInfosMap::iterator Info;
|
|
|
|
bool FoundInfo = false;
|
|
|
|
for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
|
|
|
|
Info = M.DeclContextInfos.find(This->Contexts[I]);
|
|
|
|
if (Info != M.DeclContextInfos.end() &&
|
|
|
|
Info->second.NameLookupTableData) {
|
|
|
|
FoundInfo = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!FoundInfo)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Look for this name within this module.
|
2014-03-11 15:17:35 +08:00
|
|
|
ASTDeclContextNameLookupTable *LookupTable =
|
2012-12-18 22:30:41 +08:00
|
|
|
Info->second.NameLookupTableData;
|
|
|
|
ASTDeclContextNameLookupTable::iterator Pos
|
|
|
|
= LookupTable->find(This->Name);
|
|
|
|
if (Pos == LookupTable->end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool FoundAnything = false;
|
|
|
|
ASTDeclContextNameLookupTrait::data_type Data = *Pos;
|
|
|
|
for (; Data.first != Data.second; ++Data.first) {
|
|
|
|
NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
|
|
|
|
if (!ND)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ND->getDeclName() != This->Name) {
|
|
|
|
// A name might be null because the decl's redeclarable part is
|
|
|
|
// currently read before reading its name. The lookup is triggered by
|
|
|
|
// building that decl (likely indirectly), and so it is later in the
|
|
|
|
// sense of "already existing" and can be ignored here.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Record this declaration.
|
|
|
|
FoundAnything = true;
|
|
|
|
This->Decls.push_back(ND);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FoundAnything;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-01-21 23:25:38 +08:00
|
|
|
/// \brief Retrieve the "definitive" module file for the definition of the
|
|
|
|
/// given declaration context, if there is one.
|
|
|
|
///
|
|
|
|
/// The "definitive" module file is the only place where we need to look to
|
|
|
|
/// find information about the declarations within the given declaration
|
|
|
|
/// context. For example, C++ and Objective-C classes, C structs/unions, and
|
|
|
|
/// Objective-C protocols, categories, and extensions are all defined in a
|
|
|
|
/// single place in the source code, so they have definitive module files
|
|
|
|
/// associated with them. C++ namespaces, on the other hand, can have
|
|
|
|
/// definitions in multiple different module files.
|
|
|
|
///
|
|
|
|
/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
|
|
|
|
/// NDEBUG checking.
|
|
|
|
static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
|
|
|
|
ASTReader &Reader) {
|
2013-01-23 01:08:30 +08:00
|
|
|
if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
|
|
|
|
return Reader.getOwningModuleFile(cast<Decl>(DefDC));
|
2013-01-21 23:25:38 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-07 11:30:24 +08:00
|
|
|
bool
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
|
|
|
|
DeclarationName Name) {
|
|
|
|
assert(DC->hasExternalVisibleStorage() &&
|
|
|
|
"DeclContext has no visible decls in storage");
|
|
|
|
if (!Name)
|
2013-02-07 11:30:24 +08:00
|
|
|
return false;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
SmallVector<NamedDecl *, 64> Decls;
|
|
|
|
|
|
|
|
// Compute the declaration contexts we need to look into. Multiple such
|
|
|
|
// declaration contexts occur when two declaration contexts from disjoint
|
|
|
|
// modules get merged, e.g., when two namespaces with the same name are
|
|
|
|
// independently defined in separate modules.
|
|
|
|
SmallVector<const DeclContext *, 2> Contexts;
|
|
|
|
Contexts.push_back(DC);
|
|
|
|
|
|
|
|
if (DC->isNamespace()) {
|
|
|
|
MergedDeclsMap::iterator Merged
|
|
|
|
= MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
|
|
|
|
if (Merged != MergedDecls.end()) {
|
|
|
|
for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
|
|
|
|
Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
|
2013-01-21 23:25:38 +08:00
|
|
|
|
|
|
|
// If we can definitively determine which module file to look into,
|
|
|
|
// only look there. Otherwise, look in all module files.
|
|
|
|
ModuleFile *Definitive;
|
|
|
|
if (Contexts.size() == 1 &&
|
|
|
|
(Definitive = getDefinitiveModuleFileFor(DC, *this))) {
|
|
|
|
DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
|
|
|
|
} else {
|
|
|
|
ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
++NumVisibleDeclContextsRead;
|
|
|
|
SetExternalVisibleDeclsForName(DC, Name, Decls);
|
2013-02-07 11:30:24 +08:00
|
|
|
return !Decls.empty();
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief ModuleFile visitor used to retrieve all visible names in a
|
|
|
|
/// declaration context.
|
|
|
|
class DeclContextAllNamesVisitor {
|
|
|
|
ASTReader &Reader;
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVectorImpl<const DeclContext *> &Contexts;
|
2013-07-05 12:43:31 +08:00
|
|
|
DeclsMap &Decls;
|
2012-12-20 06:21:18 +08:00
|
|
|
bool VisitAll;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
DeclContextAllNamesVisitor(ASTReader &Reader,
|
|
|
|
SmallVectorImpl<const DeclContext *> &Contexts,
|
2013-07-05 12:43:31 +08:00
|
|
|
DeclsMap &Decls, bool VisitAll)
|
2012-12-20 06:21:18 +08:00
|
|
|
: Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
static bool visit(ModuleFile &M, void *UserData) {
|
|
|
|
DeclContextAllNamesVisitor *This
|
|
|
|
= static_cast<DeclContextAllNamesVisitor *>(UserData);
|
|
|
|
|
|
|
|
// Check whether we have any visible declaration information for
|
|
|
|
// this context in this module.
|
|
|
|
ModuleFile::DeclContextInfosMap::iterator Info;
|
|
|
|
bool FoundInfo = false;
|
|
|
|
for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
|
|
|
|
Info = M.DeclContextInfos.find(This->Contexts[I]);
|
|
|
|
if (Info != M.DeclContextInfos.end() &&
|
|
|
|
Info->second.NameLookupTableData) {
|
|
|
|
FoundInfo = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!FoundInfo)
|
|
|
|
return false;
|
|
|
|
|
2014-03-11 15:17:35 +08:00
|
|
|
ASTDeclContextNameLookupTable *LookupTable =
|
2012-12-18 22:30:41 +08:00
|
|
|
Info->second.NameLookupTableData;
|
|
|
|
bool FoundAnything = false;
|
|
|
|
for (ASTDeclContextNameLookupTable::data_iterator
|
2013-01-24 06:38:11 +08:00
|
|
|
I = LookupTable->data_begin(), E = LookupTable->data_end();
|
|
|
|
I != E;
|
|
|
|
++I) {
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTDeclContextNameLookupTrait::data_type Data = *I;
|
|
|
|
for (; Data.first != Data.second; ++Data.first) {
|
|
|
|
NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
|
|
|
|
*Data.first);
|
|
|
|
if (!ND)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Record this declaration.
|
|
|
|
FoundAnything = true;
|
|
|
|
This->Decls[ND->getDeclName()].push_back(ND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-20 06:21:18 +08:00
|
|
|
return FoundAnything && !This->VisitAll;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
|
|
|
|
if (!DC->hasExternalVisibleStorage())
|
|
|
|
return;
|
2013-07-05 12:33:53 +08:00
|
|
|
DeclsMap Decls;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
// Compute the declaration contexts we need to look into. Multiple such
|
|
|
|
// declaration contexts occur when two declaration contexts from disjoint
|
|
|
|
// modules get merged, e.g., when two namespaces with the same name are
|
|
|
|
// independently defined in separate modules.
|
|
|
|
SmallVector<const DeclContext *, 2> Contexts;
|
|
|
|
Contexts.push_back(DC);
|
|
|
|
|
|
|
|
if (DC->isNamespace()) {
|
|
|
|
MergedDeclsMap::iterator Merged
|
|
|
|
= MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
|
|
|
|
if (Merged != MergedDecls.end()) {
|
|
|
|
for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
|
|
|
|
Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-20 06:21:18 +08:00
|
|
|
DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
|
|
|
|
/*VisitAll=*/DC->isFileContext());
|
2012-12-18 22:30:41 +08:00
|
|
|
ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
|
|
|
|
++NumVisibleDeclContextsRead;
|
|
|
|
|
2013-07-05 12:33:53 +08:00
|
|
|
for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
|
2012-12-18 22:30:41 +08:00
|
|
|
SetExternalVisibleDeclsForName(DC, I->first, I->second);
|
|
|
|
}
|
|
|
|
const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Under non-PCH compilation the consumer receives the objc methods
|
|
|
|
/// before receiving the implementation, and codegen depends on this.
|
|
|
|
/// We simulate this by deserializing and passing to consumer the methods of the
|
|
|
|
/// implementation before passing the deserialized implementation decl.
|
|
|
|
static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
|
|
|
|
ASTConsumer *Consumer) {
|
|
|
|
assert(ImplD && Consumer);
|
|
|
|
|
2014-03-14 03:03:34 +08:00
|
|
|
for (auto *I : ImplD->methods())
|
|
|
|
Consumer->HandleInterestingDecl(DeclGroupRef(I));
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::PassInterestingDeclsToConsumer() {
|
|
|
|
assert(Consumer);
|
|
|
|
while (!InterestingDecls.empty()) {
|
|
|
|
Decl *D = InterestingDecls.front();
|
|
|
|
InterestingDecls.pop_front();
|
|
|
|
|
|
|
|
PassInterestingDeclToConsumer(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
|
|
|
|
if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
|
|
|
|
PassObjCImplDeclToConsumer(ImplD, Consumer);
|
|
|
|
else
|
|
|
|
Consumer->HandleInterestingDecl(DeclGroupRef(D));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
|
|
|
|
this->Consumer = Consumer;
|
|
|
|
|
|
|
|
if (!Consumer)
|
|
|
|
return;
|
|
|
|
|
2014-01-31 09:06:56 +08:00
|
|
|
for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
|
2012-12-18 22:30:41 +08:00
|
|
|
// Force deserialization of this decl, which will cause it to be queued for
|
|
|
|
// passing to the consumer.
|
2014-01-31 09:06:56 +08:00
|
|
|
GetDecl(EagerlyDeserializedDecls[I]);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
2014-01-31 09:06:56 +08:00
|
|
|
EagerlyDeserializedDecls.clear();
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
PassInterestingDeclsToConsumer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::PrintStats() {
|
|
|
|
std::fprintf(stderr, "*** AST File Statistics:\n");
|
|
|
|
|
|
|
|
unsigned NumTypesLoaded
|
|
|
|
= TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
|
|
|
|
QualType());
|
|
|
|
unsigned NumDeclsLoaded
|
|
|
|
= DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
|
|
|
|
(Decl *)0);
|
|
|
|
unsigned NumIdentifiersLoaded
|
|
|
|
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
|
|
|
|
IdentifiersLoaded.end(),
|
|
|
|
(IdentifierInfo *)0);
|
|
|
|
unsigned NumMacrosLoaded
|
|
|
|
= MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
|
|
|
|
MacrosLoaded.end(),
|
2013-03-23 05:12:57 +08:00
|
|
|
(MacroInfo *)0);
|
2012-12-18 22:30:41 +08:00
|
|
|
unsigned NumSelectorsLoaded
|
|
|
|
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
|
|
|
|
SelectorsLoaded.end(),
|
|
|
|
Selector());
|
|
|
|
|
|
|
|
if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
|
|
|
|
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
|
|
|
|
NumSLocEntriesRead, TotalNumSLocEntries,
|
|
|
|
((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
|
|
|
|
if (!TypesLoaded.empty())
|
|
|
|
std::fprintf(stderr, " %u/%u types read (%f%%)\n",
|
|
|
|
NumTypesLoaded, (unsigned)TypesLoaded.size(),
|
|
|
|
((float)NumTypesLoaded/TypesLoaded.size() * 100));
|
|
|
|
if (!DeclsLoaded.empty())
|
|
|
|
std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
|
|
|
|
NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
|
|
|
|
((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
|
|
|
|
if (!IdentifiersLoaded.empty())
|
|
|
|
std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
|
|
|
|
NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
|
|
|
|
((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
|
|
|
|
if (!MacrosLoaded.empty())
|
|
|
|
std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
|
|
|
|
NumMacrosLoaded, (unsigned)MacrosLoaded.size(),
|
|
|
|
((float)NumMacrosLoaded/MacrosLoaded.size() * 100));
|
|
|
|
if (!SelectorsLoaded.empty())
|
|
|
|
std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
|
|
|
|
NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(),
|
|
|
|
((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100));
|
|
|
|
if (TotalNumStatements)
|
|
|
|
std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
|
|
|
|
NumStatementsRead, TotalNumStatements,
|
|
|
|
((float)NumStatementsRead/TotalNumStatements * 100));
|
|
|
|
if (TotalNumMacros)
|
|
|
|
std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
|
|
|
|
NumMacrosRead, TotalNumMacros,
|
|
|
|
((float)NumMacrosRead/TotalNumMacros * 100));
|
|
|
|
if (TotalLexicalDeclContexts)
|
|
|
|
std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
|
|
|
|
NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
|
|
|
|
((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
|
|
|
|
* 100));
|
|
|
|
if (TotalVisibleDeclContexts)
|
|
|
|
std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
|
|
|
|
NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
|
|
|
|
((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
|
|
|
|
* 100));
|
|
|
|
if (TotalNumMethodPoolEntries) {
|
|
|
|
std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
|
|
|
|
NumMethodPoolEntriesRead, TotalNumMethodPoolEntries,
|
|
|
|
((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries
|
|
|
|
* 100));
|
|
|
|
}
|
2013-01-29 01:54:36 +08:00
|
|
|
if (NumMethodPoolLookups) {
|
|
|
|
std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n",
|
|
|
|
NumMethodPoolHits, NumMethodPoolLookups,
|
|
|
|
((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0));
|
|
|
|
}
|
|
|
|
if (NumMethodPoolTableLookups) {
|
|
|
|
std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n",
|
|
|
|
NumMethodPoolTableHits, NumMethodPoolTableLookups,
|
|
|
|
((float)NumMethodPoolTableHits/NumMethodPoolTableLookups
|
|
|
|
* 100.0));
|
|
|
|
}
|
|
|
|
|
2013-01-25 08:38:33 +08:00
|
|
|
if (NumIdentifierLookupHits) {
|
|
|
|
std::fprintf(stderr,
|
|
|
|
" %u / %u identifier table lookups succeeded (%f%%)\n",
|
|
|
|
NumIdentifierLookupHits, NumIdentifierLookups,
|
|
|
|
(double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
|
|
|
|
}
|
|
|
|
|
2013-01-25 09:03:03 +08:00
|
|
|
if (GlobalIndex) {
|
|
|
|
std::fprintf(stderr, "\n");
|
|
|
|
GlobalIndex->printStats();
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
std::fprintf(stderr, "\n");
|
|
|
|
dump();
|
|
|
|
std::fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Key, typename ModuleFile, unsigned InitialCapacity>
|
|
|
|
static void
|
|
|
|
dumpModuleIDMap(StringRef Name,
|
|
|
|
const ContinuousRangeMap<Key, ModuleFile *,
|
|
|
|
InitialCapacity> &Map) {
|
|
|
|
if (Map.begin() == Map.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType;
|
|
|
|
llvm::errs() << Name << ":\n";
|
|
|
|
for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
|
|
|
|
I != IEnd; ++I) {
|
|
|
|
llvm::errs() << " " << I->first << " -> " << I->second->FileName
|
|
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::dump() {
|
|
|
|
llvm::errs() << "*** PCH/ModuleFile Remappings:\n";
|
|
|
|
dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
|
|
|
|
dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
|
|
|
|
dumpModuleIDMap("Global type map", GlobalTypeMap);
|
|
|
|
dumpModuleIDMap("Global declaration map", GlobalDeclMap);
|
|
|
|
dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
|
|
|
|
dumpModuleIDMap("Global macro map", GlobalMacroMap);
|
|
|
|
dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
|
|
|
|
dumpModuleIDMap("Global selector map", GlobalSelectorMap);
|
|
|
|
dumpModuleIDMap("Global preprocessed entity map",
|
|
|
|
GlobalPreprocessedEntityMap);
|
|
|
|
|
|
|
|
llvm::errs() << "\n*** PCH/Modules Loaded:";
|
|
|
|
for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
|
|
|
|
MEnd = ModuleMgr.end();
|
|
|
|
M != MEnd; ++M)
|
|
|
|
(*M)->dump();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the amount of memory used by memory buffers, breaking down
|
|
|
|
/// by heap-backed versus mmap'ed memory.
|
|
|
|
void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
|
|
|
|
for (ModuleConstIterator I = ModuleMgr.begin(),
|
|
|
|
E = ModuleMgr.end(); I != E; ++I) {
|
|
|
|
if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
|
|
|
|
size_t bytes = buf->getBufferSize();
|
|
|
|
switch (buf->getBufferKind()) {
|
|
|
|
case llvm::MemoryBuffer::MemoryBuffer_Malloc:
|
|
|
|
sizes.malloc_bytes += bytes;
|
|
|
|
break;
|
|
|
|
case llvm::MemoryBuffer::MemoryBuffer_MMap:
|
|
|
|
sizes.mmap_bytes += bytes;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::InitializeSema(Sema &S) {
|
|
|
|
SemaObj = &S;
|
|
|
|
S.addExternalSource(this);
|
|
|
|
|
|
|
|
// Makes sure any declarations that were deserialized "too early"
|
|
|
|
// still get added to the identifier's declaration chains.
|
|
|
|
for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
|
2013-04-27 05:33:35 +08:00
|
|
|
pushExternalDeclIntoScope(PreloadedDecls[I],
|
|
|
|
PreloadedDecls[I]->getDeclName());
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
PreloadedDecls.clear();
|
|
|
|
|
2013-10-18 14:54:39 +08:00
|
|
|
// FIXME: What happens if these are changed by a module import?
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!FPPragmaOptions.empty()) {
|
|
|
|
assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
|
|
|
|
SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
|
|
|
|
}
|
|
|
|
|
2013-10-18 14:54:39 +08:00
|
|
|
// FIXME: What happens if these are changed by a module import?
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!OpenCLExtensions.empty()) {
|
|
|
|
unsigned I = 0;
|
|
|
|
#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++];
|
|
|
|
#include "clang/Basic/OpenCLExtensions.def"
|
|
|
|
|
|
|
|
assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS");
|
|
|
|
}
|
2013-10-18 14:54:39 +08:00
|
|
|
|
|
|
|
UpdateSema();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::UpdateSema() {
|
|
|
|
assert(SemaObj && "no Sema to update");
|
|
|
|
|
|
|
|
// Load the offsets of the declarations that Sema references.
|
|
|
|
// They will be lazily deserialized when needed.
|
|
|
|
if (!SemaDeclRefs.empty()) {
|
|
|
|
assert(SemaDeclRefs.size() % 2 == 0);
|
|
|
|
for (unsigned I = 0; I != SemaDeclRefs.size(); I += 2) {
|
|
|
|
if (!SemaObj->StdNamespace)
|
|
|
|
SemaObj->StdNamespace = SemaDeclRefs[I];
|
|
|
|
if (!SemaObj->StdBadAlloc)
|
|
|
|
SemaObj->StdBadAlloc = SemaDeclRefs[I+1];
|
|
|
|
}
|
|
|
|
SemaDeclRefs.clear();
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
|
|
|
|
// Note that we are loading an identifier.
|
|
|
|
Deserializing AnIdentifier(this);
|
2013-01-25 09:03:03 +08:00
|
|
|
StringRef Name(NameStart, NameEnd - NameStart);
|
|
|
|
|
|
|
|
// If there is a global index, look there first to determine which modules
|
|
|
|
// provably do not have any results for this identifier.
|
2013-01-26 07:32:03 +08:00
|
|
|
GlobalModuleIndex::HitSet Hits;
|
|
|
|
GlobalModuleIndex::HitSet *HitsPtr = 0;
|
2013-01-25 09:03:03 +08:00
|
|
|
if (!loadGlobalIndex()) {
|
2013-01-26 07:32:03 +08:00
|
|
|
if (GlobalIndex->lookupIdentifier(Name, Hits)) {
|
|
|
|
HitsPtr = &Hits;
|
2013-01-25 09:03:03 +08:00
|
|
|
}
|
|
|
|
}
|
2013-01-26 07:32:03 +08:00
|
|
|
IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0,
|
2013-01-25 08:38:33 +08:00
|
|
|
NumIdentifierLookups,
|
|
|
|
NumIdentifierLookupHits);
|
2013-01-26 07:32:03 +08:00
|
|
|
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
|
2012-12-18 22:30:41 +08:00
|
|
|
IdentifierInfo *II = Visitor.getIdentifierInfo();
|
|
|
|
markIdentifierUpToDate(II);
|
|
|
|
return II;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
/// \brief An identifier-lookup iterator that enumerates all of the
|
|
|
|
/// identifiers stored within a set of AST files.
|
|
|
|
class ASTIdentifierIterator : public IdentifierIterator {
|
|
|
|
/// \brief The AST reader whose identifiers are being enumerated.
|
|
|
|
const ASTReader &Reader;
|
|
|
|
|
|
|
|
/// \brief The current index into the chain of AST files stored in
|
|
|
|
/// the AST reader.
|
|
|
|
unsigned Index;
|
|
|
|
|
|
|
|
/// \brief The current position within the identifier lookup table
|
|
|
|
/// of the current AST file.
|
|
|
|
ASTIdentifierLookupTable::key_iterator Current;
|
|
|
|
|
|
|
|
/// \brief The end position within the identifier lookup table of
|
|
|
|
/// the current AST file.
|
|
|
|
ASTIdentifierLookupTable::key_iterator End;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit ASTIdentifierIterator(const ASTReader &Reader);
|
|
|
|
|
2014-03-13 10:13:41 +08:00
|
|
|
StringRef Next() override;
|
2012-12-18 22:30:41 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader)
|
|
|
|
: Reader(Reader), Index(Reader.ModuleMgr.size() - 1) {
|
|
|
|
ASTIdentifierLookupTable *IdTable
|
|
|
|
= (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable;
|
|
|
|
Current = IdTable->key_begin();
|
|
|
|
End = IdTable->key_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ASTIdentifierIterator::Next() {
|
|
|
|
while (Current == End) {
|
|
|
|
// If we have exhausted all of our AST files, we're done.
|
|
|
|
if (Index == 0)
|
|
|
|
return StringRef();
|
|
|
|
|
|
|
|
--Index;
|
|
|
|
ASTIdentifierLookupTable *IdTable
|
|
|
|
= (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].
|
|
|
|
IdentifierLookupTable;
|
|
|
|
Current = IdTable->key_begin();
|
|
|
|
End = IdTable->key_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have any identifiers remaining in the current AST file; return
|
|
|
|
// the next one.
|
2013-01-24 02:53:14 +08:00
|
|
|
StringRef Result = *Current;
|
2012-12-18 22:30:41 +08:00
|
|
|
++Current;
|
2013-01-24 02:53:14 +08:00
|
|
|
return Result;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2013-04-18 06:10:55 +08:00
|
|
|
IdentifierIterator *ASTReader::getIdentifiers() {
|
|
|
|
if (!loadGlobalIndex())
|
|
|
|
return GlobalIndex->createIdentifierIterator();
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
return new ASTIdentifierIterator(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace clang { namespace serialization {
|
|
|
|
class ReadMethodPoolVisitor {
|
|
|
|
ASTReader &Reader;
|
|
|
|
Selector Sel;
|
|
|
|
unsigned PriorGeneration;
|
2013-04-17 08:08:58 +08:00
|
|
|
unsigned InstanceBits;
|
|
|
|
unsigned FactoryBits;
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
|
|
|
|
SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
|
|
|
|
unsigned PriorGeneration)
|
2013-04-17 08:08:58 +08:00
|
|
|
: Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration),
|
|
|
|
InstanceBits(0), FactoryBits(0) { }
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
static bool visit(ModuleFile &M, void *UserData) {
|
|
|
|
ReadMethodPoolVisitor *This
|
|
|
|
= static_cast<ReadMethodPoolVisitor *>(UserData);
|
|
|
|
|
|
|
|
if (!M.SelectorLookupTable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If we've already searched this module file, skip it now.
|
|
|
|
if (M.Generation <= This->PriorGeneration)
|
|
|
|
return true;
|
|
|
|
|
2013-01-29 01:54:36 +08:00
|
|
|
++This->Reader.NumMethodPoolTableLookups;
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTSelectorLookupTable *PoolTable
|
|
|
|
= (ASTSelectorLookupTable*)M.SelectorLookupTable;
|
|
|
|
ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
|
|
|
|
if (Pos == PoolTable->end())
|
|
|
|
return false;
|
2013-01-29 01:54:36 +08:00
|
|
|
|
|
|
|
++This->Reader.NumMethodPoolTableHits;
|
2012-12-18 22:30:41 +08:00
|
|
|
++This->Reader.NumSelectorsRead;
|
|
|
|
// FIXME: Not quite happy with the statistics here. We probably should
|
|
|
|
// disable this tracking when called via LoadSelector.
|
|
|
|
// Also, should entries without methods count as misses?
|
|
|
|
++This->Reader.NumMethodPoolEntriesRead;
|
|
|
|
ASTSelectorLookupTrait::data_type Data = *Pos;
|
|
|
|
if (This->Reader.DeserializationListener)
|
|
|
|
This->Reader.DeserializationListener->SelectorRead(Data.ID,
|
|
|
|
This->Sel);
|
|
|
|
|
|
|
|
This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
|
|
|
|
This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
|
2013-04-17 08:08:58 +08:00
|
|
|
This->InstanceBits = Data.InstanceBits;
|
|
|
|
This->FactoryBits = Data.FactoryBits;
|
2012-12-18 22:30:41 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the instance methods found by this visitor.
|
|
|
|
ArrayRef<ObjCMethodDecl *> getInstanceMethods() const {
|
|
|
|
return InstanceMethods;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the instance methods found by this visitor.
|
|
|
|
ArrayRef<ObjCMethodDecl *> getFactoryMethods() const {
|
|
|
|
return FactoryMethods;
|
|
|
|
}
|
2013-04-17 08:08:58 +08:00
|
|
|
|
|
|
|
unsigned getInstanceBits() const { return InstanceBits; }
|
|
|
|
unsigned getFactoryBits() const { return FactoryBits; }
|
2012-12-18 22:30:41 +08:00
|
|
|
};
|
|
|
|
} } // end namespace clang::serialization
|
|
|
|
|
|
|
|
/// \brief Add the given set of methods to the method list.
|
|
|
|
static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
|
|
|
|
ObjCMethodList &List) {
|
|
|
|
for (unsigned I = 0, N = Methods.size(); I != N; ++I) {
|
|
|
|
S.addMethodToGlobalList(&List, Methods[I]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadMethodPool(Selector Sel) {
|
|
|
|
// Get the selector generation and update it to the current generation.
|
|
|
|
unsigned &Generation = SelectorGeneration[Sel];
|
|
|
|
unsigned PriorGeneration = Generation;
|
|
|
|
Generation = CurrentGeneration;
|
|
|
|
|
|
|
|
// Search for methods defined with this selector.
|
2013-01-29 01:54:36 +08:00
|
|
|
++NumMethodPoolLookups;
|
2012-12-18 22:30:41 +08:00
|
|
|
ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
|
|
|
|
ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
|
|
|
|
|
|
|
|
if (Visitor.getInstanceMethods().empty() &&
|
2013-01-29 01:54:36 +08:00
|
|
|
Visitor.getFactoryMethods().empty())
|
2012-12-18 22:30:41 +08:00
|
|
|
return;
|
2013-01-29 01:54:36 +08:00
|
|
|
|
|
|
|
++NumMethodPoolHits;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
if (!getSema())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Sema &S = *getSema();
|
|
|
|
Sema::GlobalMethodPool::iterator Pos
|
|
|
|
= S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
|
|
|
|
|
|
|
|
addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
|
|
|
|
addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
|
2013-04-17 08:08:58 +08:00
|
|
|
Pos->second.first.setBits(Visitor.getInstanceBits());
|
|
|
|
Pos->second.second.setBits(Visitor.getFactoryBits());
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadKnownNamespaces(
|
|
|
|
SmallVectorImpl<NamespaceDecl *> &Namespaces) {
|
|
|
|
Namespaces.clear();
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
|
|
|
|
if (NamespaceDecl *Namespace
|
|
|
|
= dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I])))
|
|
|
|
Namespaces.push_back(Namespace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-01 16:13:20 +08:00
|
|
|
void ASTReader::ReadUndefinedButUsed(
|
2013-01-31 11:23:57 +08:00
|
|
|
llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) {
|
2013-02-01 16:13:20 +08:00
|
|
|
for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) {
|
|
|
|
NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++]));
|
2013-01-26 08:35:08 +08:00
|
|
|
SourceLocation Loc =
|
2013-02-01 16:13:20 +08:00
|
|
|
SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]);
|
2013-01-26 08:35:08 +08:00
|
|
|
Undefined.insert(std::make_pair(D, Loc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
void ASTReader::ReadTentativeDefinitions(
|
|
|
|
SmallVectorImpl<VarDecl *> &TentativeDefs) {
|
|
|
|
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
|
|
|
|
VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I]));
|
|
|
|
if (Var)
|
|
|
|
TentativeDefs.push_back(Var);
|
|
|
|
}
|
|
|
|
TentativeDefinitions.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadUnusedFileScopedDecls(
|
|
|
|
SmallVectorImpl<const DeclaratorDecl *> &Decls) {
|
|
|
|
for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
|
|
|
|
DeclaratorDecl *D
|
|
|
|
= dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
|
|
|
|
if (D)
|
|
|
|
Decls.push_back(D);
|
|
|
|
}
|
|
|
|
UnusedFileScopedDecls.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadDelegatingConstructors(
|
|
|
|
SmallVectorImpl<CXXConstructorDecl *> &Decls) {
|
|
|
|
for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
|
|
|
|
CXXConstructorDecl *D
|
|
|
|
= dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
|
|
|
|
if (D)
|
|
|
|
Decls.push_back(D);
|
|
|
|
}
|
|
|
|
DelegatingCtorDecls.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {
|
|
|
|
for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) {
|
|
|
|
TypedefNameDecl *D
|
|
|
|
= dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]));
|
|
|
|
if (D)
|
|
|
|
Decls.push_back(D);
|
|
|
|
}
|
|
|
|
ExtVectorDecls.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
|
|
|
|
for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
|
|
|
|
CXXRecordDecl *D
|
|
|
|
= dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I]));
|
|
|
|
if (D)
|
|
|
|
Decls.push_back(D);
|
|
|
|
}
|
|
|
|
DynamicClasses.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-01-11 07:43:47 +08:00
|
|
|
ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) {
|
|
|
|
for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) {
|
|
|
|
NamedDecl *D
|
|
|
|
= dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternCDecls[I]));
|
2012-12-18 22:30:41 +08:00
|
|
|
if (D)
|
|
|
|
Decls.push_back(D);
|
|
|
|
}
|
2013-01-11 07:43:47 +08:00
|
|
|
LocallyScopedExternCDecls.clear();
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadReferencedSelectors(
|
|
|
|
SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
|
|
|
|
if (ReferencedSelectorsData.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If there are @selector references added them to its pool. This is for
|
|
|
|
// implementation of -Wselector.
|
|
|
|
unsigned int DataSize = ReferencedSelectorsData.size()-1;
|
|
|
|
unsigned I = 0;
|
|
|
|
while (I < DataSize) {
|
|
|
|
Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]);
|
|
|
|
SourceLocation SelLoc
|
|
|
|
= SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]);
|
|
|
|
Sels.push_back(std::make_pair(Sel, SelLoc));
|
|
|
|
}
|
|
|
|
ReferencedSelectorsData.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadWeakUndeclaredIdentifiers(
|
|
|
|
SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) {
|
|
|
|
if (WeakUndeclaredIdentifiers.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) {
|
|
|
|
IdentifierInfo *WeakId
|
|
|
|
= DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
|
|
|
|
IdentifierInfo *AliasId
|
|
|
|
= DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
|
|
|
|
SourceLocation Loc
|
|
|
|
= SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
|
|
|
|
bool Used = WeakUndeclaredIdentifiers[I++];
|
|
|
|
WeakInfo WI(AliasId, Loc);
|
|
|
|
WI.setUsed(Used);
|
|
|
|
WeakIDs.push_back(std::make_pair(WeakId, WI));
|
|
|
|
}
|
|
|
|
WeakUndeclaredIdentifiers.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {
|
|
|
|
for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) {
|
|
|
|
ExternalVTableUse VT;
|
|
|
|
VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
|
|
|
|
VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]);
|
|
|
|
VT.DefinitionRequired = VTableUses[Idx++];
|
|
|
|
VTables.push_back(VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
VTableUses.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadPendingInstantiations(
|
|
|
|
SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) {
|
|
|
|
for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) {
|
|
|
|
ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
|
|
|
|
SourceLocation Loc
|
|
|
|
= SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
|
|
|
|
|
|
|
|
Pending.push_back(std::make_pair(D, Loc));
|
|
|
|
}
|
|
|
|
PendingInstantiations.clear();
|
|
|
|
}
|
|
|
|
|
2013-08-08 05:41:30 +08:00
|
|
|
void ASTReader::ReadLateParsedTemplates(
|
|
|
|
llvm::DenseMap<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
|
|
|
|
for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N;
|
|
|
|
/* In loop */) {
|
|
|
|
FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++]));
|
|
|
|
|
|
|
|
LateParsedTemplate *LT = new LateParsedTemplate;
|
|
|
|
LT->D = GetDecl(LateParsedTemplates[Idx++]);
|
|
|
|
|
|
|
|
ModuleFile *F = getOwningModuleFile(LT->D);
|
|
|
|
assert(F && "No module");
|
|
|
|
|
|
|
|
unsigned TokN = LateParsedTemplates[Idx++];
|
|
|
|
LT->Toks.reserve(TokN);
|
|
|
|
for (unsigned T = 0; T < TokN; ++T)
|
|
|
|
LT->Toks.push_back(ReadToken(*F, LateParsedTemplates, Idx));
|
|
|
|
|
|
|
|
LPTMap[FD] = LT;
|
|
|
|
}
|
|
|
|
|
|
|
|
LateParsedTemplates.clear();
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
void ASTReader::LoadSelector(Selector Sel) {
|
|
|
|
// It would be complicated to avoid reading the methods anyway. So don't.
|
|
|
|
ReadMethodPool(Sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
|
|
|
|
assert(ID && "Non-zero identifier ID required");
|
|
|
|
assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
|
|
|
|
IdentifiersLoaded[ID - 1] = II;
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->IdentifierRead(ID, II);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Set the globally-visible declarations associated with the given
|
|
|
|
/// identifier.
|
|
|
|
///
|
|
|
|
/// If the AST reader is currently in a state where the given declaration IDs
|
|
|
|
/// cannot safely be resolved, they are queued until it is safe to resolve
|
|
|
|
/// them.
|
|
|
|
///
|
|
|
|
/// \param II an IdentifierInfo that refers to one or more globally-visible
|
|
|
|
/// declarations.
|
|
|
|
///
|
|
|
|
/// \param DeclIDs the set of declaration IDs with the name @p II that are
|
|
|
|
/// visible at global scope.
|
|
|
|
///
|
2013-02-18 23:53:43 +08:00
|
|
|
/// \param Decls if non-null, this vector will be populated with the set of
|
|
|
|
/// deserialized declarations. These declarations will not be pushed into
|
|
|
|
/// scope.
|
2012-12-18 22:30:41 +08:00
|
|
|
void
|
|
|
|
ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
|
|
|
|
const SmallVectorImpl<uint32_t> &DeclIDs,
|
2013-02-18 23:53:43 +08:00
|
|
|
SmallVectorImpl<Decl *> *Decls) {
|
|
|
|
if (NumCurrentElementsDeserializing && !Decls) {
|
|
|
|
PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end());
|
2012-12-18 22:30:41 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
|
|
|
|
NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
|
|
|
|
if (SemaObj) {
|
2013-02-18 23:53:43 +08:00
|
|
|
// If we're simply supposed to record the declarations, do so now.
|
|
|
|
if (Decls) {
|
|
|
|
Decls->push_back(D);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Introduce this declaration into the translation-unit scope
|
|
|
|
// and add it to the declaration chain for this identifier, so
|
|
|
|
// that (unqualified) name lookup will find it.
|
2013-04-27 05:33:35 +08:00
|
|
|
pushExternalDeclIntoScope(D, II);
|
2012-12-18 22:30:41 +08:00
|
|
|
} else {
|
|
|
|
// Queue this declaration so that it will be added to the
|
|
|
|
// translation unit scope and identifier's declaration chain
|
|
|
|
// once a Sema object is known.
|
|
|
|
PreloadedDecls.push_back(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-22 00:52:34 +08:00
|
|
|
IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
if (ID == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IdentifiersLoaded.empty()) {
|
|
|
|
Error("no identifier table in AST file");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID -= 1;
|
|
|
|
if (!IdentifiersLoaded[ID]) {
|
|
|
|
GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
|
|
|
|
assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
|
|
|
|
ModuleFile *M = I->second;
|
|
|
|
unsigned Index = ID - M->BaseIdentifierID;
|
|
|
|
const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
|
|
|
|
|
|
|
|
// All of the strings in the AST file are preceded by a 16-bit length.
|
|
|
|
// Extract that 16-bit length to avoid having to execute strlen().
|
|
|
|
// NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as
|
|
|
|
// unsigned integers. This is important to avoid integer overflow when
|
|
|
|
// we cast them to 'unsigned'.
|
|
|
|
const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
|
|
|
|
unsigned StrLen = (((unsigned) StrLenPtr[0])
|
|
|
|
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
|
2013-01-22 00:52:34 +08:00
|
|
|
IdentifiersLoaded[ID]
|
|
|
|
= &PP.getIdentifierTable().get(StringRef(Str, StrLen));
|
2012-12-18 22:30:41 +08:00
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return IdentifiersLoaded[ID];
|
|
|
|
}
|
|
|
|
|
2013-01-22 00:52:34 +08:00
|
|
|
IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) {
|
|
|
|
return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
|
|
|
|
if (LocalID < NUM_PREDEF_IDENT_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
|
|
|
|
assert(I != M.IdentifierRemap.end()
|
|
|
|
&& "Invalid index into identifier index remap");
|
|
|
|
|
|
|
|
return LocalID + I->second;
|
|
|
|
}
|
|
|
|
|
2013-03-23 05:12:57 +08:00
|
|
|
MacroInfo *ASTReader::getMacro(MacroID ID) {
|
2012-12-18 22:30:41 +08:00
|
|
|
if (ID == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (MacrosLoaded.empty()) {
|
|
|
|
Error("no macro table in AST file");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID -= NUM_PREDEF_MACRO_IDS;
|
|
|
|
if (!MacrosLoaded[ID]) {
|
|
|
|
GlobalMacroMapType::iterator I
|
|
|
|
= GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
|
|
|
|
assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
|
|
|
|
ModuleFile *M = I->second;
|
|
|
|
unsigned Index = ID - M->BaseMacroID;
|
2013-03-23 05:12:57 +08:00
|
|
|
MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]);
|
|
|
|
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS,
|
|
|
|
MacrosLoaded[ID]);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return MacrosLoaded[ID];
|
|
|
|
}
|
|
|
|
|
|
|
|
MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
|
|
|
|
if (LocalID < NUM_PREDEF_MACRO_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
|
|
|
|
assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
|
|
|
|
|
|
|
|
return LocalID + I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
serialization::SubmoduleID
|
|
|
|
ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
|
|
|
|
if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
|
|
|
|
assert(I != M.SubmoduleRemap.end()
|
|
|
|
&& "Invalid index into submodule index remap");
|
|
|
|
|
|
|
|
return LocalID + I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
|
|
|
|
if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
|
|
|
|
assert(GlobalID == 0 && "Unhandled global submodule ID");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GlobalID > SubmodulesLoaded.size()) {
|
|
|
|
Error("submodule ID out of range in AST file");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
|
|
|
|
}
|
2013-01-12 09:29:50 +08:00
|
|
|
|
|
|
|
Module *ASTReader::getModule(unsigned ID) {
|
|
|
|
return getSubmodule(ID);
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
|
|
|
|
return DecodeSelector(getGlobalSelectorID(M, LocalID));
|
|
|
|
}
|
|
|
|
|
|
|
|
Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
|
|
|
|
if (ID == 0)
|
|
|
|
return Selector();
|
|
|
|
|
|
|
|
if (ID > SelectorsLoaded.size()) {
|
|
|
|
Error("selector ID out of range in AST file");
|
|
|
|
return Selector();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) {
|
|
|
|
// Load this selector from the selector table.
|
|
|
|
GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
|
|
|
|
assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
|
|
|
|
ModuleFile &M = *I->second;
|
|
|
|
ASTSelectorLookupTrait Trait(*this, M);
|
|
|
|
unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
|
|
|
|
SelectorsLoaded[ID - 1] =
|
|
|
|
Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0);
|
|
|
|
if (DeserializationListener)
|
|
|
|
DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SelectorsLoaded[ID - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) {
|
|
|
|
return DecodeSelector(ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t ASTReader::GetNumExternalSelectors() {
|
|
|
|
// ID 0 (the null selector) is considered an external selector.
|
|
|
|
return getTotalNumSelectors() + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
serialization::SelectorID
|
|
|
|
ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
|
|
|
|
if (LocalID < NUM_PREDEF_SELECTOR_IDS)
|
|
|
|
return LocalID;
|
|
|
|
|
|
|
|
ContinuousRangeMap<uint32_t, int, 2>::iterator I
|
|
|
|
= M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
|
|
|
|
assert(I != M.SelectorRemap.end()
|
|
|
|
&& "Invalid index into selector index remap");
|
|
|
|
|
|
|
|
return LocalID + I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeclarationName
|
|
|
|
ASTReader::ReadDeclarationName(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case DeclarationName::Identifier:
|
2013-01-22 00:52:34 +08:00
|
|
|
return DeclarationName(GetIdentifierInfo(F, Record, Idx));
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
return DeclarationName(ReadSelector(F, Record, Idx));
|
|
|
|
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
return Context.DeclarationNames.getCXXConstructorName(
|
|
|
|
Context.getCanonicalType(readType(F, Record, Idx)));
|
|
|
|
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
return Context.DeclarationNames.getCXXDestructorName(
|
|
|
|
Context.getCanonicalType(readType(F, Record, Idx)));
|
|
|
|
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
return Context.DeclarationNames.getCXXConversionFunctionName(
|
|
|
|
Context.getCanonicalType(readType(F, Record, Idx)));
|
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
return Context.DeclarationNames.getCXXOperatorName(
|
|
|
|
(OverloadedOperatorKind)Record[Idx++]);
|
|
|
|
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
return Context.DeclarationNames.getCXXLiteralOperatorName(
|
|
|
|
GetIdentifierInfo(F, Record, Idx));
|
|
|
|
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
return DeclarationName::getUsingDirectiveName();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Invalid NameKind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
|
|
|
|
DeclarationNameLoc &DNLoc,
|
|
|
|
DeclarationName Name,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
DNLoc.CXXOperatorName.BeginOpNameLoc
|
|
|
|
= ReadSourceLocation(F, Record, Idx).getRawEncoding();
|
|
|
|
DNLoc.CXXOperatorName.EndOpNameLoc
|
|
|
|
= ReadSourceLocation(F, Record, Idx).getRawEncoding();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
DNLoc.CXXLiteralOperatorName.OpNameLoc
|
|
|
|
= ReadSourceLocation(F, Record, Idx).getRawEncoding();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
|
|
|
|
DeclarationNameInfo &NameInfo,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
NameInfo.setName(ReadDeclarationName(F, Record, Idx));
|
|
|
|
NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
|
|
|
|
DeclarationNameLoc DNLoc;
|
|
|
|
ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
|
|
|
|
NameInfo.setInfo(DNLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
|
|
|
|
unsigned NumTPLists = Record[Idx++];
|
|
|
|
Info.NumTemplParamLists = NumTPLists;
|
|
|
|
if (NumTPLists) {
|
|
|
|
Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
|
|
|
|
for (unsigned i=0; i != NumTPLists; ++i)
|
|
|
|
Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateName
|
|
|
|
ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateName::Template:
|
|
|
|
return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
|
|
|
|
|
|
|
|
case TemplateName::OverloadedTemplate: {
|
|
|
|
unsigned size = Record[Idx++];
|
|
|
|
UnresolvedSet<8> Decls;
|
|
|
|
while (size--)
|
|
|
|
Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
|
|
|
|
|
|
|
|
return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::QualifiedTemplate: {
|
|
|
|
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
|
|
|
|
bool hasTemplKeyword = Record[Idx++];
|
|
|
|
TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
|
|
|
|
return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::DependentTemplate: {
|
|
|
|
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
|
|
|
|
if (Record[Idx++]) // isIdentifier
|
|
|
|
return Context.getDependentTemplateName(NNS,
|
|
|
|
GetIdentifierInfo(F, Record,
|
|
|
|
Idx));
|
|
|
|
return Context.getDependentTemplateName(NNS,
|
|
|
|
(OverloadedOperatorKind)Record[Idx++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::SubstTemplateTemplateParm: {
|
|
|
|
TemplateTemplateParmDecl *param
|
|
|
|
= ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
|
|
|
|
if (!param) return TemplateName();
|
|
|
|
TemplateName replacement = ReadTemplateName(F, Record, Idx);
|
|
|
|
return Context.getSubstTemplateTemplateParm(param, replacement);
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::SubstTemplateTemplateParmPack: {
|
|
|
|
TemplateTemplateParmDecl *Param
|
|
|
|
= ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
|
|
|
|
if (!Param)
|
|
|
|
return TemplateName();
|
|
|
|
|
|
|
|
TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx);
|
|
|
|
if (ArgPack.getKind() != TemplateArgument::Pack)
|
|
|
|
return TemplateName();
|
|
|
|
|
|
|
|
return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unhandled template name kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateArgument
|
|
|
|
ASTReader::ReadTemplateArgument(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
return TemplateArgument();
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
return TemplateArgument(readType(F, Record, Idx));
|
|
|
|
case TemplateArgument::Declaration: {
|
|
|
|
ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
|
|
|
|
bool ForReferenceParam = Record[Idx++];
|
|
|
|
return TemplateArgument(D, ForReferenceParam);
|
|
|
|
}
|
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
|
|
|
|
case TemplateArgument::Integral: {
|
|
|
|
llvm::APSInt Value = ReadAPSInt(Record, Idx);
|
|
|
|
QualType T = readType(F, Record, Idx);
|
|
|
|
return TemplateArgument(Context, Value, T);
|
|
|
|
}
|
|
|
|
case TemplateArgument::Template:
|
|
|
|
return TemplateArgument(ReadTemplateName(F, Record, Idx));
|
|
|
|
case TemplateArgument::TemplateExpansion: {
|
|
|
|
TemplateName Name = ReadTemplateName(F, Record, Idx);
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<unsigned> NumTemplateExpansions;
|
2012-12-18 22:30:41 +08:00
|
|
|
if (unsigned NumExpansions = Record[Idx++])
|
|
|
|
NumTemplateExpansions = NumExpansions - 1;
|
|
|
|
return TemplateArgument(Name, NumTemplateExpansions);
|
|
|
|
}
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
return TemplateArgument(ReadExpr(F));
|
|
|
|
case TemplateArgument::Pack: {
|
|
|
|
unsigned NumArgs = Record[Idx++];
|
|
|
|
TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
|
|
|
|
for (unsigned I = 0; I != NumArgs; ++I)
|
|
|
|
Args[I] = ReadTemplateArgument(F, Record, Idx);
|
|
|
|
return TemplateArgument(Args, NumArgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unhandled template argument kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateParameterList *
|
|
|
|
ASTReader::ReadTemplateParameterList(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
|
|
|
|
unsigned NumParams = Record[Idx++];
|
|
|
|
SmallVector<NamedDecl *, 16> Params;
|
|
|
|
Params.reserve(NumParams);
|
|
|
|
while (NumParams--)
|
|
|
|
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
|
|
|
|
|
|
|
|
TemplateParameterList* TemplateParams =
|
|
|
|
TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
|
|
|
|
Params.data(), Params.size(), RAngleLoc);
|
|
|
|
return TemplateParams;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ASTReader::
|
2013-07-06 03:34:19 +08:00
|
|
|
ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
|
2012-12-18 22:30:41 +08:00
|
|
|
ModuleFile &F, const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
unsigned NumTemplateArgs = Record[Idx++];
|
|
|
|
TemplArgs.reserve(NumTemplateArgs);
|
|
|
|
while (NumTemplateArgs--)
|
|
|
|
TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Read a UnresolvedSet structure.
|
2013-08-30 12:46:40 +08:00
|
|
|
void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
|
2012-12-18 22:30:41 +08:00
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
unsigned NumDecls = Record[Idx++];
|
|
|
|
Set.reserve(Context, NumDecls);
|
|
|
|
while (NumDecls--) {
|
2013-08-30 12:46:40 +08:00
|
|
|
DeclID ID = ReadDeclID(F, Record, Idx);
|
2012-12-18 22:30:41 +08:00
|
|
|
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
|
2013-08-30 12:46:40 +08:00
|
|
|
Set.addLazyDecl(Context, ID, AS);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseSpecifier
|
|
|
|
ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
bool isVirtual = static_cast<bool>(Record[Idx++]);
|
|
|
|
bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
|
|
|
|
AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
|
|
|
|
bool inheritConstructors = static_cast<bool>(Record[Idx++]);
|
|
|
|
TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
|
|
|
|
SourceRange Range = ReadSourceRange(F, Record, Idx);
|
|
|
|
SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo,
|
|
|
|
EllipsisLoc);
|
|
|
|
Result.setInheritConstructors(inheritConstructors);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<CXXCtorInitializer **, unsigned>
|
|
|
|
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
CXXCtorInitializer **CtorInitializers = 0;
|
|
|
|
unsigned NumInitializers = Record[Idx++];
|
|
|
|
if (NumInitializers) {
|
|
|
|
CtorInitializers
|
|
|
|
= new (Context) CXXCtorInitializer*[NumInitializers];
|
|
|
|
for (unsigned i=0; i != NumInitializers; ++i) {
|
|
|
|
TypeSourceInfo *TInfo = 0;
|
|
|
|
bool IsBaseVirtual = false;
|
|
|
|
FieldDecl *Member = 0;
|
|
|
|
IndirectFieldDecl *IndirectMember = 0;
|
|
|
|
|
|
|
|
CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
|
|
|
|
switch (Type) {
|
|
|
|
case CTOR_INITIALIZER_BASE:
|
|
|
|
TInfo = GetTypeSourceInfo(F, Record, Idx);
|
|
|
|
IsBaseVirtual = Record[Idx++];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CTOR_INITIALIZER_DELEGATING:
|
|
|
|
TInfo = GetTypeSourceInfo(F, Record, Idx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CTOR_INITIALIZER_MEMBER:
|
|
|
|
Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CTOR_INITIALIZER_INDIRECT_MEMBER:
|
|
|
|
IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
Expr *Init = ReadExpr(F);
|
|
|
|
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
bool IsWritten = Record[Idx++];
|
|
|
|
unsigned SourceOrderOrNumArrayIndices;
|
|
|
|
SmallVector<VarDecl *, 8> Indices;
|
|
|
|
if (IsWritten) {
|
|
|
|
SourceOrderOrNumArrayIndices = Record[Idx++];
|
|
|
|
} else {
|
|
|
|
SourceOrderOrNumArrayIndices = Record[Idx++];
|
|
|
|
Indices.reserve(SourceOrderOrNumArrayIndices);
|
|
|
|
for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
|
|
|
|
Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXCtorInitializer *BOMInit;
|
|
|
|
if (Type == CTOR_INITIALIZER_BASE) {
|
|
|
|
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
|
|
|
|
LParenLoc, Init, RParenLoc,
|
|
|
|
MemberOrEllipsisLoc);
|
|
|
|
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
|
|
|
|
BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
|
|
|
|
Init, RParenLoc);
|
|
|
|
} else if (IsWritten) {
|
|
|
|
if (Member)
|
|
|
|
BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
|
|
|
|
LParenLoc, Init, RParenLoc);
|
|
|
|
else
|
|
|
|
BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
|
|
|
|
MemberOrEllipsisLoc, LParenLoc,
|
|
|
|
Init, RParenLoc);
|
|
|
|
} else {
|
2013-05-31 07:59:46 +08:00
|
|
|
if (IndirectMember) {
|
|
|
|
assert(Indices.empty() && "Indirect field improperly initialized");
|
|
|
|
BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
|
|
|
|
MemberOrEllipsisLoc, LParenLoc,
|
|
|
|
Init, RParenLoc);
|
|
|
|
} else {
|
|
|
|
BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
|
|
|
|
LParenLoc, Init, RParenLoc,
|
|
|
|
Indices.data(), Indices.size());
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IsWritten)
|
|
|
|
BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
|
|
|
|
CtorInitializers[i] = BOMInit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(CtorInitializers, NumInitializers);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifier *
|
|
|
|
ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
|
|
|
|
const RecordData &Record, unsigned &Idx) {
|
|
|
|
unsigned N = Record[Idx++];
|
|
|
|
NestedNameSpecifier *NNS = 0, *Prev = 0;
|
|
|
|
for (unsigned I = 0; I != N; ++I) {
|
|
|
|
NestedNameSpecifier::SpecifierKind Kind
|
|
|
|
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case NestedNameSpecifier::Identifier: {
|
|
|
|
IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
|
|
|
|
NNS = NestedNameSpecifier::Create(Context, Prev, II);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace: {
|
|
|
|
NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
|
|
|
|
NNS = NestedNameSpecifier::Create(Context, Prev, NS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::NamespaceAlias: {
|
|
|
|
NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
|
|
|
|
NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
|
|
|
const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
|
|
|
|
if (!T)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bool Template = Record[Idx++];
|
|
|
|
NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global: {
|
|
|
|
NNS = NestedNameSpecifier::GlobalSpecifier(Context);
|
|
|
|
// No associated value, and there can't be a prefix.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Prev = NNS;
|
|
|
|
}
|
|
|
|
return NNS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedNameSpecifierLoc
|
|
|
|
ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
unsigned N = Record[Idx++];
|
|
|
|
NestedNameSpecifierLocBuilder Builder;
|
|
|
|
for (unsigned I = 0; I != N; ++I) {
|
|
|
|
NestedNameSpecifier::SpecifierKind Kind
|
|
|
|
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case NestedNameSpecifier::Identifier: {
|
|
|
|
IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
|
|
|
|
SourceRange Range = ReadSourceRange(F, Record, Idx);
|
|
|
|
Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace: {
|
|
|
|
NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
|
|
|
|
SourceRange Range = ReadSourceRange(F, Record, Idx);
|
|
|
|
Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::NamespaceAlias: {
|
|
|
|
NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
|
|
|
|
SourceRange Range = ReadSourceRange(F, Record, Idx);
|
|
|
|
Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
|
|
|
bool Template = Record[Idx++];
|
|
|
|
TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
|
|
|
|
if (!T)
|
|
|
|
return NestedNameSpecifierLoc();
|
|
|
|
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
|
|
|
|
// FIXME: 'template' keyword location not saved anywhere, so we fake it.
|
|
|
|
Builder.Extend(Context,
|
|
|
|
Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
|
|
|
|
T->getTypeLoc(), ColonColonLoc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global: {
|
|
|
|
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
|
|
|
|
Builder.MakeGlobal(Context, ColonColonLoc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Builder.getWithLocInContext(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceRange
|
|
|
|
ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
SourceLocation beg = ReadSourceLocation(F, Record, Idx);
|
|
|
|
SourceLocation end = ReadSourceLocation(F, Record, Idx);
|
|
|
|
return SourceRange(beg, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Read an integral value
|
|
|
|
llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
|
|
|
|
unsigned BitWidth = Record[Idx++];
|
|
|
|
unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
|
|
|
|
llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
|
|
|
|
Idx += NumWords;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Read a signed integral value
|
|
|
|
llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
|
|
|
|
bool isUnsigned = Record[Idx++];
|
|
|
|
return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Read a floating-point value
|
2013-01-22 17:46:51 +08:00
|
|
|
llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record,
|
|
|
|
const llvm::fltSemantics &Sem,
|
|
|
|
unsigned &Idx) {
|
|
|
|
return llvm::APFloat(Sem, ReadAPInt(Record, Idx));
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// \brief Read a string
|
|
|
|
std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
|
|
|
|
unsigned Len = Record[Idx++];
|
|
|
|
std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
|
|
|
|
Idx += Len;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
unsigned Major = Record[Idx++];
|
|
|
|
unsigned Minor = Record[Idx++];
|
|
|
|
unsigned Subminor = Record[Idx++];
|
|
|
|
if (Minor == 0)
|
|
|
|
return VersionTuple(Major);
|
|
|
|
if (Subminor == 0)
|
|
|
|
return VersionTuple(Major, Minor - 1);
|
|
|
|
return VersionTuple(Major, Minor - 1, Subminor - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
|
|
|
|
return CXXTemporary::Create(Context, Decl);
|
|
|
|
}
|
|
|
|
|
|
|
|
DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
|
2013-05-24 13:44:08 +08:00
|
|
|
return Diag(CurrentImportLoc, DiagID);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
|
|
|
|
return Diags.Report(Loc, DiagID);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the identifier table associated with the
|
|
|
|
/// preprocessor.
|
|
|
|
IdentifierTable &ASTReader::getIdentifierTable() {
|
|
|
|
return PP.getIdentifierTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Record that the given ID maps to the given switch-case
|
|
|
|
/// statement.
|
|
|
|
void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
|
|
|
|
assert((*CurrSwitchCaseStmts)[ID] == 0 &&
|
|
|
|
"Already have a SwitchCase with this ID");
|
|
|
|
(*CurrSwitchCaseStmts)[ID] = SC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the switch-case statement with the given ID.
|
|
|
|
SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) {
|
|
|
|
assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID");
|
|
|
|
return (*CurrSwitchCaseStmts)[ID];
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ClearSwitchCaseIDs() {
|
|
|
|
CurrSwitchCaseStmts->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::ReadComments() {
|
|
|
|
std::vector<RawComment *> Comments;
|
2013-01-20 08:56:42 +08:00
|
|
|
for (SmallVectorImpl<std::pair<BitstreamCursor,
|
2012-12-18 22:30:41 +08:00
|
|
|
serialization::ModuleFile *> >::iterator
|
|
|
|
I = CommentsCursors.begin(),
|
|
|
|
E = CommentsCursors.end();
|
|
|
|
I != E; ++I) {
|
2013-01-20 08:56:42 +08:00
|
|
|
BitstreamCursor &Cursor = I->first;
|
2012-12-18 22:30:41 +08:00
|
|
|
serialization::ModuleFile &F = *I->second;
|
|
|
|
SavedStreamPosition SavedPosition(Cursor);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
while (true) {
|
2013-01-20 08:56:42 +08:00
|
|
|
llvm::BitstreamEntry Entry =
|
|
|
|
Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd);
|
|
|
|
|
|
|
|
switch (Entry.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:
|
|
|
|
// The interesting case.
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read a record.
|
|
|
|
Record.clear();
|
2013-01-20 10:38:54 +08:00
|
|
|
switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
case COMMENTS_RAW_COMMENT: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
SourceRange SR = ReadSourceRange(F, Record, Idx);
|
|
|
|
RawComment::CommentKind Kind =
|
|
|
|
(RawComment::CommentKind) Record[Idx++];
|
|
|
|
bool IsTrailingComment = Record[Idx++];
|
|
|
|
bool IsAlmostTrailingComment = Record[Idx++];
|
2013-04-10 23:35:17 +08:00
|
|
|
Comments.push_back(new (Context) RawComment(
|
|
|
|
SR, Kind, IsTrailingComment, IsAlmostTrailingComment,
|
|
|
|
Context.getLangOpts().CommentOpts.ParseAllComments));
|
2012-12-18 22:30:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-20 08:56:42 +08:00
|
|
|
NextCursor:;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
Context.Comments.addCommentsToFront(Comments);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::finishPendingActions() {
|
|
|
|
while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
|
2013-10-18 14:05:18 +08:00
|
|
|
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
|
|
|
|
!PendingOdrMergeChecks.empty()) {
|
2012-12-18 22:30:41 +08:00
|
|
|
// If any identifiers with corresponding top-level declarations have
|
|
|
|
// been loaded, load those declarations now.
|
2013-07-05 12:33:53 +08:00
|
|
|
typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
|
|
|
|
TopLevelDeclsMap;
|
|
|
|
TopLevelDeclsMap TopLevelDecls;
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
while (!PendingIdentifierInfos.empty()) {
|
2013-02-18 23:53:43 +08:00
|
|
|
// FIXME: std::move
|
|
|
|
IdentifierInfo *II = PendingIdentifierInfos.back().first;
|
|
|
|
SmallVector<uint32_t, 4> DeclIDs = PendingIdentifierInfos.back().second;
|
2013-02-20 02:26:28 +08:00
|
|
|
PendingIdentifierInfos.pop_back();
|
2013-02-18 23:53:43 +08:00
|
|
|
|
|
|
|
SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load pending declaration chains.
|
|
|
|
for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
|
|
|
|
loadPendingDeclChain(PendingDeclChains[I]);
|
|
|
|
PendingDeclChainsKnown.erase(PendingDeclChains[I]);
|
|
|
|
}
|
|
|
|
PendingDeclChains.clear();
|
|
|
|
|
2013-02-18 23:53:43 +08:00
|
|
|
// Make the most recent of the top-level declarations visible.
|
2013-07-05 12:33:53 +08:00
|
|
|
for (TopLevelDeclsMap::iterator TLD = TopLevelDecls.begin(),
|
|
|
|
TLDEnd = TopLevelDecls.end(); TLD != TLDEnd; ++TLD) {
|
2013-02-18 23:53:43 +08:00
|
|
|
IdentifierInfo *II = TLD->first;
|
|
|
|
for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) {
|
2013-04-27 05:33:35 +08:00
|
|
|
pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II);
|
2013-02-18 23:53:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
// Load any pending macro definitions.
|
|
|
|
for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
|
2013-03-23 05:12:57 +08:00
|
|
|
IdentifierInfo *II = PendingMacroIDs.begin()[I].first;
|
|
|
|
SmallVector<PendingMacroInfo, 2> GlobalIDs;
|
|
|
|
GlobalIDs.swap(PendingMacroIDs.begin()[I].second);
|
|
|
|
// Initialize the macro history from chained-PCHs ahead of module imports.
|
2014-03-01 08:08:04 +08:00
|
|
|
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
|
2013-03-23 05:12:57 +08:00
|
|
|
++IDIdx) {
|
|
|
|
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
|
|
|
|
if (Info.M->Kind != MK_Module)
|
|
|
|
resolvePendingMacro(II, Info);
|
|
|
|
}
|
|
|
|
// Handle module imports.
|
2014-03-01 08:08:04 +08:00
|
|
|
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
|
2013-01-19 11:14:56 +08:00
|
|
|
++IDIdx) {
|
2013-03-23 05:12:57 +08:00
|
|
|
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
|
|
|
|
if (Info.M->Kind == MK_Module)
|
|
|
|
resolvePendingMacro(II, Info);
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PendingMacroIDs.clear();
|
2013-02-16 08:48:59 +08:00
|
|
|
|
|
|
|
// Wire up the DeclContexts for Decls that we delayed setting until
|
|
|
|
// recursive loading is completed.
|
|
|
|
while (!PendingDeclContextInfos.empty()) {
|
|
|
|
PendingDeclContextInfo Info = PendingDeclContextInfos.front();
|
|
|
|
PendingDeclContextInfos.pop_front();
|
|
|
|
DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC));
|
|
|
|
DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
|
|
|
|
Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
|
|
|
|
}
|
2013-10-18 14:05:18 +08:00
|
|
|
|
|
|
|
// For each declaration from a merged context, check that the canonical
|
|
|
|
// definition of that context also contains a declaration of the same
|
|
|
|
// entity.
|
|
|
|
while (!PendingOdrMergeChecks.empty()) {
|
|
|
|
NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
|
|
|
|
|
|
|
|
// FIXME: Skip over implicit declarations for now. This matters for things
|
|
|
|
// like implicitly-declared special member functions. This isn't entirely
|
|
|
|
// correct; we can end up with multiple unmerged declarations of the same
|
|
|
|
// implicit entity.
|
|
|
|
if (D->isImplicit())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DeclContext *CanonDef = D->getDeclContext();
|
|
|
|
DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
|
|
|
|
|
|
|
|
bool Found = false;
|
|
|
|
const Decl *DCanon = D->getCanonicalDecl();
|
|
|
|
|
|
|
|
llvm::SmallVector<const NamedDecl*, 4> Candidates;
|
|
|
|
for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
|
|
|
|
!Found && I != E; ++I) {
|
2014-03-07 07:45:36 +08:00
|
|
|
for (auto RI : (*I)->redecls()) {
|
|
|
|
if (RI->getLexicalDeclContext() == CanonDef) {
|
2013-10-18 14:05:18 +08:00
|
|
|
// This declaration is present in the canonical definition. If it's
|
|
|
|
// in the same redecl chain, it's the one we're looking for.
|
2014-03-07 07:45:36 +08:00
|
|
|
if (RI->getCanonicalDecl() == DCanon)
|
2013-10-18 14:05:18 +08:00
|
|
|
Found = true;
|
|
|
|
else
|
2014-03-07 07:45:36 +08:00
|
|
|
Candidates.push_back(cast<NamedDecl>(RI));
|
2013-10-18 14:05:18 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Found) {
|
|
|
|
D->setInvalidDecl();
|
|
|
|
|
|
|
|
Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule();
|
|
|
|
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
|
|
|
|
<< D << D->getOwningModule()->getFullModuleName()
|
|
|
|
<< CanonDef << !CanonDefModule
|
|
|
|
<< (CanonDefModule ? CanonDefModule->getFullModuleName() : "");
|
|
|
|
|
|
|
|
if (Candidates.empty())
|
|
|
|
Diag(cast<Decl>(CanonDef)->getLocation(),
|
|
|
|
diag::note_module_odr_violation_no_possible_decls) << D;
|
|
|
|
else {
|
|
|
|
for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
|
|
|
|
Diag(Candidates[I]->getLocation(),
|
|
|
|
diag::note_module_odr_violation_possible_decl)
|
|
|
|
<< Candidates[I];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we deserialized any C++ or Objective-C class definitions, any
|
|
|
|
// Objective-C protocol definitions, or any redeclarable templates, make sure
|
|
|
|
// that all redeclarations point to the definitions. Note that this can only
|
|
|
|
// happen now, after the redeclaration chains have been fully wired.
|
|
|
|
for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
|
|
|
|
DEnd = PendingDefinitions.end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
|
|
|
|
if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
|
|
|
|
// Make sure that the TagType points at the definition.
|
|
|
|
const_cast<TagType*>(TagT)->decl = TD;
|
|
|
|
}
|
|
|
|
|
2014-03-07 07:45:36 +08:00
|
|
|
if (auto RD = dyn_cast<CXXRecordDecl>(*D)) {
|
|
|
|
for (auto R : RD->redecls())
|
|
|
|
cast<CXXRecordDecl>(R)->DefinitionData = RD->DefinitionData;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-03-07 07:45:36 +08:00
|
|
|
if (auto ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
|
2012-12-18 22:30:41 +08:00
|
|
|
// Make sure that the ObjCInterfaceType points at the definition.
|
|
|
|
const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
|
|
|
|
->Decl = ID;
|
|
|
|
|
2014-03-07 07:45:36 +08:00
|
|
|
for (auto R : ID->redecls())
|
2012-12-18 22:30:41 +08:00
|
|
|
R->Data = ID->Data;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-03-07 07:45:36 +08:00
|
|
|
if (auto PD = dyn_cast<ObjCProtocolDecl>(*D)) {
|
|
|
|
for (auto R : PD->redecls())
|
2012-12-18 22:30:41 +08:00
|
|
|
R->Data = PD->Data;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-03-07 07:45:36 +08:00
|
|
|
auto RTD = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
|
|
|
|
for (auto R : RTD->redecls())
|
2012-12-18 22:30:41 +08:00
|
|
|
R->Common = RTD->Common;
|
|
|
|
}
|
|
|
|
PendingDefinitions.clear();
|
|
|
|
|
|
|
|
// Load the bodies of any functions or methods we've encountered. We do
|
|
|
|
// this now (delayed) so that we can be sure that the declaration chains
|
|
|
|
// have been fully wired up.
|
|
|
|
for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
|
|
|
|
PBEnd = PendingBodies.end();
|
|
|
|
PB != PBEnd; ++PB) {
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
|
|
|
|
// FIXME: Check for =delete/=default?
|
|
|
|
// FIXME: Complain about ODR violations here?
|
|
|
|
if (!getContext().getLangOpts().Modules || !FD->hasBody())
|
|
|
|
FD->setLazyBody(PB->second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
|
|
|
|
if (!getContext().getLangOpts().Modules || !MD->hasBody())
|
|
|
|
MD->setLazyBody(PB->second);
|
|
|
|
}
|
|
|
|
PendingBodies.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTReader::FinishedDeserializing() {
|
|
|
|
assert(NumCurrentElementsDeserializing &&
|
|
|
|
"FinishedDeserializing not paired with StartedDeserializing");
|
|
|
|
if (NumCurrentElementsDeserializing == 1) {
|
|
|
|
// We decrease NumCurrentElementsDeserializing only after pending actions
|
|
|
|
// are finished, to avoid recursively re-calling finishPendingActions().
|
|
|
|
finishPendingActions();
|
|
|
|
}
|
|
|
|
--NumCurrentElementsDeserializing;
|
|
|
|
|
|
|
|
if (NumCurrentElementsDeserializing == 0 &&
|
|
|
|
Consumer && !PassingDeclsToConsumer) {
|
|
|
|
// Guard variable to avoid recursively redoing the process of passing
|
|
|
|
// decls to consumer.
|
|
|
|
SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
|
|
|
|
true);
|
|
|
|
|
|
|
|
while (!InterestingDecls.empty()) {
|
|
|
|
// We are not in recursive loading, so it's safe to pass the "interesting"
|
|
|
|
// decls to the consumer.
|
|
|
|
Decl *D = InterestingDecls.front();
|
|
|
|
InterestingDecls.pop_front();
|
|
|
|
PassInterestingDeclToConsumer(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-27 05:33:35 +08:00
|
|
|
void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
|
2013-10-20 00:55:03 +08:00
|
|
|
D = D->getMostRecentDecl();
|
2013-04-27 05:33:35 +08:00
|
|
|
|
|
|
|
if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
|
|
|
|
SemaObj->TUScope->AddDecl(D);
|
|
|
|
} else if (SemaObj->TUScope) {
|
|
|
|
// Adding the decl to IdResolver may have failed because it was already in
|
|
|
|
// (even though it was not added in scope). If it is already in, make sure
|
|
|
|
// it gets in the scope as well.
|
|
|
|
if (std::find(SemaObj->IdResolver.begin(Name),
|
|
|
|
SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end())
|
|
|
|
SemaObj->TUScope->AddDecl(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:30:41 +08:00
|
|
|
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
|
|
|
|
StringRef isysroot, bool DisableValidation,
|
2014-02-06 06:21:15 +08:00
|
|
|
bool AllowASTWithCompilerErrors,
|
|
|
|
bool AllowConfigurationMismatch,
|
2014-02-08 01:31:11 +08:00
|
|
|
bool ValidateSystemInputs,
|
2014-02-06 06:21:15 +08:00
|
|
|
bool UseGlobalIndex)
|
2012-12-18 22:30:41 +08:00
|
|
|
: Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
|
|
|
|
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
|
|
|
|
Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
|
|
|
|
Consumer(0), ModuleMgr(PP.getFileManager()),
|
|
|
|
isysroot(isysroot), DisableValidation(DisableValidation),
|
2013-01-25 08:38:33 +08:00
|
|
|
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
|
2014-02-06 06:21:15 +08:00
|
|
|
AllowConfigurationMismatch(AllowConfigurationMismatch),
|
2014-02-08 01:31:11 +08:00
|
|
|
ValidateSystemInputs(ValidateSystemInputs),
|
2013-01-25 08:45:27 +08:00
|
|
|
UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
|
2012-12-18 22:30:41 +08:00
|
|
|
CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
|
|
|
|
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
|
2013-01-25 08:38:33 +08:00
|
|
|
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
|
|
|
|
TotalNumMacros(0), NumIdentifierLookups(0), NumIdentifierLookupHits(0),
|
|
|
|
NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
|
2013-01-29 01:54:36 +08:00
|
|
|
NumMethodPoolLookups(0), NumMethodPoolHits(0),
|
|
|
|
NumMethodPoolTableLookups(0), NumMethodPoolTableHits(0),
|
|
|
|
TotalNumMethodPoolEntries(0),
|
2012-12-18 22:30:41 +08:00
|
|
|
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
|
|
|
|
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
|
|
|
|
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
|
|
|
|
PassingDeclsToConsumer(false),
|
2013-07-31 08:26:46 +08:00
|
|
|
NumCXXBaseSpecifiersLoaded(0), ReadingKind(Read_None)
|
2012-12-18 22:30:41 +08:00
|
|
|
{
|
|
|
|
SourceMgr.setExternalSLocEntrySource(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTReader::~ASTReader() {
|
|
|
|
for (DeclContextVisibleUpdatesPending::iterator
|
|
|
|
I = PendingVisibleUpdates.begin(),
|
|
|
|
E = PendingVisibleUpdates.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
|
|
|
|
F = I->second.end();
|
|
|
|
J != F; ++J)
|
|
|
|
delete J->first;
|
|
|
|
}
|
|
|
|
}
|