2009-04-10 02:27:44 +04:00
|
|
|
//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// 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 PCHReader class, which reads a precompiled header.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-27 09:14:47 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
#include "clang/Frontend/PCHReader.h"
|
2009-04-11 00:39:37 +04:00
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
2009-11-12 02:58:53 +03:00
|
|
|
#include "clang/Frontend/Utils.h"
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere
|
2009-04-14 04:24:19 +04:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2009-04-10 02:27:44 +04:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-04-15 01:18:50 +04:00
|
|
|
#include "clang/AST/Expr.h"
|
2009-04-10 02:27:44 +04:00
|
|
|
#include "clang/AST/Type.h"
|
2009-10-17 01:56:05 +04:00
|
|
|
#include "clang/AST/TypeLocVisitor.h"
|
2009-04-11 01:41:48 +04:00
|
|
|
#include "clang/Lex/MacroInfo.h"
|
2009-04-10 07:52:48 +04:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-04-25 00:03:17 +04:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
#include "clang/Basic/OnDiskHashTable.h"
|
2009-04-10 07:52:48 +04:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2009-04-13 20:31:14 +04:00
|
|
|
#include "clang/Basic/SourceManagerInternals.h"
|
2009-04-10 07:52:48 +04:00
|
|
|
#include "clang/Basic/FileManager.h"
|
2009-04-11 01:16:55 +04:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2009-10-06 01:07:28 +04:00
|
|
|
#include "clang/Basic/Version.h"
|
2009-10-18 03:52:28 +04:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2009-04-10 02:27:44 +04:00
|
|
|
#include "llvm/Bitcode/BitstreamReader.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-10-29 11:12:44 +03:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-04-10 02:27:44 +04:00
|
|
|
#include <algorithm>
|
2009-04-28 22:58:38 +04:00
|
|
|
#include <iterator>
|
2009-04-10 02:27:44 +04:00
|
|
|
#include <cstdio>
|
2009-04-27 22:38:38 +04:00
|
|
|
#include <sys/stat.h>
|
2009-04-10 02:27:44 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// PCH reader validator implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
PCHReaderListener::~PCHReaderListener() {}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
|
|
|
|
const LangOptions &PPLangOpts = PP.getLangOptions();
|
|
|
|
#define PARSE_LANGOPT_BENIGN(Option)
|
|
|
|
#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
|
|
|
|
if (PPLangOpts.Option != LangOpts.Option) { \
|
|
|
|
Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \
|
|
|
|
return true; \
|
|
|
|
}
|
|
|
|
|
|
|
|
PARSE_LANGOPT_BENIGN(Trigraphs);
|
|
|
|
PARSE_LANGOPT_BENIGN(BCPLComment);
|
|
|
|
PARSE_LANGOPT_BENIGN(DollarIdents);
|
|
|
|
PARSE_LANGOPT_BENIGN(AsmPreprocessor);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
|
|
|
|
PARSE_LANGOPT_BENIGN(ImplicitInt);
|
|
|
|
PARSE_LANGOPT_BENIGN(Digraphs);
|
|
|
|
PARSE_LANGOPT_BENIGN(HexFloats);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x);
|
|
|
|
PARSE_LANGOPT_BENIGN(CXXOperatorName);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
|
|
|
|
PARSE_LANGOPT_BENIGN(PascalStrings);
|
|
|
|
PARSE_LANGOPT_BENIGN(WritableStrings);
|
2009-09-09 19:08:12 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
|
2009-06-19 04:03:23 +04:00
|
|
|
diag::warn_pch_lax_vector_conversions);
|
2009-06-26 02:57:40 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
|
2009-09-09 19:08:12 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics,
|
2009-06-19 04:03:23 +04:00
|
|
|
diag::warn_pch_thread_safe_statics);
|
2009-09-03 08:54:28 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads);
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks);
|
|
|
|
PARSE_LANGOPT_BENIGN(EmitAllDecls);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking);
|
2009-09-09 19:08:12 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(HeinousExtensions,
|
2009-06-19 04:03:23 +04:00
|
|
|
diag::warn_pch_heinous_extensions);
|
|
|
|
// FIXME: Most of the options below are benign if the macro wasn't
|
|
|
|
// used. Unfortunately, this means that a PCH compiled without
|
|
|
|
// optimization can't be used with optimization turned on, even
|
|
|
|
// though the only thing that changes is whether __OPTIMIZE__ was
|
|
|
|
// defined... but if __OPTIMIZE__ never showed up in the header, it
|
|
|
|
// doesn't matter. We could consider making this some special kind
|
|
|
|
// of check.
|
|
|
|
PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
|
|
|
|
PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
|
2009-11-05 23:14:16 +03:00
|
|
|
PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar);
|
2009-06-19 04:03:23 +04:00
|
|
|
if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) {
|
2009-09-09 19:08:12 +04:00
|
|
|
Reader.Diag(diag::warn_pch_gc_mode)
|
2009-06-19 04:03:23 +04:00
|
|
|
<< LangOpts.getGCMode() << PPLangOpts.getGCMode();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
PARSE_LANGOPT_BENIGN(getVisibilityMode());
|
2009-09-21 08:16:19 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(),
|
|
|
|
diag::warn_pch_stack_protector);
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT_BENIGN(InstantiationDepth);
|
2009-06-26 02:57:40 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
|
2009-09-21 08:16:19 +04:00
|
|
|
PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
|
2009-06-19 04:03:23 +04:00
|
|
|
#undef PARSE_LANGOPT_IRRELEVANT
|
|
|
|
#undef PARSE_LANGOPT_BENIGN
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-11-11 03:52:11 +03:00
|
|
|
bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
|
|
|
|
if (Triple == PP.getTargetInfo().getTriple().str())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Reader.Diag(diag::warn_pch_target_triple)
|
|
|
|
<< Triple << PP.getTargetInfo().getTriple().str();
|
|
|
|
return true;
|
2009-06-19 04:03:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Split the given string into a vector of lines, eliminating
|
|
|
|
/// any empty lines in the process.
|
|
|
|
///
|
|
|
|
/// \param Str the string to split.
|
|
|
|
/// \param Len the length of Str.
|
|
|
|
/// \param KeepEmptyLines true if empty lines should be included
|
|
|
|
/// \returns a vector of lines, with the line endings removed
|
2009-11-11 06:45:59 +03:00
|
|
|
static std::vector<llvm::StringRef> splitLines(llvm::StringRef Str,
|
|
|
|
bool KeepEmptyLines = false) {
|
|
|
|
std::vector<llvm::StringRef> Lines;
|
|
|
|
|
|
|
|
while (!Str.empty()) {
|
|
|
|
std::pair<llvm::StringRef, llvm::StringRef> split = Str.split('\n');
|
|
|
|
|
|
|
|
if (KeepEmptyLines || !split.first.empty())
|
|
|
|
Lines.push_back(split.first);
|
|
|
|
|
|
|
|
Str = split.second;
|
2009-06-19 04:03:23 +04:00
|
|
|
}
|
2009-11-11 06:45:59 +03:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
return Lines;
|
|
|
|
}
|
|
|
|
|
2009-11-11 03:52:11 +03:00
|
|
|
bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
2009-06-19 04:03:23 +04:00
|
|
|
FileID PCHBufferID,
|
2009-11-11 08:29:04 +03:00
|
|
|
llvm::StringRef OriginalFileName,
|
2009-06-19 04:03:23 +04:00
|
|
|
std::string &SuggestedPredefines) {
|
2009-11-12 02:58:53 +03:00
|
|
|
// We are in the context of an implicit include, so the predefines buffer will
|
|
|
|
// have a #include entry for the PCH file itself (as normalized by the
|
|
|
|
// preprocessor initialization). Find it and skip over it in the checking
|
|
|
|
// below.
|
2009-11-11 08:29:04 +03:00
|
|
|
llvm::SmallString<256> PCHInclude;
|
|
|
|
PCHInclude += "#include \"";
|
2009-11-12 02:58:53 +03:00
|
|
|
PCHInclude += NormalizeDashIncludePath(OriginalFileName);
|
2009-11-11 08:29:04 +03:00
|
|
|
PCHInclude += "\"\n";
|
|
|
|
std::pair<llvm::StringRef,llvm::StringRef> Split =
|
|
|
|
llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
|
|
|
|
llvm::StringRef Left = Split.first, Right = Split.second;
|
|
|
|
assert(Left != PP.getPredefines() && "Missing PCH include entry!");
|
|
|
|
|
|
|
|
// If the predefines is equal to the joined left and right halves, we're done!
|
|
|
|
if (Left.size() + Right.size() == PCHPredef.size() &&
|
|
|
|
PCHPredef.startswith(Left) && PCHPredef.endswith(Right))
|
2009-06-19 04:03:23 +04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
SourceManager &SourceMgr = PP.getSourceManager();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-11-11 06:45:59 +03:00
|
|
|
// The predefines buffers are different. Determine what the differences are,
|
|
|
|
// and whether they require us to reject the PCH file.
|
|
|
|
std::vector<llvm::StringRef> PCHLines = splitLines(PCHPredef);
|
2009-11-11 08:29:04 +03:00
|
|
|
std::vector<llvm::StringRef> CmdLineLines = splitLines(Left);
|
|
|
|
std::vector<llvm::StringRef> CmdLineLinesRight = splitLines(Right);
|
|
|
|
CmdLineLines.insert(CmdLineLines.end(),
|
|
|
|
CmdLineLinesRight.begin(), CmdLineLinesRight.end());
|
2009-06-19 04:03:23 +04:00
|
|
|
|
2009-11-11 08:26:28 +03:00
|
|
|
// Sort both sets of predefined buffer lines, since we allow some extra
|
|
|
|
// definitions and they may appear at any point in the output.
|
2009-06-19 04:03:23 +04:00
|
|
|
std::sort(CmdLineLines.begin(), CmdLineLines.end());
|
|
|
|
std::sort(PCHLines.begin(), PCHLines.end());
|
|
|
|
|
2009-11-11 08:26:28 +03:00
|
|
|
// Determine which predefines that were used to build the PCH file are missing
|
|
|
|
// from the command line.
|
|
|
|
std::vector<llvm::StringRef> MissingPredefines;
|
2009-06-19 04:03:23 +04:00
|
|
|
std::set_difference(PCHLines.begin(), PCHLines.end(),
|
|
|
|
CmdLineLines.begin(), CmdLineLines.end(),
|
|
|
|
std::back_inserter(MissingPredefines));
|
|
|
|
|
|
|
|
bool MissingDefines = false;
|
|
|
|
bool ConflictingDefines = false;
|
|
|
|
for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef Missing = MissingPredefines[I];
|
|
|
|
if (!Missing.startswith("#define ")) {
|
2009-06-19 04:03:23 +04:00
|
|
|
Reader.Diag(diag::warn_pch_compiler_options_mismatch);
|
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-11-11 06:45:59 +03:00
|
|
|
// This is a macro definition. Determine the name of the macro we're
|
|
|
|
// defining.
|
2009-06-19 04:03:23 +04:00
|
|
|
std::string::size_type StartOfMacroName = strlen("#define ");
|
2009-09-09 19:08:12 +04:00
|
|
|
std::string::size_type EndOfMacroName
|
2009-06-19 04:03:23 +04:00
|
|
|
= Missing.find_first_of("( \n\r", StartOfMacroName);
|
|
|
|
assert(EndOfMacroName != std::string::npos &&
|
|
|
|
"Couldn't find the end of the macro name");
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
|
2009-06-19 04:03:23 +04:00
|
|
|
|
2009-11-11 06:45:59 +03:00
|
|
|
// Determine whether this macro was given a different definition on the
|
|
|
|
// command line.
|
2009-11-11 08:26:28 +03:00
|
|
|
std::string MacroDefStart = "#define " + MacroName.str();
|
2009-06-19 04:03:23 +04:00
|
|
|
std::string::size_type MacroDefLen = MacroDefStart.size();
|
2009-11-11 06:45:59 +03:00
|
|
|
std::vector<llvm::StringRef>::iterator ConflictPos
|
2009-06-19 04:03:23 +04:00
|
|
|
= std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
|
|
|
|
MacroDefStart);
|
|
|
|
for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
|
2009-11-11 06:45:59 +03:00
|
|
|
if (!ConflictPos->startswith(MacroDefStart)) {
|
2009-06-19 04:03:23 +04:00
|
|
|
// Different macro; we're done.
|
|
|
|
ConflictPos = CmdLineLines.end();
|
2009-09-09 19:08:12 +04:00
|
|
|
break;
|
2009-06-19 04:03:23 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
|
|
|
assert(ConflictPos->size() > MacroDefLen &&
|
2009-06-19 04:03:23 +04:00
|
|
|
"Invalid #define in predefines buffer?");
|
2009-09-09 19:08:12 +04:00
|
|
|
if ((*ConflictPos)[MacroDefLen] != ' ' &&
|
2009-06-19 04:03:23 +04:00
|
|
|
(*ConflictPos)[MacroDefLen] != '(')
|
|
|
|
continue; // Longer macro name; keep trying.
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
// We found a conflicting macro definition.
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (ConflictPos != CmdLineLines.end()) {
|
|
|
|
Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
|
|
|
|
<< MacroName;
|
|
|
|
|
|
|
|
// Show the definition of this macro within the PCH file.
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
|
|
|
|
assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
|
|
|
|
SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
|
|
|
|
.getFileLocWithOffset(Offset);
|
|
|
|
Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
|
2009-06-19 04:03:23 +04:00
|
|
|
|
|
|
|
ConflictingDefines = true;
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-11-11 06:45:59 +03:00
|
|
|
// If the macro doesn't conflict, then we'll just pick up the macro
|
|
|
|
// definition from the PCH file. Warn the user that they made a mistake.
|
2009-06-19 04:03:23 +04:00
|
|
|
if (ConflictingDefines)
|
|
|
|
continue; // Don't complain if there are already conflicting defs
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (!MissingDefines) {
|
|
|
|
Reader.Diag(diag::warn_cmdline_missing_macro_defs);
|
|
|
|
MissingDefines = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show the definition of this macro within the PCH file.
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
|
|
|
|
assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
|
|
|
|
SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
|
2009-06-19 04:03:23 +04:00
|
|
|
.getFileLocWithOffset(Offset);
|
|
|
|
Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (ConflictingDefines)
|
|
|
|
return true;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
// Determine what predefines were introduced based on command-line
|
|
|
|
// parameters that were not present when building the PCH
|
|
|
|
// file. Extra #defines are okay, so long as the identifiers being
|
|
|
|
// defined were not used within the precompiled header.
|
2009-11-11 08:26:28 +03:00
|
|
|
std::vector<llvm::StringRef> ExtraPredefines;
|
2009-06-19 04:03:23 +04:00
|
|
|
std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
|
|
|
|
PCHLines.begin(), PCHLines.end(),
|
2009-09-09 19:08:12 +04:00
|
|
|
std::back_inserter(ExtraPredefines));
|
2009-06-19 04:03:23 +04:00
|
|
|
for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef &Extra = ExtraPredefines[I];
|
|
|
|
if (!Extra.startswith("#define ")) {
|
2009-06-19 04:03:23 +04:00
|
|
|
Reader.Diag(diag::warn_pch_compiler_options_mismatch);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is an extra macro definition. Determine the name of the
|
|
|
|
// macro we're defining.
|
|
|
|
std::string::size_type StartOfMacroName = strlen("#define ");
|
2009-09-09 19:08:12 +04:00
|
|
|
std::string::size_type EndOfMacroName
|
2009-06-19 04:03:23 +04:00
|
|
|
= Extra.find_first_of("( \n\r", StartOfMacroName);
|
|
|
|
assert(EndOfMacroName != std::string::npos &&
|
|
|
|
"Couldn't find the end of the macro name");
|
2009-11-11 08:26:28 +03:00
|
|
|
llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
|
2009-06-19 04:03:23 +04:00
|
|
|
|
|
|
|
// Check whether this name was used somewhere in the PCH file. If
|
|
|
|
// so, defining it as a macro could change behavior, so we reject
|
|
|
|
// the PCH file.
|
2009-11-11 08:26:28 +03:00
|
|
|
if (IdentifierInfo *II = Reader.get(MacroName)) {
|
2009-11-11 03:52:00 +03:00
|
|
|
Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
|
2009-06-19 04:03:23 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add this definition to the suggested predefines buffer.
|
|
|
|
SuggestedPredefines += Extra;
|
|
|
|
SuggestedPredefines += '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, it's because the predefines buffer had compatible
|
|
|
|
// contents. Accept the PCH file.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
|
|
|
|
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHValidator::ReadCounter(unsigned Value) {
|
|
|
|
PP.setCounterValue(Value);
|
|
|
|
}
|
|
|
|
|
2009-04-22 10:29:42 +04:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-27 09:14:47 +04:00
|
|
|
// PCH reader implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-26 22:52:16 +04:00
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
|
|
|
|
const char *isysroot)
|
2009-06-19 04:03:23 +04:00
|
|
|
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
|
|
|
|
FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
|
2009-10-16 22:18:30 +04:00
|
|
|
SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0),
|
2009-06-19 04:03:23 +04:00
|
|
|
IdentifierTableData(0), IdentifierLookupTable(0),
|
|
|
|
IdentifierOffsets(0),
|
|
|
|
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
|
|
|
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
|
2009-07-07 04:12:59 +04:00
|
|
|
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
|
2009-09-09 19:08:12 +04:00
|
|
|
NumStatHits(0), NumStatMisses(0),
|
|
|
|
NumSLocEntriesRead(0), NumStatementsRead(0),
|
2009-06-19 04:03:23 +04:00
|
|
|
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
|
2009-07-07 04:12:59 +04:00
|
|
|
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
|
2009-09-09 19:08:12 +04:00
|
|
|
CurrentlyLoadingTypeOrDecl(0) {
|
2009-07-07 04:12:59 +04:00
|
|
|
RelocatablePCH = false;
|
|
|
|
}
|
2009-06-19 04:03:23 +04:00
|
|
|
|
|
|
|
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
|
2009-09-09 19:08:12 +04:00
|
|
|
Diagnostic &Diags, const char *isysroot)
|
2009-06-19 04:03:23 +04:00
|
|
|
: SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags),
|
2009-10-16 22:18:30 +04:00
|
|
|
SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0),
|
2009-04-27 09:14:47 +04:00
|
|
|
IdentifierTableData(0), IdentifierLookupTable(0),
|
|
|
|
IdentifierOffsets(0),
|
|
|
|
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
|
|
|
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
|
2009-07-07 04:12:59 +04:00
|
|
|
TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
|
2009-09-09 19:08:12 +04:00
|
|
|
NumStatHits(0), NumStatMisses(0),
|
|
|
|
NumSLocEntriesRead(0), NumStatementsRead(0),
|
2009-04-27 10:38:32 +04:00
|
|
|
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
|
2009-07-06 22:54:52 +04:00
|
|
|
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
|
2009-09-09 19:08:12 +04:00
|
|
|
CurrentlyLoadingTypeOrDecl(0) {
|
2009-07-07 04:12:59 +04:00
|
|
|
RelocatablePCH = false;
|
|
|
|
}
|
2009-04-26 22:52:16 +04:00
|
|
|
|
2009-04-27 09:14:47 +04:00
|
|
|
PCHReader::~PCHReader() {}
|
2009-04-26 22:52:16 +04:00
|
|
|
|
2009-04-27 09:58:23 +04:00
|
|
|
Expr *PCHReader::ReadDeclExpr() {
|
|
|
|
return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor));
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *PCHReader::ReadTypeExpr() {
|
2009-10-17 04:13:19 +04:00
|
|
|
return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor));
|
2009-04-26 22:52:16 +04:00
|
|
|
}
|
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait {
|
|
|
|
PCHReader &Reader;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
|
|
|
|
|
|
|
|
typedef Selector external_key_type;
|
|
|
|
typedef external_key_type internal_key_type;
|
|
|
|
|
|
|
|
explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { }
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
static bool EqualKey(const internal_key_type& a,
|
|
|
|
const internal_key_type& b) {
|
|
|
|
return a == b;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
static unsigned ComputeHash(Selector Sel) {
|
|
|
|
unsigned N = Sel.getNumArgs();
|
|
|
|
if (N == 0)
|
|
|
|
++N;
|
|
|
|
unsigned R = 5381;
|
|
|
|
for (unsigned I = 0; I != N; ++I)
|
|
|
|
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
|
2009-10-18 03:52:28 +04:00
|
|
|
R = llvm::HashString(II->getName(), R);
|
2009-04-25 01:10:55 +04:00
|
|
|
return R;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
// This hopefully will just get inlined and removed by the optimizer.
|
|
|
|
static const internal_key_type&
|
|
|
|
GetInternalKey(const external_key_type& x) { return x; }
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
static std::pair<unsigned, unsigned>
|
|
|
|
ReadKeyDataLength(const unsigned char*& d) {
|
|
|
|
using namespace clang::io;
|
|
|
|
unsigned KeyLen = ReadUnalignedLE16(d);
|
|
|
|
unsigned DataLen = ReadUnalignedLE16(d);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 21:48:32 +04:00
|
|
|
internal_key_type ReadKey(const unsigned char* d, unsigned) {
|
2009-04-25 01:10:55 +04:00
|
|
|
using namespace clang::io;
|
2009-04-28 01:45:14 +04:00
|
|
|
SelectorTable &SelTable = Reader.getContext()->Selectors;
|
2009-04-25 01:10:55 +04:00
|
|
|
unsigned N = ReadUnalignedLE16(d);
|
2009-09-09 19:08:12 +04:00
|
|
|
IdentifierInfo *FirstII
|
2009-04-25 01:10:55 +04:00
|
|
|
= Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
|
|
|
|
if (N == 0)
|
|
|
|
return SelTable.getNullarySelector(FirstII);
|
|
|
|
else if (N == 1)
|
|
|
|
return SelTable.getUnarySelector(FirstII);
|
|
|
|
|
|
|
|
llvm::SmallVector<IdentifierInfo *, 16> Args;
|
|
|
|
Args.push_back(FirstII);
|
|
|
|
for (unsigned I = 1; I != N; ++I)
|
|
|
|
Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)));
|
|
|
|
|
2009-05-23 02:45:36 +04:00
|
|
|
return SelTable.getSelector(N, Args.data());
|
2009-04-25 01:10:55 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
unsigned NumInstanceMethods = ReadUnalignedLE16(d);
|
|
|
|
unsigned NumFactoryMethods = ReadUnalignedLE16(d);
|
|
|
|
|
|
|
|
data_type Result;
|
|
|
|
|
|
|
|
// Load instance methods
|
|
|
|
ObjCMethodList *Prev = 0;
|
|
|
|
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
|
2009-09-09 19:08:12 +04:00
|
|
|
ObjCMethodDecl *Method
|
2009-04-25 01:10:55 +04:00
|
|
|
= cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
|
|
|
|
if (!Result.first.Method) {
|
|
|
|
// This is the first method, which is the easy case.
|
|
|
|
Result.first.Method = Method;
|
|
|
|
Prev = &Result.first;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Prev->Next = new ObjCMethodList(Method, 0);
|
|
|
|
Prev = Prev->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load factory methods
|
|
|
|
Prev = 0;
|
|
|
|
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
|
2009-09-09 19:08:12 +04:00
|
|
|
ObjCMethodDecl *Method
|
2009-04-25 01:10:55 +04:00
|
|
|
= cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
|
|
|
|
if (!Result.second.Method) {
|
|
|
|
// This is the first method, which is the easy case.
|
|
|
|
Result.second.Method = Method;
|
|
|
|
Prev = &Result.second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Prev->Next = new ObjCMethodList(Method, 0);
|
|
|
|
Prev = Prev->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
};
|
2009-09-09 19:08:12 +04:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2009-04-25 01:10:55 +04:00
|
|
|
|
|
|
|
/// \brief The on-disk hash table used for the global method pool.
|
2009-09-09 19:08:12 +04:00
|
|
|
typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
|
2009-04-25 01:10:55 +04:00
|
|
|
PCHMethodPoolLookupTable;
|
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN PCHIdentifierLookupTrait {
|
|
|
|
PCHReader &Reader;
|
|
|
|
|
|
|
|
// If we know the IdentifierInfo in advance, it is here and we will
|
|
|
|
// not build a new one. Used when deserializing information about an
|
|
|
|
// identifier that was constructed before the PCH file was read.
|
|
|
|
IdentifierInfo *KnownII;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef IdentifierInfo * data_type;
|
|
|
|
|
|
|
|
typedef const std::pair<const char*, unsigned> external_key_type;
|
|
|
|
|
|
|
|
typedef external_key_type internal_key_type;
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0)
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
: Reader(Reader), KnownII(II) { }
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
static bool EqualKey(const internal_key_type& a,
|
|
|
|
const internal_key_type& b) {
|
|
|
|
return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0
|
|
|
|
: false;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
static unsigned ComputeHash(const internal_key_type& a) {
|
2009-10-18 03:52:28 +04:00
|
|
|
return llvm::HashString(llvm::StringRef(a.first, a.second));
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
// This hopefully will just get inlined and removed by the optimizer.
|
|
|
|
static const internal_key_type&
|
|
|
|
GetInternalKey(const external_key_type& x) { return x; }
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
static std::pair<unsigned, unsigned>
|
|
|
|
ReadKeyDataLength(const unsigned char*& d) {
|
|
|
|
using namespace clang::io;
|
2009-04-26 00:26:24 +04:00
|
|
|
unsigned DataLen = ReadUnalignedLE16(d);
|
2009-04-26 01:04:17 +04:00
|
|
|
unsigned KeyLen = ReadUnalignedLE16(d);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
static std::pair<const char*, unsigned>
|
|
|
|
ReadKey(const unsigned char* d, unsigned n) {
|
|
|
|
assert(n >= 2 && d[n-1] == '\0');
|
|
|
|
return std::make_pair((const char*) d, n-1);
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
|
|
|
IdentifierInfo *ReadData(const internal_key_type& k,
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
const unsigned char* d,
|
|
|
|
unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
2009-04-29 01:18:29 +04:00
|
|
|
pch::IdentID ID = ReadUnalignedLE32(d);
|
|
|
|
bool IsInteresting = ID & 0x01;
|
|
|
|
|
|
|
|
// Wipe out the "is interesting" bit.
|
|
|
|
ID = ID >> 1;
|
|
|
|
|
|
|
|
if (!IsInteresting) {
|
|
|
|
// For unintersting identifiers, just build the IdentifierInfo
|
|
|
|
// and associate it with the persistent ID.
|
|
|
|
IdentifierInfo *II = KnownII;
|
|
|
|
if (!II)
|
|
|
|
II = &Reader.getIdentifierTable().CreateIdentifierInfo(
|
|
|
|
k.first, k.first + k.second);
|
|
|
|
Reader.SetIdentifierInfo(ID, II);
|
|
|
|
return II;
|
|
|
|
}
|
|
|
|
|
2009-04-29 01:32:13 +04:00
|
|
|
unsigned Bits = ReadUnalignedLE16(d);
|
2009-04-22 22:49:13 +04:00
|
|
|
bool CPlusPlusOperatorKeyword = Bits & 0x01;
|
|
|
|
Bits >>= 1;
|
|
|
|
bool Poisoned = Bits & 0x01;
|
|
|
|
Bits >>= 1;
|
|
|
|
bool ExtensionToken = Bits & 0x01;
|
|
|
|
Bits >>= 1;
|
|
|
|
bool hasMacroDefinition = Bits & 0x01;
|
|
|
|
Bits >>= 1;
|
|
|
|
unsigned ObjCOrBuiltinID = Bits & 0x3FF;
|
|
|
|
Bits >>= 10;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-22 22:49:13 +04:00
|
|
|
assert(Bits == 0 && "Extra bits in the identifier?");
|
2009-04-29 01:32:13 +04:00
|
|
|
DataLen -= 6;
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
|
|
|
|
// Build the IdentifierInfo itself and link the identifier ID with
|
|
|
|
// the new IdentifierInfo.
|
|
|
|
IdentifierInfo *II = KnownII;
|
|
|
|
if (!II)
|
2009-04-26 00:26:24 +04:00
|
|
|
II = &Reader.getIdentifierTable().CreateIdentifierInfo(
|
|
|
|
k.first, k.first + k.second);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
Reader.SetIdentifierInfo(ID, II);
|
|
|
|
|
2009-04-22 22:49:13 +04:00
|
|
|
// Set or check the various bits in the IdentifierInfo structure.
|
|
|
|
// FIXME: Load token IDs lazily, too?
|
|
|
|
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
|
2009-09-09 19:08:12 +04:00
|
|
|
assert(II->isExtensionToken() == ExtensionToken &&
|
2009-04-22 22:49:13 +04:00
|
|
|
"Incorrect extension token flag");
|
|
|
|
(void)ExtensionToken;
|
|
|
|
II->setIsPoisoned(Poisoned);
|
|
|
|
assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
|
|
|
|
"Incorrect C++ operator keyword flag");
|
|
|
|
(void)CPlusPlusOperatorKeyword;
|
|
|
|
|
2009-04-22 03:56:24 +04:00
|
|
|
// If this identifier is a macro, deserialize the macro
|
|
|
|
// definition.
|
|
|
|
if (hasMacroDefinition) {
|
2009-04-29 01:32:13 +04:00
|
|
|
uint32_t Offset = ReadUnalignedLE32(d);
|
2009-04-22 03:56:24 +04:00
|
|
|
Reader.ReadMacroRecord(Offset);
|
2009-04-29 01:32:13 +04:00
|
|
|
DataLen -= 4;
|
2009-04-22 03:56:24 +04:00
|
|
|
}
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
|
|
|
|
// Read all of the declarations visible at global scope with this
|
|
|
|
// name.
|
2009-04-28 02:17:41 +04:00
|
|
|
if (Reader.getContext() == 0) return II;
|
2009-07-06 22:54:52 +04:00
|
|
|
if (DataLen > 0) {
|
|
|
|
llvm::SmallVector<uint32_t, 4> DeclIDs;
|
|
|
|
for (; DataLen > 0; DataLen -= 4)
|
|
|
|
DeclIDs.push_back(ReadUnalignedLE32(d));
|
|
|
|
Reader.SetGloballyVisibleDecls(II, DeclIDs);
|
2009-06-19 04:03:23 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
return II;
|
2009-04-28 22:58:38 +04:00
|
|
|
}
|
2009-06-19 04:03:23 +04:00
|
|
|
};
|
2009-09-09 19:08:12 +04:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2009-04-28 22:58:38 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
/// \brief The on-disk hash table used to contain information about
|
|
|
|
/// all of the identifiers in the program.
|
2009-09-09 19:08:12 +04:00
|
|
|
typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
|
2009-06-19 04:03:23 +04:00
|
|
|
PCHIdentifierLookupTable;
|
2009-04-28 22:58:38 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
bool PCHReader::Error(const char *Msg) {
|
|
|
|
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
|
|
|
|
Diag(DiagID);
|
|
|
|
return true;
|
2009-04-28 22:58:38 +04:00
|
|
|
}
|
|
|
|
|
2009-04-11 03:10:45 +04:00
|
|
|
/// \brief Check the contents of the predefines buffer against the
|
|
|
|
/// contents of the predefines buffer used to build the PCH file.
|
|
|
|
///
|
|
|
|
/// The contents of the two predefines buffers should be the same. If
|
|
|
|
/// not, then some command-line option changed the preprocessor state
|
|
|
|
/// and we must reject the PCH file.
|
|
|
|
///
|
|
|
|
/// \param PCHPredef The start of the predefines buffer in the PCH
|
|
|
|
/// file.
|
|
|
|
///
|
|
|
|
/// \param PCHPredefLen The length of the predefines buffer in the PCH
|
|
|
|
/// file.
|
|
|
|
///
|
|
|
|
/// \param PCHBufferID The FileID for the PCH predefines buffer.
|
|
|
|
///
|
|
|
|
/// \returns true if there was a mismatch (in which case the PCH file
|
|
|
|
/// should be ignored), or false otherwise.
|
2009-11-11 03:52:11 +03:00
|
|
|
bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef,
|
2009-04-11 03:10:45 +04:00
|
|
|
FileID PCHBufferID) {
|
2009-06-19 04:03:23 +04:00
|
|
|
if (Listener)
|
2009-11-11 03:52:11 +03:00
|
|
|
return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID,
|
2009-11-11 08:29:04 +03:00
|
|
|
ActualOriginalFileName,
|
2009-06-19 04:03:23 +04:00
|
|
|
SuggestedPredefines);
|
2009-04-28 22:58:38 +04:00
|
|
|
return false;
|
2009-04-11 03:10:45 +04:00
|
|
|
}
|
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Source Manager Deserialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-13 20:31:14 +04:00
|
|
|
/// \brief Read the line table in the source manager block.
|
|
|
|
/// \returns true if ther was an error.
|
2009-07-07 04:12:59 +04:00
|
|
|
bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) {
|
2009-04-13 20:31:14 +04:00
|
|
|
unsigned Idx = 0;
|
|
|
|
LineTableInfo &LineTable = SourceMgr.getLineTable();
|
|
|
|
|
|
|
|
// Parse the file names
|
2009-04-13 21:12:42 +04:00
|
|
|
std::map<int, int> FileIDs;
|
|
|
|
for (int I = 0, N = Record[Idx++]; I != N; ++I) {
|
2009-04-13 20:31:14 +04:00
|
|
|
// Extract the file name
|
|
|
|
unsigned FilenameLen = Record[Idx++];
|
|
|
|
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
|
|
|
|
Idx += FilenameLen;
|
2009-07-07 04:12:59 +04:00
|
|
|
MaybeAddSystemRootToFilename(Filename);
|
2009-09-09 19:08:12 +04:00
|
|
|
FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
|
2009-04-13 21:12:42 +04:00
|
|
|
Filename.size());
|
2009-04-13 20:31:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the line entries
|
|
|
|
std::vector<LineEntry> Entries;
|
|
|
|
while (Idx < Record.size()) {
|
2009-04-13 21:12:42 +04:00
|
|
|
int FID = FileIDs[Record[Idx++]];
|
2009-04-13 20:31:14 +04:00
|
|
|
|
|
|
|
// Extract the line entries
|
|
|
|
unsigned NumEntries = Record[Idx++];
|
|
|
|
Entries.clear();
|
|
|
|
Entries.reserve(NumEntries);
|
|
|
|
for (unsigned I = 0; I != NumEntries; ++I) {
|
|
|
|
unsigned FileOffset = Record[Idx++];
|
|
|
|
unsigned LineNo = Record[Idx++];
|
|
|
|
int FilenameID = Record[Idx++];
|
2009-09-09 19:08:12 +04:00
|
|
|
SrcMgr::CharacteristicKind FileKind
|
2009-04-13 20:31:14 +04:00
|
|
|
= (SrcMgr::CharacteristicKind)Record[Idx++];
|
|
|
|
unsigned IncludeOffset = Record[Idx++];
|
|
|
|
Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
|
|
|
|
FileKind, IncludeOffset));
|
|
|
|
}
|
|
|
|
LineTable.AddEntry(FID, Entries);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class VISIBILITY_HIDDEN PCHStatData {
|
|
|
|
public:
|
|
|
|
const bool hasStat;
|
|
|
|
const ino_t ino;
|
|
|
|
const dev_t dev;
|
|
|
|
const mode_t mode;
|
|
|
|
const time_t mtime;
|
|
|
|
const off_t size;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
|
2009-09-09 19:08:12 +04:00
|
|
|
: hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
|
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
PCHStatData()
|
|
|
|
: hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class VISIBILITY_HIDDEN PCHStatLookupTrait {
|
|
|
|
public:
|
|
|
|
typedef const char *external_key_type;
|
|
|
|
typedef const char *internal_key_type;
|
|
|
|
|
|
|
|
typedef PCHStatData data_type;
|
|
|
|
|
|
|
|
static unsigned ComputeHash(const char *path) {
|
2009-10-18 03:52:28 +04:00
|
|
|
return llvm::HashString(path);
|
2009-04-27 22:38:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static internal_key_type GetInternalKey(const char *path) { return path; }
|
|
|
|
|
|
|
|
static bool EqualKey(internal_key_type a, internal_key_type b) {
|
|
|
|
return strcmp(a, b) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::pair<unsigned, unsigned>
|
|
|
|
ReadKeyDataLength(const unsigned char*& d) {
|
|
|
|
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
|
|
|
|
unsigned DataLen = (unsigned) *d++;
|
|
|
|
return std::make_pair(KeyLen + 1, DataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static internal_key_type ReadKey(const unsigned char *d, unsigned) {
|
|
|
|
return (const char *)d;
|
|
|
|
}
|
|
|
|
|
|
|
|
static data_type ReadData(const internal_key_type, const unsigned char *d,
|
|
|
|
unsigned /*DataLen*/) {
|
|
|
|
using namespace clang::io;
|
|
|
|
|
|
|
|
if (*d++ == 1)
|
|
|
|
return data_type();
|
|
|
|
|
|
|
|
ino_t ino = (ino_t) ReadUnalignedLE32(d);
|
|
|
|
dev_t dev = (dev_t) ReadUnalignedLE32(d);
|
|
|
|
mode_t mode = (mode_t) ReadUnalignedLE16(d);
|
2009-09-09 19:08:12 +04:00
|
|
|
time_t mtime = (time_t) ReadUnalignedLE64(d);
|
2009-04-27 22:38:38 +04:00
|
|
|
off_t size = (off_t) ReadUnalignedLE64(d);
|
|
|
|
return data_type(ino, dev, mode, mtime, size);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief stat() cache for precompiled headers.
|
|
|
|
///
|
|
|
|
/// This cache is very similar to the stat cache used by pretokenized
|
|
|
|
/// headers.
|
|
|
|
class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache {
|
|
|
|
typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy;
|
|
|
|
CacheTy *Cache;
|
|
|
|
|
|
|
|
unsigned &NumStatHits, &NumStatMisses;
|
2009-09-09 19:08:12 +04:00
|
|
|
public:
|
2009-04-27 22:38:38 +04:00
|
|
|
PCHStatCache(const unsigned char *Buckets,
|
|
|
|
const unsigned char *Base,
|
|
|
|
unsigned &NumStatHits,
|
2009-09-09 19:08:12 +04:00
|
|
|
unsigned &NumStatMisses)
|
2009-04-27 22:38:38 +04:00
|
|
|
: Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
|
|
|
|
Cache = CacheTy::Create(Buckets, Base);
|
|
|
|
}
|
|
|
|
|
|
|
|
~PCHStatCache() { delete Cache; }
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
int stat(const char *path, struct stat *buf) {
|
|
|
|
// Do the lookup for the file's data in the PCH file.
|
|
|
|
CacheTy::iterator I = Cache->find(path);
|
|
|
|
|
|
|
|
// If we don't get a hit in the PCH file just forward to 'stat'.
|
|
|
|
if (I == Cache->end()) {
|
|
|
|
++NumStatMisses;
|
2009-10-16 22:18:30 +04:00
|
|
|
return StatSysCallCache::stat(path, buf);
|
2009-04-27 22:38:38 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
++NumStatHits;
|
|
|
|
PCHStatData Data = *I;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
if (!Data.hasStat)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
buf->st_ino = Data.ino;
|
|
|
|
buf->st_dev = Data.dev;
|
|
|
|
buf->st_mtime = Data.mtime;
|
|
|
|
buf->st_mode = Data.mode;
|
|
|
|
buf->st_size = Data.size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
|
2009-04-10 07:52:48 +04:00
|
|
|
/// \brief Read the source manager block
|
2009-04-11 03:10:45 +04:00
|
|
|
PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
|
2009-04-10 07:52:48 +04:00
|
|
|
using namespace SrcMgr;
|
2009-04-27 10:38:32 +04: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 = Stream;
|
|
|
|
|
|
|
|
// The stream itself is going to skip over the source manager block.
|
|
|
|
if (Stream.SkipBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-27 10:38:32 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enter the source manager block.
|
|
|
|
if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed source manager block record in PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 07:52:48 +04:00
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
while (true) {
|
2009-04-27 10:38:32 +04:00
|
|
|
unsigned Code = SLocEntryCursor.ReadCode();
|
2009-04-10 07:52:48 +04:00
|
|
|
if (Code == llvm::bitc::END_BLOCK) {
|
2009-04-27 10:38:32 +04:00
|
|
|
if (SLocEntryCursor.ReadBlockEnd()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("error at end of Source Manager block in PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
return Success;
|
2009-04-10 07:52:48 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-10 07:52:48 +04:00
|
|
|
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
|
|
|
// No known subblocks, always skip them.
|
2009-04-27 10:38:32 +04:00
|
|
|
SLocEntryCursor.ReadSubBlockID();
|
|
|
|
if (SLocEntryCursor.SkipBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 07:52:48 +04:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-10 07:52:48 +04:00
|
|
|
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
2009-04-27 10:38:32 +04:00
|
|
|
SLocEntryCursor.ReadAbbrevRecord();
|
2009-04-10 07:52:48 +04:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-10 07:52:48 +04:00
|
|
|
// Read a record.
|
|
|
|
const char *BlobStart;
|
|
|
|
unsigned BlobLen;
|
|
|
|
Record.clear();
|
2009-04-27 10:38:32 +04:00
|
|
|
switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
|
2009-04-10 07:52:48 +04:00
|
|
|
default: // Default behavior: ignore.
|
|
|
|
break;
|
|
|
|
|
2009-04-15 03:22:57 +04:00
|
|
|
case pch::SM_LINE_TABLE:
|
2009-07-07 04:12:59 +04:00
|
|
|
if (ParseLineTable(Record))
|
2009-04-13 20:31:14 +04:00
|
|
|
return Failure;
|
2009-04-15 03:22:57 +04:00
|
|
|
break;
|
2009-04-26 04:07:37 +04:00
|
|
|
|
|
|
|
case pch::SM_HEADER_FILE_INFO: {
|
|
|
|
HeaderFileInfo HFI;
|
|
|
|
HFI.isImport = Record[0];
|
|
|
|
HFI.DirInfo = Record[1];
|
|
|
|
HFI.NumIncludes = Record[2];
|
|
|
|
HFI.ControllingMacroID = Record[3];
|
2009-06-19 04:03:23 +04:00
|
|
|
if (Listener)
|
|
|
|
Listener->ReadHeaderFileInfo(HFI);
|
2009-04-26 04:07:37 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-04-27 10:38:32 +04:00
|
|
|
|
|
|
|
case pch::SM_SLOC_FILE_ENTRY:
|
|
|
|
case pch::SM_SLOC_BUFFER_ENTRY:
|
|
|
|
case pch::SM_SLOC_INSTANTIATION_ENTRY:
|
|
|
|
// Once we hit one of the source location entries, we're done.
|
|
|
|
return Success;
|
2009-04-10 07:52:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-27 10:38:32 +04:00
|
|
|
/// \brief Read in the source location entry with the given ID.
|
|
|
|
PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
|
|
|
|
if (ID == 0)
|
|
|
|
return Success;
|
|
|
|
|
|
|
|
if (ID > TotalNumSLocEntries) {
|
|
|
|
Error("source location entry ID out-of-range for PCH file");
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
++NumSLocEntriesRead;
|
|
|
|
SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]);
|
|
|
|
unsigned Code = SLocEntryCursor.ReadCode();
|
|
|
|
if (Code == llvm::bitc::END_BLOCK ||
|
|
|
|
Code == llvm::bitc::ENTER_SUBBLOCK ||
|
|
|
|
Code == llvm::bitc::DEFINE_ABBREV) {
|
|
|
|
Error("incorrectly-formatted source location entry in PCH file");
|
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
const char *BlobStart;
|
|
|
|
unsigned BlobLen;
|
|
|
|
switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
|
|
|
|
default:
|
|
|
|
Error("incorrectly-formatted source location entry in PCH file");
|
|
|
|
return Failure;
|
|
|
|
|
|
|
|
case pch::SM_SLOC_FILE_ENTRY: {
|
2009-07-07 04:12:59 +04:00
|
|
|
std::string Filename(BlobStart, BlobStart + BlobLen);
|
|
|
|
MaybeAddSystemRootToFilename(Filename);
|
|
|
|
const FileEntry *File = FileMgr.getFile(Filename);
|
2009-06-15 08:35:16 +04:00
|
|
|
if (File == 0) {
|
|
|
|
std::string ErrorStr = "could not find file '";
|
2009-07-07 04:12:59 +04:00
|
|
|
ErrorStr += Filename;
|
2009-06-15 08:35:16 +04:00
|
|
|
ErrorStr += "' referenced by PCH file";
|
|
|
|
Error(ErrorStr.c_str());
|
|
|
|
return Failure;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 10:38:32 +04:00
|
|
|
FileID FID = SourceMgr.createFileID(File,
|
|
|
|
SourceLocation::getFromRawEncoding(Record[1]),
|
|
|
|
(SrcMgr::CharacteristicKind)Record[2],
|
|
|
|
ID, Record[0]);
|
|
|
|
if (Record[3])
|
|
|
|
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
|
|
|
|
.setHasLineDirectives();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case pch::SM_SLOC_BUFFER_ENTRY: {
|
|
|
|
const char *Name = BlobStart;
|
|
|
|
unsigned Offset = Record[0];
|
|
|
|
unsigned Code = SLocEntryCursor.ReadCode();
|
|
|
|
Record.clear();
|
2009-09-09 19:08:12 +04:00
|
|
|
unsigned RecCode
|
2009-04-27 10:38:32 +04:00
|
|
|
= SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
|
|
|
|
assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
|
|
|
|
(void)RecCode;
|
|
|
|
llvm::MemoryBuffer *Buffer
|
2009-09-09 19:08:12 +04:00
|
|
|
= llvm::MemoryBuffer::getMemBuffer(BlobStart,
|
2009-04-27 10:38:32 +04:00
|
|
|
BlobStart + BlobLen - 1,
|
|
|
|
Name);
|
|
|
|
FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-29 00:33:11 +04:00
|
|
|
if (strcmp(Name, "<built-in>") == 0) {
|
|
|
|
PCHPredefinesBufferID = BufferID;
|
|
|
|
PCHPredefines = BlobStart;
|
|
|
|
PCHPredefinesLen = BlobLen - 1;
|
|
|
|
}
|
2009-04-27 10:38:32 +04:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case pch::SM_SLOC_INSTANTIATION_ENTRY: {
|
2009-09-09 19:08:12 +04:00
|
|
|
SourceLocation SpellingLoc
|
2009-04-27 10:38:32 +04:00
|
|
|
= SourceLocation::getFromRawEncoding(Record[1]);
|
|
|
|
SourceMgr.createInstantiationLoc(SpellingLoc,
|
|
|
|
SourceLocation::getFromRawEncoding(Record[2]),
|
|
|
|
SourceLocation::getFromRawEncoding(Record[3]),
|
|
|
|
Record[4],
|
|
|
|
ID,
|
|
|
|
Record[0]);
|
|
|
|
break;
|
2009-09-09 19:08:12 +04:00
|
|
|
}
|
2009-04-27 10:38:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
2009-04-27 05:05:14 +04:00
|
|
|
/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
|
|
|
|
/// specified cursor. Read the abbreviations that are at the top of the block
|
|
|
|
/// and then leave the cursor pointing into the block.
|
|
|
|
bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
|
|
|
|
unsigned BlockID) {
|
|
|
|
if (Cursor.EnterSubBlock(BlockID)) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-27 05:05:14 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 05:05:14 +04:00
|
|
|
while (true) {
|
|
|
|
unsigned Code = Cursor.ReadCode();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-27 05:05:14 +04:00
|
|
|
// We expect all abbrevs to be at the start of the block.
|
|
|
|
if (Code != llvm::bitc::DEFINE_ABBREV)
|
|
|
|
return false;
|
|
|
|
Cursor.ReadAbbrevRecord();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-22 03:56:24 +04:00
|
|
|
void PCHReader::ReadMacroRecord(uint64_t Offset) {
|
2009-06-19 04:03:23 +04:00
|
|
|
assert(PP && "Forgot to set Preprocessor ?");
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-22 03:56:24 +04:00
|
|
|
// Keep track of where we are in the stream, then jump back there
|
|
|
|
// after reading this macro.
|
|
|
|
SavedStreamPosition SavedPosition(Stream);
|
|
|
|
|
|
|
|
Stream.JumpToBit(Offset);
|
2009-04-11 01:41:48 +04:00
|
|
|
RecordData Record;
|
|
|
|
llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
|
2009-04-22 03:56:24 +04:00
|
|
|
MacroInfo *Macro = 0;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
while (true) {
|
|
|
|
unsigned Code = Stream.ReadCode();
|
|
|
|
switch (Code) {
|
|
|
|
case llvm::bitc::END_BLOCK:
|
2009-04-22 03:56:24 +04:00
|
|
|
return;
|
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
case llvm::bitc::ENTER_SUBBLOCK:
|
|
|
|
// No known subblocks, always skip them.
|
|
|
|
Stream.ReadSubBlockID();
|
2009-04-22 03:56:24 +04:00
|
|
|
if (Stream.SkipBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-22 03:56:24 +04:00
|
|
|
return;
|
|
|
|
}
|
2009-04-11 01:41:48 +04:00
|
|
|
continue;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
case llvm::bitc::DEFINE_ABBREV:
|
|
|
|
Stream.ReadAbbrevRecord();
|
|
|
|
continue;
|
|
|
|
default: break;
|
|
|
|
}
|
2009-04-22 03:56:24 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
// Read a record.
|
|
|
|
Record.clear();
|
|
|
|
pch::PreprocessorRecordTypes RecType =
|
|
|
|
(pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record);
|
|
|
|
switch (RecType) {
|
|
|
|
case pch::PP_MACRO_OBJECT_LIKE:
|
|
|
|
case pch::PP_MACRO_FUNCTION_LIKE: {
|
2009-04-22 03:56:24 +04:00
|
|
|
// If we already have a macro, that means that we've hit the end
|
|
|
|
// of the definition of the macro we were looking for. We're
|
|
|
|
// done.
|
|
|
|
if (Macro)
|
|
|
|
return;
|
|
|
|
|
2009-04-12 01:15:38 +04:00
|
|
|
IdentifierInfo *II = DecodeIdentifierInfo(Record[0]);
|
2009-04-22 03:56:24 +04:00
|
|
|
if (II == 0) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("macro must have a name in PCH file");
|
2009-04-22 03:56:24 +04:00
|
|
|
return;
|
|
|
|
}
|
2009-04-11 01:41:48 +04:00
|
|
|
SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]);
|
|
|
|
bool isUsed = Record[2];
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
MacroInfo *MI = PP->AllocateMacroInfo(Loc);
|
2009-04-11 01:41:48 +04:00
|
|
|
MI->setIsUsed(isUsed);
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
|
|
|
|
// Decode function-like macro info.
|
|
|
|
bool isC99VarArgs = Record[3];
|
|
|
|
bool isGNUVarArgs = Record[4];
|
|
|
|
MacroArgs.clear();
|
|
|
|
unsigned NumArgs = Record[5];
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i)
|
2009-04-12 01:15:38 +04:00
|
|
|
MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
|
2009-04-11 01:41:48 +04:00
|
|
|
|
|
|
|
// Install function-like macro info.
|
|
|
|
MI->setIsFunctionLike();
|
|
|
|
if (isC99VarArgs) MI->setIsC99Varargs();
|
|
|
|
if (isGNUVarArgs) MI->setIsGNUVarargs();
|
2009-05-23 02:45:36 +04:00
|
|
|
MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
|
2009-06-19 04:03:23 +04:00
|
|
|
PP->getPreprocessorAllocator());
|
2009-04-11 01:41:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, install the macro.
|
2009-06-19 04:03:23 +04:00
|
|
|
PP->setMacroInfo(II, MI);
|
2009-04-11 01:41:48 +04:00
|
|
|
|
|
|
|
// Remember that we saw this macro last so that we add the tokens that
|
|
|
|
// form its body to it.
|
2009-04-22 03:56:24 +04:00
|
|
|
Macro = MI;
|
|
|
|
++NumMacrosRead;
|
2009-04-11 01:41:48 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
case pch::PP_TOKEN: {
|
2009-04-22 03:56:24 +04:00
|
|
|
// 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;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 01:41:48 +04:00
|
|
|
Token Tok;
|
|
|
|
Tok.startToken();
|
|
|
|
Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0]));
|
|
|
|
Tok.setLength(Record[1]);
|
2009-04-12 01:15:38 +04:00
|
|
|
if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
|
|
|
|
Tok.setIdentifierInfo(II);
|
2009-04-11 01:41:48 +04:00
|
|
|
Tok.setKind((tok::TokenKind)Record[3]);
|
|
|
|
Tok.setFlag((Token::TokenFlags)Record[4]);
|
2009-04-22 03:56:24 +04:00
|
|
|
Macro->AddTokenToBody(Tok);
|
2009-04-11 01:41:48 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-04-25 00:03:17 +04:00
|
|
|
}
|
2009-04-11 01:41:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
/// \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 PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) {
|
|
|
|
// If this is not a relocatable PCH file, there's nothing to do.
|
|
|
|
if (!RelocatablePCH)
|
|
|
|
return;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
if (Filename.empty() || Filename[0] == '/' || Filename[0] == '<')
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::string FIXME = Filename;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
if (isysroot == 0) {
|
|
|
|
// If no system root was given, default to '/'
|
|
|
|
Filename.insert(Filename.begin(), '/');
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
unsigned Length = strlen(isysroot);
|
|
|
|
if (isysroot[Length - 1] != '/')
|
|
|
|
Filename.insert(Filename.begin(), '/');
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
Filename.insert(Filename.begin(), isysroot, isysroot + Length);
|
|
|
|
}
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
PCHReader::PCHReadResult
|
2009-04-26 04:07:37 +04:00
|
|
|
PCHReader::ReadPCHBlock() {
|
2009-04-11 00:39:37 +04:00
|
|
|
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
|
2009-04-10 21:25:41 +04:00
|
|
|
// Read all of the records and blocks for the PCH file.
|
2009-04-10 02:27:44 +04:00
|
|
|
RecordData Record;
|
2009-04-10 21:25:41 +04:00
|
|
|
while (!Stream.AtEndOfStream()) {
|
2009-04-10 02:27:44 +04:00
|
|
|
unsigned Code = Stream.ReadCode();
|
|
|
|
if (Code == llvm::bitc::END_BLOCK) {
|
2009-04-11 00:39:37 +04:00
|
|
|
if (Stream.ReadBlockEnd()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("error at end of module block in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-12 01:15:38 +04:00
|
|
|
|
2009-04-11 00:39:37 +04:00
|
|
|
return Success;
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
2009-04-10 21:25:41 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
2009-04-10 21:25:41 +04:00
|
|
|
switch (Stream.ReadSubBlockID()) {
|
2009-10-17 04:13:19 +04:00
|
|
|
case pch::DECLTYPES_BLOCK_ID:
|
2009-04-27 05:05:14 +04:00
|
|
|
// 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.
|
|
|
|
DeclsCursor = Stream;
|
|
|
|
if (Stream.SkipBlock() || // Skip with the main cursor.
|
|
|
|
// Read the abbrevs.
|
2009-10-17 04:13:19 +04:00
|
|
|
ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-27 05:05:14 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
break;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-12 01:15:38 +04:00
|
|
|
case pch::PREPROCESSOR_BLOCK_ID:
|
|
|
|
if (Stream.SkipBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-12 01:15:38 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
break;
|
2009-04-23 14:39:46 +04:00
|
|
|
|
2009-04-10 21:25:41 +04:00
|
|
|
case pch::SOURCE_MANAGER_BLOCK_ID:
|
2009-04-11 03:10:45 +04:00
|
|
|
switch (ReadSourceManagerBlock()) {
|
|
|
|
case Success:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Failure:
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed source manager block in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
2009-04-11 03:10:45 +04:00
|
|
|
|
|
|
|
case IgnorePCH:
|
|
|
|
return IgnorePCH;
|
2009-04-11 00:39:37 +04:00
|
|
|
}
|
2009-04-10 21:25:41 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
continue;
|
|
|
|
}
|
2009-04-10 21:25:41 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
|
|
|
Stream.ReadAbbrevRecord();
|
|
|
|
continue;
|
|
|
|
}
|
2009-04-10 21:25:41 +04:00
|
|
|
|
|
|
|
// Read and process a record.
|
2009-04-10 02:27:44 +04:00
|
|
|
Record.clear();
|
2009-04-11 01:16:55 +04:00
|
|
|
const char *BlobStart = 0;
|
|
|
|
unsigned BlobLen = 0;
|
2009-09-09 19:08:12 +04:00
|
|
|
switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record,
|
2009-04-11 01:16:55 +04:00
|
|
|
&BlobStart, &BlobLen)) {
|
2009-04-10 02:27:44 +04:00
|
|
|
default: // Default behavior: ignore.
|
|
|
|
break;
|
2009-04-10 21:25:41 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
case pch::TYPE_OFFSET:
|
2009-04-25 22:35:21 +04:00
|
|
|
if (!TypesLoaded.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate TYPE_OFFSET record in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-27 22:24:17 +04:00
|
|
|
TypeOffsets = (const uint32_t *)BlobStart;
|
2009-04-25 22:35:21 +04:00
|
|
|
TypesLoaded.resize(Record[0]);
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case pch::DECL_OFFSET:
|
2009-04-25 22:35:21 +04:00
|
|
|
if (!DeclsLoaded.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate DECL_OFFSET record in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-27 22:24:17 +04:00
|
|
|
DeclOffsets = (const uint32_t *)BlobStart;
|
2009-04-25 22:35:21 +04:00
|
|
|
DeclsLoaded.resize(Record[0]);
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
2009-04-11 00:39:37 +04:00
|
|
|
|
|
|
|
case pch::LANGUAGE_OPTIONS:
|
|
|
|
if (ParseLanguageOptions(Record))
|
|
|
|
return IgnorePCH;
|
|
|
|
break;
|
2009-04-11 01:16:55 +04:00
|
|
|
|
2009-04-28 02:23:34 +04:00
|
|
|
case pch::METADATA: {
|
|
|
|
if (Record[0] != pch::VERSION_MAJOR) {
|
|
|
|
Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old
|
|
|
|
: diag::warn_pch_version_too_new);
|
|
|
|
return IgnorePCH;
|
|
|
|
}
|
|
|
|
|
2009-07-07 04:12:59 +04:00
|
|
|
RelocatablePCH = Record[4];
|
2009-06-19 04:03:23 +04:00
|
|
|
if (Listener) {
|
|
|
|
std::string TargetTriple(BlobStart, BlobLen);
|
|
|
|
if (Listener->ReadTargetTriple(TargetTriple))
|
|
|
|
return IgnorePCH;
|
2009-04-11 01:16:55 +04:00
|
|
|
}
|
|
|
|
break;
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
2009-04-11 04:14:32 +04:00
|
|
|
|
|
|
|
case pch::IDENTIFIER_TABLE:
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
IdentifierTableData = BlobStart;
|
2009-04-25 23:10:14 +04:00
|
|
|
if (Record[0]) {
|
2009-09-09 19:08:12 +04:00
|
|
|
IdentifierLookupTable
|
2009-04-25 23:10:14 +04:00
|
|
|
= PCHIdentifierLookupTable::Create(
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
(const unsigned char *)IdentifierTableData + Record[0],
|
2009-09-09 19:08:12 +04:00
|
|
|
(const unsigned char *)IdentifierTableData,
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
PCHIdentifierLookupTrait(*this));
|
2009-06-19 04:03:23 +04:00
|
|
|
if (PP)
|
|
|
|
PP->getIdentifierTable().setExternalIdentifierLookup(this);
|
2009-04-25 23:10:14 +04:00
|
|
|
}
|
2009-04-11 04:14:32 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case pch::IDENTIFIER_OFFSET:
|
2009-04-25 23:10:14 +04:00
|
|
|
if (!IdentifiersLoaded.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate IDENTIFIER_OFFSET record in PCH file");
|
2009-04-11 04:14:32 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-25 23:10:14 +04:00
|
|
|
IdentifierOffsets = (const uint32_t *)BlobStart;
|
|
|
|
IdentifiersLoaded.resize(Record[0]);
|
2009-06-19 04:03:23 +04:00
|
|
|
if (PP)
|
|
|
|
PP->getHeaderSearchInfo().SetExternalLookup(this);
|
2009-04-11 04:14:32 +04:00
|
|
|
break;
|
2009-04-14 04:24:19 +04:00
|
|
|
|
|
|
|
case pch::EXTERNAL_DEFINITIONS:
|
|
|
|
if (!ExternalDefinitions.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate EXTERNAL_DEFINITIONS record in PCH file");
|
2009-04-14 04:24:19 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
ExternalDefinitions.swap(Record);
|
|
|
|
break;
|
2009-04-18 02:13:46 +04:00
|
|
|
|
2009-04-18 09:55:16 +04:00
|
|
|
case pch::SPECIAL_TYPES:
|
|
|
|
SpecialTypes.swap(Record);
|
|
|
|
break;
|
|
|
|
|
2009-04-18 02:13:46 +04:00
|
|
|
case pch::STATISTICS:
|
|
|
|
TotalNumStatements = Record[0];
|
2009-04-22 03:56:24 +04:00
|
|
|
TotalNumMacros = Record[1];
|
2009-04-23 02:34:57 +04:00
|
|
|
TotalLexicalDeclContexts = Record[2];
|
|
|
|
TotalVisibleDeclContexts = Record[3];
|
2009-04-18 02:13:46 +04:00
|
|
|
break;
|
2009-04-27 10:38:32 +04:00
|
|
|
|
2009-04-23 02:02:47 +04:00
|
|
|
case pch::TENTATIVE_DEFINITIONS:
|
|
|
|
if (!TentativeDefinitions.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate TENTATIVE_DEFINITIONS record in PCH file");
|
2009-04-23 02:02:47 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
TentativeDefinitions.swap(Record);
|
|
|
|
break;
|
2009-04-23 02:18:58 +04:00
|
|
|
|
|
|
|
case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
|
|
|
|
if (!LocallyScopedExternalDecls.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
|
2009-04-23 02:18:58 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
LocallyScopedExternalDecls.swap(Record);
|
|
|
|
break;
|
2009-04-25 01:10:55 +04:00
|
|
|
|
2009-04-25 21:48:32 +04:00
|
|
|
case pch::SELECTOR_OFFSETS:
|
|
|
|
SelectorOffsets = (const uint32_t *)BlobStart;
|
|
|
|
TotalNumSelectors = Record[0];
|
|
|
|
SelectorsLoaded.resize(TotalNumSelectors);
|
|
|
|
break;
|
|
|
|
|
2009-04-25 01:10:55 +04:00
|
|
|
case pch::METHOD_POOL:
|
2009-04-25 21:48:32 +04:00
|
|
|
MethodPoolLookupTableData = (const unsigned char *)BlobStart;
|
|
|
|
if (Record[0])
|
2009-09-09 19:08:12 +04:00
|
|
|
MethodPoolLookupTable
|
2009-04-25 21:48:32 +04:00
|
|
|
= PCHMethodPoolLookupTable::Create(
|
|
|
|
MethodPoolLookupTableData + Record[0],
|
2009-09-09 19:08:12 +04:00
|
|
|
MethodPoolLookupTableData,
|
2009-04-25 01:10:55 +04:00
|
|
|
PCHMethodPoolLookupTrait(*this));
|
2009-04-25 21:48:32 +04:00
|
|
|
TotalSelectorsInMethodPool = Record[1];
|
2009-04-25 01:10:55 +04:00
|
|
|
break;
|
2009-04-26 04:07:37 +04:00
|
|
|
|
|
|
|
case pch::PP_COUNTER_VALUE:
|
2009-06-19 04:03:23 +04:00
|
|
|
if (!Record.empty() && Listener)
|
|
|
|
Listener->ReadCounter(Record[0]);
|
2009-04-26 04:07:37 +04:00
|
|
|
break;
|
2009-04-27 10:38:32 +04:00
|
|
|
|
|
|
|
case pch::SOURCE_LOCATION_OFFSETS:
|
2009-04-27 23:01:47 +04:00
|
|
|
SLocOffsets = (const uint32_t *)BlobStart;
|
2009-04-27 10:38:32 +04:00
|
|
|
TotalNumSLocEntries = Record[0];
|
2009-10-06 01:07:28 +04:00
|
|
|
SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]);
|
2009-04-27 10:38:32 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case pch::SOURCE_LOCATION_PRELOADS:
|
|
|
|
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
|
|
|
|
PCHReadResult Result = ReadSLocEntryRecord(Record[I]);
|
|
|
|
if (Result != Success)
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
break;
|
2009-04-27 22:38:38 +04:00
|
|
|
|
2009-10-16 22:18:30 +04:00
|
|
|
case pch::STAT_CACHE: {
|
|
|
|
PCHStatCache *MyStatCache =
|
|
|
|
new PCHStatCache((const unsigned char *)BlobStart + Record[0],
|
|
|
|
(const unsigned char *)BlobStart,
|
|
|
|
NumStatHits, NumStatMisses);
|
|
|
|
FileMgr.addStatCache(MyStatCache);
|
|
|
|
StatCache = MyStatCache;
|
2009-04-27 22:38:38 +04:00
|
|
|
break;
|
2009-10-16 22:18:30 +04:00
|
|
|
}
|
|
|
|
|
2009-04-28 00:06:05 +04:00
|
|
|
case pch::EXT_VECTOR_DECLS:
|
|
|
|
if (!ExtVectorDecls.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("duplicate EXT_VECTOR_DECLS record in PCH file");
|
2009-04-28 00:06:05 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
|
|
|
ExtVectorDecls.swap(Record);
|
|
|
|
break;
|
|
|
|
|
2009-05-12 05:31:05 +04:00
|
|
|
case pch::ORIGINAL_FILE_NAME:
|
2009-11-11 08:29:04 +03:00
|
|
|
ActualOriginalFileName.assign(BlobStart, BlobLen);
|
|
|
|
OriginalFileName = ActualOriginalFileName;
|
2009-07-07 04:12:59 +04:00
|
|
|
MaybeAddSystemRootToFilename(OriginalFileName);
|
2009-05-12 05:31:05 +04:00
|
|
|
break;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74704 91177308-0d34-0410-b5e6-96231b3b80d8
2009-07-02 21:08:52 +04:00
|
|
|
case pch::COMMENT_RANGES:
|
|
|
|
Comments = (SourceRange *)BlobStart;
|
|
|
|
NumComments = BlobLen / sizeof(SourceRange);
|
|
|
|
break;
|
2009-10-06 01:07:28 +04:00
|
|
|
|
|
|
|
case pch::SVN_BRANCH_REVISION: {
|
|
|
|
unsigned CurRevision = getClangSubversionRevision();
|
|
|
|
if (Record[0] && CurRevision && Record[0] != CurRevision) {
|
|
|
|
Diag(Record[0] < CurRevision? diag::warn_pch_version_too_old
|
|
|
|
: diag::warn_pch_version_too_new);
|
|
|
|
return IgnorePCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *CurBranch = getClangSubversionPath();
|
|
|
|
if (strncmp(CurBranch, BlobStart, BlobLen)) {
|
|
|
|
std::string PCHBranch(BlobStart, BlobLen);
|
|
|
|
Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
|
|
|
|
return IgnorePCH;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-04-11 04:14:32 +04:00
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("premature end of bitstream in PCH file");
|
2009-04-11 00:39:37 +04:00
|
|
|
return Failure;
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
2009-04-11 03:10:45 +04:00
|
|
|
PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
2009-04-11 00:39:37 +04:00
|
|
|
// Set the PCH file name.
|
|
|
|
this->FileName = FileName;
|
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
// Open the PCH file.
|
2009-09-22 09:38:01 +04:00
|
|
|
//
|
|
|
|
// FIXME: This shouldn't be here, we should just take a raw_ostream.
|
2009-04-10 02:27:44 +04:00
|
|
|
std::string ErrStr;
|
2009-11-10 03:46:19 +03:00
|
|
|
Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr));
|
2009-04-11 03:10:45 +04:00
|
|
|
if (!Buffer) {
|
|
|
|
Error(ErrStr.c_str());
|
|
|
|
return IgnorePCH;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
// Initialize the stream
|
2009-09-09 19:08:12 +04:00
|
|
|
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
|
2009-04-27 00:59:20 +04:00
|
|
|
(const unsigned char *)Buffer->getBufferEnd());
|
|
|
|
Stream.init(StreamFile);
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
// Sniff for the signature.
|
|
|
|
if (Stream.Read(8) != 'C' ||
|
|
|
|
Stream.Read(8) != 'P' ||
|
|
|
|
Stream.Read(8) != 'C' ||
|
2009-04-11 03:10:45 +04:00
|
|
|
Stream.Read(8) != 'H') {
|
2009-04-29 01:53:25 +04:00
|
|
|
Diag(diag::err_not_a_pch_file) << FileName;
|
|
|
|
return Failure;
|
2009-04-11 03:10:45 +04:00
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
while (!Stream.AtEndOfStream()) {
|
|
|
|
unsigned Code = Stream.ReadCode();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-11 03:10:45 +04:00
|
|
|
if (Code != llvm::bitc::ENTER_SUBBLOCK) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("invalid record at top-level of PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
unsigned BlockID = Stream.ReadSubBlockID();
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
// We only know the PCH subblock ID.
|
|
|
|
switch (BlockID) {
|
|
|
|
case llvm::bitc::BLOCKINFO_BLOCK_ID:
|
2009-04-11 03:10:45 +04:00
|
|
|
if (Stream.ReadBlockInfoBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed BlockInfoBlock in PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
|
|
|
case pch::PCH_BLOCK_ID:
|
2009-04-26 04:07:37 +04:00
|
|
|
switch (ReadPCHBlock()) {
|
2009-04-11 00:39:37 +04:00
|
|
|
case Success:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Failure:
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
2009-04-11 00:39:37 +04:00
|
|
|
|
|
|
|
case IgnorePCH:
|
2009-04-11 01:16:55 +04:00
|
|
|
// FIXME: We could consider reading through to the end of this
|
|
|
|
// PCH block, skipping subblocks, to see if there are other
|
|
|
|
// PCH blocks elsewhere.
|
2009-04-28 01:28:04 +04:00
|
|
|
|
|
|
|
// Clear out any preallocated source location entries, so that
|
|
|
|
// the source manager does not try to resolve them later.
|
2009-06-19 04:03:23 +04:00
|
|
|
SourceMgr.ClearPreallocatedSLocEntries();
|
2009-04-28 01:28:04 +04:00
|
|
|
|
|
|
|
// Remove the stat cache.
|
2009-10-16 22:18:30 +04:00
|
|
|
if (StatCache)
|
|
|
|
FileMgr.removeStatCache((PCHStatCache*)StatCache);
|
2009-04-28 01:28:04 +04:00
|
|
|
|
2009-04-11 03:10:45 +04:00
|
|
|
return IgnorePCH;
|
2009-04-11 00:39:37 +04:00
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
|
|
|
default:
|
2009-04-11 03:10:45 +04:00
|
|
|
if (Stream.SkipBlock()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("malformed block record in PCH file");
|
2009-04-11 03:10:45 +04:00
|
|
|
return Failure;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
}
|
|
|
|
|
2009-04-29 00:33:11 +04:00
|
|
|
// Check the predefines buffer.
|
2009-11-11 03:52:11 +03:00
|
|
|
if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen),
|
2009-04-29 00:33:11 +04:00
|
|
|
PCHPredefinesBufferID))
|
|
|
|
return IgnorePCH;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (PP) {
|
2009-07-18 13:26:51 +04:00
|
|
|
// Initialization of keywords and pragmas occurs before the
|
2009-06-19 04:03:23 +04:00
|
|
|
// PCH file is read, so there may be some identifiers that were
|
|
|
|
// loaded into the IdentifierTable before we intercepted the
|
|
|
|
// creation of identifiers. Iterate through the list of known
|
|
|
|
// identifiers and determine whether we have to establish
|
|
|
|
// preprocessor definitions or top-level identifier declaration
|
|
|
|
// chains for those identifiers.
|
|
|
|
//
|
|
|
|
// We copy the IdentifierInfo pointers to a small vector first,
|
|
|
|
// since de-serializing declarations or macro definitions can add
|
|
|
|
// new entries into the identifier table, invalidating the
|
|
|
|
// iterators.
|
|
|
|
llvm::SmallVector<IdentifierInfo *, 128> Identifiers;
|
|
|
|
for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(),
|
|
|
|
IdEnd = PP->getIdentifierTable().end();
|
|
|
|
Id != IdEnd; ++Id)
|
|
|
|
Identifiers.push_back(Id->second);
|
2009-09-09 19:08:12 +04:00
|
|
|
PCHIdentifierLookupTable *IdTable
|
2009-06-19 04:03:23 +04:00
|
|
|
= (PCHIdentifierLookupTable *)IdentifierLookupTable;
|
|
|
|
for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
|
|
|
|
IdentifierInfo *II = Identifiers[I];
|
|
|
|
// Look in the on-disk hash table for an entry for
|
|
|
|
PCHIdentifierLookupTrait Info(*this, II);
|
2009-10-19 00:26:12 +04:00
|
|
|
std::pair<const char*, unsigned> Key(II->getNameStart(), II->getLength());
|
2009-06-19 04:03:23 +04:00
|
|
|
PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info);
|
|
|
|
if (Pos == IdTable->end())
|
|
|
|
continue;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
// Dereferencing the iterator has the effect of populating the
|
|
|
|
// IdentifierInfo node with the various declarations it needs.
|
|
|
|
(void)*Pos;
|
|
|
|
}
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
}
|
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (Context)
|
|
|
|
InitializeContext(*Context);
|
2009-04-15 01:18:50 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
return Success;
|
2009-04-15 01:18:50 +04:00
|
|
|
}
|
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
void PCHReader::InitializeContext(ASTContext &Ctx) {
|
|
|
|
Context = &Ctx;
|
|
|
|
assert(Context && "Passed null context!");
|
|
|
|
|
|
|
|
assert(PP && "Forgot to set Preprocessor ?");
|
|
|
|
PP->getIdentifierTable().setExternalIdentifierLookup(this);
|
|
|
|
PP->getHeaderSearchInfo().SetExternalLookup(this);
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
// Load the translation unit declaration
|
|
|
|
ReadDeclRecord(DeclOffsets[0], 0);
|
|
|
|
|
|
|
|
// Load the special types.
|
|
|
|
Context->setBuiltinVaListType(
|
|
|
|
GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST]));
|
|
|
|
if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID])
|
|
|
|
Context->setObjCIdType(GetType(Id));
|
|
|
|
if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR])
|
|
|
|
Context->setObjCSelType(GetType(Sel));
|
|
|
|
if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL])
|
|
|
|
Context->setObjCProtoType(GetType(Proto));
|
|
|
|
if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
|
|
|
|
Context->setObjCClassType(GetType(Class));
|
2009-07-11 03:34:53 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
|
|
|
|
Context->setCFConstantStringType(GetType(String));
|
2009-09-09 19:08:12 +04:00
|
|
|
if (unsigned FastEnum
|
2009-06-19 04:03:23 +04:00
|
|
|
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE])
|
|
|
|
Context->setObjCFastEnumerationStateType(GetType(FastEnum));
|
2009-07-07 20:35:42 +04:00
|
|
|
if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) {
|
|
|
|
QualType FileType = GetType(File);
|
|
|
|
assert(!FileType.isNull() && "FILE type is NULL");
|
2009-09-22 03:43:11 +04:00
|
|
|
if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
|
2009-07-07 20:35:42 +04:00
|
|
|
Context->setFILEDecl(Typedef->getDecl());
|
|
|
|
else {
|
2009-07-30 01:53:49 +04:00
|
|
|
const TagType *Tag = FileType->getAs<TagType>();
|
2009-07-07 20:35:42 +04:00
|
|
|
assert(Tag && "Invalid FILE type in PCH file");
|
|
|
|
Context->setFILEDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
2009-07-28 06:25:19 +04:00
|
|
|
if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) {
|
|
|
|
QualType Jmp_bufType = GetType(Jmp_buf);
|
|
|
|
assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL");
|
2009-09-22 03:43:11 +04:00
|
|
|
if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
|
2009-07-28 06:25:19 +04:00
|
|
|
Context->setjmp_bufDecl(Typedef->getDecl());
|
|
|
|
else {
|
2009-07-30 01:53:49 +04:00
|
|
|
const TagType *Tag = Jmp_bufType->getAs<TagType>();
|
2009-07-28 06:25:19 +04:00
|
|
|
assert(Tag && "Invalid jmp_bug type in PCH file");
|
|
|
|
Context->setjmp_bufDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) {
|
|
|
|
QualType Sigjmp_bufType = GetType(Sigjmp_buf);
|
|
|
|
assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL");
|
2009-09-22 03:43:11 +04:00
|
|
|
if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
|
2009-07-28 06:25:19 +04:00
|
|
|
Context->setsigjmp_bufDecl(Typedef->getDecl());
|
|
|
|
else {
|
2009-07-30 01:53:49 +04:00
|
|
|
const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
|
2009-07-28 06:25:19 +04:00
|
|
|
assert(Tag && "Invalid sigjmp_buf type in PCH file");
|
|
|
|
Context->setsigjmp_bufDecl(Tag->getDecl());
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
if (unsigned ObjCIdRedef
|
2009-08-21 04:27:50 +04:00
|
|
|
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID_REDEFINITION])
|
|
|
|
Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef);
|
2009-09-09 19:08:12 +04:00
|
|
|
if (unsigned ObjCClassRedef
|
2009-08-21 04:27:50 +04:00
|
|
|
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
|
|
|
|
Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
|
2009-10-20 06:12:22 +04:00
|
|
|
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR])
|
|
|
|
Context->setBlockDescriptorType(GetType(String));
|
2009-10-22 04:49:09 +04:00
|
|
|
if (unsigned String
|
|
|
|
= SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR])
|
|
|
|
Context->setBlockDescriptorExtendedType(GetType(String));
|
2009-06-19 04:03:23 +04:00
|
|
|
}
|
|
|
|
|
2009-05-12 05:31:05 +04:00
|
|
|
/// \brief Retrieve the name of the original source file name
|
|
|
|
/// directly from the PCH file, without actually loading the PCH
|
|
|
|
/// file.
|
|
|
|
std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
|
|
|
|
// Open the PCH file.
|
|
|
|
std::string ErrStr;
|
|
|
|
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
|
|
|
|
Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
|
|
|
|
if (!Buffer) {
|
|
|
|
fprintf(stderr, "error: %s\n", ErrStr.c_str());
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the stream
|
|
|
|
llvm::BitstreamReader StreamFile;
|
|
|
|
llvm::BitstreamCursor Stream;
|
2009-09-09 19:08:12 +04:00
|
|
|
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
|
2009-05-12 05:31:05 +04:00
|
|
|
(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') {
|
2009-09-09 19:08:12 +04:00
|
|
|
fprintf(stderr,
|
2009-05-12 05:31:05 +04:00
|
|
|
"error: '%s' does not appear to be a precompiled header file\n",
|
|
|
|
PCHFileName.c_str());
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
while (!Stream.AtEndOfStream()) {
|
|
|
|
unsigned Code = Stream.ReadCode();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-05-12 05:31:05 +04:00
|
|
|
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
|
|
|
unsigned BlockID = Stream.ReadSubBlockID();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-05-12 05:31:05 +04:00
|
|
|
// We only know the PCH subblock ID.
|
|
|
|
switch (BlockID) {
|
|
|
|
case pch::PCH_BLOCK_ID:
|
|
|
|
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
|
|
|
|
fprintf(stderr, "error: malformed block record in PCH file\n");
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
break;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-05-12 05:31:05 +04:00
|
|
|
default:
|
|
|
|
if (Stream.SkipBlock()) {
|
|
|
|
fprintf(stderr, "error: malformed block record in PCH file\n");
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Code == llvm::bitc::END_BLOCK) {
|
|
|
|
if (Stream.ReadBlockEnd()) {
|
|
|
|
fprintf(stderr, "error: error at end of module block in PCH file\n");
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
|
|
|
Stream.ReadAbbrevRecord();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.clear();
|
|
|
|
const char *BlobStart = 0;
|
|
|
|
unsigned BlobLen = 0;
|
2009-09-09 19:08:12 +04:00
|
|
|
if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
|
2009-05-12 05:31:05 +04:00
|
|
|
== pch::ORIGINAL_FILE_NAME)
|
|
|
|
return std::string(BlobStart, BlobLen);
|
2009-09-09 19:08:12 +04:00
|
|
|
}
|
2009-05-12 05:31:05 +04:00
|
|
|
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
2009-04-11 00:39:37 +04:00
|
|
|
/// \brief Parse the record that corresponds to a LangOptions data
|
|
|
|
/// structure.
|
|
|
|
///
|
|
|
|
/// This routine compares the language options used to generate the
|
|
|
|
/// PCH file against the language options set for the current
|
|
|
|
/// compilation. For each option, we classify differences between the
|
|
|
|
/// two compiler states as either "benign" or "important". Benign
|
|
|
|
/// differences don't matter, and we accept them without complaint
|
|
|
|
/// (and without modifying the language options). Differences between
|
|
|
|
/// the states for important options cause the PCH file to be
|
|
|
|
/// unusable, so we emit a warning and return true to indicate that
|
|
|
|
/// there was an error.
|
|
|
|
///
|
|
|
|
/// \returns true if the PCH file is unacceptable, false otherwise.
|
|
|
|
bool PCHReader::ParseLanguageOptions(
|
|
|
|
const llvm::SmallVectorImpl<uint64_t> &Record) {
|
2009-06-19 04:03:23 +04:00
|
|
|
if (Listener) {
|
|
|
|
LangOptions LangOpts;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
#define PARSE_LANGOPT(Option) \
|
|
|
|
LangOpts.Option = Record[Idx]; \
|
|
|
|
++Idx
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
unsigned Idx = 0;
|
|
|
|
PARSE_LANGOPT(Trigraphs);
|
|
|
|
PARSE_LANGOPT(BCPLComment);
|
|
|
|
PARSE_LANGOPT(DollarIdents);
|
|
|
|
PARSE_LANGOPT(AsmPreprocessor);
|
|
|
|
PARSE_LANGOPT(GNUMode);
|
|
|
|
PARSE_LANGOPT(ImplicitInt);
|
|
|
|
PARSE_LANGOPT(Digraphs);
|
|
|
|
PARSE_LANGOPT(HexFloats);
|
|
|
|
PARSE_LANGOPT(C99);
|
|
|
|
PARSE_LANGOPT(Microsoft);
|
|
|
|
PARSE_LANGOPT(CPlusPlus);
|
|
|
|
PARSE_LANGOPT(CPlusPlus0x);
|
|
|
|
PARSE_LANGOPT(CXXOperatorNames);
|
|
|
|
PARSE_LANGOPT(ObjC1);
|
|
|
|
PARSE_LANGOPT(ObjC2);
|
|
|
|
PARSE_LANGOPT(ObjCNonFragileABI);
|
|
|
|
PARSE_LANGOPT(PascalStrings);
|
|
|
|
PARSE_LANGOPT(WritableStrings);
|
|
|
|
PARSE_LANGOPT(LaxVectorConversions);
|
2009-06-26 03:01:11 +04:00
|
|
|
PARSE_LANGOPT(AltiVec);
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT(Exceptions);
|
|
|
|
PARSE_LANGOPT(NeXTRuntime);
|
|
|
|
PARSE_LANGOPT(Freestanding);
|
|
|
|
PARSE_LANGOPT(NoBuiltin);
|
|
|
|
PARSE_LANGOPT(ThreadsafeStatics);
|
2009-09-03 18:36:33 +04:00
|
|
|
PARSE_LANGOPT(POSIXThreads);
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT(Blocks);
|
|
|
|
PARSE_LANGOPT(EmitAllDecls);
|
|
|
|
PARSE_LANGOPT(MathErrno);
|
|
|
|
PARSE_LANGOPT(OverflowChecking);
|
|
|
|
PARSE_LANGOPT(HeinousExtensions);
|
|
|
|
PARSE_LANGOPT(Optimize);
|
|
|
|
PARSE_LANGOPT(OptimizeSize);
|
|
|
|
PARSE_LANGOPT(Static);
|
|
|
|
PARSE_LANGOPT(PICLevel);
|
|
|
|
PARSE_LANGOPT(GNUInline);
|
|
|
|
PARSE_LANGOPT(NoInline);
|
|
|
|
PARSE_LANGOPT(AccessControl);
|
|
|
|
PARSE_LANGOPT(CharIsSigned);
|
2009-11-05 23:14:16 +03:00
|
|
|
PARSE_LANGOPT(ShortWChar);
|
2009-06-19 04:03:23 +04:00
|
|
|
LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]);
|
|
|
|
++Idx;
|
|
|
|
LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]);
|
|
|
|
++Idx;
|
2009-09-21 08:16:19 +04:00
|
|
|
LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode)
|
|
|
|
Record[Idx]);
|
|
|
|
++Idx;
|
2009-06-19 04:03:23 +04:00
|
|
|
PARSE_LANGOPT(InstantiationDepth);
|
2009-06-26 03:01:11 +04:00
|
|
|
PARSE_LANGOPT(OpenCL);
|
2009-06-19 04:03:23 +04:00
|
|
|
#undef PARSE_LANGOPT
|
|
|
|
|
|
|
|
return Listener->ReadLanguageOptions(LangOpts);
|
2009-04-11 00:39:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74704 91177308-0d34-0410-b5e6-96231b3b80d8
2009-07-02 21:08:52 +04:00
|
|
|
void PCHReader::ReadComments(std::vector<SourceRange> &Comments) {
|
|
|
|
Comments.resize(NumComments);
|
|
|
|
std::copy(this->Comments, this->Comments + NumComments,
|
|
|
|
Comments.begin());
|
|
|
|
}
|
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
/// \brief Read and return the type at the given offset.
|
|
|
|
///
|
|
|
|
/// This routine actually reads the record corresponding to the type
|
|
|
|
/// at the given offset in the bitstream. It is a helper routine for
|
|
|
|
/// GetType, which deals with reading type IDs.
|
|
|
|
QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
2009-04-15 01:18:50 +04:00
|
|
|
// Keep track of where we are in the stream, then jump back there
|
|
|
|
// after reading this type.
|
2009-10-17 04:13:19 +04:00
|
|
|
SavedStreamPosition SavedPosition(DeclsCursor);
|
2009-04-15 01:18:50 +04:00
|
|
|
|
2009-07-06 22:54:52 +04:00
|
|
|
// Note that we are loading a type record.
|
|
|
|
LoadingTypeOrDecl Loading(*this);
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-10-17 04:13:19 +04:00
|
|
|
DeclsCursor.JumpToBit(Offset);
|
2009-04-10 02:27:44 +04:00
|
|
|
RecordData Record;
|
2009-10-17 04:13:19 +04:00
|
|
|
unsigned Code = DeclsCursor.ReadCode();
|
|
|
|
switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
|
2009-04-16 02:00:08 +04:00
|
|
|
case pch::TYPE_EXT_QUAL: {
|
2009-09-24 23:53:00 +04:00
|
|
|
assert(Record.size() == 2 &&
|
2009-04-16 02:00:08 +04:00
|
|
|
"Incorrect encoding of extended qualifier type");
|
|
|
|
QualType Base = GetType(Record[0]);
|
2009-09-24 23:53:00 +04:00
|
|
|
Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
|
|
|
|
return Context->getQualifiedType(Base, Quals);
|
2009-04-16 02:00:08 +04:00
|
|
|
}
|
2009-04-14 00:46:52 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
case pch::TYPE_FIXED_WIDTH_INT: {
|
|
|
|
assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getFixedWidthIntType(Record[0], Record[1]);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_COMPLEX: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of complex type");
|
|
|
|
QualType ElemType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getComplexType(ElemType);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_POINTER: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of pointer type");
|
|
|
|
QualType PointeeType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getPointerType(PointeeType);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_BLOCK_POINTER: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
|
|
|
|
QualType PointeeType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getBlockPointerType(PointeeType);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_LVALUE_REFERENCE: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
|
|
|
|
QualType PointeeType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getLValueReferenceType(PointeeType);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_RVALUE_REFERENCE: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
|
|
|
|
QualType PointeeType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getRValueReferenceType(PointeeType);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_MEMBER_POINTER: {
|
|
|
|
assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
|
|
|
|
QualType PointeeType = GetType(Record[0]);
|
|
|
|
QualType ClassType = GetType(Record[1]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
2009-04-14 00:46:52 +04:00
|
|
|
case pch::TYPE_CONSTANT_ARRAY: {
|
|
|
|
QualType ElementType = GetType(Record[0]);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
|
|
|
unsigned Idx = 3;
|
|
|
|
llvm::APInt Size = ReadAPInt(Record, Idx);
|
2009-07-06 19:59:29 +04:00
|
|
|
return Context->getConstantArrayType(ElementType, Size,
|
|
|
|
ASM, IndexTypeQuals);
|
|
|
|
}
|
|
|
|
|
2009-04-14 00:46:52 +04:00
|
|
|
case pch::TYPE_INCOMPLETE_ARRAY: {
|
|
|
|
QualType ElementType = GetType(Record[0]);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_VARIABLE_ARRAY: {
|
2009-04-15 01:18:50 +04:00
|
|
|
QualType ElementType = GetType(Record[0]);
|
|
|
|
ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
|
|
|
|
unsigned IndexTypeQuals = Record[2];
|
2009-07-06 19:59:29 +04:00
|
|
|
SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]);
|
|
|
|
SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getVariableArrayType(ElementType, ReadTypeExpr(),
|
2009-07-06 19:59:29 +04:00
|
|
|
ASM, IndexTypeQuals,
|
|
|
|
SourceRange(LBLoc, RBLoc));
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_VECTOR: {
|
|
|
|
if (Record.size() != 2) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("incorrect encoding of vector type in PCH file");
|
2009-04-14 00:46:52 +04:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ElementType = GetType(Record[0]);
|
|
|
|
unsigned NumElements = Record[1];
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getVectorType(ElementType, NumElements);
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_EXT_VECTOR: {
|
|
|
|
if (Record.size() != 2) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("incorrect encoding of extended vector type in PCH file");
|
2009-04-14 00:46:52 +04:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ElementType = GetType(Record[0]);
|
|
|
|
unsigned NumElements = Record[1];
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getExtVectorType(ElementType, NumElements);
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_FUNCTION_NO_PROTO: {
|
|
|
|
if (Record.size() != 1) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("incorrect encoding of no-proto function type");
|
2009-04-14 00:46:52 +04:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType ResultType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getFunctionNoProtoType(ResultType);
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_FUNCTION_PROTO: {
|
|
|
|
QualType ResultType = GetType(Record[0]);
|
|
|
|
unsigned Idx = 1;
|
|
|
|
unsigned NumParams = Record[Idx++];
|
|
|
|
llvm::SmallVector<QualType, 16> ParamTypes;
|
|
|
|
for (unsigned I = 0; I != NumParams; ++I)
|
|
|
|
ParamTypes.push_back(GetType(Record[Idx++]));
|
|
|
|
bool isVariadic = Record[Idx++];
|
|
|
|
unsigned Quals = Record[Idx++];
|
2009-05-28 02:11:52 +04:00
|
|
|
bool hasExceptionSpec = Record[Idx++];
|
|
|
|
bool hasAnyExceptionSpec = Record[Idx++];
|
|
|
|
unsigned NumExceptions = Record[Idx++];
|
|
|
|
llvm::SmallVector<QualType, 2> Exceptions;
|
|
|
|
for (unsigned I = 0; I != NumExceptions; ++I)
|
|
|
|
Exceptions.push_back(GetType(Record[Idx++]));
|
2009-05-21 13:52:38 +04:00
|
|
|
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
|
2009-05-28 02:11:52 +04:00
|
|
|
isVariadic, Quals, hasExceptionSpec,
|
|
|
|
hasAnyExceptionSpec, NumExceptions,
|
|
|
|
Exceptions.data());
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
case pch::TYPE_TYPEDEF:
|
2009-04-29 01:53:25 +04:00
|
|
|
assert(Record.size() == 1 && "incorrect encoding of typedef type");
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
|
2009-04-14 00:46:52 +04:00
|
|
|
|
|
|
|
case pch::TYPE_TYPEOF_EXPR:
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getTypeOfExprType(ReadTypeExpr());
|
2009-04-14 00:46:52 +04:00
|
|
|
|
|
|
|
case pch::TYPE_TYPEOF: {
|
|
|
|
if (Record.size() != 1) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("incorrect encoding of typeof(type) in PCH file");
|
2009-04-14 00:46:52 +04:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
QualType UnderlyingType = GetType(Record[0]);
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getTypeOfType(UnderlyingType);
|
2009-04-14 00:46:52 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-24 23:06:50 +04:00
|
|
|
case pch::TYPE_DECLTYPE:
|
|
|
|
return Context->getDecltypeType(ReadTypeExpr());
|
|
|
|
|
2009-04-14 00:46:52 +04:00
|
|
|
case pch::TYPE_RECORD:
|
2009-04-29 01:53:25 +04:00
|
|
|
assert(Record.size() == 1 && "incorrect encoding of record type");
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
|
2009-04-14 00:46:52 +04:00
|
|
|
|
2009-04-13 22:14:40 +04:00
|
|
|
case pch::TYPE_ENUM:
|
2009-04-29 01:53:25 +04:00
|
|
|
assert(Record.size() == 1 && "incorrect encoding of enum type");
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
|
2009-04-13 22:14:40 +04:00
|
|
|
|
2009-09-05 04:15:47 +04:00
|
|
|
case pch::TYPE_ELABORATED: {
|
|
|
|
assert(Record.size() == 2 && "incorrect encoding of elaborated type");
|
|
|
|
unsigned Tag = Record[1];
|
|
|
|
return Context->getElaboratedType(GetType(Record[0]),
|
|
|
|
(ElaboratedType::TagKind) Tag);
|
|
|
|
}
|
|
|
|
|
2009-07-18 19:33:26 +04:00
|
|
|
case pch::TYPE_OBJC_INTERFACE: {
|
2009-04-22 10:45:28 +04:00
|
|
|
unsigned Idx = 0;
|
|
|
|
ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
|
|
|
|
unsigned NumProtos = Record[Idx++];
|
|
|
|
llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
|
|
|
|
for (unsigned I = 0; I != NumProtos; ++I)
|
|
|
|
Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
|
2009-07-18 19:33:26 +04:00
|
|
|
return Context->getObjCInterfaceType(ItfD, Protos.data(), NumProtos);
|
2009-04-22 10:45:28 +04:00
|
|
|
}
|
2009-04-14 00:46:52 +04:00
|
|
|
|
2009-06-18 02:40:22 +04:00
|
|
|
case pch::TYPE_OBJC_OBJECT_POINTER: {
|
2009-04-22 10:40:03 +04:00
|
|
|
unsigned Idx = 0;
|
2009-07-11 03:34:53 +04:00
|
|
|
QualType OIT = GetType(Record[Idx++]);
|
2009-04-22 10:40:03 +04:00
|
|
|
unsigned NumProtos = Record[Idx++];
|
|
|
|
llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
|
|
|
|
for (unsigned I = 0; I != NumProtos; ++I)
|
|
|
|
Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
|
2009-07-11 03:34:53 +04:00
|
|
|
return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos);
|
2009-04-22 10:40:03 +04:00
|
|
|
}
|
2009-09-29 23:42:55 +04:00
|
|
|
|
2009-10-18 13:09:24 +04:00
|
|
|
case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: {
|
|
|
|
unsigned Idx = 0;
|
|
|
|
QualType Parm = GetType(Record[Idx++]);
|
|
|
|
QualType Replacement = GetType(Record[Idx++]);
|
|
|
|
return
|
|
|
|
Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
|
|
|
|
Replacement);
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
// Suppress a GCC warning
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2009-10-17 01:56:05 +04:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
|
|
|
|
PCHReader &Reader;
|
|
|
|
const PCHReader::RecordData &Record;
|
|
|
|
unsigned &Idx;
|
|
|
|
|
|
|
|
public:
|
|
|
|
TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record,
|
|
|
|
unsigned &Idx)
|
|
|
|
: Reader(Reader), Record(Record), Idx(Idx) { }
|
|
|
|
|
2009-10-18 05:05:36 +04:00
|
|
|
// 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)
|
2009-10-17 01:56:05 +04:00
|
|
|
#define TYPELOC(CLASS, PARENT) \
|
2009-10-18 05:05:36 +04:00
|
|
|
void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
|
2009-10-17 01:56:05 +04:00
|
|
|
#include "clang/AST/TypeLocNodes.def"
|
|
|
|
|
2009-10-18 05:05:36 +04:00
|
|
|
void VisitFunctionTypeLoc(FunctionTypeLoc);
|
|
|
|
void VisitArrayTypeLoc(ArrayTypeLoc);
|
2009-10-17 01:56:05 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
2009-10-17 01:56:05 +04:00
|
|
|
// nothing to do
|
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
|
|
|
TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
|
|
|
|
TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
|
|
|
|
TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
|
|
|
|
TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
if (Record[Idx++])
|
2009-10-18 05:05:36 +04:00
|
|
|
TL.setSizeExpr(Reader.ReadDeclExpr());
|
2009-10-17 04:13:19 +04:00
|
|
|
else
|
2009-10-18 05:05:36 +04:00
|
|
|
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(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
|
|
|
|
TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
|
2009-10-23 05:28:53 +04:00
|
|
|
TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
|
2009-10-18 05:05:36 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
2009-10-18 13:09:24 +04:00
|
|
|
void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
|
|
|
|
SubstTemplateTypeParmTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
2009-10-18 05:05:36 +04:00
|
|
|
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
|
|
|
|
TemplateSpecializationTypeLoc TL) {
|
2009-10-29 11:12:44 +03:00
|
|
|
TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
|
|
|
TL.setArgLocInfo(i,
|
|
|
|
Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(),
|
|
|
|
Record, Idx));
|
2009-10-18 05:05:36 +04:00
|
|
|
}
|
|
|
|
void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
}
|
|
|
|
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
|
|
|
|
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-23 02:37:11 +04:00
|
|
|
TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
|
|
|
|
TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-18 05:05:36 +04:00
|
|
|
}
|
|
|
|
void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
|
|
|
|
TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
|
|
|
TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-23 02:37:11 +04:00
|
|
|
TL.setHasBaseTypeAsWritten(Record[Idx++]);
|
|
|
|
TL.setHasProtocolsAsWritten(Record[Idx++]);
|
|
|
|
if (TL.hasProtocolsAsWritten())
|
|
|
|
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
|
|
|
|
TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
|
2009-10-17 01:56:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record,
|
|
|
|
unsigned &Idx) {
|
|
|
|
QualType InfoTy = GetType(Record[Idx++]);
|
|
|
|
if (InfoTy.isNull())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy);
|
|
|
|
TypeLocReader TLR(*this, Record, Idx);
|
|
|
|
for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
|
|
|
|
TLR.Visit(TL);
|
|
|
|
return DInfo;
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
|
2009-04-10 21:25:41 +04:00
|
|
|
QualType PCHReader::GetType(pch::TypeID ID) {
|
2009-09-24 23:53:00 +04:00
|
|
|
unsigned FastQuals = ID & Qualifiers::FastMask;
|
|
|
|
unsigned Index = ID >> Qualifiers::FastWidth;
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
if (Index < pch::NUM_PREDEF_TYPE_IDS) {
|
|
|
|
QualType T;
|
|
|
|
switch ((pch::PredefinedTypeIDs)Index) {
|
|
|
|
case pch::PREDEF_TYPE_NULL_ID: return QualType();
|
2009-04-28 01:45:14 +04:00
|
|
|
case pch::PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break;
|
|
|
|
case pch::PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break;
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
case pch::PREDEF_TYPE_CHAR_U_ID:
|
|
|
|
case pch::PREDEF_TYPE_CHAR_S_ID:
|
|
|
|
// FIXME: Check that the signedness of CharTy is correct!
|
2009-04-28 01:45:14 +04:00
|
|
|
T = Context->CharTy;
|
2009-04-10 02:27:44 +04:00
|
|
|
break;
|
|
|
|
|
2009-04-28 01:45:14 +04:00
|
|
|
case pch::PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break;
|
|
|
|
case pch::PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break;
|
|
|
|
case pch::PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break;
|
|
|
|
case pch::PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break;
|
|
|
|
case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break;
|
2009-04-30 06:43:43 +04:00
|
|
|
case pch::PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break;
|
2009-04-28 01:45:14 +04:00
|
|
|
case pch::PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break;
|
|
|
|
case pch::PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break;
|
|
|
|
case pch::PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break;
|
|
|
|
case pch::PREDEF_TYPE_INT_ID: T = Context->IntTy; break;
|
|
|
|
case pch::PREDEF_TYPE_LONG_ID: T = Context->LongTy; break;
|
|
|
|
case pch::PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break;
|
2009-04-30 06:43:43 +04:00
|
|
|
case pch::PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break;
|
2009-04-28 01:45:14 +04:00
|
|
|
case pch::PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break;
|
|
|
|
case pch::PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
|
|
|
|
case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
|
|
|
|
case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
|
|
|
|
case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
|
2009-05-10 22:38:11 +04:00
|
|
|
case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
|
2009-07-14 10:30:34 +04:00
|
|
|
case pch::PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
|
|
|
|
case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
|
2009-07-15 22:40:39 +04:00
|
|
|
case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break;
|
|
|
|
case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break;
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(!T.isNull() && "Unknown predefined type");
|
2009-09-24 23:53:00 +04:00
|
|
|
return T.withFastQualifiers(FastQuals);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Index -= pch::NUM_PREDEF_TYPE_IDS;
|
2009-07-18 19:33:26 +04:00
|
|
|
//assert(Index < TypesLoaded.size() && "Type index out-of-range");
|
2009-09-24 23:53:00 +04:00
|
|
|
if (TypesLoaded[Index].isNull())
|
|
|
|
TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]);
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-09-24 23:53:00 +04:00
|
|
|
return TypesLoaded[Index].withFastQualifiers(FastQuals);
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
2009-10-29 11:12:44 +03:00
|
|
|
TemplateArgumentLocInfo
|
|
|
|
PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
|
|
|
|
const RecordData &Record,
|
|
|
|
unsigned &Index) {
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
return ReadDeclExpr();
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
return GetDeclaratorInfo(Record, Index);
|
2009-11-11 04:00:40 +03:00
|
|
|
case TemplateArgument::Template: {
|
|
|
|
SourceLocation
|
|
|
|
QualStart = SourceLocation::getFromRawEncoding(Record[Index++]),
|
|
|
|
QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]),
|
|
|
|
TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]);
|
|
|
|
return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd),
|
|
|
|
TemplateNameLoc);
|
|
|
|
}
|
2009-10-29 11:12:44 +03:00
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
return TemplateArgumentLocInfo();
|
|
|
|
}
|
|
|
|
llvm::llvm_unreachable("unexpected template argument loc");
|
|
|
|
return TemplateArgumentLocInfo();
|
|
|
|
}
|
|
|
|
|
2009-04-10 21:25:41 +04:00
|
|
|
Decl *PCHReader::GetDecl(pch::DeclID ID) {
|
2009-04-10 02:27:44 +04:00
|
|
|
if (ID == 0)
|
|
|
|
return 0;
|
|
|
|
|
2009-04-25 22:35:21 +04:00
|
|
|
if (ID > DeclsLoaded.size()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("declaration ID out-of-range for PCH file");
|
2009-04-25 22:35:21 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
unsigned Index = ID - 1;
|
2009-04-25 22:35:21 +04:00
|
|
|
if (!DeclsLoaded[Index])
|
|
|
|
ReadDeclRecord(DeclOffsets[Index], Index);
|
2009-04-10 02:27:44 +04:00
|
|
|
|
2009-04-25 22:35:21 +04:00
|
|
|
return DeclsLoaded[Index];
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
2009-04-27 09:46:25 +04:00
|
|
|
/// \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 *PCHReader::GetDeclStmt(uint64_t Offset) {
|
2009-04-27 09:58:23 +04:00
|
|
|
// Since we know tha this statement is part of a decl, make sure to use the
|
|
|
|
// decl cursor to read it.
|
|
|
|
DeclsCursor.JumpToBit(Offset);
|
|
|
|
return ReadStmt(DeclsCursor);
|
2009-04-18 04:07:54 +04:00
|
|
|
}
|
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
|
2009-04-10 21:25:41 +04:00
|
|
|
llvm::SmallVectorImpl<pch::DeclID> &Decls) {
|
2009-09-09 19:08:12 +04:00
|
|
|
assert(DC->hasExternalLexicalStorage() &&
|
2009-04-10 02:27:44 +04:00
|
|
|
"DeclContext has no lexical decls in storage");
|
|
|
|
uint64_t Offset = DeclContextOffsets[DC].first;
|
|
|
|
assert(Offset && "DeclContext has no lexical decls in storage");
|
|
|
|
|
2009-04-15 01:18:50 +04:00
|
|
|
// Keep track of where we are in the stream, then jump back there
|
|
|
|
// after reading this context.
|
2009-04-27 11:35:40 +04:00
|
|
|
SavedStreamPosition SavedPosition(DeclsCursor);
|
2009-04-15 01:18:50 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
// Load the record containing all of the declarations lexically in
|
|
|
|
// this context.
|
2009-04-27 11:35:40 +04:00
|
|
|
DeclsCursor.JumpToBit(Offset);
|
2009-04-10 02:27:44 +04:00
|
|
|
RecordData Record;
|
2009-04-27 11:35:40 +04:00
|
|
|
unsigned Code = DeclsCursor.ReadCode();
|
|
|
|
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
|
2009-04-15 22:43:11 +04:00
|
|
|
(void)RecCode;
|
2009-04-10 02:27:44 +04:00
|
|
|
assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
|
|
|
|
|
|
|
|
// Load all of the declaration IDs
|
|
|
|
Decls.clear();
|
|
|
|
Decls.insert(Decls.end(), Record.begin(), Record.end());
|
2009-04-23 02:34:57 +04:00
|
|
|
++NumLexicalDeclContextsRead;
|
2009-04-10 02:27:44 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
|
2009-04-27 11:35:40 +04:00
|
|
|
llvm::SmallVectorImpl<VisibleDeclaration> &Decls) {
|
2009-09-09 19:08:12 +04:00
|
|
|
assert(DC->hasExternalVisibleStorage() &&
|
2009-04-10 02:27:44 +04:00
|
|
|
"DeclContext has no visible decls in storage");
|
|
|
|
uint64_t Offset = DeclContextOffsets[DC].second;
|
|
|
|
assert(Offset && "DeclContext has no visible decls in storage");
|
|
|
|
|
2009-04-15 01:18:50 +04:00
|
|
|
// Keep track of where we are in the stream, then jump back there
|
|
|
|
// after reading this context.
|
2009-04-27 11:35:40 +04:00
|
|
|
SavedStreamPosition SavedPosition(DeclsCursor);
|
2009-04-15 01:18:50 +04:00
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
// Load the record containing all of the declarations visible in
|
|
|
|
// this context.
|
2009-04-27 11:35:40 +04:00
|
|
|
DeclsCursor.JumpToBit(Offset);
|
2009-04-10 02:27:44 +04:00
|
|
|
RecordData Record;
|
2009-04-27 11:35:40 +04:00
|
|
|
unsigned Code = DeclsCursor.ReadCode();
|
|
|
|
unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
|
2009-04-15 22:43:11 +04:00
|
|
|
(void)RecCode;
|
2009-04-10 02:27:44 +04:00
|
|
|
assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
|
|
|
|
if (Record.size() == 0)
|
2009-09-09 19:08:12 +04:00
|
|
|
return false;
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
Decls.clear();
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
while (Idx < Record.size()) {
|
|
|
|
Decls.push_back(VisibleDeclaration());
|
|
|
|
Decls.back().Name = ReadDeclarationName(Record, Idx);
|
|
|
|
|
|
|
|
unsigned Size = Record[Idx++];
|
2009-04-27 11:35:40 +04:00
|
|
|
llvm::SmallVector<unsigned, 4> &LoadedDecls = Decls.back().Declarations;
|
2009-04-10 02:27:44 +04:00
|
|
|
LoadedDecls.reserve(Size);
|
|
|
|
for (unsigned I = 0; I < Size; ++I)
|
|
|
|
LoadedDecls.push_back(Record[Idx++]);
|
|
|
|
}
|
|
|
|
|
2009-04-23 02:34:57 +04:00
|
|
|
++NumVisibleDeclContextsRead;
|
2009-04-10 02:27:44 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:24:19 +04:00
|
|
|
void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) {
|
2009-04-22 23:09:20 +04:00
|
|
|
this->Consumer = Consumer;
|
|
|
|
|
2009-04-14 04:24:19 +04:00
|
|
|
if (!Consumer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
|
2009-09-17 07:06:44 +04:00
|
|
|
// Force deserialization of this decl, which will cause it to be passed to
|
|
|
|
// the consumer (or queued).
|
|
|
|
GetDecl(ExternalDefinitions[I]);
|
2009-04-14 04:24:19 +04:00
|
|
|
}
|
2009-04-25 04:41:30 +04:00
|
|
|
|
|
|
|
for (unsigned I = 0, N = InterestingDecls.size(); I != N; ++I) {
|
|
|
|
DeclGroupRef DG(InterestingDecls[I]);
|
|
|
|
Consumer->HandleTopLevelDecl(DG);
|
|
|
|
}
|
2009-04-14 04:24:19 +04:00
|
|
|
}
|
|
|
|
|
2009-04-10 02:27:44 +04:00
|
|
|
void PCHReader::PrintStats() {
|
|
|
|
std::fprintf(stderr, "*** PCH Statistics:\n");
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
unsigned NumTypesLoaded
|
2009-04-25 23:10:14 +04:00
|
|
|
= TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
|
2009-09-24 23:53:00 +04:00
|
|
|
QualType());
|
2009-04-25 23:10:14 +04:00
|
|
|
unsigned NumDeclsLoaded
|
|
|
|
= DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
|
|
|
|
(Decl *)0);
|
|
|
|
unsigned NumIdentifiersLoaded
|
|
|
|
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
|
|
|
|
IdentifiersLoaded.end(),
|
|
|
|
(IdentifierInfo *)0);
|
2009-09-09 19:08:12 +04:00
|
|
|
unsigned NumSelectorsLoaded
|
2009-04-25 23:10:14 +04:00
|
|
|
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
|
|
|
|
SelectorsLoaded.end(),
|
|
|
|
Selector());
|
2009-04-25 21:48:32 +04:00
|
|
|
|
2009-04-27 22:38:38 +04:00
|
|
|
std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
|
|
|
|
std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
|
2009-04-27 10:38:32 +04:00
|
|
|
if (TotalNumSLocEntries)
|
|
|
|
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
|
|
|
|
NumSLocEntriesRead, TotalNumSLocEntries,
|
|
|
|
((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
|
2009-04-25 22:35:21 +04:00
|
|
|
if (!TypesLoaded.empty())
|
2009-04-25 21:48:32 +04:00
|
|
|
std::fprintf(stderr, " %u/%u types read (%f%%)\n",
|
2009-04-25 22:35:21 +04:00
|
|
|
NumTypesLoaded, (unsigned)TypesLoaded.size(),
|
|
|
|
((float)NumTypesLoaded/TypesLoaded.size() * 100));
|
|
|
|
if (!DeclsLoaded.empty())
|
2009-04-25 21:48:32 +04:00
|
|
|
std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
|
2009-04-25 22:35:21 +04:00
|
|
|
NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
|
|
|
|
((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
|
2009-04-25 23:10:14 +04:00
|
|
|
if (!IdentifiersLoaded.empty())
|
2009-04-25 21:48:32 +04:00
|
|
|
std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
|
2009-04-25 23:10:14 +04:00
|
|
|
NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
|
|
|
|
((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
|
2009-04-25 21:48:32 +04:00
|
|
|
if (TotalNumSelectors)
|
|
|
|
std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
|
|
|
|
NumSelectorsLoaded, TotalNumSelectors,
|
|
|
|
((float)NumSelectorsLoaded/TotalNumSelectors * 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 (TotalSelectorsInMethodPool) {
|
|
|
|
std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
|
|
|
|
NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool,
|
|
|
|
((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool
|
|
|
|
* 100));
|
|
|
|
std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
|
|
|
|
}
|
2009-04-10 02:27:44 +04:00
|
|
|
std::fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
void PCHReader::InitializeSema(Sema &S) {
|
|
|
|
SemaObj = &S;
|
2009-04-25 01:10:55 +04:00
|
|
|
S.ExternalSource = this;
|
|
|
|
|
2009-04-23 01:15:06 +04:00
|
|
|
// 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) {
|
|
|
|
SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I]));
|
|
|
|
SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
|
|
|
|
}
|
|
|
|
PreloadedDecls.clear();
|
2009-04-23 02:02:47 +04:00
|
|
|
|
|
|
|
// If there were any tentative definitions, deserialize them and add
|
|
|
|
// them to Sema's table of tentative definitions.
|
|
|
|
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
|
|
|
|
VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
|
|
|
|
SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
|
2009-09-08 22:19:27 +04:00
|
|
|
SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
|
2009-04-23 02:02:47 +04:00
|
|
|
}
|
2009-04-23 02:18:58 +04:00
|
|
|
|
|
|
|
// If there were any locally-scoped external declarations,
|
|
|
|
// deserialize them and add them to Sema's table of locally-scoped
|
|
|
|
// external declarations.
|
|
|
|
for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
|
|
|
|
NamedDecl *D = cast<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
|
|
|
|
SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D;
|
|
|
|
}
|
2009-04-28 00:06:05 +04:00
|
|
|
|
|
|
|
// If there were any ext_vector type declarations, deserialize them
|
|
|
|
// and add them to Sema's vector of such declarations.
|
|
|
|
for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I)
|
|
|
|
SemaObj->ExtVectorDecls.push_back(
|
|
|
|
cast<TypedefDecl>(GetDecl(ExtVectorDecls[I])));
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) {
|
|
|
|
// Try to find this name within our on-disk hash table
|
2009-09-09 19:08:12 +04:00
|
|
|
PCHIdentifierLookupTable *IdTable
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
= (PCHIdentifierLookupTable *)IdentifierLookupTable;
|
|
|
|
std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart);
|
|
|
|
PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key);
|
|
|
|
if (Pos == IdTable->end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Dereferencing the iterator has the effect of building the
|
|
|
|
// IdentifierInfo node and populating it with the various
|
|
|
|
// declarations it needs.
|
|
|
|
return *Pos;
|
|
|
|
}
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
std::pair<ObjCMethodList, ObjCMethodList>
|
2009-04-25 01:10:55 +04:00
|
|
|
PCHReader::ReadMethodPool(Selector Sel) {
|
|
|
|
if (!MethodPoolLookupTable)
|
|
|
|
return std::pair<ObjCMethodList, ObjCMethodList>();
|
|
|
|
|
|
|
|
// Try to find this selector within our on-disk hash table.
|
|
|
|
PCHMethodPoolLookupTable *PoolTable
|
|
|
|
= (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
|
|
|
|
PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
|
2009-04-25 21:48:32 +04:00
|
|
|
if (Pos == PoolTable->end()) {
|
|
|
|
++NumMethodPoolMisses;
|
2009-04-25 01:10:55 +04:00
|
|
|
return std::pair<ObjCMethodList, ObjCMethodList>();;
|
2009-04-25 21:48:32 +04:00
|
|
|
}
|
2009-04-25 01:10:55 +04:00
|
|
|
|
2009-04-25 21:48:32 +04:00
|
|
|
++NumMethodPoolSelectorsRead;
|
2009-04-25 01:10:55 +04:00
|
|
|
return *Pos;
|
|
|
|
}
|
|
|
|
|
2009-04-25 23:10:14 +04:00
|
|
|
void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
assert(ID && "Non-zero identifier ID required");
|
2009-04-29 01:53:25 +04:00
|
|
|
assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
|
2009-04-25 23:10:14 +04:00
|
|
|
IdentifiersLoaded[ID - 1] = II;
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
}
|
|
|
|
|
2009-07-06 22:54:52 +04:00
|
|
|
/// \brief Set the globally-visible declarations associated with the given
|
|
|
|
/// identifier.
|
|
|
|
///
|
|
|
|
/// If the PCH reader is currently in a state where the given declaration IDs
|
2009-09-09 19:08:12 +04:00
|
|
|
/// cannot safely be resolved, they are queued until it is safe to resolve
|
2009-07-06 22:54:52 +04:00
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// \param Nonrecursive should be true to indicate that the caller knows that
|
|
|
|
/// this call is non-recursive, and therefore the globally-visible declarations
|
|
|
|
/// will not be placed onto the pending queue.
|
2009-09-09 19:08:12 +04:00
|
|
|
void
|
|
|
|
PCHReader::SetGloballyVisibleDecls(IdentifierInfo *II,
|
2009-07-06 22:54:52 +04:00
|
|
|
const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
|
|
|
|
bool Nonrecursive) {
|
|
|
|
if (CurrentlyLoadingTypeOrDecl && !Nonrecursive) {
|
|
|
|
PendingIdentifierInfos.push_back(PendingIdentifierInfo());
|
|
|
|
PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
|
|
|
|
PII.II = II;
|
|
|
|
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I)
|
|
|
|
PII.DeclIDs.push_back(DeclIDs[I]);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-07-06 22:54:52 +04:00
|
|
|
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
|
|
|
|
NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
|
|
|
|
if (SemaObj) {
|
|
|
|
// 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.
|
|
|
|
SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D));
|
|
|
|
SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-12 01:15:38 +04:00
|
|
|
IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
|
2009-04-11 04:14:32 +04:00
|
|
|
if (ID == 0)
|
|
|
|
return 0;
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 23:10:14 +04:00
|
|
|
if (!IdentifierTableData || IdentifiersLoaded.empty()) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("no identifier table in PCH file");
|
2009-04-11 04:14:32 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-06-19 04:03:23 +04:00
|
|
|
assert(PP && "Forgot to set Preprocessor ?");
|
2009-04-25 23:10:14 +04:00
|
|
|
if (!IdentifiersLoaded[ID - 1]) {
|
|
|
|
uint32_t Offset = IdentifierOffsets[ID - 1];
|
2009-04-26 01:21:38 +04:00
|
|
|
const char *Str = IdentifierTableData + Offset;
|
2009-04-26 01:04:17 +04:00
|
|
|
|
2009-04-29 00:01:51 +04:00
|
|
|
// All of the strings in the PCH file are preceded by a 16-bit
|
|
|
|
// length. Extract that 16-bit length to avoid having to execute
|
|
|
|
// strlen().
|
2009-10-23 08:45:31 +04:00
|
|
|
// 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'.
|
2009-10-23 07:57:22 +04:00
|
|
|
const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
|
2009-04-29 00:01:51 +04:00
|
|
|
unsigned StrLen = (((unsigned) StrLenPtr[0])
|
|
|
|
| (((unsigned) StrLenPtr[1]) << 8)) - 1;
|
2009-09-09 19:08:12 +04:00
|
|
|
IdentifiersLoaded[ID - 1]
|
2009-06-19 04:03:23 +04:00
|
|
|
= &PP->getIdentifierTable().get(Str, Str + StrLen);
|
2009-04-11 04:14:32 +04:00
|
|
|
}
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-25 23:10:14 +04:00
|
|
|
return IdentifiersLoaded[ID - 1];
|
2009-04-10 02:27:44 +04:00
|
|
|
}
|
|
|
|
|
2009-04-27 10:38:32 +04:00
|
|
|
void PCHReader::ReadSLocEntry(unsigned ID) {
|
|
|
|
ReadSLocEntryRecord(ID);
|
|
|
|
}
|
|
|
|
|
2009-04-23 14:39:46 +04:00
|
|
|
Selector PCHReader::DecodeSelector(unsigned ID) {
|
|
|
|
if (ID == 0)
|
|
|
|
return Selector();
|
2009-09-09 19:08:12 +04:00
|
|
|
|
2009-04-29 01:53:25 +04:00
|
|
|
if (!MethodPoolLookupTableData)
|
2009-04-23 14:39:46 +04:00
|
|
|
return Selector();
|
2009-04-25 21:48:32 +04:00
|
|
|
|
|
|
|
if (ID > TotalNumSelectors) {
|
2009-04-29 01:53:25 +04:00
|
|
|
Error("selector ID out of range in PCH file");
|
2009-04-23 14:39:46 +04:00
|
|
|
return Selector();
|
|
|
|
}
|
2009-04-25 21:48:32 +04:00
|
|
|
|
|
|
|
unsigned Index = ID - 1;
|
|
|
|
if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) {
|
|
|
|
// Load this selector from the selector table.
|
|
|
|
// FIXME: endianness portability issues with SelectorOffsets table
|
|
|
|
PCHMethodPoolLookupTrait Trait(*this);
|
2009-09-09 19:08:12 +04:00
|
|
|
SelectorsLoaded[Index]
|
2009-04-25 21:48:32 +04:00
|
|
|
= Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SelectorsLoaded[Index];
|
2009-04-23 14:39:46 +04:00
|
|
|
}
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
DeclarationName
|
2009-04-10 02:27:44 +04:00
|
|
|
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
|
|
|
|
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
|
|
|
|
switch (Kind) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
return DeclarationName(GetIdentifierInfo(Record, Idx));
|
|
|
|
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
2009-04-23 19:15:40 +04:00
|
|
|
return DeclarationName(GetSelector(Record, Idx));
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
case DeclarationName::CXXConstructorName:
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->DeclarationNames.getCXXConstructorName(
|
2009-08-05 09:36:45 +04:00
|
|
|
Context->getCanonicalType(GetType(Record[Idx++])));
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
case DeclarationName::CXXDestructorName:
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->DeclarationNames.getCXXDestructorName(
|
2009-08-05 09:36:45 +04:00
|
|
|
Context->getCanonicalType(GetType(Record[Idx++])));
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->DeclarationNames.getCXXConversionFunctionName(
|
2009-08-05 09:36:45 +04:00
|
|
|
Context->getCanonicalType(GetType(Record[Idx++])));
|
2009-04-10 02:27:44 +04:00
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
2009-04-28 01:45:14 +04:00
|
|
|
return Context->DeclarationNames.getCXXOperatorName(
|
2009-04-10 02:27:44 +04:00
|
|
|
(OverloadedOperatorKind)Record[Idx++]);
|
|
|
|
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
return DeclarationName::getUsingDirectiveName();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Required to silence GCC warning
|
|
|
|
return DeclarationName();
|
|
|
|
}
|
2009-04-11 00:39:37 +04:00
|
|
|
|
2009-04-13 22:14:40 +04:00
|
|
|
/// \brief Read an integral value
|
|
|
|
llvm::APInt PCHReader::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 PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
|
|
|
|
bool isUnsigned = Record[Idx++];
|
|
|
|
return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
|
|
|
|
}
|
|
|
|
|
2009-04-15 01:55:33 +04:00
|
|
|
/// \brief Read a floating-point value
|
|
|
|
llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
|
|
|
|
return llvm::APFloat(ReadAPInt(Record, Idx));
|
|
|
|
}
|
|
|
|
|
2009-04-16 01:30:51 +04:00
|
|
|
// \brief Read a string
|
|
|
|
std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) {
|
|
|
|
unsigned Len = Record[Idx++];
|
2009-05-21 13:52:38 +04:00
|
|
|
std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
|
2009-04-16 01:30:51 +04:00
|
|
|
Idx += Len;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2009-04-11 00:39:37 +04:00
|
|
|
DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
|
2009-04-11 03:10:45 +04:00
|
|
|
return Diag(SourceLocation(), DiagID);
|
|
|
|
}
|
|
|
|
|
|
|
|
DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) {
|
2009-06-19 04:03:23 +04:00
|
|
|
return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
|
2009-04-11 00:39:37 +04:00
|
|
|
}
|
2009-04-17 04:04:06 +04:00
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
/// \brief Retrieve the identifier table associated with the
|
|
|
|
/// preprocessor.
|
|
|
|
IdentifierTable &PCHReader::getIdentifierTable() {
|
2009-06-19 04:03:23 +04:00
|
|
|
assert(PP && "Forgot to set Preprocessor ?");
|
|
|
|
return PP->getIdentifierTable();
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69737 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-22 02:25:48 +04:00
|
|
|
}
|
|
|
|
|
2009-04-17 04:04:06 +04:00
|
|
|
/// \brief Record that the given ID maps to the given switch-case
|
|
|
|
/// statement.
|
|
|
|
void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
|
|
|
|
assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID");
|
|
|
|
SwitchCaseStmts[ID] = SC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the switch-case statement with the given ID.
|
|
|
|
SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) {
|
|
|
|
assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID");
|
|
|
|
return SwitchCaseStmts[ID];
|
|
|
|
}
|
2009-04-17 22:18:49 +04:00
|
|
|
|
|
|
|
/// \brief Record that the given label statement has been
|
|
|
|
/// deserialized and has the given ID.
|
|
|
|
void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) {
|
2009-09-09 19:08:12 +04:00
|
|
|
assert(LabelStmts.find(ID) == LabelStmts.end() &&
|
2009-04-17 22:18:49 +04:00
|
|
|
"Deserialized label twice");
|
|
|
|
LabelStmts[ID] = S;
|
|
|
|
|
|
|
|
// If we've already seen any goto statements that point to this
|
|
|
|
// label, resolve them now.
|
|
|
|
typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter;
|
|
|
|
std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID);
|
|
|
|
for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto)
|
|
|
|
Goto->second->setLabel(S);
|
|
|
|
UnresolvedGotoStmts.erase(Gotos.first, Gotos.second);
|
2009-04-17 22:58:21 +04:00
|
|
|
|
|
|
|
// If we've already seen any address-label statements that point to
|
|
|
|
// this label, resolve them now.
|
|
|
|
typedef std::multimap<unsigned, AddrLabelExpr *>::iterator AddrLabelIter;
|
2009-09-09 19:08:12 +04:00
|
|
|
std::pair<AddrLabelIter, AddrLabelIter> AddrLabels
|
2009-04-17 22:58:21 +04:00
|
|
|
= UnresolvedAddrLabelExprs.equal_range(ID);
|
2009-09-09 19:08:12 +04:00
|
|
|
for (AddrLabelIter AddrLabel = AddrLabels.first;
|
2009-04-17 22:58:21 +04:00
|
|
|
AddrLabel != AddrLabels.second; ++AddrLabel)
|
|
|
|
AddrLabel->second->setLabel(S);
|
|
|
|
UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second);
|
2009-04-17 22:18:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Set the label of the given statement to the label
|
|
|
|
/// identified by ID.
|
|
|
|
///
|
|
|
|
/// Depending on the order in which the label and other statements
|
|
|
|
/// referencing that label occur, this operation may complete
|
|
|
|
/// immediately (updating the statement) or it may queue the
|
|
|
|
/// statement to be back-patched later.
|
|
|
|
void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) {
|
|
|
|
std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
|
|
|
|
if (Label != LabelStmts.end()) {
|
|
|
|
// We've already seen this label, so set the label of the goto and
|
|
|
|
// we're done.
|
|
|
|
S->setLabel(Label->second);
|
|
|
|
} else {
|
|
|
|
// We haven't seen this label yet, so add this goto to the set of
|
|
|
|
// unresolved goto statements.
|
|
|
|
UnresolvedGotoStmts.insert(std::make_pair(ID, S));
|
|
|
|
}
|
|
|
|
}
|
2009-04-17 22:58:21 +04:00
|
|
|
|
|
|
|
/// \brief Set the label of the given expression to the label
|
|
|
|
/// identified by ID.
|
|
|
|
///
|
|
|
|
/// Depending on the order in which the label and other statements
|
|
|
|
/// referencing that label occur, this operation may complete
|
|
|
|
/// immediately (updating the statement) or it may queue the
|
|
|
|
/// statement to be back-patched later.
|
|
|
|
void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) {
|
|
|
|
std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
|
|
|
|
if (Label != LabelStmts.end()) {
|
|
|
|
// We've already seen this label, so set the label of the
|
|
|
|
// label-address expression and we're done.
|
|
|
|
S->setLabel(Label->second);
|
|
|
|
} else {
|
|
|
|
// We haven't seen this label yet, so add this label-address
|
|
|
|
// expression to the set of unresolved label-address expressions.
|
|
|
|
UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S));
|
|
|
|
}
|
|
|
|
}
|
2009-07-06 22:54:52 +04:00
|
|
|
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
PCHReader::LoadingTypeOrDecl::LoadingTypeOrDecl(PCHReader &Reader)
|
2009-07-06 22:54:52 +04:00
|
|
|
: Reader(Reader), Parent(Reader.CurrentlyLoadingTypeOrDecl) {
|
|
|
|
Reader.CurrentlyLoadingTypeOrDecl = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
PCHReader::LoadingTypeOrDecl::~LoadingTypeOrDecl() {
|
|
|
|
if (!Parent) {
|
|
|
|
// If any identifiers with corresponding top-level declarations have
|
|
|
|
// been loaded, load those declarations now.
|
|
|
|
while (!Reader.PendingIdentifierInfos.empty()) {
|
|
|
|
Reader.SetGloballyVisibleDecls(Reader.PendingIdentifierInfos.front().II,
|
|
|
|
Reader.PendingIdentifierInfos.front().DeclIDs,
|
|
|
|
true);
|
|
|
|
Reader.PendingIdentifierInfos.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 19:08:12 +04:00
|
|
|
Reader.CurrentlyLoadingTypeOrDecl = Parent;
|
2009-07-06 22:54:52 +04:00
|
|
|
}
|