summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Serialization
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization')
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp253
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h113
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp8451
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp3875
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h249
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp3058
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp5769
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp2100
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp2203
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp73
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp886
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/Module.cpp123
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp540
13 files changed, 27693 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
new file mode 100644
index 0000000..85c574c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
@@ -0,0 +1,253 @@
+//===--- ASTCommon.cpp - Common stuff for ASTReader/ASTWriter----*- 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 common functions that both ASTReader and ASTWriter use.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTCommon.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+
+// Give ASTDeserializationListener's VTable a home.
+ASTDeserializationListener::~ASTDeserializationListener() { }
+
+serialization::TypeIdx
+serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
+ unsigned ID = 0;
+ switch (BT->getKind()) {
+ case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break;
+ case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break;
+ case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break;
+ case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break;
+ case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break;
+ case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break;
+ case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break;
+ case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break;
+ case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break;
+ case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break;
+ case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break;
+ case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break;
+ case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break;
+ case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break;
+ case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break;
+ case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break;
+ case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break;
+ case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break;
+ case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break;
+ case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break;
+ case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break;
+ case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break;
+ case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
+ case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
+ case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
+ case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
+ case BuiltinType::ARCUnbridgedCast:
+ ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break;
+ case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
+ case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
+ case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
+ case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break;
+ case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break;
+ case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break;
+ case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break;
+ case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break;
+ case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break;
+ case BuiltinType::OCLSampler: ID = PREDEF_TYPE_SAMPLER_ID; break;
+ case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break;
+ case BuiltinType::BuiltinFn:
+ ID = PREDEF_TYPE_BUILTIN_FN; break;
+
+ }
+
+ return TypeIdx(ID);
+}
+
+unsigned serialization::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))
+ R = llvm::HashString(II->getName(), R);
+ return R;
+}
+
+const DeclContext *
+serialization::getDefinitiveDeclContext(const DeclContext *DC) {
+ switch (DC->getDeclKind()) {
+ // These entities may have multiple definitions.
+ case Decl::TranslationUnit:
+ case Decl::ExternCContext:
+ case Decl::Namespace:
+ case Decl::LinkageSpec:
+ return nullptr;
+
+ // C/C++ tag types can only be defined in one place.
+ case Decl::Enum:
+ case Decl::Record:
+ if (const TagDecl *Def = cast<TagDecl>(DC)->getDefinition())
+ return Def;
+ return nullptr;
+
+ // FIXME: These can be defined in one place... except special member
+ // functions and out-of-line definitions.
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ return nullptr;
+
+ // Each function, method, and block declaration is its own DeclContext.
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::ObjCMethod:
+ case Decl::Block:
+ case Decl::Captured:
+ // Objective C categories, category implementations, and class
+ // implementations can only be defined in one place.
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ return DC;
+
+ case Decl::ObjCProtocol:
+ if (const ObjCProtocolDecl *Def
+ = cast<ObjCProtocolDecl>(DC)->getDefinition())
+ return Def;
+ return nullptr;
+
+ // FIXME: These are defined in one place, but properties in class extensions
+ // end up being back-patched into the main interface. See
+ // Sema::HandlePropertyInClassExtension for the offending code.
+ case Decl::ObjCInterface:
+ return nullptr;
+
+ default:
+ llvm_unreachable("Unhandled DeclContext in AST reader");
+ }
+
+ llvm_unreachable("Unhandled decl kind");
+}
+
+bool serialization::isRedeclarableDeclKind(unsigned Kind) {
+ switch (static_cast<Decl::Kind>(Kind)) {
+ case Decl::TranslationUnit:
+ case Decl::ExternCContext:
+ // Special case of a "merged" declaration.
+ return true;
+
+ case Decl::Namespace:
+ case Decl::NamespaceAlias:
+ case Decl::Typedef:
+ case Decl::TypeAlias:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::VarTemplateSpecialization:
+ case Decl::VarTemplatePartialSpecialization:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::UsingShadow:
+ case Decl::Var:
+ case Decl::FunctionTemplate:
+ case Decl::ClassTemplate:
+ case Decl::VarTemplate:
+ case Decl::TypeAliasTemplate:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::Empty:
+ return true;
+
+ // Never redeclarable.
+ case Decl::UsingDirective:
+ case Decl::Label:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::TemplateTypeParm:
+ case Decl::EnumConstant:
+ case Decl::UnresolvedUsingValue:
+ case Decl::IndirectField:
+ case Decl::Field:
+ case Decl::MSProperty:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
+ case Decl::NonTypeTemplateParm:
+ case Decl::TemplateTemplateParm:
+ case Decl::Using:
+ case Decl::ObjCMethod:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCProperty:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::FileScopeAsm:
+ case Decl::AccessSpec:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::StaticAssert:
+ case Decl::Block:
+ case Decl::Captured:
+ case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
+ case Decl::OMPThreadPrivate:
+ return false;
+
+ // These indirectly derive from Redeclarable<T> but are not actually
+ // redeclarable.
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ return false;
+ }
+
+ llvm_unreachable("Unhandled declaration kind");
+}
+
+bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
+ // Friend declarations in dependent contexts aren't anonymous in the usual
+ // sense, but they cannot be found by name lookup in their semantic context
+ // (or indeed in any context), so we treat them as anonymous.
+ //
+ // This doesn't apply to friend tag decls; Sema makes those available to name
+ // lookup in the surrounding context.
+ if (D->getFriendObjectKind() &&
+ D->getLexicalDeclContext()->isDependentContext() && !isa<TagDecl>(D)) {
+ // For function templates and class templates, the template is numbered and
+ // not its pattern.
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return !FD->getDescribedFunctionTemplate();
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return !RD->getDescribedClassTemplate();
+ return true;
+ }
+
+ // Otherwise, we only care about anonymous class members.
+ if (D->getDeclName() || !isa<CXXRecordDecl>(D->getLexicalDeclContext()))
+ return false;
+ return isa<TagDecl>(D) || isa<FieldDecl>(D);
+}
+
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h
new file mode 100644
index 0000000..79d1817
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h
@@ -0,0 +1,113 @@
+//===- ASTCommon.h - Common stuff for ASTReader/ASTWriter -*- 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 common functions that both ASTReader and ASTWriter use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
+#define LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/Serialization/ASTBitCodes.h"
+
+namespace clang {
+
+namespace serialization {
+
+enum DeclUpdateKind {
+ UPD_CXX_ADDED_IMPLICIT_MEMBER,
+ UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
+ UPD_CXX_ADDED_FUNCTION_DEFINITION,
+ UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+ UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_RESOLVED_DTOR_DELETE,
+ UPD_CXX_RESOLVED_EXCEPTION_SPEC,
+ UPD_CXX_DEDUCED_RETURN_TYPE,
+ UPD_DECL_MARKED_USED,
+ UPD_MANGLING_NUMBER,
+ UPD_STATIC_LOCAL_NUMBER,
+ UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+ UPD_DECL_EXPORTED
+};
+
+TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
+
+template <typename IdxForTypeTy>
+TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) {
+ if (T.isNull())
+ return PREDEF_TYPE_NULL_ID;
+
+ unsigned FastQuals = T.getLocalFastQualifiers();
+ T.removeLocalFastQualifiers();
+
+ if (T.hasLocalNonFastQualifiers())
+ return IdxForType(T).asTypeID(FastQuals);
+
+ assert(!T.hasLocalQualifiers());
+
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr()))
+ return TypeIdxFromBuiltin(BT).asTypeID(FastQuals);
+
+ if (T == Context.AutoDeductTy)
+ return TypeIdx(PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals);
+ if (T == Context.AutoRRefDeductTy)
+ return TypeIdx(PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals);
+ if (T == Context.VaListTagTy)
+ return TypeIdx(PREDEF_TYPE_VA_LIST_TAG).asTypeID(FastQuals);
+
+ return IdxForType(T).asTypeID(FastQuals);
+}
+
+unsigned ComputeHash(Selector Sel);
+
+/// \brief Retrieve the "definitive" declaration that provides all of the
+/// visible entries for the given declaration context, if there is one.
+///
+/// The "definitive" declaration is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive declarations
+/// associated with them. C++ namespaces, on the other hand, can have
+/// multiple definitions.
+const DeclContext *getDefinitiveDeclContext(const DeclContext *DC);
+
+/// \brief Determine whether the given declaration kind is redeclarable.
+bool isRedeclarableDeclKind(unsigned Kind);
+
+/// \brief Determine whether the given declaration needs an anonymous
+/// declaration number.
+bool needsAnonymousDeclarationNumber(const NamedDecl *D);
+
+/// \brief Visit each declaration within \c DC that needs an anonymous
+/// declaration number and call \p Visit with the declaration and its number.
+template<typename Fn> void numberAnonymousDeclsWithin(const DeclContext *DC,
+ Fn Visit) {
+ unsigned Index = 0;
+ for (Decl *LexicalD : DC->decls()) {
+ // For a friend decl, we care about the declaration within it, if any.
+ if (auto *FD = dyn_cast<FriendDecl>(LexicalD))
+ LexicalD = FD->getFriendDecl();
+
+ auto *ND = dyn_cast_or_null<NamedDecl>(LexicalD);
+ if (!ND || !needsAnonymousDeclarationNumber(ND))
+ continue;
+
+ Visit(ND, Index++);
+ }
+}
+
+} // namespace serialization
+
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
new file mode 100644
index 0000000..609c25d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
@@ -0,0 +1,8451 @@
+//===-- ASTReader.cpp - AST File Reader ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTReader class, which reads AST files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTReader.h"
+#include "ASTCommon.h"
+#include "ASTReaderInternals.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/Version.h"
+#include "clang/Basic/VersionTuple.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <iterator>
+#include <system_error>
+
+using namespace clang;
+using namespace clang::serialization;
+using namespace clang::serialization::reader;
+using llvm::BitstreamCursor;
+
+
+//===----------------------------------------------------------------------===//
+// ChainedASTReaderListener implementation
+//===----------------------------------------------------------------------===//
+
+bool
+ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) {
+ return First->ReadFullVersionInformation(FullVersion) ||
+ Second->ReadFullVersionInformation(FullVersion);
+}
+void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) {
+ First->ReadModuleName(ModuleName);
+ Second->ReadModuleName(ModuleName);
+}
+void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) {
+ First->ReadModuleMapFile(ModuleMapPath);
+ Second->ReadModuleMapFile(ModuleMapPath);
+}
+bool
+ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain,
+ bool AllowCompatibleDifferences) {
+ return First->ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences) ||
+ Second->ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences);
+}
+bool ChainedASTReaderListener::ReadTargetOptions(
+ const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) {
+ return First->ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences) ||
+ Second->ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences);
+}
+bool ChainedASTReaderListener::ReadDiagnosticOptions(
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
+ return First->ReadDiagnosticOptions(DiagOpts, Complain) ||
+ Second->ReadDiagnosticOptions(DiagOpts, Complain);
+}
+bool
+ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts,
+ bool Complain) {
+ return First->ReadFileSystemOptions(FSOpts, Complain) ||
+ Second->ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ChainedASTReaderListener::ReadHeaderSearchOptions(
+ const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath,
+ bool Complain) {
+ return First->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ Complain) ||
+ Second->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ Complain);
+}
+bool ChainedASTReaderListener::ReadPreprocessorOptions(
+ const PreprocessorOptions &PPOpts, bool Complain,
+ std::string &SuggestedPredefines) {
+ return First->ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines) ||
+ Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines);
+}
+void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M,
+ unsigned Value) {
+ First->ReadCounter(M, Value);
+ Second->ReadCounter(M, Value);
+}
+bool ChainedASTReaderListener::needsInputFileVisitation() {
+ return First->needsInputFileVisitation() ||
+ Second->needsInputFileVisitation();
+}
+bool ChainedASTReaderListener::needsSystemInputFileVisitation() {
+ return First->needsSystemInputFileVisitation() ||
+ Second->needsSystemInputFileVisitation();
+}
+void ChainedASTReaderListener::visitModuleFile(StringRef Filename) {
+ First->visitModuleFile(Filename);
+ Second->visitModuleFile(Filename);
+}
+bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
+ bool isSystem,
+ bool isOverridden) {
+ bool Continue = false;
+ if (First->needsInputFileVisitation() &&
+ (!isSystem || First->needsSystemInputFileVisitation()))
+ Continue |= First->visitInputFile(Filename, isSystem, isOverridden);
+ if (Second->needsInputFileVisitation() &&
+ (!isSystem || Second->needsSystemInputFileVisitation()))
+ Continue |= Second->visitInputFile(Filename, isSystem, isOverridden);
+ return Continue;
+}
+
+//===----------------------------------------------------------------------===//
+// PCH validator implementation
+//===----------------------------------------------------------------------===//
+
+ASTReaderListener::~ASTReaderListener() {}
+
+/// \brief Compare the given set of language options against an existing set of
+/// language options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+/// \param AllowCompatibleDifferences If true, differences between compatible
+/// language options will be permitted.
+///
+/// \returns true if the languagae options mis-match, false otherwise.
+static bool checkLanguageOptions(const LangOptions &LangOpts,
+ const LangOptions &ExistingLangOpts,
+ DiagnosticsEngine *Diags,
+ bool AllowCompatibleDifferences = true) {
+#define LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_mismatch) \
+ << Description << LangOpts.Name << ExistingLangOpts.Name; \
+ return true; \
+ }
+
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
+ }
+
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
+ }
+
+#define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \
+ if (!AllowCompatibleDifferences) \
+ LANGOPT(Name, Bits, Default, Description)
+
+#define COMPATIBLE_ENUM_LANGOPT(Name, Bits, Default, Description) \
+ if (!AllowCompatibleDifferences) \
+ ENUM_LANGOPT(Name, Bits, Default, Description)
+
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+ if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
+ << "target Objective-C runtime";
+ return true;
+ }
+
+ if (ExistingLangOpts.CommentOpts.BlockCommandNames !=
+ LangOpts.CommentOpts.BlockCommandNames) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
+ << "block command names";
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Compare the given set of target options against an existing set of
+/// target options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the target options mis-match, false otherwise.
+static bool checkTargetOptions(const TargetOptions &TargetOpts,
+ const TargetOptions &ExistingTargetOpts,
+ DiagnosticsEngine *Diags,
+ bool AllowCompatibleDifferences = true) {
+#define CHECK_TARGET_OPT(Field, Name) \
+ if (TargetOpts.Field != ExistingTargetOpts.Field) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_targetopt_mismatch) \
+ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \
+ return true; \
+ }
+
+ // The triple and ABI must match exactly.
+ CHECK_TARGET_OPT(Triple, "target");
+ CHECK_TARGET_OPT(ABI, "target ABI");
+
+ // We can tolerate different CPUs in many cases, notably when one CPU
+ // supports a strict superset of another. When allowing compatible
+ // differences skip this check.
+ if (!AllowCompatibleDifferences)
+ CHECK_TARGET_OPT(CPU, "target CPU");
+
+#undef CHECK_TARGET_OPT
+
+ // Compare feature sets.
+ SmallVector<StringRef, 4> ExistingFeatures(
+ ExistingTargetOpts.FeaturesAsWritten.begin(),
+ ExistingTargetOpts.FeaturesAsWritten.end());
+ SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
+ TargetOpts.FeaturesAsWritten.end());
+ std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
+ std::sort(ReadFeatures.begin(), ReadFeatures.end());
+
+ // We compute the set difference in both directions explicitly so that we can
+ // diagnose the differences differently.
+ SmallVector<StringRef, 4> UnmatchedExistingFeatures, UnmatchedReadFeatures;
+ std::set_difference(
+ ExistingFeatures.begin(), ExistingFeatures.end(), ReadFeatures.begin(),
+ ReadFeatures.end(), std::back_inserter(UnmatchedExistingFeatures));
+ std::set_difference(ReadFeatures.begin(), ReadFeatures.end(),
+ ExistingFeatures.begin(), ExistingFeatures.end(),
+ std::back_inserter(UnmatchedReadFeatures));
+
+ // If we are allowing compatible differences and the read feature set is
+ // a strict subset of the existing feature set, there is nothing to diagnose.
+ if (AllowCompatibleDifferences && UnmatchedReadFeatures.empty())
+ return false;
+
+ if (Diags) {
+ for (StringRef Feature : UnmatchedReadFeatures)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << /* is-existing-feature */ false << Feature;
+ for (StringRef Feature : UnmatchedExistingFeatures)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << /* is-existing-feature */ true << Feature;
+ }
+
+ return !UnmatchedReadFeatures.empty() || !UnmatchedExistingFeatures.empty();
+}
+
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain,
+ bool AllowCompatibleDifferences) {
+ const LangOptions &ExistingLangOpts = PP.getLangOpts();
+ return checkLanguageOptions(LangOpts, ExistingLangOpts,
+ Complain ? &Reader.Diags : nullptr,
+ AllowCompatibleDifferences);
+}
+
+bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain,
+ bool AllowCompatibleDifferences) {
+ const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
+ return checkTargetOptions(TargetOpts, ExistingTargetOpts,
+ Complain ? &Reader.Diags : nullptr,
+ AllowCompatibleDifferences);
+}
+
+namespace {
+ typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
+ MacroDefinitionsMap;
+ typedef llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> >
+ DeclsMap;
+}
+
+static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags,
+ DiagnosticsEngine &Diags,
+ bool Complain) {
+ typedef DiagnosticsEngine::Level Level;
+
+ // Check current mappings for new -Werror mappings, and the stored mappings
+ // for cases that were explicitly mapped to *not* be errors that are now
+ // errors because of options like -Werror.
+ DiagnosticsEngine *MappingSources[] = { &Diags, &StoredDiags };
+
+ for (DiagnosticsEngine *MappingSource : MappingSources) {
+ for (auto DiagIDMappingPair : MappingSource->getDiagnosticMappings()) {
+ diag::kind DiagID = DiagIDMappingPair.first;
+ Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation());
+ if (CurLevel < DiagnosticsEngine::Error)
+ continue; // not significant
+ Level StoredLevel =
+ StoredDiags.getDiagnosticLevel(DiagID, SourceLocation());
+ if (StoredLevel < DiagnosticsEngine::Error) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" +
+ Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool isExtHandlingFromDiagsError(DiagnosticsEngine &Diags) {
+ diag::Severity Ext = Diags.getExtensionHandlingBehavior();
+ if (Ext == diag::Severity::Warning && Diags.getWarningsAsErrors())
+ return true;
+ return Ext >= diag::Severity::Error;
+}
+
+static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags,
+ DiagnosticsEngine &Diags,
+ bool IsSystem, bool Complain) {
+ // Top-level options
+ if (IsSystem) {
+ if (Diags.getSuppressSystemWarnings())
+ return false;
+ // If -Wsystem-headers was not enabled before, be conservative
+ if (StoredDiags.getSuppressSystemWarnings()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Wsystem-headers";
+ return true;
+ }
+ }
+
+ if (Diags.getWarningsAsErrors() && !StoredDiags.getWarningsAsErrors()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror";
+ return true;
+ }
+
+ if (Diags.getWarningsAsErrors() && Diags.getEnableAllWarnings() &&
+ !StoredDiags.getEnableAllWarnings()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Weverything -Werror";
+ return true;
+ }
+
+ if (isExtHandlingFromDiagsError(Diags) &&
+ !isExtHandlingFromDiagsError(StoredDiags)) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-pedantic-errors";
+ return true;
+ }
+
+ return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain);
+}
+
+bool PCHValidator::ReadDiagnosticOptions(
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
+ DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
+ // This should never fail, because we would have processed these options
+ // before writing them to an ASTFile.
+ ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
+
+ ModuleManager &ModuleMgr = Reader.getModuleManager();
+ assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
+
+ // If the original import came from a file explicitly generated by the user,
+ // don't check the diagnostic mappings.
+ // FIXME: currently this is approximated by checking whether this is not a
+ // module import of an implicitly-loaded module file.
+ // Note: ModuleMgr.rbegin() may not be the current module, but it must be in
+ // the transitive closure of its imports, since unrelated modules cannot be
+ // imported until after this module finishes validation.
+ ModuleFile *TopImport = *ModuleMgr.rbegin();
+ while (!TopImport->ImportedBy.empty())
+ TopImport = TopImport->ImportedBy[0];
+ if (TopImport->Kind != MK_ImplicitModule)
+ return false;
+
+ StringRef ModuleName = TopImport->ModuleName;
+ assert(!ModuleName.empty() && "diagnostic options read before module name");
+
+ Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName);
+ assert(M && "missing module");
+
+ // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that
+ // contains the union of their flags.
+ return checkDiagnosticMappings(*Diags, ExistingDiags, M->IsSystem, Complain);
+}
+
+/// \brief Collect the macro definitions provided by the given preprocessor
+/// options.
+static void
+collectMacroDefinitions(const PreprocessorOptions &PPOpts,
+ MacroDefinitionsMap &Macros,
+ SmallVectorImpl<StringRef> *MacroNames = nullptr) {
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ StringRef Macro = PPOpts.Macros[I].first;
+ bool IsUndef = PPOpts.Macros[I].second;
+
+ std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
+ StringRef MacroName = MacroPair.first;
+ StringRef MacroBody = MacroPair.second;
+
+ // For an #undef'd macro, we only care about the name.
+ if (IsUndef) {
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+
+ Macros[MacroName] = std::make_pair("", true);
+ continue;
+ }
+
+ // For a #define'd macro, figure out the actual definition.
+ if (MacroName.size() == Macro.size())
+ MacroBody = "1";
+ else {
+ // Note: GCC drops anything following an end-of-line character.
+ StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ MacroBody = MacroBody.substr(0, End);
+ }
+
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+ Macros[MacroName] = std::make_pair(MacroBody, false);
+ }
+}
+
+/// \brief Check the preprocessor options deserialized from the control block
+/// against the preprocessor options in an existing preprocessor.
+///
+/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
+static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ DiagnosticsEngine *Diags,
+ FileManager &FileMgr,
+ std::string &SuggestedPredefines,
+ const LangOptions &LangOpts) {
+ // Check macro definitions.
+ MacroDefinitionsMap ASTFileMacros;
+ collectMacroDefinitions(PPOpts, ASTFileMacros);
+ MacroDefinitionsMap ExistingMacros;
+ SmallVector<StringRef, 4> ExistingMacroNames;
+ collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
+
+ for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
+ // Dig out the macro definition in the existing preprocessor options.
+ StringRef MacroName = ExistingMacroNames[I];
+ std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
+
+ // Check whether we know anything about this macro name or not.
+ llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
+ = ASTFileMacros.find(MacroName);
+ if (Known == ASTFileMacros.end()) {
+ // FIXME: Check whether this identifier was referenced anywhere in the
+ // AST file. If so, we should reject the AST file. Unfortunately, this
+ // information isn't in the control block. What shall we do about it?
+
+ if (Existing.second) {
+ SuggestedPredefines += "#undef ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += '\n';
+ } else {
+ SuggestedPredefines += "#define ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += ' ';
+ SuggestedPredefines += Existing.first.str();
+ SuggestedPredefines += '\n';
+ }
+ continue;
+ }
+
+ // If the macro was defined in one but undef'd in the other, we have a
+ // conflict.
+ if (Existing.second != Known->second.second) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef)
+ << MacroName << Known->second.second;
+ }
+ return true;
+ }
+
+ // If the macro was #undef'd in both, or if the macro bodies are identical,
+ // it's fine.
+ if (Existing.second || Existing.first == Known->second.first)
+ continue;
+
+ // The macro bodies differ; complain.
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_conflict)
+ << MacroName << Known->second.first << Existing.first;
+ }
+ return true;
+ }
+
+ // Check whether we're using predefines.
+ if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
+ }
+ return true;
+ }
+
+ // Detailed record is important since it is used for the module cache hash.
+ if (LangOpts.Modules &&
+ PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord;
+ }
+ return true;
+ }
+
+ // Compute the #include and #include_macros lines we need.
+ for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.Includes[I];
+ if (File == ExistingPPOpts.ImplicitPCHInclude)
+ continue;
+
+ if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
+ != PPOpts.Includes.end())
+ continue;
+
+ SuggestedPredefines += "#include \"";
+ SuggestedPredefines += File;
+ SuggestedPredefines += "\"\n";
+ }
+
+ for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.MacroIncludes[I];
+ if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
+ File)
+ != PPOpts.MacroIncludes.end())
+ continue;
+
+ SuggestedPredefines += "#__include_macros \"";
+ SuggestedPredefines += File;
+ SuggestedPredefines += "\"\n##\n";
+ }
+
+ return false;
+}
+
+bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
+
+ return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
+ Complain? &Reader.Diags : nullptr,
+ PP.getFileManager(),
+ SuggestedPredefines,
+ PP.getLangOpts());
+}
+
+/// Check the header search options deserialized from the control block
+/// against the header search options in an existing preprocessor.
+///
+/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
+static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ StringRef ExistingModuleCachePath,
+ DiagnosticsEngine *Diags,
+ const LangOptions &LangOpts) {
+ if (LangOpts.Modules) {
+ if (SpecificModuleCachePath != ExistingModuleCachePath) {
+ if (Diags)
+ Diags->Report(diag::err_pch_modulecache_mismatch)
+ << SpecificModuleCachePath << ExistingModuleCachePath;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ bool Complain) {
+ return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ PP.getHeaderSearchInfo().getModuleCachePath(),
+ Complain ? &Reader.Diags : nullptr,
+ PP.getLangOpts());
+}
+
+void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
+ PP.setCounterValue(Value);
+}
+
+//===----------------------------------------------------------------------===//
+// AST reader implementation
+//===----------------------------------------------------------------------===//
+
+void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener,
+ bool TakeOwnership) {
+ DeserializationListener = Listener;
+ OwnsDeserializationListener = TakeOwnership;
+}
+
+
+
+unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
+ return serialization::ComputeHash(Sel);
+}
+
+
+std::pair<unsigned, unsigned>
+ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+ASTSelectorLookupTrait::internal_key_type
+ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace llvm::support;
+ SelectorTable &SelTable = Reader.getContext().Selectors;
+ unsigned N = endian::readNext<uint16_t, little, unaligned>(d);
+ IdentifierInfo *FirstII = Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
+ if (N == 0)
+ return SelTable.getNullarySelector(FirstII);
+ else if (N == 1)
+ return SelTable.getUnarySelector(FirstII);
+
+ SmallVector<IdentifierInfo *, 16> Args;
+ Args.push_back(FirstII);
+ for (unsigned I = 1; I != N; ++I)
+ Args.push_back(Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d)));
+
+ return SelTable.getSelector(N, Args.data());
+}
+
+ASTSelectorLookupTrait::data_type
+ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
+ unsigned DataLen) {
+ using namespace llvm::support;
+
+ data_type Result;
+
+ Result.ID = Reader.getGlobalSelectorID(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
+ unsigned FullInstanceBits = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned FullFactoryBits = endian::readNext<uint16_t, little, unaligned>(d);
+ Result.InstanceBits = FullInstanceBits & 0x3;
+ Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1;
+ Result.FactoryBits = FullFactoryBits & 0x3;
+ Result.FactoryHasMoreThanOneDecl = (FullFactoryBits >> 2) & 0x1;
+ unsigned NumInstanceMethods = FullInstanceBits >> 3;
+ unsigned NumFactoryMethods = FullFactoryBits >> 3;
+
+ // Load instance methods
+ for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+ if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
+ F, endian::readNext<uint32_t, little, unaligned>(d)))
+ Result.Instance.push_back(Method);
+ }
+
+ // Load factory methods
+ for (unsigned I = 0; I != NumFactoryMethods; ++I) {
+ if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
+ F, endian::readNext<uint32_t, little, unaligned>(d)))
+ Result.Factory.push_back(Method);
+ }
+
+ return Result;
+}
+
+unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(a);
+}
+
+std::pair<unsigned, unsigned>
+ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace llvm::support;
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+ASTIdentifierLookupTraitBase::internal_key_type
+ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
+ assert(n >= 2 && d[n-1] == '\0');
+ return StringRef((const char*) d, n-1);
+}
+
+/// \brief Whether the given identifier is "interesting".
+static bool isInterestingIdentifier(IdentifierInfo &II) {
+ return II.isPoisoned() ||
+ II.isExtensionToken() ||
+ II.getObjCOrBuiltinID() ||
+ II.hasRevertedTokenIDToIdentifier() ||
+ II.hadMacroDefinition() ||
+ II.getFETokenInfo<void>();
+}
+
+IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace llvm::support;
+ unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
+ bool IsInteresting = RawID & 0x01;
+
+ // Wipe out the "is interesting" bit.
+ RawID = RawID >> 1;
+
+ IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
+ if (!IsInteresting) {
+ // For uninteresting identifiers, just build the IdentifierInfo
+ // and associate it with the persistent ID.
+ IdentifierInfo *II = KnownII;
+ if (!II) {
+ II = &Reader.getIdentifierTable().getOwn(k);
+ KnownII = II;
+ }
+ Reader.SetIdentifierInfo(ID, II);
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
+ Reader.markIdentifierUpToDate(II);
+ return II;
+ }
+
+ unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d);
+ bool CPlusPlusOperatorKeyword = Bits & 0x01;
+ Bits >>= 1;
+ bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
+ Bits >>= 1;
+ bool Poisoned = Bits & 0x01;
+ Bits >>= 1;
+ bool ExtensionToken = Bits & 0x01;
+ Bits >>= 1;
+ bool hadMacroDefinition = Bits & 0x01;
+ Bits >>= 1;
+
+ assert(Bits == 0 && "Extra bits in the identifier?");
+ DataLen -= 8;
+
+ // Build the IdentifierInfo itself and link the identifier ID with
+ // the new IdentifierInfo.
+ IdentifierInfo *II = KnownII;
+ if (!II) {
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k));
+ KnownII = II;
+ }
+ Reader.markIdentifierUpToDate(II);
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
+
+ // Set or check the various bits in the IdentifierInfo structure.
+ // Token IDs are read-only.
+ if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier)
+ II->RevertTokenIDToIdentifier();
+ II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ assert(II->isExtensionToken() == ExtensionToken &&
+ "Incorrect extension token flag");
+ (void)ExtensionToken;
+ if (Poisoned)
+ II->setIsPoisoned(true);
+ assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
+ "Incorrect C++ operator keyword flag");
+ (void)CPlusPlusOperatorKeyword;
+
+ // If this identifier is a macro, deserialize the macro
+ // definition.
+ if (hadMacroDefinition) {
+ uint32_t MacroDirectivesOffset =
+ endian::readNext<uint32_t, little, unaligned>(d);
+ DataLen -= 4;
+
+ Reader.addPendingMacro(II, &F, MacroDirectivesOffset);
+ }
+
+ Reader.SetIdentifierInfo(ID, II);
+
+ // Read all of the declarations visible at global scope with this
+ // name.
+ if (DataLen > 0) {
+ SmallVector<uint32_t, 4> DeclIDs;
+ for (; DataLen > 0; DataLen -= 4)
+ DeclIDs.push_back(Reader.getGlobalDeclID(
+ F, endian::readNext<uint32_t, little, unaligned>(d)));
+ Reader.SetGloballyVisibleDecls(II, DeclIDs);
+ }
+
+ return II;
+}
+
+unsigned
+ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(Key.Kind);
+
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ case DeclarationName::CXXLiteralOperatorName:
+ ID.AddString(((IdentifierInfo*)Key.Data)->getName());
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
+ break;
+ case DeclarationName::CXXOperatorName:
+ ID.AddInteger((OverloadedOperatorKind)Key.Data);
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+
+ return ID.ComputeHash();
+}
+
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::GetInternalKey(
+ const external_key_type& Name) const {
+ DeclNameKey Key;
+ Key.Kind = Name.getNameKind();
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Name.getAsIdentifierInfo();
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = Name.getCXXOverloadedOperator();
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
+ }
+
+ return Key;
+}
+
+std::pair<unsigned, unsigned>
+ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace llvm::support;
+
+ DeclNameKey Key;
+ Key.Kind = (DeclarationName::NameKind)*d++;
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data =
+ (uint64_t)Reader.getLocalSelector(
+ F, endian::readNext<uint32_t, little, unaligned>(
+ d)).getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = *d++; // OverloadedOperatorKind
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
+ }
+
+ return Key;
+}
+
+ASTDeclContextNameLookupTrait::data_type
+ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace llvm::support;
+ unsigned NumDecls = endian::readNext<uint16_t, little, unaligned>(d);
+ LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
+ const_cast<unsigned char *>(d));
+ return std::make_pair(Start, Start + NumDecls);
+}
+
+bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
+ BitstreamCursor &Cursor,
+ const std::pair<uint64_t, uint64_t> &Offsets,
+ DeclContextInfo &Info) {
+ SavedStreamPosition SavedPosition(Cursor);
+ // First the lexical decls.
+ if (Offsets.first != 0) {
+ Cursor.JumpToBit(Offsets.first);
+
+ RecordData Record;
+ StringRef Blob;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
+ if (RecCode != DECL_CONTEXT_LEXICAL) {
+ Error("Expected lexical block");
+ return true;
+ }
+
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
+ Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
+ }
+
+ // Now the lookup table.
+ if (Offsets.second != 0) {
+ Cursor.JumpToBit(Offsets.second);
+
+ RecordData Record;
+ StringRef Blob;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
+ if (RecCode != DECL_CONTEXT_VISIBLE) {
+ Error("Expected visible lookup table block");
+ return true;
+ }
+ Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, M));
+ }
+
+ return false;
+}
+
+void ASTReader::Error(StringRef Msg) {
+ Error(diag::err_fe_pch_malformed, Msg);
+ if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
+ Diag(diag::note_module_cache_path)
+ << PP.getHeaderSearchInfo().getModuleCachePath();
+ }
+}
+
+void ASTReader::Error(unsigned DiagID,
+ StringRef Arg1, StringRef Arg2) {
+ if (Diags.isDiagnosticInFlight())
+ Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
+ else
+ Diag(DiagID) << Arg1 << Arg2;
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Deserialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Read the line table in the source manager block.
+/// \returns true if there was an error.
+bool ASTReader::ParseLineTable(ModuleFile &F,
+ const RecordData &Record) {
+ unsigned Idx = 0;
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ // Parse the file names
+ std::map<int, int> FileIDs;
+ for (int I = 0, N = Record[Idx++]; I != N; ++I) {
+ // Extract the file name
+ auto Filename = ReadPath(F, Record, Idx);
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
+ }
+
+ // Parse the line entries
+ std::vector<LineEntry> Entries;
+ while (Idx < Record.size()) {
+ int FID = Record[Idx++];
+ assert(FID >= 0 && "Serialized line entries for non-local file.");
+ // Remap FileID from 1-based old view.
+ FID += F.SLocEntryBaseID - 1;
+
+ // Extract the line entries
+ unsigned NumEntries = Record[Idx++];
+ assert(NumEntries && "Numentries is 00000");
+ Entries.clear();
+ Entries.reserve(NumEntries);
+ for (unsigned I = 0; I != NumEntries; ++I) {
+ unsigned FileOffset = Record[Idx++];
+ unsigned LineNo = Record[Idx++];
+ int FilenameID = FileIDs[Record[Idx++]];
+ SrcMgr::CharacteristicKind FileKind
+ = (SrcMgr::CharacteristicKind)Record[Idx++];
+ unsigned IncludeOffset = Record[Idx++];
+ Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
+ FileKind, IncludeOffset));
+ }
+ LineTable.AddEntry(FileID::get(FID), Entries);
+ }
+
+ return false;
+}
+
+/// \brief Read a source manager block
+bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
+ using namespace SrcMgr;
+
+ BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
+
+ // Set the source-location entry cursor to the current position in
+ // the stream. This cursor will be used to read the contents of the
+ // source manager block initially, and then lazily read
+ // source-location entries as needed.
+ SLocEntryCursor = F.Stream;
+
+ // The stream itself is going to skip over the source manager block.
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+
+ // Enter the source manager block.
+ if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
+ Error("malformed source manager block record in AST file");
+ return true;
+ }
+
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock:
+ return false;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SM_SLOC_FILE_ENTRY:
+ case SM_SLOC_BUFFER_ENTRY:
+ case SM_SLOC_EXPANSION_ENTRY:
+ // Once we hit one of the source location entries, we're done.
+ return false;
+ }
+ }
+}
+
+/// \brief If a header file is not found at the path that we expect it to be
+/// and the PCH file was moved from its original location, try to resolve the
+/// file by assuming that header+PCH were moved together and the header is in
+/// the same place relative to the PCH.
+static std::string
+resolveFileRelativeToOriginalDir(const std::string &Filename,
+ const std::string &OriginalDir,
+ const std::string &CurrDir) {
+ assert(OriginalDir != CurrDir &&
+ "No point trying to resolve the file if the PCH dir didn't change");
+ using namespace llvm::sys;
+ SmallString<128> filePath(Filename);
+ fs::make_absolute(filePath);
+ assert(path::is_absolute(OriginalDir));
+ SmallString<128> currPCHPath(CurrDir);
+
+ path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
+ fileDirE = path::end(path::parent_path(filePath));
+ path::const_iterator origDirI = path::begin(OriginalDir),
+ origDirE = path::end(OriginalDir);
+ // Skip the common path components from filePath and OriginalDir.
+ while (fileDirI != fileDirE && origDirI != origDirE &&
+ *fileDirI == *origDirI) {
+ ++fileDirI;
+ ++origDirI;
+ }
+ for (; origDirI != origDirE; ++origDirI)
+ path::append(currPCHPath, "..");
+ path::append(currPCHPath, fileDirI, fileDirE);
+ path::append(currPCHPath, path::filename(Filename));
+ return currPCHPath.str();
+}
+
+bool ASTReader::ReadSLocEntry(int ID) {
+ if (ID == 0)
+ return false;
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return true;
+ }
+
+ ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
+ F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
+ BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ unsigned BaseOffset = F->SLocEntryBaseOffset;
+
+ ++NumSLocEntriesRead;
+ llvm::BitstreamEntry Entry = SLocEntryCursor.advance();
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Error("incorrectly-formatted source location entry in AST file");
+ return true;
+ }
+
+ RecordData Record;
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) {
+ default:
+ Error("incorrectly-formatted source location entry in AST file");
+ return true;
+
+ case SM_SLOC_FILE_ENTRY: {
+ // We will detect whether a file changed and return 'Failure' for it, but
+ // we will also try to fail gracefully by setting up the SLocEntry.
+ unsigned InputID = Record[4];
+ InputFile IF = getInputFile(*F, InputID);
+ const FileEntry *File = IF.getFile();
+ bool OverriddenBuffer = IF.isOverridden();
+
+ // Note that we only check if a File was returned. If it was out-of-date
+ // we have complained but we will continue creating a FileID to recover
+ // gracefully.
+ if (!File)
+ return true;
+
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
+ // This is the module's main file.
+ IncludeLoc = getImportLocation(F);
+ }
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
+ ID, BaseOffset + Record[0]);
+ SrcMgr::FileInfo &FileInfo =
+ const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
+ FileInfo.NumCreatedFIDs = Record[5];
+ if (Record[3])
+ FileInfo.setHasLineDirectives();
+
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
+ unsigned NumFileDecls = Record[7];
+ if (NumFileDecls) {
+ assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
+ FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
+ NumFileDecls));
+ }
+
+ const SrcMgr::ContentCache *ContentCache
+ = SourceMgr.getOrCreateContentCache(File,
+ /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ if (OverriddenBuffer && !ContentCache->BufferOverridden &&
+ ContentCache->ContentsEntry == ContentCache->OrigEntry) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return true;
+ }
+
+ std::unique_ptr<llvm::MemoryBuffer> Buffer
+ = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
+ SourceMgr.overrideFileContents(File, std::move(Buffer));
+ }
+
+ break;
+ }
+
+ case SM_SLOC_BUFFER_ENTRY: {
+ const char *Name = Blob.data();
+ unsigned Offset = Record[0];
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() &&
+ (F->Kind == MK_ImplicitModule || F->Kind == MK_ExplicitModule)) {
+ IncludeLoc = getImportLocation(F);
+ }
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.readRecord(Code, Record, &Blob);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return true;
+ }
+
+ std::unique_ptr<llvm::MemoryBuffer> Buffer =
+ llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
+ SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID,
+ BaseOffset + Offset, IncludeLoc);
+ break;
+ }
+
+ case SM_SLOC_EXPANSION_ENTRY: {
+ SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
+ SourceMgr.createExpansionLoc(SpellingLoc,
+ ReadSourceLocation(*F, Record[2]),
+ ReadSourceLocation(*F, Record[3]),
+ Record[4],
+ ID,
+ BaseOffset + Record[0]);
+ break;
+ }
+ }
+
+ return false;
+}
+
+std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
+ if (ID == 0)
+ return std::make_pair(SourceLocation(), "");
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return std::make_pair(SourceLocation(), "");
+ }
+
+ // Find which module file this entry lands in.
+ ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
+ if (M->Kind != MK_ImplicitModule && M->Kind != MK_ExplicitModule)
+ return std::make_pair(SourceLocation(), "");
+
+ // FIXME: Can we map this down to a particular submodule? That would be
+ // ideal.
+ return std::make_pair(M->ImportLoc, StringRef(M->ModuleName));
+}
+
+/// \brief Find the location where the module F is imported.
+SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
+ if (F->ImportLoc.isValid())
+ return F->ImportLoc;
+
+ // Otherwise we have a PCH. It's considered to be "imported" at the first
+ // location of its includer.
+ if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
+ // Main file is the importer.
+ assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file");
+ return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ }
+ return F->ImportedBy[0]->FirstLoc;
+}
+
+/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
+/// specified cursor. Read the abbreviations that are at the top of the block
+/// and then leave the cursor pointing into the block.
+bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
+ if (Cursor.EnterSubBlock(BlockID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ while (true) {
+ uint64_t Offset = Cursor.GetCurrentBitNo();
+ unsigned Code = Cursor.ReadCode();
+
+ // We expect all abbrevs to be at the start of the block.
+ if (Code != llvm::bitc::DEFINE_ABBREV) {
+ Cursor.JumpToBit(Offset);
+ return false;
+ }
+ Cursor.ReadAbbrevRecord();
+ }
+}
+
+Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
+ unsigned &Idx) {
+ Token Tok;
+ Tok.startToken();
+ Tok.setLocation(ReadSourceLocation(F, Record, Idx));
+ Tok.setLength(Record[Idx++]);
+ if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
+ Tok.setIdentifierInfo(II);
+ Tok.setKind((tok::TokenKind)Record[Idx++]);
+ Tok.setFlag((Token::TokenFlags)Record[Idx++]);
+ return Tok;
+}
+
+MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
+ BitstreamCursor &Stream = F.MacroCursor;
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this macro.
+ SavedStreamPosition SavedPosition(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ SmallVector<IdentifierInfo*, 16> MacroArgs;
+ MacroInfo *Macro = nullptr;
+
+ while (true) {
+ // Advance to the next record, but if we get to the end of the block, don't
+ // pop it (removing all the abbreviations from the cursor) since we want to
+ // be able to reseek within the block and read entries.
+ unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd;
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Macro;
+ case llvm::BitstreamEntry::EndBlock:
+ return Macro;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ PreprocessorRecordTypes RecType =
+ (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record);
+ switch (RecType) {
+ case PP_MODULE_MACRO:
+ case PP_MACRO_DIRECTIVE_HISTORY:
+ return Macro;
+
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return Macro;
+
+ unsigned NextIndex = 1; // Skip identifier ID.
+ SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
+ SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
+ MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
+ MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
+ MI->setIsUsed(Record[NextIndex++]);
+ MI->setUsedForHeaderGuard(Record[NextIndex++]);
+
+ if (RecType == PP_MACRO_FUNCTION_LIKE) {
+ // Decode function-like macro info.
+ bool isC99VarArgs = Record[NextIndex++];
+ bool isGNUVarArgs = Record[NextIndex++];
+ bool hasCommaPasting = Record[NextIndex++];
+ MacroArgs.clear();
+ unsigned NumArgs = Record[NextIndex++];
+ for (unsigned i = 0; i != NumArgs; ++i)
+ MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
+
+ // Install function-like macro info.
+ MI->setIsFunctionLike();
+ if (isC99VarArgs) MI->setIsC99Varargs();
+ if (isGNUVarArgs) MI->setIsGNUVarargs();
+ if (hasCommaPasting) MI->setHasCommaPasting();
+ MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
+ PP.getPreprocessorAllocator());
+ }
+
+ // Remember that we saw this macro last so that we add the tokens that
+ // form its body to it.
+ Macro = MI;
+
+ if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() &&
+ Record[NextIndex]) {
+ // We have a macro definition. Register the association
+ PreprocessedEntityID
+ GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ PreprocessingRecord::PPEntityID PPID =
+ PPRec.getPPEntityID(GlobalID - 1, /*isLoaded=*/true);
+ MacroDefinitionRecord *PPDef = cast_or_null<MacroDefinitionRecord>(
+ PPRec.getPreprocessedEntity(PPID));
+ if (PPDef)
+ PPRec.RegisterMacroDefinition(Macro, PPDef);
+ }
+
+ ++NumMacrosRead;
+ break;
+ }
+
+ case PP_TOKEN: {
+ // If we see a TOKEN before a PP_MACRO_*, then the file is
+ // erroneous, just pretend we didn't see this.
+ if (!Macro) break;
+
+ unsigned Idx = 0;
+ Token Tok = ReadToken(F, Record, Idx);
+ Macro->AddTokenToBody(Tok);
+ break;
+ }
+ }
+ }
+}
+
+PreprocessedEntityID
+ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
+ ContinuousRangeMap<uint32_t, int, 2>::const_iterator
+ I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
+ assert(I != M.PreprocessedEntityRemap.end()
+ && "Invalid index into preprocessed entity index remap");
+
+ return LocalID + I->second;
+}
+
+unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
+ return llvm::hash_combine(ikey.Size, ikey.ModTime);
+}
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
+ internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
+ FE->getName(), /*Imported*/false };
+ return ikey;
+}
+
+bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
+ if (a.Size != b.Size || a.ModTime != b.ModTime)
+ return false;
+
+ if (llvm::sys::path::is_absolute(a.Filename) &&
+ strcmp(a.Filename, b.Filename) == 0)
+ return true;
+
+ // Determine whether the actual files are equivalent.
+ FileManager &FileMgr = Reader.getFileManager();
+ auto GetFile = [&](const internal_key_type &Key) -> const FileEntry* {
+ if (!Key.Imported)
+ return FileMgr.getFile(Key.Filename);
+
+ std::string Resolved = Key.Filename;
+ Reader.ResolveImportedPath(M, Resolved);
+ return FileMgr.getFile(Resolved);
+ };
+
+ const FileEntry *FEA = GetFile(a);
+ const FileEntry *FEB = GetFile(b);
+ return FEA && FEA == FEB;
+}
+
+std::pair<unsigned, unsigned>
+HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace llvm::support;
+ unsigned KeyLen = (unsigned) endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = (unsigned) *d++;
+ return std::make_pair(KeyLen, DataLen);
+}
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
+ using namespace llvm::support;
+ internal_key_type ikey;
+ ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d));
+ ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d));
+ ikey.Filename = (const char *)d;
+ ikey.Imported = true;
+ return ikey;
+}
+
+HeaderFileInfoTrait::data_type
+HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
+ unsigned DataLen) {
+ const unsigned char *End = d + DataLen;
+ using namespace llvm::support;
+ HeaderFileInfo HFI;
+ unsigned Flags = *d++;
+ HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
+ ((Flags >> 6) & 0x03);
+ HFI.isImport = (Flags >> 5) & 0x01;
+ HFI.isPragmaOnce = (Flags >> 4) & 0x01;
+ HFI.DirInfo = (Flags >> 2) & 0x03;
+ HFI.Resolved = (Flags >> 1) & 0x01;
+ HFI.IndexHeaderMapHeader = Flags & 0x01;
+ HFI.NumIncludes = endian::readNext<uint16_t, little, unaligned>(d);
+ HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
+ M, endian::readNext<uint32_t, little, unaligned>(d));
+ if (unsigned FrameworkOffset =
+ endian::readNext<uint32_t, little, unaligned>(d)) {
+ // The framework offset is 1 greater than the actual offset,
+ // since 0 is used as an indicator for "no framework name".
+ StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
+ HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
+ }
+
+ if (d != End) {
+ uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d);
+ if (LocalSMID) {
+ // This header is part of a module. Associate it with the module to enable
+ // implicit module import.
+ SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
+ Module *Mod = Reader.getSubmodule(GlobalSMID);
+ HFI.isModuleHeader = true;
+ FileManager &FileMgr = Reader.getFileManager();
+ ModuleMap &ModMap =
+ Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ // FIXME: This information should be propagated through the
+ // SUBMODULE_HEADER etc records rather than from here.
+ // FIXME: We don't ever mark excluded headers.
+ std::string Filename = key.Filename;
+ if (key.Imported)
+ Reader.ResolveImportedPath(M, Filename);
+ Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
+ ModMap.addHeader(Mod, H, HFI.getHeaderRole());
+ }
+ }
+
+ assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
+ (void)End;
+
+ // This HeaderFileInfo was externally loaded.
+ HFI.External = true;
+ return HFI;
+}
+
+void ASTReader::addPendingMacro(IdentifierInfo *II,
+ ModuleFile *M,
+ uint64_t MacroDirectivesOffset) {
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset));
+}
+
+void ASTReader::ReadDefinedMacros() {
+ // Note that we are loading defined macros.
+ Deserializing Macros(this);
+
+ for (ModuleReverseIterator I = ModuleMgr.rbegin(),
+ E = ModuleMgr.rend(); I != E; ++I) {
+ BitstreamCursor &MacroCursor = (*I)->MacroCursor;
+
+ // If there was no preprocessor block, skip this file.
+ if (!MacroCursor.getBitStreamReader())
+ continue;
+
+ BitstreamCursor Cursor = MacroCursor;
+ Cursor.JumpToBit((*I)->MacroStartOffset);
+
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+
+ case llvm::BitstreamEntry::Record:
+ Record.clear();
+ switch (Cursor.readRecord(E.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE:
+ getLocalIdentifier(**I, Record[0]);
+ break;
+
+ case PP_TOKEN:
+ // Ignore tokens.
+ break;
+ }
+ break;
+ }
+ }
+ NextCursor: ;
+ }
+}
+
+namespace {
+ /// \brief Visitor class used to look up identifirs in an AST file.
+ class IdentifierLookupVisitor {
+ StringRef Name;
+ unsigned PriorGeneration;
+ unsigned &NumIdentifierLookups;
+ unsigned &NumIdentifierLookupHits;
+ IdentifierInfo *Found;
+
+ public:
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration,
+ unsigned &NumIdentifierLookups,
+ unsigned &NumIdentifierLookupHits)
+ : Name(Name), PriorGeneration(PriorGeneration),
+ NumIdentifierLookups(NumIdentifierLookups),
+ NumIdentifierLookupHits(NumIdentifierLookupHits),
+ Found()
+ {
+ }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ IdentifierLookupVisitor *This
+ = static_cast<IdentifierLookupVisitor *>(UserData);
+
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
+ if (!IdTable)
+ return false;
+
+ ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
+ M, This->Found);
+ ++This->NumIdentifierLookups;
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait);
+ if (Pos == IdTable->end())
+ return false;
+
+ // Dereferencing the iterator has the effect of building the
+ // IdentifierInfo node and populating it with the various
+ // declarations it needs.
+ ++This->NumIdentifierLookupHits;
+ This->Found = *Pos;
+ return true;
+ }
+
+ // \brief Retrieve the identifier info found within the module
+ // files.
+ IdentifierInfo *getIdentifierInfo() const { return Found; }
+ };
+}
+
+void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
+ unsigned PriorGeneration = 0;
+ if (getContext().getLangOpts().Modules)
+ PriorGeneration = IdentifierGeneration[&II];
+
+ // If there is a global index, look there first to determine which modules
+ // provably do not have any results for this identifier.
+ GlobalModuleIndex::HitSet Hits;
+ GlobalModuleIndex::HitSet *HitsPtr = nullptr;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
+ markIdentifierUpToDate(&II);
+}
+
+void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
+ if (!II)
+ return;
+
+ II->setOutOfDate(false);
+
+ // Update the generation for this identifier.
+ if (getContext().getLangOpts().Modules)
+ IdentifierGeneration[II] = getGeneration();
+}
+
+void ASTReader::resolvePendingMacro(IdentifierInfo *II,
+ const PendingMacroInfo &PMInfo) {
+ ModuleFile &M = *PMInfo.M;
+
+ BitstreamCursor &Cursor = M.MacroCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(PMInfo.MacroDirectivesOffset);
+
+ struct ModuleMacroRecord {
+ SubmoduleID SubModID;
+ MacroInfo *MI;
+ SmallVector<SubmoduleID, 8> Overrides;
+ };
+ llvm::SmallVector<ModuleMacroRecord, 8> ModuleMacros;
+
+ // We expect to see a sequence of PP_MODULE_MACRO records listing exported
+ // macros, followed by a PP_MACRO_DIRECTIVE_HISTORY record with the complete
+ // macro histroy.
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry Entry =
+ Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ Record.clear();
+ switch ((PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record)) {
+ case PP_MACRO_DIRECTIVE_HISTORY:
+ break;
+
+ case PP_MODULE_MACRO: {
+ ModuleMacros.push_back(ModuleMacroRecord());
+ auto &Info = ModuleMacros.back();
+ Info.SubModID = getGlobalSubmoduleID(M, Record[0]);
+ Info.MI = getMacro(getGlobalMacroID(M, Record[1]));
+ for (int I = 2, N = Record.size(); I != N; ++I)
+ Info.Overrides.push_back(getGlobalSubmoduleID(M, Record[I]));
+ continue;
+ }
+
+ default:
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ // We found the macro directive history; that's the last record
+ // for this macro.
+ break;
+ }
+
+ // Module macros are listed in reverse dependency order.
+ {
+ std::reverse(ModuleMacros.begin(), ModuleMacros.end());
+ llvm::SmallVector<ModuleMacro*, 8> Overrides;
+ for (auto &MMR : ModuleMacros) {
+ Overrides.clear();
+ for (unsigned ModID : MMR.Overrides) {
+ Module *Mod = getSubmodule(ModID);
+ auto *Macro = PP.getModuleMacro(Mod, II);
+ assert(Macro && "missing definition for overridden macro");
+ Overrides.push_back(Macro);
+ }
+
+ bool Inserted = false;
+ Module *Owner = getSubmodule(MMR.SubModID);
+ PP.addModuleMacro(Owner, II, MMR.MI, Overrides, Inserted);
+ }
+ }
+
+ // Don't read the directive history for a module; we don't have anywhere
+ // to put it.
+ if (M.Kind == MK_ImplicitModule || M.Kind == MK_ExplicitModule)
+ return;
+
+ // Deserialize the macro directives history in reverse source-order.
+ MacroDirective *Latest = nullptr, *Earliest = nullptr;
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ MacroDirective *MD = nullptr;
+ SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
+ MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++];
+ switch (K) {
+ case MacroDirective::MD_Define: {
+ MacroInfo *MI = getMacro(getGlobalMacroID(M, Record[Idx++]));
+ MD = PP.AllocateDefMacroDirective(MI, Loc);
+ break;
+ }
+ case MacroDirective::MD_Undefine: {
+ MD = PP.AllocateUndefMacroDirective(Loc);
+ break;
+ }
+ case MacroDirective::MD_Visibility:
+ bool isPublic = Record[Idx++];
+ MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic);
+ break;
+ }
+
+ if (!Latest)
+ Latest = MD;
+ if (Earliest)
+ Earliest->setPrevious(MD);
+ Earliest = MD;
+ }
+
+ if (Latest)
+ PP.setLoadedMacroDirective(II, Latest);
+}
+
+ASTReader::InputFileInfo
+ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
+ // Go find this input file.
+ BitstreamCursor &Cursor = F.InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
+
+ unsigned Code = Cursor.ReadCode();
+ RecordData Record;
+ StringRef Blob;
+
+ unsigned Result = Cursor.readRecord(Code, Record, &Blob);
+ assert(static_cast<InputFileRecordTypes>(Result) == INPUT_FILE &&
+ "invalid record type for input file");
+ (void)Result;
+
+ std::string Filename;
+ off_t StoredSize;
+ time_t StoredTime;
+ bool Overridden;
+
+ assert(Record[0] == ID && "Bogus stored ID or offset");
+ StoredSize = static_cast<off_t>(Record[1]);
+ StoredTime = static_cast<time_t>(Record[2]);
+ Overridden = static_cast<bool>(Record[3]);
+ Filename = Blob;
+ ResolveImportedPath(F, Filename);
+
+ InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
+ return R;
+}
+
+std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) {
+ return readInputFileInfo(F, ID).Filename;
+}
+
+InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+ // If this ID is bogus, just return an empty input file.
+ if (ID == 0 || ID > F.InputFilesLoaded.size())
+ return InputFile();
+
+ // If we've already loaded this input file, return it.
+ if (F.InputFilesLoaded[ID-1].getFile())
+ return F.InputFilesLoaded[ID-1];
+
+ if (F.InputFilesLoaded[ID-1].isNotFound())
+ return InputFile();
+
+ // Go find this input file.
+ BitstreamCursor &Cursor = F.InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
+
+ InputFileInfo FI = readInputFileInfo(F, ID);
+ off_t StoredSize = FI.StoredSize;
+ time_t StoredTime = FI.StoredTime;
+ bool Overridden = FI.Overridden;
+ StringRef Filename = FI.Filename;
+
+ const FileEntry *File
+ = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
+
+ // If we didn't find the file, resolve it relative to the
+ // original directory from which this AST file was created.
+ if (File == nullptr && !F.OriginalDir.empty() && !CurrentDir.empty() &&
+ F.OriginalDir != CurrentDir) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
+ F.OriginalDir,
+ CurrentDir);
+ if (!Resolved.empty())
+ File = FileMgr.getFile(Resolved);
+ }
+
+ // For an overridden file, create a virtual file with the stored
+ // size/timestamp.
+ if (Overridden && File == nullptr) {
+ File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
+ }
+
+ if (File == nullptr) {
+ if (Complain) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ }
+ // Record that we didn't find the file.
+ F.InputFilesLoaded[ID-1] = InputFile::getNotFound();
+ return InputFile();
+ }
+
+ // Check if there was a request to override the contents of the file
+ // that was part of the precompiled header. Overridding such a file
+ // can lead to problems when lexing using the source locations from the
+ // PCH.
+ SourceManager &SM = getSourceManager();
+ if (!Overridden && SM.isFileOverridden(File)) {
+ if (Complain)
+ Error(diag::err_fe_pch_file_overridden, Filename);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ bool IsOutOfDate = false;
+
+ // For an overridden file, there is nothing to validate.
+ if (!Overridden && //
+ (StoredSize != File->getSize() ||
+#if defined(LLVM_ON_WIN32)
+ false
+#else
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ //
+ // This also happens in networked file systems, so disable this
+ // check if validation is disabled or if we have an explicitly
+ // built PCM file.
+ //
+ // FIXME: Should we also do this for PCH files? They could also
+ // reasonably get shared across a network during a distributed build.
+ (StoredTime != File->getModificationTime() && !DisableValidation &&
+ F.Kind != MK_ExplicitModule)
+#endif
+ )) {
+ if (Complain) {
+ // Build a list of the PCH imports that got us here (in reverse).
+ SmallVector<ModuleFile *, 4> ImportStack(1, &F);
+ while (ImportStack.back()->ImportedBy.size() > 0)
+ ImportStack.push_back(ImportStack.back()->ImportedBy[0]);
+
+ // The top-level PCH is stale.
+ StringRef TopLevelPCHName(ImportStack.back()->FileName);
+ Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName);
+
+ // Print the import stack.
+ if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) {
+ Diag(diag::note_pch_required_by)
+ << Filename << ImportStack[0]->FileName;
+ for (unsigned I = 1; I < ImportStack.size(); ++I)
+ Diag(diag::note_pch_required_by)
+ << ImportStack[I-1]->FileName << ImportStack[I]->FileName;
+ }
+
+ if (!Diags.isDiagnosticInFlight())
+ Diag(diag::note_pch_rebuild_required) << TopLevelPCHName;
+ }
+
+ IsOutOfDate = true;
+ }
+
+ InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = IF;
+ return IF;
+}
+
+/// \brief If we are loading a relocatable PCH or module file, and the filename
+/// is not an absolute path, add the system or module root to the beginning of
+/// the file name.
+void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) {
+ // Resolve relative to the base directory, if we have one.
+ if (!M.BaseDirectory.empty())
+ return ResolveImportedPath(Filename, M.BaseDirectory);
+}
+
+void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
+ if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
+ return;
+
+ SmallString<128> Buffer;
+ llvm::sys::path::append(Buffer, Prefix, Filename);
+ Filename.assign(Buffer.begin(), Buffer.end());
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadControlBlock(ModuleFile &F,
+ SmallVectorImpl<ImportedModule> &Loaded,
+ const ModuleFile *ImportedBy,
+ unsigned ClientLoadCapabilities) {
+ BitstreamCursor &Stream = F.Stream;
+
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ // Should we allow the configuration of the module file to differ from the
+ // configuration of the current translation unit in a compatible way?
+ //
+ // FIXME: Allow this for files explicitly specified with -include-pch too.
+ bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule;
+
+ // Read all of the records and blocks in the control block.
+ RecordData Record;
+ unsigned NumInputs = 0;
+ unsigned NumUserInputs = 0;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Failure;
+ case llvm::BitstreamEntry::EndBlock: {
+ // Validate input files.
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+
+ // All user input files reside at the index range [0, NumUserInputs), and
+ // system input files reside at [NumUserInputs, NumInputs).
+ if (!DisableValidation) {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+
+ // If we are reading a module, we will create a verification timestamp,
+ // so we verify all input files. Otherwise, verify only user input
+ // files.
+
+ unsigned N = NumUserInputs;
+ if (ValidateSystemInputs ||
+ (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp &&
+ F.Kind == MK_ImplicitModule))
+ N = NumInputs;
+
+ for (unsigned I = 0; I < N; ++I) {
+ InputFile IF = getInputFile(F, I+1, Complain);
+ if (!IF.getFile() || IF.isOutOfDate())
+ return OutOfDate;
+ }
+ }
+
+ if (Listener)
+ Listener->visitModuleFile(F.FileName);
+
+ if (Listener && Listener->needsInputFileVisitation()) {
+ unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs
+ : NumUserInputs;
+ for (unsigned I = 0; I < N; ++I) {
+ bool IsSystem = I >= NumUserInputs;
+ InputFileInfo FI = readInputFileInfo(F, I+1);
+ Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden);
+ }
+ }
+
+ return Success;
+ }
+
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
+ case INPUT_FILES_BLOCK_ID:
+ F.InputFilesCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor
+ // Read the abbreviations
+ ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+ }
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ StringRef Blob;
+ switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old
+ : diag::err_pch_version_too_new);
+ return VersionMismatch;
+ }
+
+ bool hasErrors = Record[5];
+ if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+ Diag(diag::err_pch_with_compiler_errors);
+ return HadErrors;
+ }
+
+ F.RelocatablePCH = Record[4];
+ // Relative paths in a relocatable PCH are relative to our sysroot.
+ if (F.RelocatablePCH)
+ F.BaseDirectory = isysroot.empty() ? "/" : isysroot;
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch = Blob;
+ if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch;
+ return VersionMismatch;
+ }
+ break;
+ }
+
+ case SIGNATURE:
+ assert((!F.Signature || F.Signature == Record[0]) && "signature changed");
+ F.Signature = Record[0];
+ break;
+
+ case IMPORTS: {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ // The import location will be the local one for now; we will adjust
+ // all import locations of module imports after the global source
+ // location info are setup.
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(Record[Idx++]);
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
+ ASTFileSignature StoredSignature = Record[Idx++];
+ auto ImportedFile = ReadPath(F, Record, Idx);
+
+ // Load the AST file.
+ switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
+ StoredSize, StoredModTime, StoredSignature,
+ ClientLoadCapabilities)) {
+ case Failure: return Failure;
+ // If we have to ignore the dependency, we'll have to ignore this too.
+ case Missing:
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ case Success: break;
+ }
+ }
+ break;
+ }
+
+ case KNOWN_MODULE_FILES:
+ break;
+
+ case LANGUAGE_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseLanguageOptions(Record, Complain, *Listener,
+ AllowCompatibleConfigurationMismatch) &&
+ !DisableValidation && !AllowConfigurationMismatch)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case TARGET_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseTargetOptions(Record, Complain, *Listener,
+ AllowCompatibleConfigurationMismatch) &&
+ !DisableValidation && !AllowConfigurationMismatch)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParseDiagnosticOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return OutOfDate;
+ break;
+ }
+
+ case FILE_SYSTEM_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParseFileSystemOptions(Record, Complain, *Listener) &&
+ !DisableValidation && !AllowConfigurationMismatch)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case HEADER_SEARCH_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParseHeaderSearchOptions(Record, Complain, *Listener) &&
+ !DisableValidation && !AllowConfigurationMismatch)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case PREPROCESSOR_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParsePreprocessorOptions(Record, Complain, *Listener,
+ SuggestedPredefines) &&
+ !DisableValidation && !AllowConfigurationMismatch)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case ORIGINAL_FILE:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ F.ActualOriginalSourceFileName = Blob;
+ F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
+ ResolveImportedPath(F, F.OriginalSourceFileName);
+ break;
+
+ case ORIGINAL_FILE_ID:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ break;
+
+ case ORIGINAL_PCH_DIR:
+ F.OriginalDir = Blob;
+ break;
+
+ case MODULE_NAME:
+ F.ModuleName = Blob;
+ if (Listener)
+ Listener->ReadModuleName(F.ModuleName);
+ break;
+
+ case MODULE_DIRECTORY: {
+ assert(!F.ModuleName.empty() &&
+ "MODULE_DIRECTORY found before MODULE_NAME");
+ // If we've already loaded a module map file covering this module, we may
+ // have a better path for it (relative to the current build).
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ if (M && M->Directory) {
+ // If we're implicitly loading a module, the base directory can't
+ // change between the build and use.
+ if (F.Kind != MK_ExplicitModule) {
+ const DirectoryEntry *BuildDir =
+ PP.getFileManager().getDirectory(Blob);
+ if (!BuildDir || BuildDir != M->Directory) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_relocated)
+ << F.ModuleName << Blob << M->Directory->getName();
+ return OutOfDate;
+ }
+ }
+ F.BaseDirectory = M->Directory->getName();
+ } else {
+ F.BaseDirectory = Blob;
+ }
+ break;
+ }
+
+ case MODULE_MAP_FILE:
+ if (ASTReadResult Result =
+ ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities))
+ return Result;
+ break;
+
+ case INPUT_FILE_OFFSETS:
+ NumInputs = Record[0];
+ NumUserInputs = Record[1];
+ F.InputFileOffsets = (const uint64_t *)Blob.data();
+ F.InputFilesLoaded.resize(NumInputs);
+ break;
+ }
+ }
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
+ BitstreamCursor &Stream = F.Stream;
+
+ if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ // Read all of the records and blocks for the AST file.
+ RecordData Record;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Error("error at end of module block in AST file");
+ return Failure;
+ case llvm::BitstreamEntry::EndBlock: {
+ // Outside of C++, we do not store a lookup map for the translation unit.
+ // Instead, mark it as needing a lookup map to be built if this module
+ // contains any declarations lexically within it (which it always does!).
+ // This usually has no cost, since we very rarely need the lookup map for
+ // the translation unit outside C++.
+ DeclContext *DC = Context.getTranslationUnitDecl();
+ if (DC->hasExternalLexicalStorage() &&
+ !getContext().getLangOpts().CPlusPlus)
+ DC->setMustBuildLookupTable();
+
+ return Success;
+ }
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
+ case DECLTYPES_BLOCK_ID:
+ // We lazily load the decls block, but we want to set up the
+ // DeclsCursor cursor to point into it. Clone our current bitcode
+ // cursor to it, enter the block and read the abbrevs in that block.
+ // With the main cursor, we just skip over it.
+ F.DeclsCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor.
+ // Read the abbrevs.
+ ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ break;
+
+ case PREPROCESSOR_BLOCK_ID:
+ F.MacroCursor = Stream;
+ if (!PP.getExternalSource())
+ PP.setExternalSource(this);
+
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
+ break;
+
+ case PREPROCESSOR_DETAIL_BLOCK_ID:
+ F.PreprocessorDetailCursor = Stream;
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(F.PreprocessorDetailCursor,
+ PREPROCESSOR_DETAIL_BLOCK_ID)) {
+ Error("malformed preprocessor detail record in AST file");
+ return Failure;
+ }
+ F.PreprocessorDetailStartOffset
+ = F.PreprocessorDetailCursor.GetCurrentBitNo();
+
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord();
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
+ break;
+
+ case SOURCE_MANAGER_BLOCK_ID:
+ if (ReadSourceManagerBlock(F))
+ return Failure;
+ break;
+
+ case SUBMODULE_BLOCK_ID:
+ if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ return Result;
+ break;
+
+ case COMMENTS_BLOCK_ID: {
+ BitstreamCursor C = Stream;
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
+ Error("malformed comments block in AST file");
+ return Failure;
+ }
+ CommentsCursors.push_back(std::make_pair(C, &F));
+ break;
+ }
+
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ break;
+ }
+ continue;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ StringRef Blob;
+ switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case TYPE_OFFSET: {
+ if (F.LocalNumTypes != 0) {
+ Error("duplicate TYPE_OFFSET record in AST file");
+ return Failure;
+ }
+ F.TypeOffsets = (const uint32_t *)Blob.data();
+ F.LocalNumTypes = Record[0];
+ unsigned LocalBaseTypeIndex = Record[1];
+ F.BaseTypeIndex = getTotalNumTypes();
+
+ if (F.LocalNumTypes > 0) {
+ // Introduce the global -> local mapping for types within this module.
+ GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
+
+ // Introduce the local -> global mapping for types within this module.
+ F.TypeRemap.insertOrReplace(
+ std::make_pair(LocalBaseTypeIndex,
+ F.BaseTypeIndex - LocalBaseTypeIndex));
+
+ TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
+ }
+ break;
+ }
+
+ case DECL_OFFSET: {
+ if (F.LocalNumDecls != 0) {
+ Error("duplicate DECL_OFFSET record in AST file");
+ return Failure;
+ }
+ F.DeclOffsets = (const DeclOffset *)Blob.data();
+ F.LocalNumDecls = Record[0];
+ unsigned LocalBaseDeclID = Record[1];
+ F.BaseDeclID = getTotalNumDecls();
+
+ if (F.LocalNumDecls > 0) {
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ GlobalDeclMap.insert(
+ std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
+
+ // Introduce the local -> global mapping for declarations within this
+ // module.
+ F.DeclRemap.insertOrReplace(
+ std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
+
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
+
+ DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
+ }
+ break;
+ }
+
+ case TU_UPDATE_LEXICAL: {
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ DeclContextInfo &Info = F.DeclContextInfos[TU];
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data());
+ Info.NumLexicalDecls
+ = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair));
+ TU->setHasExternalLexicalStorage(true);
+ break;
+ }
+
+ case UPDATE_VISIBLE: {
+ unsigned Idx = 0;
+ serialization::DeclID ID = ReadDeclID(F, Record, Idx);
+ ASTDeclContextNameLookupTable *Table =
+ ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[Idx++],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, F));
+ if (Decl *D = GetExistingDecl(ID)) {
+ auto *DC = cast<DeclContext>(D);
+ DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
+ auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
+ delete LookupTable;
+ LookupTable = Table;
+ } else
+ PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
+ break;
+ }
+
+ case IDENTIFIER_TABLE:
+ F.IdentifierTableData = Blob.data();
+ if (Record[0]) {
+ F.IdentifierLookupTable = ASTIdentifierLookupTable::Create(
+ (const unsigned char *)F.IdentifierTableData + Record[0],
+ (const unsigned char *)F.IdentifierTableData + sizeof(uint32_t),
+ (const unsigned char *)F.IdentifierTableData,
+ ASTIdentifierLookupTrait(*this, F));
+
+ PP.getIdentifierTable().setExternalIdentifierLookup(this);
+ }
+ break;
+
+ case IDENTIFIER_OFFSET: {
+ if (F.LocalNumIdentifiers != 0) {
+ Error("duplicate IDENTIFIER_OFFSET record in AST file");
+ return Failure;
+ }
+ F.IdentifierOffsets = (const uint32_t *)Blob.data();
+ F.LocalNumIdentifiers = Record[0];
+ unsigned LocalBaseIdentifierID = Record[1];
+ F.BaseIdentifierID = getTotalNumIdentifiers();
+
+ if (F.LocalNumIdentifiers > 0) {
+ // Introduce the global -> local mapping for identifiers within this
+ // module.
+ GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1,
+ &F));
+
+ // Introduce the local -> global mapping for identifiers within this
+ // module.
+ F.IdentifierRemap.insertOrReplace(
+ std::make_pair(LocalBaseIdentifierID,
+ F.BaseIdentifierID - LocalBaseIdentifierID));
+
+ IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ + F.LocalNumIdentifiers);
+ }
+ break;
+ }
+
+ case EAGERLY_DESERIALIZED_DECLS:
+ // FIXME: Skip reading this record if our ASTConsumer doesn't care
+ // about "interesting" decls (for instance, if we're building a module).
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case SPECIAL_TYPES:
+ if (SpecialTypes.empty()) {
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ break;
+ }
+
+ if (SpecialTypes.size() != Record.size()) {
+ Error("invalid special-types record");
+ return Failure;
+ }
+
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ serialization::TypeID ID = getGlobalTypeID(F, Record[I]);
+ if (!SpecialTypes[I])
+ SpecialTypes[I] = ID;
+ // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate
+ // merge step?
+ }
+ break;
+
+ case STATISTICS:
+ TotalNumStatements += Record[0];
+ TotalNumMacros += Record[1];
+ TotalLexicalDeclContexts += Record[2];
+ TotalVisibleDeclContexts += Record[3];
+ break;
+
+ case UNUSED_FILESCOPED_DECLS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case DELEGATING_CTORS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case WEAK_UNDECLARED_IDENTIFIERS:
+ if (Record.size() % 4 != 0) {
+ Error("invalid weak identifiers record");
+ return Failure;
+ }
+
+ // FIXME: Ignore weak undeclared identifiers from non-original PCH
+ // files. This isn't the way to do it :)
+ WeakUndeclaredIdentifiers.clear();
+
+ // Translate the weak, undeclared identifiers into global IDs.
+ for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ WeakUndeclaredIdentifiers.push_back(Record[I++]);
+ }
+ break;
+
+ case SELECTOR_OFFSETS: {
+ F.SelectorOffsets = (const uint32_t *)Blob.data();
+ F.LocalNumSelectors = Record[0];
+ unsigned LocalBaseSelectorID = Record[1];
+ F.BaseSelectorID = getTotalNumSelectors();
+
+ if (F.LocalNumSelectors > 0) {
+ // Introduce the global -> local mapping for selectors within this
+ // module.
+ GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F));
+
+ // Introduce the local -> global mapping for selectors within this
+ // module.
+ F.SelectorRemap.insertOrReplace(
+ std::make_pair(LocalBaseSelectorID,
+ F.BaseSelectorID - LocalBaseSelectorID));
+
+ SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
+ }
+ break;
+ }
+
+ case METHOD_POOL:
+ F.SelectorLookupTableData = (const unsigned char *)Blob.data();
+ if (Record[0])
+ F.SelectorLookupTable
+ = ASTSelectorLookupTable::Create(
+ F.SelectorLookupTableData + Record[0],
+ F.SelectorLookupTableData,
+ ASTSelectorLookupTrait(*this, F));
+ TotalNumMethodPoolEntries += Record[1];
+ break;
+
+ case REFERENCED_SELECTOR_POOL:
+ if (!Record.empty()) {
+ for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+ ReferencedSelectorsData.push_back(getGlobalSelectorID(F,
+ Record[Idx++]));
+ ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx).
+ getRawEncoding());
+ }
+ }
+ break;
+
+ case PP_COUNTER_VALUE:
+ if (!Record.empty() && Listener)
+ Listener->ReadCounter(F, Record[0]);
+ break;
+
+ case FILE_SORTED_DECLS:
+ F.FileSortedDecls = (const DeclID *)Blob.data();
+ F.NumFileSortedDecls = Record[0];
+ break;
+
+ case SOURCE_LOCATION_OFFSETS: {
+ F.SLocEntryOffsets = (const uint32_t *)Blob.data();
+ F.LocalNumSLocEntries = Record[0];
+ unsigned SLocSpaceSize = Record[1];
+ std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
+ SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
+ SLocSpaceSize);
+ // Make our entry in the range map. BaseID is negative and growing, so
+ // we invert it. Because we invert it, though, we need the other end of
+ // the range.
+ unsigned RangeStart =
+ unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
+ GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
+ F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
+
+ // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
+ assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0);
+ GlobalSLocOffsetMap.insert(
+ std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
+ - SLocSpaceSize,&F));
+
+ // Initialize the remapping table.
+ // Invalid stays invalid.
+ F.SLocRemap.insertOrReplace(std::make_pair(0U, 0));
+ // This module. Base was 2 when being compiled.
+ F.SLocRemap.insertOrReplace(std::make_pair(2U,
+ static_cast<int>(F.SLocEntryBaseOffset - 2)));
+
+ TotalNumSLocEntries += F.LocalNumSLocEntries;
+ break;
+ }
+
+ case MODULE_OFFSET_MAP: {
+ // Additional remapping information.
+ const unsigned char *Data = (const unsigned char*)Blob.data();
+ const unsigned char *DataEnd = Data + Blob.size();
+
+ // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders.
+ if (F.SLocRemap.find(0) == F.SLocRemap.end()) {
+ F.SLocRemap.insert(std::make_pair(0U, 0));
+ F.SLocRemap.insert(std::make_pair(2U, 1));
+ }
+
+ // Continuous range maps we may be updating in our module.
+ typedef ContinuousRangeMap<uint32_t, int, 2>::Builder
+ RemapBuilder;
+ RemapBuilder SLocRemap(F.SLocRemap);
+ RemapBuilder IdentifierRemap(F.IdentifierRemap);
+ RemapBuilder MacroRemap(F.MacroRemap);
+ RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap);
+ RemapBuilder SubmoduleRemap(F.SubmoduleRemap);
+ RemapBuilder SelectorRemap(F.SelectorRemap);
+ RemapBuilder DeclRemap(F.DeclRemap);
+ RemapBuilder TypeRemap(F.TypeRemap);
+
+ while(Data < DataEnd) {
+ using namespace llvm::support;
+ uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
+ StringRef Name = StringRef((const char*)Data, Len);
+ Data += Len;
+ ModuleFile *OM = ModuleMgr.lookup(Name);
+ if (!OM) {
+ Error("SourceLocation remap refers to unknown module");
+ return Failure;
+ }
+
+ uint32_t SLocOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t IdentifierIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t MacroIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t PreprocessedEntityIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SubmoduleIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SelectorIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t DeclIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t TypeIndexOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+
+ uint32_t None = std::numeric_limits<uint32_t>::max();
+
+ auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
+ RemapBuilder &Remap) {
+ if (Offset != None)
+ Remap.insert(std::make_pair(Offset,
+ static_cast<int>(BaseOffset - Offset)));
+ };
+ mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap);
+ mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap);
+ mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap);
+ mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID,
+ PreprocessedEntityRemap);
+ mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap);
+ mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap);
+ mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap);
+ mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap);
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
+ }
+ break;
+ }
+
+ case SOURCE_MANAGER_LINE_TABLE:
+ if (ParseLineTable(F, Record))
+ return Failure;
+ break;
+
+ case SOURCE_LOCATION_PRELOADS: {
+ // Need to transform from the local view (1-based IDs) to the global view,
+ // which is based off F.SLocEntryBaseID.
+ if (!F.PreloadSLocEntries.empty()) {
+ Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
+ return Failure;
+ }
+
+ F.PreloadSLocEntries.swap(Record);
+ break;
+ }
+
+ case EXT_VECTOR_DECLS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case VTABLE_USES:
+ if (Record.size() % 3 != 0) {
+ Error("Invalid VTABLE_USES record");
+ return Failure;
+ }
+
+ // Later tables overwrite earlier ones.
+ // FIXME: Modules will have some trouble with this. This is clearly not
+ // the right way to do this.
+ VTableUses.clear();
+
+ for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) {
+ VTableUses.push_back(getGlobalDeclID(F, Record[Idx++]));
+ VTableUses.push_back(
+ ReadSourceLocation(F, Record, Idx).getRawEncoding());
+ VTableUses.push_back(Record[Idx++]);
+ }
+ break;
+
+ case PENDING_IMPLICIT_INSTANTIATIONS:
+ if (PendingInstantiations.size() % 2 != 0) {
+ Error("Invalid existing PendingInstantiations");
+ return Failure;
+ }
+
+ if (Record.size() % 2 != 0) {
+ Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
+ return Failure;
+ }
+
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
+ PendingInstantiations.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
+ break;
+
+ case SEMA_DECL_REFS:
+ if (Record.size() != 2) {
+ Error("Invalid SEMA_DECL_REFS block");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case PPD_ENTITIES_OFFSETS: {
+ F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data();
+ assert(Blob.size() % sizeof(PPEntityOffset) == 0);
+ F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset);
+
+ unsigned LocalBasePreprocessedEntityID = Record[0];
+
+ unsigned StartingID;
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord();
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
+ StartingID
+ = PP.getPreprocessingRecord()
+ ->allocateLoadedEntities(F.NumPreprocessedEntities);
+ F.BasePreprocessedEntityID = StartingID;
+
+ if (F.NumPreprocessedEntities > 0) {
+ // Introduce the global -> local mapping for preprocessed entities in
+ // this module.
+ GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F));
+
+ // Introduce the local -> global mapping for preprocessed entities in
+ // this module.
+ F.PreprocessedEntityRemap.insertOrReplace(
+ std::make_pair(LocalBasePreprocessedEntityID,
+ F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
+ }
+
+ break;
+ }
+
+ case DECL_UPDATE_OFFSETS: {
+ if (Record.size() % 2 != 0) {
+ Error("invalid DECL_UPDATE_OFFSETS block in AST file");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 2) {
+ GlobalDeclID ID = getGlobalDeclID(F, Record[I]);
+ DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1]));
+
+ // If we've already loaded the decl, perform the updates when we finish
+ // loading this block.
+ if (Decl *D = GetExistingDecl(ID))
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ }
+ break;
+ }
+
+ case DECL_REPLACEMENTS: {
+ if (Record.size() % 3 != 0) {
+ Error("invalid DECL_REPLACEMENTS block in AST file");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 3)
+ ReplacedDecls[getGlobalDeclID(F, Record[I])]
+ = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]);
+ break;
+ }
+
+ case OBJC_CATEGORIES_MAP: {
+ if (F.LocalNumObjCCategoriesInMap != 0) {
+ Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumObjCCategoriesInMap = Record[0];
+ F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data();
+ break;
+ }
+
+ case OBJC_CATEGORIES:
+ F.ObjCCategories.swap(Record);
+ break;
+
+ case CXX_BASE_SPECIFIER_OFFSETS: {
+ if (F.LocalNumCXXBaseSpecifiers != 0) {
+ Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumCXXBaseSpecifiers = Record[0];
+ F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
+ break;
+ }
+
+ case CXX_CTOR_INITIALIZERS_OFFSETS: {
+ if (F.LocalNumCXXCtorInitializers != 0) {
+ Error("duplicate CXX_CTOR_INITIALIZERS_OFFSETS record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumCXXCtorInitializers = Record[0];
+ F.CXXCtorInitializersOffsets = (const uint32_t *)Blob.data();
+ break;
+ }
+
+ case DIAG_PRAGMA_MAPPINGS:
+ if (F.PragmaDiagMappings.empty())
+ F.PragmaDiagMappings.swap(Record);
+ else
+ F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
+ Record.begin(), Record.end());
+ break;
+
+ case CUDA_SPECIAL_DECL_REFS:
+ // Later tables overwrite earlier ones.
+ // FIXME: Modules will have trouble with this.
+ CUDASpecialDeclRefs.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case HEADER_SEARCH_TABLE: {
+ F.HeaderFileInfoTableData = Blob.data();
+ F.LocalNumHeaderFileInfos = Record[1];
+ if (Record[0]) {
+ F.HeaderFileInfoTable
+ = HeaderFileInfoLookupTable::Create(
+ (const unsigned char *)F.HeaderFileInfoTableData + Record[0],
+ (const unsigned char *)F.HeaderFileInfoTableData,
+ HeaderFileInfoTrait(*this, F,
+ &PP.getHeaderSearchInfo(),
+ Blob.data() + Record[2]));
+
+ PP.getHeaderSearchInfo().SetExternalSource(this);
+ if (!PP.getHeaderSearchInfo().getExternalLookup())
+ PP.getHeaderSearchInfo().SetExternalLookup(this);
+ }
+ break;
+ }
+
+ case FP_PRAGMA_OPTIONS:
+ // Later tables overwrite earlier ones.
+ FPPragmaOptions.swap(Record);
+ break;
+
+ case OPENCL_EXTENSIONS:
+ // Later tables overwrite earlier ones.
+ OpenCLExtensions.swap(Record);
+ break;
+
+ case TENTATIVE_DEFINITIONS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case KNOWN_NAMESPACES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case UNDEFINED_BUT_USED:
+ if (UndefinedButUsed.size() % 2 != 0) {
+ Error("Invalid existing UndefinedButUsed");
+ return Failure;
+ }
+
+ if (Record.size() % 2 != 0) {
+ Error("invalid undefined-but-used record");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
+ UndefinedButUsed.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
+ break;
+ case DELETE_EXPRS_TO_ANALYZE:
+ for (unsigned I = 0, N = Record.size(); I != N;) {
+ DelayedDeleteExprs.push_back(getGlobalDeclID(F, Record[I++]));
+ const uint64_t Count = Record[I++];
+ DelayedDeleteExprs.push_back(Count);
+ for (uint64_t C = 0; C < Count; ++C) {
+ DelayedDeleteExprs.push_back(ReadSourceLocation(F, Record, I).getRawEncoding());
+ bool IsArrayForm = Record[I++] == 1;
+ DelayedDeleteExprs.push_back(IsArrayForm);
+ }
+ }
+ break;
+
+ case IMPORTED_MODULES: {
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) {
+ // If we aren't loading a module (which has its own exports), make
+ // all of the imported modules visible.
+ // FIXME: Deal with macros-only imports.
+ for (unsigned I = 0, N = Record.size(); I != N; /**/) {
+ unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]);
+ SourceLocation Loc = ReadSourceLocation(F, Record, I);
+ if (GlobalID)
+ ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc));
+ }
+ }
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS: {
+ F.RedeclarationChains.swap(Record);
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS_MAP: {
+ if (F.LocalNumRedeclarationsInMap != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumRedeclarationsInMap = Record[0];
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
+ break;
+ }
+
+ case MACRO_OFFSET: {
+ if (F.LocalNumMacros != 0) {
+ Error("duplicate MACRO_OFFSET record in AST file");
+ return Failure;
+ }
+ F.MacroOffsets = (const uint32_t *)Blob.data();
+ F.LocalNumMacros = Record[0];
+ unsigned LocalBaseMacroID = Record[1];
+ F.BaseMacroID = getTotalNumMacros();
+
+ if (F.LocalNumMacros > 0) {
+ // Introduce the global -> local mapping for macros within this module.
+ GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F));
+
+ // Introduce the local -> global mapping for macros within this module.
+ F.MacroRemap.insertOrReplace(
+ std::make_pair(LocalBaseMacroID,
+ F.BaseMacroID - LocalBaseMacroID));
+
+ MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros);
+ }
+ break;
+ }
+
+ case LATE_PARSED_TEMPLATE: {
+ LateParsedTemplates.append(Record.begin(), Record.end());
+ break;
+ }
+
+ case OPTIMIZE_PRAGMA_OPTIONS:
+ if (Record.size() != 1) {
+ Error("invalid pragma optimize record");
+ return Failure;
+ }
+ OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]);
+ break;
+
+ case UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ UnusedLocalTypedefNameCandidates.push_back(
+ getGlobalDeclID(F, Record[I]));
+ break;
+ }
+ }
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
+ const ModuleFile *ImportedBy,
+ unsigned ClientLoadCapabilities) {
+ unsigned Idx = 0;
+ F.ModuleMapPath = ReadPath(F, Record, Idx);
+
+ if (F.Kind == MK_ExplicitModule) {
+ // For an explicitly-loaded module, we don't care whether the original
+ // module map file exists or matches.
+ return Success;
+ }
+
+ // Try to resolve ModuleName in the current header search context and
+ // verify that it is found in the same module map file as we saved. If the
+ // top-level AST file is a main file, skip this check because there is no
+ // usable header search context.
+ assert(!F.ModuleName.empty() &&
+ "MODULE_NAME should come before MODULE_MAP_FILE");
+ if (F.Kind == MK_ImplicitModule &&
+ (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ // An implicitly-loaded module file should have its module listed in some
+ // module map file that we've already loaded.
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
+ if (!ModMap) {
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_Missing) == 0)
+ Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName
+ << ImportedBy->FileName
+ << F.ModuleMapPath;
+ return Missing;
+ }
+
+ assert(M->Name == F.ModuleName && "found module with different name");
+
+ // Check the primary module map file.
+ const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
+ if (StoredModMap == nullptr || StoredModMap != ModMap) {
+ assert(ModMap && "found module is missing module map file");
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_modmap_changed)
+ << F.ModuleName << ImportedBy->FileName
+ << ModMap->getName() << F.ModuleMapPath;
+ return OutOfDate;
+ }
+
+ llvm::SmallPtrSet<const FileEntry *, 1> AdditionalStoredMaps;
+ for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) {
+ // FIXME: we should use input files rather than storing names.
+ std::string Filename = ReadPath(F, Record, Idx);
+ const FileEntry *F =
+ FileMgr.getFile(Filename, false, false);
+ if (F == nullptr) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("could not find file '" + Filename +"' referenced by AST file");
+ return OutOfDate;
+ }
+ AdditionalStoredMaps.insert(F);
+ }
+
+ // Check any additional module map files (e.g. module.private.modulemap)
+ // that are not in the pcm.
+ if (auto *AdditionalModuleMaps = Map.getAdditionalModuleMapFiles(M)) {
+ for (const FileEntry *ModMap : *AdditionalModuleMaps) {
+ // Remove files that match
+ // Note: SmallPtrSet::erase is really remove
+ if (!AdditionalStoredMaps.erase(ModMap)) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_different_modmap)
+ << F.ModuleName << /*new*/0 << ModMap->getName();
+ return OutOfDate;
+ }
+ }
+ }
+
+ // Check any additional module map files that are in the pcm, but not
+ // found in header search. Cases that match are already removed.
+ for (const FileEntry *ModMap : AdditionalStoredMaps) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_different_modmap)
+ << F.ModuleName << /*not new*/1 << ModMap->getName();
+ return OutOfDate;
+ }
+ }
+
+ if (Listener)
+ Listener->ReadModuleMapFile(F.ModuleMapPath);
+ return Success;
+}
+
+
+/// \brief Move the given method to the back of the global list of methods.
+static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
+ // Find the entry for this selector in the method pool.
+ Sema::GlobalMethodPool::iterator Known
+ = S.MethodPool.find(Method->getSelector());
+ if (Known == S.MethodPool.end())
+ return;
+
+ // Retrieve the appropriate method list.
+ ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first
+ : Known->second.second;
+ bool Found = false;
+ for (ObjCMethodList *List = &Start; List; List = List->getNext()) {
+ if (!Found) {
+ if (List->getMethod() == Method) {
+ Found = true;
+ } else {
+ // Keep searching.
+ continue;
+ }
+ }
+
+ if (List->getNext())
+ List->setMethod(List->getNext()->getMethod());
+ else
+ List->setMethod(Method);
+ }
+}
+
+void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
+ assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
+ for (Decl *D : Names) {
+ bool wasHidden = D->Hidden;
+ D->Hidden = false;
+
+ if (wasHidden && SemaObj) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
+ moveMethodToBackOfGlobalList(*SemaObj, Method);
+ }
+ }
+ }
+}
+
+void ASTReader::makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind NameVisibility,
+ SourceLocation ImportLoc) {
+ llvm::SmallPtrSet<Module *, 4> Visited;
+ SmallVector<Module *, 4> Stack;
+ Stack.push_back(Mod);
+ while (!Stack.empty()) {
+ Mod = Stack.pop_back_val();
+
+ if (NameVisibility <= Mod->NameVisibility) {
+ // This module already has this level of visibility (or greater), so
+ // there is nothing more to do.
+ continue;
+ }
+
+ if (!Mod->isAvailable()) {
+ // Modules that aren't available cannot be made visible.
+ continue;
+ }
+
+ // Update the module's name visibility.
+ Mod->NameVisibility = NameVisibility;
+
+ // If we've already deserialized any names from this module,
+ // mark them as visible.
+ HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
+ if (Hidden != HiddenNamesMap.end()) {
+ auto HiddenNames = std::move(*Hidden);
+ HiddenNamesMap.erase(Hidden);
+ makeNamesVisible(HiddenNames.second, HiddenNames.first);
+ assert(HiddenNamesMap.find(Mod) == HiddenNamesMap.end() &&
+ "making names visible added hidden names");
+ }
+
+ // Push any exported modules onto the stack to be marked as visible.
+ SmallVector<Module *, 16> Exports;
+ Mod->getExportedModules(Exports);
+ for (SmallVectorImpl<Module *>::iterator
+ I = Exports.begin(), E = Exports.end(); I != E; ++I) {
+ Module *Exported = *I;
+ if (Visited.insert(Exported).second)
+ Stack.push_back(Exported);
+ }
+ }
+}
+
+bool ASTReader::loadGlobalIndex() {
+ if (GlobalIndex)
+ return false;
+
+ if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
+ !Context.getLangOpts().Modules)
+ return true;
+
+ // Try to load the global index.
+ TriedLoadingGlobalIndex = true;
+ StringRef ModuleCachePath
+ = getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
+ std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result
+ = GlobalModuleIndex::readIndex(ModuleCachePath);
+ if (!Result.first)
+ return true;
+
+ GlobalIndex.reset(Result.first);
+ ModuleMgr.setGlobalIndex(GlobalIndex.get());
+ return false;
+}
+
+bool ASTReader::isGlobalIndexUnavailable() const {
+ return Context.getLangOpts().Modules && UseGlobalIndex &&
+ !hasGlobalIndex() && TriedLoadingGlobalIndex;
+}
+
+static void updateModuleTimestamp(ModuleFile &MF) {
+ // Overwrite the timestamp file contents so that file's mtime changes.
+ std::string TimestampFilename = MF.getTimestampFilename();
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::F_Text);
+ if (EC)
+ return;
+ OS << "Timestamp file\n";
+}
+
+ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
+ ModuleKind Type,
+ SourceLocation ImportLoc,
+ unsigned ClientLoadCapabilities) {
+ llvm::SaveAndRestore<SourceLocation>
+ SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
+
+ // Defer any pending actions until we get to the end of reading the AST file.
+ Deserializing AnASTFile(this);
+
+ // Bump the generation number.
+ unsigned PreviousGeneration = incrementGeneration(Context);
+
+ unsigned NumModules = ModuleMgr.size();
+ SmallVector<ImportedModule, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
+ /*ImportedBy=*/nullptr, Loaded,
+ 0, 0, 0,
+ ClientLoadCapabilities)) {
+ case Failure:
+ case Missing:
+ case OutOfDate:
+ case VersionMismatch:
+ case ConfigurationMismatch:
+ case HadErrors: {
+ llvm::SmallPtrSet<ModuleFile *, 4> LoadedSet;
+ for (const ImportedModule &IM : Loaded)
+ LoadedSet.insert(IM.Mod);
+
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ LoadedSet,
+ Context.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : nullptr);
+
+ // If we find that any modules are unusable, the global index is going
+ // to be out-of-date. Just remove it.
+ GlobalIndex.reset();
+ ModuleMgr.setGlobalIndex(nullptr);
+ return ReadResult;
+ }
+ case Success:
+ break;
+ }
+
+ // Here comes stuff that we only do once the entire chain is loaded.
+
+ // Load the AST blocks of all of the modules that we loaded.
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+
+ // Read the AST block.
+ if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
+ return Result;
+
+ // Once read, set the ModuleFile bit base offset and update the size in
+ // bits of all files we've seen.
+ F.GlobalBitOffset = TotalModulesSizeInBits;
+ TotalModulesSizeInBits += F.SizeInBits;
+ GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
+
+ // Preload SLocEntries.
+ for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
+ int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
+ // Load it through the SourceManager and don't call ReadSLocEntry()
+ // directly because the entry may have already been loaded in which case
+ // calling ReadSLocEntry() directly would trigger an assertion in
+ // SourceManager.
+ SourceMgr.getLoadedSLocEntryByID(Index);
+ }
+ }
+
+ // Setup the import locations and notify the module manager that we've
+ // committed to these module files.
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+
+ ModuleMgr.moduleFileAccepted(&F);
+
+ // Set the import location.
+ F.DirectImportLoc = ImportLoc;
+ if (!M->ImportedBy)
+ F.ImportLoc = M->ImportLoc;
+ else
+ F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
+ M->ImportLoc.getRawEncoding());
+ }
+
+ // Mark all of the identifiers in the identifier table as being out of date,
+ // so that various accessors know to check the loaded modules when the
+ // identifier is used.
+ for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
+ IdEnd = PP.getIdentifierTable().end();
+ Id != IdEnd; ++Id)
+ Id->second->setOutOfDate(true);
+
+ // Resolve any unresolved module exports.
+ for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
+ UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I];
+ SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
+ Module *ResolvedMod = getSubmodule(GlobalID);
+
+ switch (Unresolved.Kind) {
+ case UnresolvedModuleRef::Conflict:
+ if (ResolvedMod) {
+ Module::Conflict Conflict;
+ Conflict.Other = ResolvedMod;
+ Conflict.Message = Unresolved.String.str();
+ Unresolved.Mod->Conflicts.push_back(Conflict);
+ }
+ continue;
+
+ case UnresolvedModuleRef::Import:
+ if (ResolvedMod)
+ Unresolved.Mod->Imports.insert(ResolvedMod);
+ continue;
+
+ case UnresolvedModuleRef::Export:
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ continue;
+ }
+ }
+ UnresolvedModuleRefs.clear();
+
+ // FIXME: How do we load the 'use'd modules? They may not be submodules.
+ // Might be unnecessary as use declarations are only used to build the
+ // module itself.
+
+ InitializeContext();
+
+ if (SemaObj)
+ UpdateSema();
+
+ if (DeserializationListener)
+ DeserializationListener->ReaderInitialized(this);
+
+ ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
+ if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
+ PrimaryModule.OriginalSourceFileID
+ = FileID::get(PrimaryModule.SLocEntryBaseID
+ + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
+
+ // If this AST file is a precompiled preamble, then set the
+ // preamble file ID of the source manager to the file source file
+ // from which the preamble was built.
+ if (Type == MK_Preamble) {
+ SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
+ } else if (Type == MK_MainFile) {
+ SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
+ }
+ }
+
+ // For any Objective-C class definitions we have already loaded, make sure
+ // that we load any additional categories.
+ for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
+ loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
+ ObjCClassesLoaded[I],
+ PreviousGeneration);
+ }
+
+ if (PP.getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ModulesValidateOncePerBuildSession) {
+ // Now we are certain that the module and all modules it depends on are
+ // up to date. Create or update timestamp files for modules that are
+ // located in the module cache (not for PCH files that could be anywhere
+ // in the filesystem).
+ for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
+ ImportedModule &M = Loaded[I];
+ if (M.Mod->Kind == MK_ImplicitModule) {
+ updateModuleTimestamp(*M.Mod);
+ }
+ }
+ }
+
+ return Success;
+}
+
+static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile);
+
+/// \brief Whether \p Stream starts with the AST/PCH file magic number 'CPCH'.
+static bool startsWithASTFileMagic(BitstreamCursor &Stream) {
+ return Stream.Read(8) == 'C' &&
+ Stream.Read(8) == 'P' &&
+ Stream.Read(8) == 'C' &&
+ Stream.Read(8) == 'H';
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadASTCore(StringRef FileName,
+ ModuleKind Type,
+ SourceLocation ImportLoc,
+ ModuleFile *ImportedBy,
+ SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ASTFileSignature ExpectedSignature,
+ unsigned ClientLoadCapabilities) {
+ ModuleFile *M;
+ std::string ErrorStr;
+ ModuleManager::AddModuleResult AddResult
+ = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
+ getGeneration(), ExpectedSize, ExpectedModTime,
+ ExpectedSignature, readASTFileSignature,
+ M, ErrorStr);
+
+ switch (AddResult) {
+ case ModuleManager::AlreadyLoaded:
+ return Success;
+
+ case ModuleManager::NewlyLoaded:
+ // Load module file below.
+ break;
+
+ case ModuleManager::Missing:
+ // The module file was missing; if the client can handle that, return
+ // it.
+ if (ClientLoadCapabilities & ARR_Missing)
+ return Missing;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
+
+ case ModuleManager::OutOfDate:
+ // We couldn't load the module file because it is out-of-date. If the
+ // client can handle out-of-date, return it.
+ if (ClientLoadCapabilities & ARR_OutOfDate)
+ return OutOfDate;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
+ }
+
+ assert(M && "Missing module file");
+
+ // FIXME: This seems rather a hack. Should CurrentDir be part of the
+ // module?
+ if (FileName != "-") {
+ CurrentDir = llvm::sys::path::parent_path(FileName);
+ if (CurrentDir.empty()) CurrentDir = ".";
+ }
+
+ ModuleFile &F = *M;
+ BitstreamCursor &Stream = F.Stream;
+ Stream.init(&F.StreamFile);
+ F.SizeInBits = F.Buffer->getBufferSize() * 8;
+
+ // Sniff for the signature.
+ if (!startsWithASTFileMagic(Stream)) {
+ Diag(diag::err_not_a_pch_file) << FileName;
+ return Failure;
+ }
+
+ // This is used for compatibility with older PCH formats.
+ bool HaveReadControlBlock = false;
+
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ case llvm::BitstreamEntry::Record:
+ Error("invalid record at top-level of AST file");
+ return Failure;
+
+ case llvm::BitstreamEntry::SubBlock:
+ break;
+ }
+
+ // We only know the control subblock ID.
+ switch (Entry.ID) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock()) {
+ Error("malformed BlockInfoBlock in AST file");
+ return Failure;
+ }
+ break;
+ case CONTROL_BLOCK_ID:
+ HaveReadControlBlock = true;
+ switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) {
+ case Success:
+ break;
+
+ case Failure: return Failure;
+ case Missing: return Missing;
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ }
+ break;
+ case AST_BLOCK_ID:
+ if (!HaveReadControlBlock) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::err_pch_version_too_old);
+ return VersionMismatch;
+ }
+
+ // Record that we've loaded this module.
+ Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
+ return Success;
+
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ break;
+ }
+ }
+
+ return Success;
+}
+
+void ASTReader::InitializeContext() {
+ // If there's a listener, notify them that we "read" the translation unit.
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
+
+ // FIXME: Find a better way to deal with collisions between these
+ // built-in types. Right now, we just ignore the problem.
+
+ // Load the special types.
+ if (SpecialTypes.size() >= NumSpecialTypeIDs) {
+ if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
+ if (!Context.CFConstantStringTypeDecl)
+ Context.setCFConstantStringType(GetType(String));
+ }
+
+ if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
+ QualType FileType = GetType(File);
+ if (FileType.isNull()) {
+ Error("FILE type is NULL");
+ return;
+ }
+
+ if (!Context.FILEDecl) {
+ if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
+ Context.setFILEDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = FileType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid FILE type in AST file");
+ return;
+ }
+ Context.setFILEDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) {
+ QualType Jmp_bufType = GetType(Jmp_buf);
+ if (Jmp_bufType.isNull()) {
+ Error("jmp_buf type is NULL");
+ return;
+ }
+
+ if (!Context.jmp_bufDecl) {
+ if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
+ Context.setjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Jmp_bufType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid jmp_buf type in AST file");
+ return;
+ }
+ Context.setjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) {
+ QualType Sigjmp_bufType = GetType(Sigjmp_buf);
+ if (Sigjmp_bufType.isNull()) {
+ Error("sigjmp_buf type is NULL");
+ return;
+ }
+
+ if (!Context.sigjmp_bufDecl) {
+ if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
+ Context.setsigjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid sigjmp_buf type in AST file");
+ Context.setsigjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned ObjCIdRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) {
+ if (Context.ObjCIdRedefinitionType.isNull())
+ Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef);
+ }
+
+ if (unsigned ObjCClassRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) {
+ if (Context.ObjCClassRedefinitionType.isNull())
+ Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef);
+ }
+
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) {
+ if (Context.ObjCSelRedefinitionType.isNull())
+ Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+ }
+
+ if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) {
+ QualType Ucontext_tType = GetType(Ucontext_t);
+ if (Ucontext_tType.isNull()) {
+ Error("ucontext_t type is NULL");
+ return;
+ }
+
+ if (!Context.ucontext_tDecl) {
+ if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>())
+ Context.setucontext_tDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Ucontext_tType->getAs<TagType>();
+ assert(Tag && "Invalid ucontext_t type in AST file");
+ Context.setucontext_tDecl(Tag->getDecl());
+ }
+ }
+ }
+ }
+
+ ReadPragmaDiagnosticMappings(Context.getDiagnostics());
+
+ // If there were any CUDA special declarations, deserialize them.
+ if (!CUDASpecialDeclRefs.empty()) {
+ assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!");
+ Context.setcudaConfigureCallDecl(
+ cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
+ }
+
+ // Re-export any modules that were imported by a non-module AST file.
+ // FIXME: This does not make macro-only imports visible again.
+ for (auto &Import : ImportedModules) {
+ if (Module *Imported = getSubmodule(Import.ID)) {
+ makeModuleVisible(Imported, Module::AllVisible,
+ /*ImportLoc=*/Import.ImportLoc);
+ PP.makeModuleVisible(Imported, Import.ImportLoc);
+ }
+ }
+ ImportedModules.clear();
+}
+
+void ASTReader::finalizeForWriting() {
+ // Nothing to do for now.
+}
+
+/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
+/// cursor into the start of the given block ID, returning false on success and
+/// true on failure.
+static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ return true;
+
+ case llvm::BitstreamEntry::Record:
+ // Ignore top-level records.
+ Cursor.skipRecord(Entry.ID);
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == BlockID) {
+ if (Cursor.EnterSubBlock(BlockID))
+ return true;
+ // Found it!
+ return false;
+ }
+
+ if (Cursor.SkipBlock())
+ return true;
+ }
+ }
+}
+
+/// \brief Reads and return the signature record from \p StreamFile's control
+/// block, or else returns 0.
+static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){
+ BitstreamCursor Stream(StreamFile);
+ if (!startsWithASTFileMagic(Stream))
+ return 0;
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
+ return 0;
+
+ // Scan for SIGNATURE inside the control block.
+ ASTReader::RecordData Record;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock ||
+ Entry.Kind != llvm::BitstreamEntry::Record)
+ return 0;
+
+ Record.clear();
+ StringRef Blob;
+ if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob))
+ return Record[0];
+ }
+}
+
+/// \brief Retrieve the name of the original source file name
+/// directly from the AST file, without actually loading the AST
+/// file.
+std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
+ FileManager &FileMgr,
+ DiagnosticsEngine &Diags) {
+ // Open the AST file.
+ auto Buffer = FileMgr.getBufferForFile(ASTFileName);
+ if (!Buffer) {
+ Diags.Report(diag::err_fe_unable_to_read_pch_file)
+ << ASTFileName << Buffer.getError().message();
+ return std::string();
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ BitstreamCursor Stream(StreamFile);
+
+ // Sniff for the signature.
+ if (!startsWithASTFileMagic(Stream)) {
+ Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
+ return std::string();
+ }
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+
+ // Scan for ORIGINAL_FILE inside the control block.
+ RecordData Record;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return std::string();
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+
+ Record.clear();
+ StringRef Blob;
+ if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE)
+ return Blob.str();
+ }
+}
+
+namespace {
+ class SimplePCHValidator : public ASTReaderListener {
+ const LangOptions &ExistingLangOpts;
+ const TargetOptions &ExistingTargetOpts;
+ const PreprocessorOptions &ExistingPPOpts;
+ std::string ExistingModuleCachePath;
+ FileManager &FileMgr;
+
+ public:
+ SimplePCHValidator(const LangOptions &ExistingLangOpts,
+ const TargetOptions &ExistingTargetOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ StringRef ExistingModuleCachePath,
+ FileManager &FileMgr)
+ : ExistingLangOpts(ExistingLangOpts),
+ ExistingTargetOpts(ExistingTargetOpts),
+ ExistingPPOpts(ExistingPPOpts),
+ ExistingModuleCachePath(ExistingModuleCachePath),
+ FileMgr(FileMgr)
+ {
+ }
+
+ bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr,
+ AllowCompatibleDifferences);
+ }
+ bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
+ bool AllowCompatibleDifferences) override {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr,
+ AllowCompatibleDifferences);
+ }
+ bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ bool Complain) override {
+ return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ ExistingModuleCachePath,
+ nullptr, ExistingLangOpts);
+ }
+ bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) override {
+ return checkPreprocessorOptions(ExistingPPOpts, PPOpts, nullptr, FileMgr,
+ SuggestedPredefines, ExistingLangOpts);
+ }
+ };
+}
+
+bool ASTReader::readASTFileControlBlock(StringRef Filename,
+ FileManager &FileMgr,
+ ASTReaderListener &Listener) {
+ // Open the AST file.
+ // FIXME: This allows use of the VFS; we do not allow use of the
+ // VFS when actually loading a module.
+ auto Buffer = FileMgr.getBufferForFile(Filename);
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ BitstreamCursor Stream(StreamFile);
+
+ // Sniff for the signature.
+ if (!startsWithASTFileMagic(Stream))
+ return true;
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
+ return true;
+
+ bool NeedsInputFiles = Listener.needsInputFileVisitation();
+ bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation();
+ bool NeedsImports = Listener.needsImportVisitation();
+ BitstreamCursor InputFilesCursor;
+ if (NeedsInputFiles) {
+ InputFilesCursor = Stream;
+ if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID))
+ return true;
+
+ // Read the abbreviations
+ while (true) {
+ uint64_t Offset = InputFilesCursor.GetCurrentBitNo();
+ unsigned Code = InputFilesCursor.ReadCode();
+
+ // We expect all abbrevs to be at the start of the block.
+ if (Code != llvm::bitc::DEFINE_ABBREV) {
+ InputFilesCursor.JumpToBit(Offset);
+ break;
+ }
+ InputFilesCursor.ReadAbbrevRecord();
+ }
+ }
+
+ // Scan for ORIGINAL_FILE inside the control block.
+ RecordData Record;
+ std::string ModuleDir;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return false;
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return true;
+
+ Record.clear();
+ StringRef Blob;
+ unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
+ switch ((ControlRecordTypes)RecCode) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR)
+ return true;
+
+ if (Listener.ReadFullVersionInformation(Blob))
+ return true;
+
+ break;
+ }
+ case MODULE_NAME:
+ Listener.ReadModuleName(Blob);
+ break;
+ case MODULE_DIRECTORY:
+ ModuleDir = Blob;
+ break;
+ case MODULE_MAP_FILE: {
+ unsigned Idx = 0;
+ auto Path = ReadString(Record, Idx);
+ ResolveImportedPath(Path, ModuleDir);
+ Listener.ReadModuleMapFile(Path);
+ break;
+ }
+ case LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record, false, Listener,
+ /*AllowCompatibleConfigurationMismatch*/false))
+ return true;
+ break;
+
+ case TARGET_OPTIONS:
+ if (ParseTargetOptions(Record, false, Listener,
+ /*AllowCompatibleConfigurationMismatch*/ false))
+ return true;
+ break;
+
+ case DIAGNOSTIC_OPTIONS:
+ if (ParseDiagnosticOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case FILE_SYSTEM_OPTIONS:
+ if (ParseFileSystemOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case HEADER_SEARCH_OPTIONS:
+ if (ParseHeaderSearchOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
+
+ case INPUT_FILE_OFFSETS: {
+ if (!NeedsInputFiles)
+ break;
+
+ unsigned NumInputFiles = Record[0];
+ unsigned NumUserFiles = Record[1];
+ const uint64_t *InputFileOffs = (const uint64_t *)Blob.data();
+ for (unsigned I = 0; I != NumInputFiles; ++I) {
+ // Go find this input file.
+ bool isSystemFile = I >= NumUserFiles;
+
+ if (isSystemFile && !NeedsSystemInputFiles)
+ break; // the rest are system input files
+
+ BitstreamCursor &Cursor = InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(InputFileOffs[I]);
+
+ unsigned Code = Cursor.ReadCode();
+ RecordData Record;
+ StringRef Blob;
+ bool shouldContinue = false;
+ switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
+ case INPUT_FILE:
+ bool Overridden = static_cast<bool>(Record[3]);
+ std::string Filename = Blob;
+ ResolveImportedPath(Filename, ModuleDir);
+ shouldContinue =
+ Listener.visitInputFile(Filename, isSystemFile, Overridden);
+ break;
+ }
+ if (!shouldContinue)
+ break;
+ }
+ break;
+ }
+
+ case IMPORTS: {
+ if (!NeedsImports)
+ break;
+
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ Idx += 5; // ImportLoc, Size, ModTime, Signature
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(Filename, ModuleDir);
+ Listener.visitImport(Filename);
+ }
+ break;
+ }
+
+ case KNOWN_MODULE_FILES: {
+ // Known-but-not-technically-used module files are treated as imports.
+ if (!NeedsImports)
+ break;
+
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(Filename, ModuleDir);
+ Listener.visitImport(Filename);
+ }
+ break;
+ }
+
+ default:
+ // No other validation to perform.
+ break;
+ }
+ }
+}
+
+
+bool ASTReader::isAcceptableASTFile(StringRef Filename,
+ FileManager &FileMgr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts,
+ std::string ExistingModuleCachePath) {
+ SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts,
+ ExistingModuleCachePath, FileMgr);
+ return !readASTFileControlBlock(Filename, FileMgr, validator);
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
+ // Enter the submodule block.
+ if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
+ Error("malformed submodule block record in AST file");
+ return Failure;
+ }
+
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ bool First = true;
+ Module *CurrentModule = nullptr;
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Failure;
+ case llvm::BitstreamEntry::EndBlock:
+ return Success;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ StringRef Blob;
+ Record.clear();
+ auto Kind = F.Stream.readRecord(Entry.ID, Record, &Blob);
+
+ if ((Kind == SUBMODULE_METADATA) != First) {
+ Error("submodule metadata record should be at beginning of block");
+ return Failure;
+ }
+ First = false;
+
+ // Submodule information is only valid if we have a current module.
+ // FIXME: Should we error on these cases?
+ if (!CurrentModule && Kind != SUBMODULE_METADATA &&
+ Kind != SUBMODULE_DEFINITION)
+ continue;
+
+ switch (Kind) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SUBMODULE_DEFINITION: {
+ if (Record.size() < 8) {
+ Error("malformed module definition");
+ return Failure;
+ }
+
+ StringRef Name = Blob;
+ unsigned Idx = 0;
+ SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]);
+ SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]);
+ bool IsFramework = Record[Idx++];
+ bool IsExplicit = Record[Idx++];
+ bool IsSystem = Record[Idx++];
+ bool IsExternC = Record[Idx++];
+ bool InferSubmodules = Record[Idx++];
+ bool InferExplicitSubmodules = Record[Idx++];
+ bool InferExportWildcard = Record[Idx++];
+ bool ConfigMacrosExhaustive = Record[Idx++];
+
+ Module *ParentModule = nullptr;
+ if (Parent)
+ ParentModule = getSubmodule(Parent);
+
+ // Retrieve this (sub)module from the module map, creating it if
+ // necessary.
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework,
+ IsExplicit).first;
+
+ // FIXME: set the definition loc for CurrentModule, or call
+ // ModMap.setInferredModuleAllowedBy()
+
+ SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
+ if (GlobalIndex >= SubmodulesLoaded.size() ||
+ SubmodulesLoaded[GlobalIndex]) {
+ Error("too many submodules");
+ return Failure;
+ }
+
+ if (!ParentModule) {
+ if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
+ if (CurFile != F.File) {
+ if (!Diags.isDiagnosticInFlight()) {
+ Diag(diag::err_module_file_conflict)
+ << CurrentModule->getTopLevelModuleName()
+ << CurFile->getName()
+ << F.File->getName();
+ }
+ return Failure;
+ }
+ }
+
+ CurrentModule->setASTFile(F.File);
+ }
+
+ CurrentModule->IsFromModuleFile = true;
+ CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
+ CurrentModule->IsExternC = IsExternC;
+ CurrentModule->InferSubmodules = InferSubmodules;
+ CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
+ CurrentModule->InferExportWildcard = InferExportWildcard;
+ CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
+ if (DeserializationListener)
+ DeserializationListener->ModuleRead(GlobalID, CurrentModule);
+
+ SubmodulesLoaded[GlobalIndex] = CurrentModule;
+
+ // Clear out data that will be replaced by what is the module file.
+ CurrentModule->LinkLibraries.clear();
+ CurrentModule->ConfigMacros.clear();
+ CurrentModule->UnresolvedConflicts.clear();
+ CurrentModule->Conflicts.clear();
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_HEADER: {
+ std::string Filename = Blob;
+ ResolveImportedPath(F, Filename);
+ if (auto *Umbrella = PP.getFileManager().getFile(Filename)) {
+ if (!CurrentModule->getUmbrellaHeader())
+ ModMap.setUmbrellaHeader(CurrentModule, Umbrella, Blob);
+ else if (CurrentModule->getUmbrellaHeader().Entry != Umbrella) {
+ // This can be a spurious difference caused by changing the VFS to
+ // point to a different copy of the file, and it is too late to
+ // to rebuild safely.
+ // FIXME: If we wrote the virtual paths instead of the 'real' paths,
+ // after input file validation only real problems would remain and we
+ // could just error. For now, assume it's okay.
+ break;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_HEADER:
+ case SUBMODULE_EXCLUDED_HEADER:
+ case SUBMODULE_PRIVATE_HEADER:
+ // We lazily associate headers with their modules via the HeaderInfo table.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
+ break;
+
+ case SUBMODULE_TEXTUAL_HEADER:
+ case SUBMODULE_PRIVATE_TEXTUAL_HEADER:
+ // FIXME: Textual headers are not marked in the HeaderInfo table. Load
+ // them here.
+ break;
+
+ case SUBMODULE_TOPHEADER: {
+ CurrentModule->addTopHeaderFilename(Blob);
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_DIR: {
+ std::string Dirname = Blob;
+ ResolveImportedPath(F, Dirname);
+ if (auto *Umbrella = PP.getFileManager().getDirectory(Dirname)) {
+ if (!CurrentModule->getUmbrellaDir())
+ ModMap.setUmbrellaDir(CurrentModule, Umbrella, Blob);
+ else if (CurrentModule->getUmbrellaDir().Entry != Umbrella) {
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella directories in submodule");
+ return OutOfDate;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_METADATA: {
+ F.BaseSubmoduleID = getTotalNumSubmodules();
+ F.LocalNumSubmodules = Record[0];
+ unsigned LocalBaseSubmoduleID = Record[1];
+ if (F.LocalNumSubmodules > 0) {
+ // Introduce the global -> local mapping for submodules within this
+ // module.
+ GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F));
+
+ // Introduce the local -> global mapping for submodules within this
+ // module.
+ F.SubmoduleRemap.insertOrReplace(
+ std::make_pair(LocalBaseSubmoduleID,
+ F.BaseSubmoduleID - LocalBaseSubmoduleID));
+
+ SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
+ }
+ break;
+ }
+
+ case SUBMODULE_IMPORTS: {
+ for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.Kind = UnresolvedModuleRef::Import;
+ Unresolved.IsWildcard = false;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ }
+ break;
+ }
+
+ case SUBMODULE_EXPORTS: {
+ for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.Kind = UnresolvedModuleRef::Export;
+ Unresolved.IsWildcard = Record[Idx + 1];
+ UnresolvedModuleRefs.push_back(Unresolved);
+ }
+
+ // Once we've loaded the set of exports, there's no reason to keep
+ // the parsed, unresolved exports around.
+ CurrentModule->UnresolvedExports.clear();
+ break;
+ }
+ case SUBMODULE_REQUIRES: {
+ CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
+ Context.getTargetInfo());
+ break;
+ }
+
+ case SUBMODULE_LINK_LIBRARY:
+ CurrentModule->LinkLibraries.push_back(
+ Module::LinkLibrary(Blob, Record[0]));
+ break;
+
+ case SUBMODULE_CONFIG_MACRO:
+ CurrentModule->ConfigMacros.push_back(Blob.str());
+ break;
+
+ case SUBMODULE_CONFLICT: {
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[0];
+ Unresolved.Kind = UnresolvedModuleRef::Conflict;
+ Unresolved.IsWildcard = false;
+ Unresolved.String = Blob;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ break;
+ }
+ }
+ }
+}
+
+/// \brief Parse the record that corresponds to a LangOptions data
+/// structure.
+///
+/// This routine parses the language options from the AST file and then gives
+/// them to the AST listener if one is set.
+///
+/// \returns true if the listener deems the file unacceptable, false otherwise.
+bool ASTReader::ParseLanguageOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener,
+ bool AllowCompatibleDifferences) {
+ LangOptions LangOpts;
+ unsigned Idx = 0;
+#define LANGOPT(Name, Bits, Default, Description) \
+ LangOpts.Name = Record[Idx++];
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
+#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) \
+ LangOpts.Sanitize.set(SanitizerKind::ID, Record[Idx++]);
+#include "clang/Basic/Sanitizers.def"
+
+ ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
+ VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
+ LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
+
+ unsigned Length = Record[Idx++];
+ LangOpts.CurrentModule.assign(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+
+ Idx += Length;
+
+ // Comment options.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ LangOpts.CommentOpts.BlockCommandNames.push_back(
+ ReadString(Record, Idx));
+ }
+ LangOpts.CommentOpts.ParseAllComments = Record[Idx++];
+
+ return Listener.ReadLanguageOptions(LangOpts, Complain,
+ AllowCompatibleDifferences);
+}
+
+bool ASTReader::ParseTargetOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener,
+ bool AllowCompatibleDifferences) {
+ unsigned Idx = 0;
+ TargetOptions TargetOpts;
+ TargetOpts.Triple = ReadString(Record, Idx);
+ TargetOpts.CPU = ReadString(Record, Idx);
+ TargetOpts.ABI = ReadString(Record, Idx);
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
+ }
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.Features.push_back(ReadString(Record, Idx));
+ }
+
+ return Listener.ReadTargetOptions(TargetOpts, Complain,
+ AllowCompatibleDifferences);
+}
+
+bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+ unsigned Idx = 0;
+#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
+#include "clang/Basic/DiagnosticOptions.def"
+
+ for (unsigned N = Record[Idx++]; N; --N)
+ DiagOpts->Warnings.push_back(ReadString(Record, Idx));
+ for (unsigned N = Record[Idx++]; N; --N)
+ DiagOpts->Remarks.push_back(ReadString(Record, Idx));
+
+ return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
+}
+
+bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ FileSystemOptions FSOpts;
+ unsigned Idx = 0;
+ FSOpts.WorkingDir = ReadString(Record, Idx);
+ return Listener.ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ HeaderSearchOptions HSOpts;
+ unsigned Idx = 0;
+ HSOpts.Sysroot = ReadString(Record, Idx);
+
+ // Include entries.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Path = ReadString(Record, Idx);
+ frontend::IncludeDirGroup Group
+ = static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
+ bool IsFramework = Record[Idx++];
+ bool IgnoreSysRoot = Record[Idx++];
+ HSOpts.UserEntries.emplace_back(std::move(Path), Group, IsFramework,
+ IgnoreSysRoot);
+ }
+
+ // System header prefixes.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Prefix = ReadString(Record, Idx);
+ bool IsSystemHeader = Record[Idx++];
+ HSOpts.SystemHeaderPrefixes.emplace_back(std::move(Prefix), IsSystemHeader);
+ }
+
+ HSOpts.ResourceDir = ReadString(Record, Idx);
+ HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
+ HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.UseBuiltinIncludes = Record[Idx++];
+ HSOpts.UseStandardSystemIncludes = Record[Idx++];
+ HSOpts.UseStandardCXXIncludes = Record[Idx++];
+ HSOpts.UseLibcxx = Record[Idx++];
+ std::string SpecificModuleCachePath = ReadString(Record, Idx);
+
+ return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ Complain);
+}
+
+bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener,
+ std::string &SuggestedPredefines) {
+ PreprocessorOptions PPOpts;
+ unsigned Idx = 0;
+
+ // Macro definitions/undefs
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Macro = ReadString(Record, Idx);
+ bool IsUndef = Record[Idx++];
+ PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
+ }
+
+ // Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.Includes.push_back(ReadString(Record, Idx));
+ }
+
+ // Macro Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
+ }
+
+ PPOpts.UsePredefines = Record[Idx++];
+ PPOpts.DetailedRecord = Record[Idx++];
+ PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
+ PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
+ PPOpts.ObjCXXARCStandardLibrary =
+ static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
+ SuggestedPredefines.clear();
+ return Listener.ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines);
+}
+
+std::pair<ModuleFile *, unsigned>
+ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
+ GlobalPreprocessedEntityMapType::iterator
+ I = GlobalPreprocessedEntityMap.find(GlobalIndex);
+ assert(I != GlobalPreprocessedEntityMap.end() &&
+ "Corrupted global preprocessed entity map");
+ ModuleFile *M = I->second;
+ unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID;
+ return std::make_pair(M, LocalIndex);
+}
+
+llvm::iterator_range<PreprocessingRecord::iterator>
+ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
+ if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
+ return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
+ Mod.NumPreprocessedEntities);
+
+ return llvm::make_range(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+llvm::iterator_range<ASTReader::ModuleDeclIterator>
+ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
+ return llvm::make_range(
+ ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
+ ModuleDeclIterator(this, &Mod,
+ Mod.FileSortedDecls + Mod.NumFileSortedDecls));
+}
+
+PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
+ PreprocessedEntityID PPID = Index+1;
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
+
+ if (!PP.getPreprocessingRecord()) {
+ Error("no preprocessing record");
+ return nullptr;
+ }
+
+ SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
+ M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
+
+ llvm::BitstreamEntry Entry =
+ M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return nullptr;
+
+ // Read the record.
+ SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
+ ReadSourceLocation(M, PPOffs.End));
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ StringRef Blob;
+ RecordData Record;
+ PreprocessorDetailRecordTypes RecType =
+ (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord(
+ Entry.ID, Record, &Blob);
+ switch (RecType) {
+ case PPD_MACRO_EXPANSION: {
+ bool isBuiltin = Record[0];
+ IdentifierInfo *Name = nullptr;
+ MacroDefinitionRecord *Def = nullptr;
+ if (isBuiltin)
+ Name = getLocalIdentifier(M, Record[1]);
+ else {
+ PreprocessedEntityID GlobalID =
+ getGlobalPreprocessedEntityID(M, Record[1]);
+ Def = cast<MacroDefinitionRecord>(
+ PPRec.getLoadedPreprocessedEntity(GlobalID - 1));
+ }
+
+ MacroExpansion *ME;
+ if (isBuiltin)
+ ME = new (PPRec) MacroExpansion(Name, Range);
+ else
+ ME = new (PPRec) MacroExpansion(Def, Range);
+
+ return ME;
+ }
+
+ case PPD_MACRO_DEFINITION: {
+ // Decode the identifier info and then check again; if the macro is
+ // still defined and associated with the identifier,
+ IdentifierInfo *II = getLocalIdentifier(M, Record[0]);
+ MacroDefinitionRecord *MD = new (PPRec) MacroDefinitionRecord(II, Range);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroDefinitionRead(PPID, MD);
+
+ return MD;
+ }
+
+ case PPD_INCLUSION_DIRECTIVE: {
+ const char *FullFileNameStart = Blob.data() + Record[0];
+ StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
+ const FileEntry *File = nullptr;
+ if (!FullFileName.empty())
+ File = PP.getFileManager().getFile(FullFileName);
+
+ // FIXME: Stable encoding
+ InclusionDirective::InclusionKind Kind
+ = static_cast<InclusionDirective::InclusionKind>(Record[2]);
+ InclusionDirective *ID
+ = new (PPRec) InclusionDirective(PPRec, Kind,
+ StringRef(Blob.data(), Record[0]),
+ Record[1], Record[3],
+ File,
+ Range);
+ return ID;
+ }
+ }
+
+ llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
+}
+
+/// \brief \arg SLocMapI points at a chunk of a module that contains no
+/// preprocessed entities or the entities it contains are not the ones we are
+/// looking for. Find the next module that contains entities and return the ID
+/// of the first entry.
+PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
+ GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
+ ++SLocMapI;
+ for (GlobalSLocOffsetMapType::const_iterator
+ EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
+ ModuleFile &M = *SLocMapI->second;
+ if (M.NumPreprocessedEntities)
+ return M.BasePreprocessedEntityID;
+ }
+
+ return getTotalNumPreprocessedEntities();
+}
+
+namespace {
+
+template <unsigned PPEntityOffset::*PPLoc>
+struct PPEntityComp {
+ const ASTReader &Reader;
+ ModuleFile &M;
+
+ PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { }
+
+ bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
+ SourceLocation LHS = getLoc(L);
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(const PPEntityOffset &L, SourceLocation RHS) const {
+ SourceLocation LHS = getLoc(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, const PPEntityOffset &R) const {
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLoc(const PPEntityOffset &PPE) const {
+ return Reader.ReadSourceLocation(M, PPE.*PPLoc);
+ }
+};
+
+}
+
+PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc,
+ bool EndsAfter) const {
+ if (SourceMgr.isLocalSourceLocation(Loc))
+ return getTotalNumPreprocessedEntities();
+
+ GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(
+ SourceManager::MaxLoadedOffset - Loc.getOffset() - 1);
+ assert(SLocMapI != GlobalSLocOffsetMap.end() &&
+ "Corrupted global sloc offset map");
+
+ if (SLocMapI->second->NumPreprocessedEntities == 0)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ ModuleFile &M = *SLocMapI->second;
+ typedef const PPEntityOffset *pp_iterator;
+ pp_iterator pp_begin = M.PreprocessedEntityOffsets;
+ pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
+
+ size_t Count = M.NumPreprocessedEntities;
+ size_t Half;
+ pp_iterator First = pp_begin;
+ pp_iterator PPI;
+
+ if (EndsAfter) {
+ PPI = std::upper_bound(pp_begin, pp_end, Loc,
+ PPEntityComp<&PPEntityOffset::Begin>(*this, M));
+ } else {
+ // Do a binary search manually instead of using std::lower_bound because
+ // The end locations of entities may be unordered (when a macro expansion
+ // is inside another macro argument), but for this case it is not important
+ // whether we get the first macro expansion or its containing macro.
+ while (Count > 0) {
+ Half = Count / 2;
+ PPI = First;
+ std::advance(PPI, Half);
+ if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
+ Loc)) {
+ First = PPI;
+ ++First;
+ Count = Count - Half - 1;
+ } else
+ Count = Half;
+ }
+ }
+
+ if (PPI == pp_end)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
+}
+
+/// \brief Returns a pair of [Begin, End) indices of preallocated
+/// preprocessed entities that \arg Range encompasses.
+std::pair<unsigned, unsigned>
+ ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) {
+ if (Range.isInvalid())
+ return std::make_pair(0,0);
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
+ PreprocessedEntityID BeginID =
+ findPreprocessedEntity(Range.getBegin(), false);
+ PreprocessedEntityID EndID = findPreprocessedEntity(Range.getEnd(), true);
+ return std::make_pair(BeginID, EndID);
+}
+
+/// \brief Optionally returns true or false if the preallocated preprocessed
+/// entity with index \arg Index came from file \arg FID.
+Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
+ if (FID.isInvalid())
+ return false;
+
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
+
+ SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin);
+ if (Loc.isInvalid())
+ return false;
+
+ if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID))
+ return true;
+ else
+ return false;
+}
+
+namespace {
+ /// \brief Visitor used to search for information about a header file.
+ class HeaderFileInfoVisitor {
+ const FileEntry *FE;
+
+ Optional<HeaderFileInfo> HFI;
+
+ public:
+ explicit HeaderFileInfoVisitor(const FileEntry *FE)
+ : FE(FE) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ HeaderFileInfoVisitor *This
+ = static_cast<HeaderFileInfoVisitor *>(UserData);
+
+ HeaderFileInfoLookupTable *Table
+ = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
+ if (!Table)
+ return false;
+
+ // Look in the on-disk hash table for an entry for this file name.
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
+ if (Pos == Table->end())
+ return false;
+
+ This->HFI = *Pos;
+ return true;
+ }
+
+ Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ };
+}
+
+HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
+ HeaderFileInfoVisitor Visitor(FE);
+ ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
+ if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
+ return *HFI;
+
+ return HeaderFileInfo();
+}
+
+void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
+ for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
+ ModuleFile &F = *(*I);
+ unsigned Idx = 0;
+ DiagStates.clear();
+ assert(!Diag.DiagStates.empty());
+ DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
+ while (Idx < F.PragmaDiagMappings.size()) {
+ SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
+ if (DiagStateID != 0) {
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
+ FullSourceLoc(Loc, SourceMgr)));
+ continue;
+ }
+
+ assert(DiagStateID == 0);
+ // A new DiagState was created here.
+ Diag.DiagStates.push_back(*Diag.GetCurDiagState());
+ DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ DiagStates.push_back(NewState);
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(NewState,
+ FullSourceLoc(Loc, SourceMgr)));
+ while (1) {
+ assert(Idx < F.PragmaDiagMappings.size() &&
+ "Invalid data, didn't find '-1' marking end of diag/map pairs");
+ if (Idx >= F.PragmaDiagMappings.size()) {
+ break; // Something is messed up but at least avoid infinite loop in
+ // release build.
+ }
+ unsigned DiagID = F.PragmaDiagMappings[Idx++];
+ if (DiagID == (unsigned)-1) {
+ break; // no more diag/map pairs for this location.
+ }
+ diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++];
+ DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
+ Diag.GetCurDiagState()->setMapping(DiagID, Mapping);
+ }
+ }
+ }
+}
+
+/// \brief Get the correct cursor and offset for loading a type.
+ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
+ GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
+ assert(I != GlobalTypeMap.end() && "Corrupted global type map");
+ ModuleFile *M = I->second;
+ return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
+}
+
+/// \brief Read and return the type with the given index..
+///
+/// The index is the type ID, shifted and minus the number of predefs. This
+/// routine actually reads the record corresponding to the type at the given
+/// location. It is a helper routine for GetType, which deals with reading type
+/// IDs.
+QualType ASTReader::readTypeRecord(unsigned Index) {
+ RecordLocation Loc = TypeCursorForIndex(Index);
+ BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this type.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ ReadingKindTracker ReadingKind(Read_Type, *this);
+
+ // Note that we are loading a type record.
+ Deserializing AType(this);
+
+ unsigned Idx = 0;
+ DeclsCursor.JumpToBit(Loc.Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) {
+ case TYPE_EXT_QUAL: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of extended qualifier type");
+ return QualType();
+ }
+ QualType Base = readType(*Loc.F, Record, Idx);
+ Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]);
+ return Context.getQualifiedType(Base, Quals);
+ }
+
+ case TYPE_COMPLEX: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of complex type");
+ return QualType();
+ }
+ QualType ElemType = readType(*Loc.F, Record, Idx);
+ return Context.getComplexType(ElemType);
+ }
+
+ case TYPE_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getPointerType(PointeeType);
+ }
+
+ case TYPE_DECAYED: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of decayed type");
+ return QualType();
+ }
+ QualType OriginalType = readType(*Loc.F, Record, Idx);
+ QualType DT = Context.getAdjustedParameterType(OriginalType);
+ if (!isa<DecayedType>(DT))
+ Error("Decayed type does not decay");
+ return DT;
+ }
+
+ case TYPE_ADJUSTED: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of adjusted type");
+ return QualType();
+ }
+ QualType OriginalTy = readType(*Loc.F, Record, Idx);
+ QualType AdjustedTy = readType(*Loc.F, Record, Idx);
+ return Context.getAdjustedType(OriginalTy, AdjustedTy);
+ }
+
+ case TYPE_BLOCK_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of block pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getBlockPointerType(PointeeType);
+ }
+
+ case TYPE_LVALUE_REFERENCE: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of lvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getLValueReferenceType(PointeeType, Record[1]);
+ }
+
+ case TYPE_RVALUE_REFERENCE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of rvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getRValueReferenceType(PointeeType);
+ }
+
+ case TYPE_MEMBER_POINTER: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of member pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ QualType ClassType = readType(*Loc.F, Record, Idx);
+ if (PointeeType.isNull() || ClassType.isNull())
+ return QualType();
+
+ return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
+ }
+
+ case TYPE_CONSTANT_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ unsigned Idx = 3;
+ llvm::APInt Size = ReadAPInt(Record, Idx);
+ return Context.getConstantArrayType(ElementType, Size,
+ ASM, IndexTypeQuals);
+ }
+
+ case TYPE_INCOMPLETE_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
+ }
+
+ case TYPE_VARIABLE_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
+ SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
+ return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
+ ASM, IndexTypeQuals,
+ SourceRange(LBLoc, RBLoc));
+ }
+
+ case TYPE_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of vector type in AST file");
+ return QualType();
+ }
+
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ unsigned NumElements = Record[1];
+ unsigned VecKind = Record[2];
+ return Context.getVectorType(ElementType, NumElements,
+ (VectorType::VectorKind)VecKind);
+ }
+
+ case TYPE_EXT_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of extended vector type in AST file");
+ return QualType();
+ }
+
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ unsigned NumElements = Record[1];
+ return Context.getExtVectorType(ElementType, NumElements);
+ }
+
+ case TYPE_FUNCTION_NO_PROTO: {
+ if (Record.size() != 6) {
+ Error("incorrect encoding of no-proto function type");
+ return QualType();
+ }
+ QualType ResultType = readType(*Loc.F, Record, Idx);
+ FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
+ (CallingConv)Record[4], Record[5]);
+ return Context.getFunctionNoProtoType(ResultType, Info);
+ }
+
+ case TYPE_FUNCTION_PROTO: {
+ QualType ResultType = readType(*Loc.F, Record, Idx);
+
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
+ /*hasregparm*/ Record[2],
+ /*regparm*/ Record[3],
+ static_cast<CallingConv>(Record[4]),
+ /*produces*/ Record[5]);
+
+ unsigned Idx = 6;
+
+ EPI.Variadic = Record[Idx++];
+ EPI.HasTrailingReturn = Record[Idx++];
+ EPI.TypeQuals = Record[Idx++];
+ EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
+ SmallVector<QualType, 8> ExceptionStorage;
+ readExceptionSpec(*Loc.F, ExceptionStorage, EPI.ExceptionSpec, Record, Idx);
+
+ unsigned NumParams = Record[Idx++];
+ SmallVector<QualType, 16> ParamTypes;
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamTypes.push_back(readType(*Loc.F, Record, Idx));
+
+ return Context.getFunctionType(ResultType, ParamTypes, EPI);
+ }
+
+ case TYPE_UNRESOLVED_USING: {
+ unsigned Idx = 0;
+ return Context.getTypeDeclType(
+ ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx));
+ }
+
+ case TYPE_TYPEDEF: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of typedef type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx);
+ QualType Canonical = readType(*Loc.F, Record, Idx);
+ if (!Canonical.isNull())
+ Canonical = Context.getCanonicalType(Canonical);
+ return Context.getTypedefType(Decl, Canonical);
+ }
+
+ case TYPE_TYPEOF_EXPR:
+ return Context.getTypeOfExprType(ReadExpr(*Loc.F));
+
+ case TYPE_TYPEOF: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of typeof(type) in AST file");
+ return QualType();
+ }
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getTypeOfType(UnderlyingType);
+ }
+
+ case TYPE_DECLTYPE: {
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
+ }
+
+ case TYPE_UNARY_TRANSFORM: {
+ QualType BaseType = readType(*Loc.F, Record, Idx);
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
+ return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
+ }
+
+ case TYPE_AUTO: {
+ QualType Deduced = readType(*Loc.F, Record, Idx);
+ bool IsDecltypeAuto = Record[Idx++];
+ bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
+ return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
+ }
+
+ case TYPE_RECORD: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of record type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
+ RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
+ QualType T = Context.getRecordType(RD);
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ENUM: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of enum type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ QualType T
+ = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx));
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ATTRIBUTED: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of attributed type");
+ return QualType();
+ }
+ QualType modifiedType = readType(*Loc.F, Record, Idx);
+ QualType equivalentType = readType(*Loc.F, Record, Idx);
+ AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
+ return Context.getAttributedType(kind, modifiedType, equivalentType);
+ }
+
+ case TYPE_PAREN: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of paren type");
+ return QualType();
+ }
+ QualType InnerType = readType(*Loc.F, Record, Idx);
+ return Context.getParenType(InnerType);
+ }
+
+ case TYPE_PACK_EXPANSION: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of pack expansion type");
+ return QualType();
+ }
+ QualType Pattern = readType(*Loc.F, Record, Idx);
+ if (Pattern.isNull())
+ return QualType();
+ Optional<unsigned> NumExpansions;
+ if (Record[1])
+ NumExpansions = Record[1] - 1;
+ return Context.getPackExpansionType(Pattern, NumExpansions);
+ }
+
+ case TYPE_ELABORATED: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ QualType NamedType = readType(*Loc.F, Record, Idx);
+ return Context.getElaboratedType(Keyword, NNS, NamedType);
+ }
+
+ case TYPE_OBJC_INTERFACE: {
+ unsigned Idx = 0;
+ ObjCInterfaceDecl *ItfD
+ = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
+ return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
+ }
+
+ case TYPE_OBJC_OBJECT: {
+ unsigned Idx = 0;
+ QualType Base = readType(*Loc.F, Record, Idx);
+ unsigned NumProtos = Record[Idx++];
+ SmallVector<ObjCProtocolDecl*, 4> Protos;
+ for (unsigned I = 0; I != NumProtos; ++I)
+ Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
+ return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
+ }
+
+ case TYPE_OBJC_OBJECT_POINTER: {
+ unsigned Idx = 0;
+ QualType Pointee = readType(*Loc.F, Record, Idx);
+ return Context.getObjCObjectPointerType(Pointee);
+ }
+
+ case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ QualType Parm = readType(*Loc.F, Record, Idx);
+ QualType Replacement = readType(*Loc.F, Record, Idx);
+ return Context.getSubstTemplateTypeParmType(
+ cast<TemplateTypeParmType>(Parm),
+ Context.getCanonicalType(Replacement));
+ }
+
+ case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
+ unsigned Idx = 0;
+ QualType Parm = readType(*Loc.F, Record, Idx);
+ TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
+ return Context.getSubstTemplateTypeParmPackType(
+ cast<TemplateTypeParmType>(Parm),
+ ArgPack);
+ }
+
+ case TYPE_INJECTED_CLASS_NAME: {
+ CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx);
+ QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
+ // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
+ // for AST reading, too much interdependencies.
+ const Type *T = nullptr;
+ for (auto *DI = D; DI; DI = DI->getPreviousDecl()) {
+ if (const Type *Existing = DI->getTypeForDecl()) {
+ T = Existing;
+ break;
+ }
+ }
+ if (!T) {
+ T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
+ for (auto *DI = D; DI; DI = DI->getPreviousDecl())
+ DI->setTypeForDecl(T);
+ }
+ return QualType(T, 0);
+ }
+
+ case TYPE_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ unsigned Depth = Record[Idx++];
+ unsigned Index = Record[Idx++];
+ bool Pack = Record[Idx++];
+ TemplateTypeParmDecl *D
+ = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
+ return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
+ }
+
+ case TYPE_DEPENDENT_NAME: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ QualType Canon = readType(*Loc.F, Record, Idx);
+ if (!Canon.isNull())
+ Canon = Context.getCanonicalType(Canon);
+ return Context.getDependentNameType(Keyword, NNS, Name, Canon);
+ }
+
+ case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ unsigned NumArgs = Record[Idx++];
+ SmallVector<TemplateArgument, 8> Args;
+ Args.reserve(NumArgs);
+ while (NumArgs--)
+ Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
+ return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
+ Args.size(), Args.data());
+ }
+
+ case TYPE_DEPENDENT_SIZED_ARRAY: {
+ unsigned Idx = 0;
+
+ // ArrayType
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM
+ = (ArrayType::ArraySizeModifier)Record[Idx++];
+ unsigned IndexTypeQuals = Record[Idx++];
+
+ // DependentSizedArrayType
+ Expr *NumElts = ReadExpr(*Loc.F);
+ SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
+
+ return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
+ IndexTypeQuals, Brackets);
+ }
+
+ case TYPE_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
+ SmallVector<TemplateArgument, 8> Args;
+ ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
+ QualType Underlying = readType(*Loc.F, Record, Idx);
+ QualType T;
+ if (Underlying.isNull())
+ T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(),
+ Args.size());
+ else
+ T = Context.getTemplateSpecializationType(Name, Args.data(),
+ Args.size(), Underlying);
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ATOMIC: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of atomic type");
+ return QualType();
+ }
+ QualType ValueType = readType(*Loc.F, Record, Idx);
+ return Context.getAtomicType(ValueType);
+ }
+ }
+ llvm_unreachable("Invalid TypeCode!");
+}
+
+void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
+ SmallVectorImpl<QualType> &Exceptions,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ const RecordData &Record, unsigned &Idx) {
+ ExceptionSpecificationType EST =
+ static_cast<ExceptionSpecificationType>(Record[Idx++]);
+ ESI.Type = EST;
+ if (EST == EST_Dynamic) {
+ for (unsigned I = 0, N = Record[Idx++]; I != N; ++I)
+ Exceptions.push_back(readType(ModuleFile, Record, Idx));
+ ESI.Exceptions = Exceptions;
+ } else if (EST == EST_ComputedNoexcept) {
+ ESI.NoexceptExpr = ReadExpr(ModuleFile);
+ } else if (EST == EST_Uninstantiated) {
+ ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ ESI.SourceTemplate = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ } else if (EST == EST_Unevaluated) {
+ ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ }
+}
+
+class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
+ ASTReader &Reader;
+ ModuleFile &F;
+ const ASTReader::RecordData &Record;
+ unsigned &Idx;
+
+ SourceLocation ReadSourceLocation(const ASTReader::RecordData &R,
+ unsigned &I) {
+ return Reader.ReadSourceLocation(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) {
+ return Reader.ReadDeclAs<T>(F, Record, Idx);
+ }
+
+public:
+ TypeLocReader(ASTReader &Reader, ModuleFile &F,
+ const ASTReader::RecordData &Record, unsigned &Idx)
+ : Reader(Reader), F(F), Record(Record), Idx(Idx)
+ { }
+
+ // We want compile-time assurance that we've enumerated all of
+ // these, so unfortunately we have to declare them first, then
+ // define them out-of-line.
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitFunctionTypeLoc(FunctionTypeLoc);
+ void VisitArrayTypeLoc(ArrayTypeLoc);
+};
+
+void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ TL.setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ if (TL.needsExtraLocalData()) {
+ TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
+ TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
+ TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
+ TL.setModeAttr(Record[Idx++]);
+ }
+}
+void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ TL.setCaretLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ TL.setAmpLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+ TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ TL.setLBracketLoc(ReadSourceLocation(Record, Idx));
+ TL.setRBracketLoc(ReadSourceLocation(Record, Idx));
+ if (Record[Idx++])
+ TL.setSizeExpr(Reader.ReadExpr(F));
+ else
+ TL.setSizeExpr(nullptr);
+}
+void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedArrayTypeLoc(
+ DependentSizedArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
+ DependentSizedExtVectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) {
+ TL.setParam(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
+ }
+}
+void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ TL.setAttrNameLoc(ReadSourceLocation(Record, Idx));
+ if (TL.hasAttrOperand()) {
+ SourceRange range;
+ range.setBegin(ReadSourceLocation(Record, Idx));
+ range.setEnd(ReadSourceLocation(Record, Idx));
+ TL.setAttrOperandParensRange(range);
+ }
+ if (TL.hasAttrExprOperand()) {
+ if (Record[Idx++])
+ TL.setAttrExprOperand(Reader.ReadExpr(F));
+ else
+ TL.setAttrExprOperand(nullptr);
+ } else if (TL.hasAttrEnumOperand())
+ TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
+ SubstTemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
+ SubstTemplateTypeParmPackTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ TL.setArgLocInfo(i,
+ Reader.GetTemplateArgumentLocInfo(F,
+ TL.getTypePtr()->getArg(i).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+}
+void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ TL.setArgLocInfo(I,
+ Reader.GetTemplateArgumentLocInfo(F,
+ TL.getTypePtr()->getArg(I).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+ TL.setEllipsisLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ TL.setHasBaseTypeAsWritten(Record[Idx++]);
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
+ TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ QualType InfoTy = readType(F, Record, Idx);
+ if (InfoTy.isNull())
+ return nullptr;
+
+ TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
+ TypeLocReader TLR(*this, F, Record, Idx);
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLR.Visit(TL);
+ return TInfo;
+}
+
+QualType ASTReader::GetType(TypeID ID) {
+ unsigned FastQuals = ID & Qualifiers::FastMask;
+ unsigned Index = ID >> Qualifiers::FastWidth;
+
+ if (Index < NUM_PREDEF_TYPE_IDS) {
+ QualType T;
+ switch ((PredefinedTypeIDs)Index) {
+ case PREDEF_TYPE_NULL_ID: return QualType();
+ case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
+ case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
+
+ case PREDEF_TYPE_CHAR_U_ID:
+ case PREDEF_TYPE_CHAR_S_ID:
+ // FIXME: Check that the signedness of CharTy is correct!
+ T = Context.CharTy;
+ break;
+
+ case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
+ case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
+ case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
+ case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
+ case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
+ case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
+ case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
+ case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
+ case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
+ case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
+ case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
+ case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
+ case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
+ case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
+ case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
+ case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
+ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
+ case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
+ case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
+ case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
+ case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
+ case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
+ case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
+ case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
+ case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
+ case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
+ case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
+ case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
+ case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
+ case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
+ case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
+ case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
+ case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
+ case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
+ case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break;
+ case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break;
+ case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
+
+ case PREDEF_TYPE_AUTO_RREF_DEDUCT:
+ T = Context.getAutoRRefDeductType();
+ break;
+
+ case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
+ T = Context.ARCUnbridgedCastTy;
+ break;
+
+ case PREDEF_TYPE_VA_LIST_TAG:
+ T = Context.getVaListTagType();
+ break;
+
+ case PREDEF_TYPE_BUILTIN_FN:
+ T = Context.BuiltinFnTy;
+ break;
+ }
+
+ assert(!T.isNull() && "Unknown predefined type");
+ return T.withFastQualifiers(FastQuals);
+ }
+
+ Index -= NUM_PREDEF_TYPE_IDS;
+ assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (TypesLoaded[Index].isNull()) {
+ TypesLoaded[Index] = readTypeRecord(Index);
+ if (TypesLoaded[Index].isNull())
+ return QualType();
+
+ TypesLoaded[Index]->setFromAST();
+ if (DeserializationListener)
+ DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
+ TypesLoaded[Index]);
+ }
+
+ return TypesLoaded[Index].withFastQualifiers(FastQuals);
+}
+
+QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) {
+ return GetType(getGlobalTypeID(F, LocalID));
+}
+
+serialization::TypeID
+ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
+ unsigned FastQuals = LocalID & Qualifiers::FastMask;
+ unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
+
+ if (LocalIndex < NUM_PREDEF_TYPE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
+ assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
+
+ unsigned GlobalIndex = LocalIndex + I->second;
+ return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
+}
+
+TemplateArgumentLocInfo
+ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
+ TemplateArgument::ArgKind Kind,
+ const RecordData &Record,
+ unsigned &Index) {
+ switch (Kind) {
+ case TemplateArgument::Expression:
+ return ReadExpr(F);
+ case TemplateArgument::Type:
+ return GetTypeSourceInfo(F, Record, Index);
+ case TemplateArgument::Template: {
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
+ SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
+ SourceLocation());
+ }
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
+ SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
+ SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
+ EllipsisLoc);
+ }
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Pack:
+ // FIXME: Is this right?
+ return TemplateArgumentLocInfo();
+ }
+ llvm_unreachable("unexpected template argument loc");
+}
+
+TemplateArgumentLoc
+ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
+ const RecordData &Record, unsigned &Index) {
+ TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
+
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ if (Record[Index++]) // bool InfoHasSameExpr.
+ return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
+ }
+ return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(),
+ Record, Index));
+}
+
+const ASTTemplateArgumentListInfo*
+ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Index) {
+ SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index);
+ SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index);
+ unsigned NumArgsAsWritten = Record[Index++];
+ TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
+ for (unsigned i = 0; i != NumArgsAsWritten; ++i)
+ TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index));
+ return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
+}
+
+Decl *ASTReader::GetExternalDecl(uint32_t ID) {
+ return GetDecl(ID);
+}
+
+template<typename TemplateSpecializationDecl>
+static void completeRedeclChainForTemplateSpecialization(Decl *D) {
+ if (auto *TSD = dyn_cast<TemplateSpecializationDecl>(D))
+ TSD->getSpecializedTemplate()->LoadLazySpecializations();
+}
+
+void ASTReader::CompleteRedeclChain(const Decl *D) {
+ if (NumCurrentElementsDeserializing) {
+ // We arrange to not care about the complete redeclaration chain while we're
+ // deserializing. Just remember that the AST has marked this one as complete
+ // but that it's not actually complete yet, so we know we still need to
+ // complete it later.
+ PendingIncompleteDeclChains.push_back(const_cast<Decl*>(D));
+ return;
+ }
+
+ const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+
+ // If this is a named declaration, complete it by looking it up
+ // within its context.
+ //
+ // FIXME: Merging a function definition should merge
+ // all mergeable entities within it.
+ if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
+ isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) {
+ if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) {
+ auto *II = Name.getAsIdentifierInfo();
+ if (isa<TranslationUnitDecl>(DC) && II) {
+ // Outside of C++, we don't have a lookup table for the TU, so update
+ // the identifier instead. In C++, either way should work fine.
+ if (II->isOutOfDate())
+ updateOutOfDateIdentifier(*II);
+ } else
+ DC->lookup(Name);
+ } else if (needsAnonymousDeclarationNumber(cast<NamedDecl>(D))) {
+ // FIXME: It'd be nice to do something a bit more targeted here.
+ D->getDeclContext()->decls_begin();
+ }
+ }
+
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
+ CTSD->getSpecializedTemplate()->LoadLazySpecializations();
+ if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
+ VTSD->getSpecializedTemplate()->LoadLazySpecializations();
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *Template = FD->getPrimaryTemplate())
+ Template->LoadLazySpecializations();
+ }
+}
+
+uint64_t ASTReader::ReadCXXCtorInitializersRef(ModuleFile &M,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXCtorInitializers) {
+ Error("malformed AST file: missing C++ ctor initializers");
+ return 0;
+ }
+
+ unsigned LocalID = Record[Idx++];
+ return getGlobalBitOffset(M, M.CXXCtorInitializersOffsets[LocalID - 1]);
+}
+
+CXXCtorInitializer **
+ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Loc.Offset);
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record);
+ if (RecCode != DECL_CXX_CTOR_INITIALIZERS) {
+ Error("malformed AST file: missing C++ ctor initializers");
+ return nullptr;
+ }
+
+ unsigned Idx = 0;
+ return ReadCXXCtorInitializers(*Loc.F, Record, Idx);
+}
+
+uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXBaseSpecifiers) {
+ Error("malformed AST file: missing C++ base specifier");
+ return 0;
+ }
+
+ unsigned LocalID = Record[Idx++];
+ return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
+}
+
+CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Loc.Offset);
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record);
+ if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
+ Error("malformed AST file: missing C++ base specifiers");
+ return nullptr;
+ }
+
+ unsigned Idx = 0;
+ unsigned NumBases = Record[Idx++];
+ void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
+ CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
+ for (unsigned I = 0; I != NumBases; ++I)
+ Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
+ return Bases;
+}
+
+serialization::DeclID
+ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
+ if (LocalID < NUM_PREDEF_DECL_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
+ assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
+
+ return LocalID + I->second;
+}
+
+bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
+ ModuleFile &M) const {
+ // Predefined decls aren't from any module.
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return false;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return &M == I->second;
+}
+
+ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
+ if (!D->isFromASTFile())
+ return nullptr;
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return I->second;
+}
+
+SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return SourceLocation();
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index > DeclsLoaded.size()) {
+ Error("declaration ID out-of-range for AST file");
+ return SourceLocation();
+ }
+
+ if (Decl *D = DeclsLoaded[Index])
+ return D->getLocation();
+
+ unsigned RawLocation = 0;
+ RecordLocation Rec = DeclCursorForID(ID, RawLocation);
+ return ReadSourceLocation(*Rec.F, RawLocation);
+}
+
+static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
+ switch (ID) {
+ case PREDEF_DECL_NULL_ID:
+ return nullptr;
+
+ case PREDEF_DECL_TRANSLATION_UNIT_ID:
+ return Context.getTranslationUnitDecl();
+
+ case PREDEF_DECL_OBJC_ID_ID:
+ return Context.getObjCIdDecl();
+
+ case PREDEF_DECL_OBJC_SEL_ID:
+ return Context.getObjCSelDecl();
+
+ case PREDEF_DECL_OBJC_CLASS_ID:
+ return Context.getObjCClassDecl();
+
+ case PREDEF_DECL_OBJC_PROTOCOL_ID:
+ return Context.getObjCProtocolDecl();
+
+ case PREDEF_DECL_INT_128_ID:
+ return Context.getInt128Decl();
+
+ case PREDEF_DECL_UNSIGNED_INT_128_ID:
+ return Context.getUInt128Decl();
+
+ case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
+ return Context.getObjCInstanceTypeDecl();
+
+ case PREDEF_DECL_BUILTIN_VA_LIST_ID:
+ return Context.getBuiltinVaListDecl();
+
+ case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
+ return Context.getExternCContextDecl();
+ }
+ llvm_unreachable("PredefinedDeclIDs unknown enum value");
+}
+
+Decl *ASTReader::GetExistingDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS) {
+ Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID);
+ if (D) {
+ // Track that we have merged the declaration with ID \p ID into the
+ // pre-existing predefined declaration \p D.
+ auto &Merged = MergedDecls[D->getCanonicalDecl()];
+ if (Merged.empty())
+ Merged.push_back(ID);
+ }
+ return D;
+ }
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index >= DeclsLoaded.size()) {
+ assert(0 && "declaration ID out-of-range for AST file");
+ Error("declaration ID out-of-range for AST file");
+ return nullptr;
+ }
+
+ return DeclsLoaded[Index];
+}
+
+Decl *ASTReader::GetDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return GetExistingDecl(ID);
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index >= DeclsLoaded.size()) {
+ assert(0 && "declaration ID out-of-range for AST file");
+ Error("declaration ID out-of-range for AST file");
+ return nullptr;
+ }
+
+ if (!DeclsLoaded[Index]) {
+ ReadDeclRecord(ID);
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
+ }
+
+ return DeclsLoaded[Index];
+}
+
+DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ DeclID GlobalID) {
+ if (GlobalID < NUM_PREDEF_DECL_IDS)
+ return GlobalID;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *Owner = I->second;
+
+ llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
+ = M.GlobalToLocalDeclIDs.find(Owner);
+ if (Pos == M.GlobalToLocalDeclIDs.end())
+ return 0;
+
+ return GlobalID - Owner->BaseDeclID + Pos->second;
+}
+
+serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size()) {
+ Error("Corrupted AST file");
+ return 0;
+ }
+
+ return getGlobalDeclID(F, Record[Idx++]);
+}
+
+/// \brief Resolve the offset of a statement into a statement.
+///
+/// This operation will read a new statement from the external
+/// source each time it is called, and is meant to be used via a
+/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
+Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
+ // Switch case IDs are per Decl.
+ ClearSwitchCaseIDs();
+
+ // Offset here is a global offset across the entire chain.
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
+ return ReadStmtFromStream(*Loc.F);
+}
+
+namespace {
+ class FindExternalLexicalDeclsVisitor {
+ ASTReader &Reader;
+ const DeclContext *DC;
+ bool (*isKindWeWant)(Decl::Kind);
+
+ SmallVectorImpl<Decl*> &Decls;
+ bool PredefsVisited[NUM_PREDEF_DECL_IDS];
+
+ public:
+ FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls)
+ : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
+ {
+ for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
+ PredefsVisited[I] = false;
+ }
+
+ static bool visitPostorder(ModuleFile &M, void *UserData) {
+ FindExternalLexicalDeclsVisitor *This
+ = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
+
+ ModuleFile::DeclContextInfosMap::iterator Info
+ = M.DeclContextInfos.find(This->DC);
+ if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
+ return false;
+
+ // Load all of the declaration IDs
+ for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
+ *IDE = ID + Info->second.NumLexicalDecls;
+ ID != IDE; ++ID) {
+ if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
+ continue;
+
+ // Don't add predefined declarations to the lexical context more
+ // than once.
+ if (ID->second < NUM_PREDEF_DECL_IDS) {
+ if (This->PredefsVisited[ID->second])
+ continue;
+
+ This->PredefsVisited[ID->second] = true;
+ }
+
+ if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
+ if (!This->DC->isDeclInLexicalTraversal(D))
+ This->Decls.push_back(D);
+ }
+ }
+
+ return false;
+ }
+ };
+}
+
+ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls) {
+ // There might be lexical decls in multiple modules, for the TU at
+ // least. Walk all of the modules in the order they were loaded.
+ FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
+ ModuleMgr.visitDepthFirst(
+ nullptr, &FindExternalLexicalDeclsVisitor::visitPostorder, &Visitor);
+ ++NumLexicalDeclContextsRead;
+ return ELR_Success;
+}
+
+namespace {
+
+class DeclIDComp {
+ ASTReader &Reader;
+ ModuleFile &Mod;
+
+public:
+ DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
+
+ bool operator()(LocalDeclID L, LocalDeclID R) const {
+ SourceLocation LHS = getLocation(L);
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, LocalDeclID R) const {
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(LocalDeclID L, SourceLocation RHS) const {
+ SourceLocation LHS = getLocation(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLocation(LocalDeclID ID) const {
+ return Reader.getSourceManager().getFileLoc(
+ Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
+ }
+};
+
+}
+
+void ASTReader::FindFileRegionDecls(FileID File,
+ unsigned Offset, unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {
+ SourceManager &SM = getSourceManager();
+
+ llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File);
+ if (I == FileDeclIDs.end())
+ return;
+
+ FileDeclsInfo &DInfo = I->second;
+ if (DInfo.Decls.empty())
+ return;
+
+ SourceLocation
+ BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
+ SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
+
+ DeclIDComp DIDComp(*this, *DInfo.Mod);
+ ArrayRef<serialization::LocalDeclID>::iterator
+ BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ BeginLoc, DIDComp);
+ if (BeginIt != DInfo.Decls.begin())
+ --BeginIt;
+
+ // If we are pointing at a top-level decl inside an objc container, we need
+ // to backtrack until we find it otherwise we will fail to report that the
+ // region overlaps with an objc container.
+ while (BeginIt != DInfo.Decls.begin() &&
+ GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
+ ->isTopLevelDeclInObjCContainer())
+ --BeginIt;
+
+ ArrayRef<serialization::LocalDeclID>::iterator
+ EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ EndLoc, DIDComp);
+ if (EndIt != DInfo.Decls.end())
+ ++EndIt;
+
+ for (ArrayRef<serialization::LocalDeclID>::iterator
+ DIt = BeginIt; DIt != EndIt; ++DIt)
+ Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to perform name lookup into a
+ /// declaration context.
+ class DeclContextNameLookupVisitor {
+ ASTReader &Reader;
+ ArrayRef<const DeclContext *> Contexts;
+ DeclarationName Name;
+ SmallVectorImpl<NamedDecl *> &Decls;
+ llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet;
+
+ public:
+ DeclContextNameLookupVisitor(ASTReader &Reader,
+ ArrayRef<const DeclContext *> Contexts,
+ DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Decls,
+ llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet)
+ : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls),
+ DeclSet(DeclSet) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ DeclContextNameLookupVisitor *This
+ = static_cast<DeclContextNameLookupVisitor *>(UserData);
+
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (auto *DC : This->Contexts) {
+ Info = M.DeclContextInfos.find(DC);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+
+ if (!FoundInfo)
+ return false;
+
+ // Look for this name within this module.
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ ASTDeclContextNameLookupTable::iterator Pos
+ = LookupTable->find(This->Name);
+ if (Pos == LookupTable->end())
+ return false;
+
+ bool FoundAnything = false;
+ ASTDeclContextNameLookupTrait::data_type Data = *Pos;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
+ if (!ND)
+ continue;
+
+ if (ND->getDeclName() != This->Name) {
+ // A name might be null because the decl's redeclarable part is
+ // currently read before reading its name. The lookup is triggered by
+ // building that decl (likely indirectly), and so it is later in the
+ // sense of "already existing" and can be ignored here.
+ // FIXME: This should not happen; deserializing declarations should
+ // not perform lookups since that can lead to deserialization cycles.
+ continue;
+ }
+
+ // Record this declaration.
+ FoundAnything = true;
+ if (This->DeclSet.insert(ND).second)
+ This->Decls.push_back(ND);
+ }
+
+ return FoundAnything;
+ }
+ };
+}
+
+/// \brief Retrieve the "definitive" module file for the definition of the
+/// given declaration context, if there is one.
+///
+/// The "definitive" module file is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive module files
+/// associated with them. C++ namespaces, on the other hand, can have
+/// definitions in multiple different module files.
+///
+/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
+/// NDEBUG checking.
+static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
+ ASTReader &Reader) {
+ if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
+ return Reader.getOwningModuleFile(cast<Decl>(DefDC));
+
+ return nullptr;
+}
+
+bool
+ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ assert(DC->hasExternalVisibleStorage() &&
+ "DeclContext has no visible decls in storage");
+ if (!Name)
+ return false;
+
+ Deserializing LookupResults(this);
+
+ SmallVector<NamedDecl *, 64> Decls;
+ llvm::SmallPtrSet<NamedDecl*, 64> DeclSet;
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ auto LookUpInContexts = [&](ArrayRef<const DeclContext*> Contexts) {
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls, DeclSet);
+
+ // If we can definitively determine which module file to look into,
+ // only look there. Otherwise, look in all module files.
+ ModuleFile *Definitive;
+ if (Contexts.size() == 1 &&
+ (Definitive = getDefinitiveModuleFileFor(Contexts[0], *this))) {
+ DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
+ } else {
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ }
+ };
+
+ LookUpInContexts(Contexts);
+
+ // If this might be an implicit special member function, then also search
+ // all merged definitions of the surrounding class. We need to search them
+ // individually, because finding an entity in one of them doesn't imply that
+ // we can't find a different entity in another one.
+ if (isa<CXXRecordDecl>(DC)) {
+ auto Merged = MergedLookups.find(DC);
+ if (Merged != MergedLookups.end()) {
+ for (unsigned I = 0; I != Merged->second.size(); ++I) {
+ const DeclContext *Context = Merged->second[I];
+ LookUpInContexts(Context);
+ // We might have just added some more merged lookups. If so, our
+ // iterator is now invalid, so grab a fresh one before continuing.
+ Merged = MergedLookups.find(DC);
+ }
+ }
+ }
+
+ ++NumVisibleDeclContextsRead;
+ SetExternalVisibleDeclsForName(DC, Name, Decls);
+ return !Decls.empty();
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to retrieve all visible names in a
+ /// declaration context.
+ class DeclContextAllNamesVisitor {
+ ASTReader &Reader;
+ SmallVectorImpl<const DeclContext *> &Contexts;
+ DeclsMap &Decls;
+ llvm::SmallPtrSet<NamedDecl *, 256> DeclSet;
+ bool VisitAll;
+
+ public:
+ DeclContextAllNamesVisitor(ASTReader &Reader,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclsMap &Decls, bool VisitAll)
+ : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ DeclContextAllNamesVisitor *This
+ = static_cast<DeclContextAllNamesVisitor *>(UserData);
+
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(This->Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+
+ if (!FoundInfo)
+ return false;
+
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ bool FoundAnything = false;
+ for (ASTDeclContextNameLookupTable::data_iterator
+ I = LookupTable->data_begin(), E = LookupTable->data_end();
+ I != E;
+ ++I) {
+ ASTDeclContextNameLookupTrait::data_type Data = *I;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
+ *Data.first);
+ if (!ND)
+ continue;
+
+ // Record this declaration.
+ FoundAnything = true;
+ if (This->DeclSet.insert(ND).second)
+ This->Decls[ND->getDeclName()].push_back(ND);
+ }
+ }
+
+ return FoundAnything && !This->VisitAll;
+ }
+ };
+}
+
+void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
+ if (!DC->hasExternalVisibleStorage())
+ return;
+ DeclsMap Decls;
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
+ /*VisitAll=*/DC->isFileContext());
+ ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
+ ++NumVisibleDeclContextsRead;
+
+ for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ SetExternalVisibleDeclsForName(DC, I->first, I->second);
+ }
+ const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
+}
+
+/// \brief Under non-PCH compilation the consumer receives the objc methods
+/// before receiving the implementation, and codegen depends on this.
+/// We simulate this by deserializing and passing to consumer the methods of the
+/// implementation before passing the deserialized implementation decl.
+static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
+ ASTConsumer *Consumer) {
+ assert(ImplD && Consumer);
+
+ for (auto *I : ImplD->methods())
+ Consumer->HandleInterestingDecl(DeclGroupRef(I));
+
+ Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
+}
+
+void ASTReader::PassInterestingDeclsToConsumer() {
+ assert(Consumer);
+
+ if (PassingDeclsToConsumer)
+ return;
+
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
+ // Ensure that we've loaded all potentially-interesting declarations
+ // that need to be eagerly loaded.
+ for (auto ID : EagerlyDeserializedDecls)
+ GetDecl(ID);
+ EagerlyDeserializedDecls.clear();
+
+ while (!InterestingDecls.empty()) {
+ Decl *D = InterestingDecls.front();
+ InterestingDecls.pop_front();
+
+ PassInterestingDeclToConsumer(D);
+ }
+}
+
+void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ PassObjCImplDeclToConsumer(ImplD, Consumer);
+ else
+ Consumer->HandleInterestingDecl(DeclGroupRef(D));
+}
+
+void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
+ this->Consumer = Consumer;
+
+ if (Consumer)
+ PassInterestingDeclsToConsumer();
+
+ if (DeserializationListener)
+ DeserializationListener->ReaderInitialized(this);
+}
+
+void ASTReader::PrintStats() {
+ std::fprintf(stderr, "*** AST File Statistics:\n");
+
+ unsigned NumTypesLoaded
+ = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
+ QualType());
+ unsigned NumDeclsLoaded
+ = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
+ (Decl *)nullptr);
+ unsigned NumIdentifiersLoaded
+ = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
+ IdentifiersLoaded.end(),
+ (IdentifierInfo *)nullptr);
+ unsigned NumMacrosLoaded
+ = MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
+ MacrosLoaded.end(),
+ (MacroInfo *)nullptr);
+ unsigned NumSelectorsLoaded
+ = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
+ SelectorsLoaded.end(),
+ Selector());
+
+ if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
+ std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
+ NumSLocEntriesRead, TotalNumSLocEntries,
+ ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
+ if (!TypesLoaded.empty())
+ std::fprintf(stderr, " %u/%u types read (%f%%)\n",
+ NumTypesLoaded, (unsigned)TypesLoaded.size(),
+ ((float)NumTypesLoaded/TypesLoaded.size() * 100));
+ if (!DeclsLoaded.empty())
+ std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
+ NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
+ ((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
+ if (!IdentifiersLoaded.empty())
+ std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
+ NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
+ ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (!MacrosLoaded.empty())
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosLoaded, (unsigned)MacrosLoaded.size(),
+ ((float)NumMacrosLoaded/MacrosLoaded.size() * 100));
+ if (!SelectorsLoaded.empty())
+ std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
+ NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(),
+ ((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100));
+ if (TotalNumStatements)
+ std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
+ NumStatementsRead, TotalNumStatements,
+ ((float)NumStatementsRead/TotalNumStatements * 100));
+ if (TotalNumMacros)
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosRead, TotalNumMacros,
+ ((float)NumMacrosRead/TotalNumMacros * 100));
+ if (TotalLexicalDeclContexts)
+ std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
+ NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
+ ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
+ * 100));
+ if (TotalVisibleDeclContexts)
+ std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
+ NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
+ ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
+ * 100));
+ if (TotalNumMethodPoolEntries) {
+ std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
+ NumMethodPoolEntriesRead, TotalNumMethodPoolEntries,
+ ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries
+ * 100));
+ }
+ if (NumMethodPoolLookups) {
+ std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n",
+ NumMethodPoolHits, NumMethodPoolLookups,
+ ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0));
+ }
+ if (NumMethodPoolTableLookups) {
+ std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n",
+ NumMethodPoolTableHits, NumMethodPoolTableLookups,
+ ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups
+ * 100.0));
+ }
+
+ if (NumIdentifierLookupHits) {
+ std::fprintf(stderr,
+ " %u / %u identifier table lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+
+ if (GlobalIndex) {
+ std::fprintf(stderr, "\n");
+ GlobalIndex->printStats();
+ }
+
+ std::fprintf(stderr, "\n");
+ dump();
+ std::fprintf(stderr, "\n");
+}
+
+template<typename Key, typename ModuleFile, unsigned InitialCapacity>
+static void
+dumpModuleIDMap(StringRef Name,
+ const ContinuousRangeMap<Key, ModuleFile *,
+ InitialCapacity> &Map) {
+ if (Map.begin() == Map.end())
+ return;
+
+ typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType;
+ llvm::errs() << Name << ":\n";
+ for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
+ I != IEnd; ++I) {
+ llvm::errs() << " " << I->first << " -> " << I->second->FileName
+ << "\n";
+ }
+}
+
+void ASTReader::dump() {
+ llvm::errs() << "*** PCH/ModuleFile Remappings:\n";
+ dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
+ dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
+ dumpModuleIDMap("Global type map", GlobalTypeMap);
+ dumpModuleIDMap("Global declaration map", GlobalDeclMap);
+ dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global macro map", GlobalMacroMap);
+ dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
+ dumpModuleIDMap("Global selector map", GlobalSelectorMap);
+ dumpModuleIDMap("Global preprocessed entity map",
+ GlobalPreprocessedEntityMap);
+
+ llvm::errs() << "\n*** PCH/Modules Loaded:";
+ for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
+ MEnd = ModuleMgr.end();
+ M != MEnd; ++M)
+ (*M)->dump();
+}
+
+/// Return the amount of memory used by memory buffers, breaking down
+/// by heap-backed versus mmap'ed memory.
+void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
+ for (ModuleConstIterator I = ModuleMgr.begin(),
+ E = ModuleMgr.end(); I != E; ++I) {
+ if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
+ size_t bytes = buf->getBufferSize();
+ switch (buf->getBufferKind()) {
+ case llvm::MemoryBuffer::MemoryBuffer_Malloc:
+ sizes.malloc_bytes += bytes;
+ break;
+ case llvm::MemoryBuffer::MemoryBuffer_MMap:
+ sizes.mmap_bytes += bytes;
+ break;
+ }
+ }
+ }
+}
+
+void ASTReader::InitializeSema(Sema &S) {
+ SemaObj = &S;
+ S.addExternalSource(this);
+
+ // Makes sure any declarations that were deserialized "too early"
+ // still get added to the identifier's declaration chains.
+ for (uint64_t ID : PreloadedDeclIDs) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(ID));
+ pushExternalDeclIntoScope(D, D->getDeclName());
+ }
+ PreloadedDeclIDs.clear();
+
+ // FIXME: What happens if these are changed by a module import?
+ if (!FPPragmaOptions.empty()) {
+ assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
+ SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
+ }
+
+ // FIXME: What happens if these are changed by a module import?
+ if (!OpenCLExtensions.empty()) {
+ unsigned I = 0;
+#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++];
+#include "clang/Basic/OpenCLExtensions.def"
+
+ assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS");
+ }
+
+ UpdateSema();
+}
+
+void ASTReader::UpdateSema() {
+ assert(SemaObj && "no Sema to update");
+
+ // Load the offsets of the declarations that Sema references.
+ // They will be lazily deserialized when needed.
+ if (!SemaDeclRefs.empty()) {
+ assert(SemaDeclRefs.size() % 2 == 0);
+ for (unsigned I = 0; I != SemaDeclRefs.size(); I += 2) {
+ if (!SemaObj->StdNamespace)
+ SemaObj->StdNamespace = SemaDeclRefs[I];
+ if (!SemaObj->StdBadAlloc)
+ SemaObj->StdBadAlloc = SemaDeclRefs[I+1];
+ }
+ SemaDeclRefs.clear();
+ }
+
+ // Update the state of 'pragma clang optimize'. Use the same API as if we had
+ // encountered the pragma in the source.
+ if(OptimizeOffPragmaLocation.isValid())
+ SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation);
+}
+
+IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+ StringRef Name(NameStart, NameEnd - NameStart);
+
+ // If there is a global index, look there first to determine which modules
+ // provably do not have any results for this identifier.
+ GlobalModuleIndex::HitSet Hits;
+ GlobalModuleIndex::HitSet *HitsPtr = nullptr;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(Name, Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+ IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
+ IdentifierInfo *II = Visitor.getIdentifierInfo();
+ markIdentifierUpToDate(II);
+ return II;
+}
+
+namespace clang {
+ /// \brief An identifier-lookup iterator that enumerates all of the
+ /// identifiers stored within a set of AST files.
+ class ASTIdentifierIterator : public IdentifierIterator {
+ /// \brief The AST reader whose identifiers are being enumerated.
+ const ASTReader &Reader;
+
+ /// \brief The current index into the chain of AST files stored in
+ /// the AST reader.
+ unsigned Index;
+
+ /// \brief The current position within the identifier lookup table
+ /// of the current AST file.
+ ASTIdentifierLookupTable::key_iterator Current;
+
+ /// \brief The end position within the identifier lookup table of
+ /// the current AST file.
+ ASTIdentifierLookupTable::key_iterator End;
+
+ public:
+ explicit ASTIdentifierIterator(const ASTReader &Reader);
+
+ StringRef Next() override;
+ };
+}
+
+ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader)
+ : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) {
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable;
+ Current = IdTable->key_begin();
+ End = IdTable->key_end();
+}
+
+StringRef ASTIdentifierIterator::Next() {
+ while (Current == End) {
+ // If we have exhausted all of our AST files, we're done.
+ if (Index == 0)
+ return StringRef();
+
+ --Index;
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].
+ IdentifierLookupTable;
+ Current = IdTable->key_begin();
+ End = IdTable->key_end();
+ }
+
+ // We have any identifiers remaining in the current AST file; return
+ // the next one.
+ StringRef Result = *Current;
+ ++Current;
+ return Result;
+}
+
+IdentifierIterator *ASTReader::getIdentifiers() {
+ if (!loadGlobalIndex())
+ return GlobalIndex->createIdentifierIterator();
+
+ return new ASTIdentifierIterator(*this);
+}
+
+namespace clang { namespace serialization {
+ class ReadMethodPoolVisitor {
+ ASTReader &Reader;
+ Selector Sel;
+ unsigned PriorGeneration;
+ unsigned InstanceBits;
+ unsigned FactoryBits;
+ bool InstanceHasMoreThanOneDecl;
+ bool FactoryHasMoreThanOneDecl;
+ SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
+ SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
+
+ public:
+ ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
+ unsigned PriorGeneration)
+ : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration),
+ InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false),
+ FactoryHasMoreThanOneDecl(false) {}
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ ReadMethodPoolVisitor *This
+ = static_cast<ReadMethodPoolVisitor *>(UserData);
+
+ if (!M.SelectorLookupTable)
+ return false;
+
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
+ ++This->Reader.NumMethodPoolTableLookups;
+ ASTSelectorLookupTable *PoolTable
+ = (ASTSelectorLookupTable*)M.SelectorLookupTable;
+ ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
+ if (Pos == PoolTable->end())
+ return false;
+
+ ++This->Reader.NumMethodPoolTableHits;
+ ++This->Reader.NumSelectorsRead;
+ // FIXME: Not quite happy with the statistics here. We probably should
+ // disable this tracking when called via LoadSelector.
+ // Also, should entries without methods count as misses?
+ ++This->Reader.NumMethodPoolEntriesRead;
+ ASTSelectorLookupTrait::data_type Data = *Pos;
+ if (This->Reader.DeserializationListener)
+ This->Reader.DeserializationListener->SelectorRead(Data.ID,
+ This->Sel);
+
+ This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
+ This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
+ This->InstanceBits = Data.InstanceBits;
+ This->FactoryBits = Data.FactoryBits;
+ This->InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl;
+ This->FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl;
+ return true;
+ }
+
+ /// \brief Retrieve the instance methods found by this visitor.
+ ArrayRef<ObjCMethodDecl *> getInstanceMethods() const {
+ return InstanceMethods;
+ }
+
+ /// \brief Retrieve the instance methods found by this visitor.
+ ArrayRef<ObjCMethodDecl *> getFactoryMethods() const {
+ return FactoryMethods;
+ }
+
+ unsigned getInstanceBits() const { return InstanceBits; }
+ unsigned getFactoryBits() const { return FactoryBits; }
+ bool instanceHasMoreThanOneDecl() const {
+ return InstanceHasMoreThanOneDecl;
+ }
+ bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; }
+ };
+} } // end namespace clang::serialization
+
+/// \brief Add the given set of methods to the method list.
+static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
+ ObjCMethodList &List) {
+ for (unsigned I = 0, N = Methods.size(); I != N; ++I) {
+ S.addMethodToGlobalList(&List, Methods[I]);
+ }
+}
+
+void ASTReader::ReadMethodPool(Selector Sel) {
+ // Get the selector generation and update it to the current generation.
+ unsigned &Generation = SelectorGeneration[Sel];
+ unsigned PriorGeneration = Generation;
+ Generation = getGeneration();
+
+ // Search for methods defined with this selector.
+ ++NumMethodPoolLookups;
+ ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
+ ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
+
+ if (Visitor.getInstanceMethods().empty() &&
+ Visitor.getFactoryMethods().empty())
+ return;
+
+ ++NumMethodPoolHits;
+
+ if (!getSema())
+ return;
+
+ Sema &S = *getSema();
+ Sema::GlobalMethodPool::iterator Pos
+ = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
+
+ Pos->second.first.setBits(Visitor.getInstanceBits());
+ Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl());
+ Pos->second.second.setBits(Visitor.getFactoryBits());
+ Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl());
+
+ // Add methods to the global pool *after* setting hasMoreThanOneDecl, since
+ // when building a module we keep every method individually and may need to
+ // update hasMoreThanOneDecl as we add the methods.
+ addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
+ addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
+}
+
+void ASTReader::ReadKnownNamespaces(
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ Namespaces.clear();
+
+ for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
+ if (NamespaceDecl *Namespace
+ = dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I])))
+ Namespaces.push_back(Namespace);
+ }
+}
+
+void ASTReader::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) {
+ for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++]));
+ SourceLocation Loc =
+ SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]);
+ Undefined.insert(std::make_pair(D, Loc));
+ }
+}
+
+void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector<
+ FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &
+ Exprs) {
+ for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) {
+ FieldDecl *FD = cast<FieldDecl>(GetDecl(DelayedDeleteExprs[Idx++]));
+ uint64_t Count = DelayedDeleteExprs[Idx++];
+ for (uint64_t C = 0; C < Count; ++C) {
+ SourceLocation DeleteLoc =
+ SourceLocation::getFromRawEncoding(DelayedDeleteExprs[Idx++]);
+ const bool IsArrayForm = DelayedDeleteExprs[Idx++];
+ Exprs[FD].push_back(std::make_pair(DeleteLoc, IsArrayForm));
+ }
+ }
+}
+
+void ASTReader::ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl *> &TentativeDefs) {
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ if (Var)
+ TentativeDefs.push_back(Var);
+ }
+ TentativeDefinitions.clear();
+}
+
+void ASTReader::ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl *> &Decls) {
+ for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
+ DeclaratorDecl *D
+ = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ UnusedFileScopedDecls.clear();
+}
+
+void ASTReader::ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl *> &Decls) {
+ for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
+ CXXConstructorDecl *D
+ = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ DelegatingCtorDecls.clear();
+}
+
+void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {
+ for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) {
+ TypedefNameDecl *D
+ = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ ExtVectorDecls.clear();
+}
+
+void ASTReader::ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
+ for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N;
+ ++I) {
+ TypedefNameDecl *D = dyn_cast_or_null<TypedefNameDecl>(
+ GetDecl(UnusedLocalTypedefNameCandidates[I]));
+ if (D)
+ Decls.insert(D);
+ }
+ UnusedLocalTypedefNameCandidates.clear();
+}
+
+void ASTReader::ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
+ if (ReferencedSelectorsData.empty())
+ return;
+
+ // If there are @selector references added them to its pool. This is for
+ // implementation of -Wselector.
+ unsigned int DataSize = ReferencedSelectorsData.size()-1;
+ unsigned I = 0;
+ while (I < DataSize) {
+ Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]);
+ SourceLocation SelLoc
+ = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]);
+ Sels.push_back(std::make_pair(Sel, SelLoc));
+ }
+ ReferencedSelectorsData.clear();
+}
+
+void ASTReader::ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) {
+ if (WeakUndeclaredIdentifiers.empty())
+ return;
+
+ for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) {
+ IdentifierInfo *WeakId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ IdentifierInfo *AliasId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
+ bool Used = WeakUndeclaredIdentifiers[I++];
+ WeakInfo WI(AliasId, Loc);
+ WI.setUsed(Used);
+ WeakIDs.push_back(std::make_pair(WeakId, WI));
+ }
+ WeakUndeclaredIdentifiers.clear();
+}
+
+void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {
+ for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) {
+ ExternalVTableUse VT;
+ VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
+ VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]);
+ VT.DefinitionRequired = VTableUses[Idx++];
+ VTables.push_back(VT);
+ }
+
+ VTableUses.clear();
+}
+
+void ASTReader::ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) {
+ for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) {
+ ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
+
+ Pending.push_back(std::make_pair(D, Loc));
+ }
+ PendingInstantiations.clear();
+}
+
+void ASTReader::ReadLateParsedTemplates(
+ llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) {
+ for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N;
+ /* In loop */) {
+ FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++]));
+
+ LateParsedTemplate *LT = new LateParsedTemplate;
+ LT->D = GetDecl(LateParsedTemplates[Idx++]);
+
+ ModuleFile *F = getOwningModuleFile(LT->D);
+ assert(F && "No module");
+
+ unsigned TokN = LateParsedTemplates[Idx++];
+ LT->Toks.reserve(TokN);
+ for (unsigned T = 0; T < TokN; ++T)
+ LT->Toks.push_back(ReadToken(*F, LateParsedTemplates, Idx));
+
+ LPTMap.insert(std::make_pair(FD, LT));
+ }
+
+ LateParsedTemplates.clear();
+}
+
+void ASTReader::LoadSelector(Selector Sel) {
+ // It would be complicated to avoid reading the methods anyway. So don't.
+ ReadMethodPool(Sel);
+}
+
+void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
+ assert(ID && "Non-zero identifier ID required");
+ assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
+ IdentifiersLoaded[ID - 1] = II;
+ if (DeserializationListener)
+ DeserializationListener->IdentifierRead(ID, II);
+}
+
+/// \brief Set the globally-visible declarations associated with the given
+/// identifier.
+///
+/// If the AST reader is currently in a state where the given declaration IDs
+/// cannot safely be resolved, they are queued until it is safe to resolve
+/// them.
+///
+/// \param II an IdentifierInfo that refers to one or more globally-visible
+/// declarations.
+///
+/// \param DeclIDs the set of declaration IDs with the name @p II that are
+/// visible at global scope.
+///
+/// \param Decls if non-null, this vector will be populated with the set of
+/// deserialized declarations. These declarations will not be pushed into
+/// scope.
+void
+ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
+ const SmallVectorImpl<uint32_t> &DeclIDs,
+ SmallVectorImpl<Decl *> *Decls) {
+ if (NumCurrentElementsDeserializing && !Decls) {
+ PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end());
+ return;
+ }
+
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
+ if (!SemaObj) {
+ // 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.
+ PreloadedDeclIDs.push_back(DeclIDs[I]);
+ continue;
+ }
+
+ NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+
+ // If we're simply supposed to record the declarations, do so now.
+ if (Decls) {
+ Decls->push_back(D);
+ continue;
+ }
+
+ // 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.
+ pushExternalDeclIntoScope(D, II);
+ }
+}
+
+IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
+ if (ID == 0)
+ return nullptr;
+
+ if (IdentifiersLoaded.empty()) {
+ Error("no identifier table in AST file");
+ return nullptr;
+ }
+
+ ID -= 1;
+ if (!IdentifiersLoaded[ID]) {
+ GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
+ assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseIdentifierID;
+ const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
+
+ // All of the strings in the AST file are preceded by a 16-bit length.
+ // Extract that 16-bit length to avoid having to execute strlen().
+ // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as
+ // unsigned integers. This is important to avoid integer overflow when
+ // we cast them to 'unsigned'.
+ const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
+ unsigned StrLen = (((unsigned) StrLenPtr[0])
+ | (((unsigned) StrLenPtr[1]) << 8)) - 1;
+ IdentifiersLoaded[ID]
+ = &PP.getIdentifierTable().get(StringRef(Str, StrLen));
+ if (DeserializationListener)
+ DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
+ }
+
+ return IdentifiersLoaded[ID];
+}
+
+IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) {
+ return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
+}
+
+IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_IDENT_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
+ assert(I != M.IdentifierRemap.end()
+ && "Invalid index into identifier index remap");
+
+ return LocalID + I->second;
+}
+
+MacroInfo *ASTReader::getMacro(MacroID ID) {
+ if (ID == 0)
+ return nullptr;
+
+ if (MacrosLoaded.empty()) {
+ Error("no macro table in AST file");
+ return nullptr;
+ }
+
+ ID -= NUM_PREDEF_MACRO_IDS;
+ if (!MacrosLoaded[ID]) {
+ GlobalMacroMapType::iterator I
+ = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
+ assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseMacroID;
+ MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS,
+ MacrosLoaded[ID]);
+ }
+
+ return MacrosLoaded[ID];
+}
+
+MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_MACRO_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
+ assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
+
+ return LocalID + I->second;
+}
+
+serialization::SubmoduleID
+ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
+ assert(I != M.SubmoduleRemap.end()
+ && "Invalid index into submodule index remap");
+
+ return LocalID + I->second;
+}
+
+Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
+ if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
+ assert(GlobalID == 0 && "Unhandled global submodule ID");
+ return nullptr;
+ }
+
+ if (GlobalID > SubmodulesLoaded.size()) {
+ Error("submodule ID out of range in AST file");
+ return nullptr;
+ }
+
+ return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
+}
+
+Module *ASTReader::getModule(unsigned ID) {
+ return getSubmodule(ID);
+}
+
+Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
+ return DecodeSelector(getGlobalSelectorID(M, LocalID));
+}
+
+Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
+ if (ID == 0)
+ return Selector();
+
+ if (ID > SelectorsLoaded.size()) {
+ Error("selector ID out of range in AST file");
+ return Selector();
+ }
+
+ if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == nullptr) {
+ // Load this selector from the selector table.
+ GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
+ assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
+ ModuleFile &M = *I->second;
+ ASTSelectorLookupTrait Trait(*this, M);
+ unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
+ SelectorsLoaded[ID - 1] =
+ Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0);
+ if (DeserializationListener)
+ DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
+ }
+
+ return SelectorsLoaded[ID - 1];
+}
+
+Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) {
+ return DecodeSelector(ID);
+}
+
+uint32_t ASTReader::GetNumExternalSelectors() {
+ // ID 0 (the null selector) is considered an external selector.
+ return getTotalNumSelectors() + 1;
+}
+
+serialization::SelectorID
+ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
+ if (LocalID < NUM_PREDEF_SELECTOR_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
+ assert(I != M.SelectorRemap.end()
+ && "Invalid index into selector index remap");
+
+ return LocalID + I->second;
+}
+
+DeclarationName
+ASTReader::ReadDeclarationName(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case DeclarationName::Identifier:
+ return DeclarationName(GetIdentifierInfo(F, Record, Idx));
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclarationName(ReadSelector(F, Record, Idx));
+
+ case DeclarationName::CXXConstructorName:
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXDestructorName:
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXConversionFunctionName:
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXOperatorName:
+ return Context.DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Record[Idx++]);
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return Context.DeclarationNames.getCXXLiteralOperatorName(
+ GetIdentifierInfo(F, Record, Idx));
+
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ llvm_unreachable("Invalid NameKind!");
+}
+
+void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
+ DeclarationNameLoc &DNLoc,
+ DeclarationName Name,
+ const RecordData &Record, unsigned &Idx) {
+ switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ DNLoc.CXXOperatorName.BeginOpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ DNLoc.CXXOperatorName.EndOpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ DNLoc.CXXLiteralOperatorName.OpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ break;
+
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+}
+
+void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
+ DeclarationNameInfo &NameInfo,
+ const RecordData &Record, unsigned &Idx) {
+ NameInfo.setName(ReadDeclarationName(F, Record, Idx));
+ NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
+ DeclarationNameLoc DNLoc;
+ ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
+ NameInfo.setInfo(DNLoc);
+}
+
+void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
+ const RecordData &Record, unsigned &Idx) {
+ Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
+ unsigned NumTPLists = Record[Idx++];
+ Info.NumTemplParamLists = NumTPLists;
+ if (NumTPLists) {
+ Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
+ for (unsigned i=0; i != NumTPLists; ++i)
+ Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
+ }
+}
+
+TemplateName
+ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case TemplateName::Template:
+ return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
+
+ case TemplateName::OverloadedTemplate: {
+ unsigned size = Record[Idx++];
+ UnresolvedSet<8> Decls;
+ while (size--)
+ Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
+
+ return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
+ bool hasTemplKeyword = Record[Idx++];
+ TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
+ return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
+ }
+
+ case TemplateName::DependentTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
+ if (Record[Idx++]) // isIdentifier
+ return Context.getDependentTemplateName(NNS,
+ GetIdentifierInfo(F, Record,
+ Idx));
+ return Context.getDependentTemplateName(NNS,
+ (OverloadedOperatorKind)Record[Idx++]);
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ TemplateTemplateParmDecl *param
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
+ if (!param) return TemplateName();
+ TemplateName replacement = ReadTemplateName(F, Record, Idx);
+ return Context.getSubstTemplateTemplateParm(param, replacement);
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ TemplateTemplateParmDecl *Param
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
+ if (!Param)
+ return TemplateName();
+
+ TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx);
+ if (ArgPack.getKind() != TemplateArgument::Pack)
+ return TemplateName();
+
+ return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
+ }
+ }
+
+ llvm_unreachable("Unhandled template name kind!");
+}
+
+TemplateArgument
+ASTReader::ReadTemplateArgument(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
+ switch (Kind) {
+ case TemplateArgument::Null:
+ return TemplateArgument();
+ case TemplateArgument::Type:
+ return TemplateArgument(readType(F, Record, Idx));
+ case TemplateArgument::Declaration: {
+ ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
+ return TemplateArgument(D, readType(F, Record, Idx));
+ }
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
+ case TemplateArgument::Integral: {
+ llvm::APSInt Value = ReadAPSInt(Record, Idx);
+ QualType T = readType(F, Record, Idx);
+ return TemplateArgument(Context, Value, T);
+ }
+ case TemplateArgument::Template:
+ return TemplateArgument(ReadTemplateName(F, Record, Idx));
+ case TemplateArgument::TemplateExpansion: {
+ TemplateName Name = ReadTemplateName(F, Record, Idx);
+ Optional<unsigned> NumTemplateExpansions;
+ if (unsigned NumExpansions = Record[Idx++])
+ NumTemplateExpansions = NumExpansions - 1;
+ return TemplateArgument(Name, NumTemplateExpansions);
+ }
+ case TemplateArgument::Expression:
+ return TemplateArgument(ReadExpr(F));
+ case TemplateArgument::Pack: {
+ unsigned NumArgs = Record[Idx++];
+ TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I] = ReadTemplateArgument(F, Record, Idx);
+ return TemplateArgument(Args, NumArgs);
+ }
+ }
+
+ llvm_unreachable("Unhandled template argument kind!");
+}
+
+TemplateParameterList *
+ASTReader::ReadTemplateParameterList(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
+
+ unsigned NumParams = Record[Idx++];
+ SmallVector<NamedDecl *, 16> Params;
+ Params.reserve(NumParams);
+ while (NumParams--)
+ Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
+
+ TemplateParameterList* TemplateParams =
+ TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
+ Params.data(), Params.size(), RAngleLoc);
+ return TemplateParams;
+}
+
+void
+ASTReader::
+ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
+ ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned NumTemplateArgs = Record[Idx++];
+ TemplArgs.reserve(NumTemplateArgs);
+ while (NumTemplateArgs--)
+ TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx));
+}
+
+/// \brief Read a UnresolvedSet structure.
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned NumDecls = Record[Idx++];
+ Set.reserve(Context, NumDecls);
+ while (NumDecls--) {
+ DeclID ID = ReadDeclID(F, Record, Idx);
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ Set.addLazyDecl(Context, ID, AS);
+ }
+}
+
+CXXBaseSpecifier
+ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ bool isVirtual = static_cast<bool>(Record[Idx++]);
+ bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
+ AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
+ bool inheritConstructors = static_cast<bool>(Record[Idx++]);
+ TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo,
+ EllipsisLoc);
+ Result.setInheritConstructors(inheritConstructors);
+ return Result;
+}
+
+CXXCtorInitializer **
+ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned NumInitializers = Record[Idx++];
+ assert(NumInitializers && "wrote ctor initializers but have no inits");
+ auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
+ for (unsigned i = 0; i != NumInitializers; ++i) {
+ TypeSourceInfo *TInfo = nullptr;
+ bool IsBaseVirtual = false;
+ FieldDecl *Member = nullptr;
+ IndirectFieldDecl *IndirectMember = nullptr;
+
+ CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ switch (Type) {
+ case CTOR_INITIALIZER_BASE:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ IsBaseVirtual = Record[Idx++];
+ break;
+
+ case CTOR_INITIALIZER_DELEGATING:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ break;
+
+ case CTOR_INITIALIZER_MEMBER:
+ Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
+ break;
+
+ case CTOR_INITIALIZER_INDIRECT_MEMBER:
+ IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
+ break;
+ }
+
+ SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ Expr *Init = ReadExpr(F);
+ SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
+ bool IsWritten = Record[Idx++];
+ unsigned SourceOrderOrNumArrayIndices;
+ SmallVector<VarDecl *, 8> Indices;
+ if (IsWritten) {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ } else {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ Indices.reserve(SourceOrderOrNumArrayIndices);
+ for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
+ Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
+ }
+
+ CXXCtorInitializer *BOMInit;
+ if (Type == CTOR_INITIALIZER_BASE) {
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init,
+ RParenLoc, MemberOrEllipsisLoc);
+ } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc);
+ } else if (IsWritten) {
+ if (Member)
+ BOMInit = new (Context) CXXCtorInitializer(
+ Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc);
+ else
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+ } else {
+ if (IndirectMember) {
+ assert(Indices.empty() && "Indirect field improperly initialized");
+ BOMInit = new (Context)
+ CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+ } else {
+ BOMInit = CXXCtorInitializer::Create(
+ Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc,
+ Indices.data(), Indices.size());
+ }
+ }
+
+ if (IsWritten)
+ BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
+ CtorInitializers[i] = BOMInit;
+ }
+
+ return CtorInitializers;
+}
+
+NestedNameSpecifier *
+ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifier *NNS = nullptr, *Prev = nullptr;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, II);
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, NS);
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
+ if (!T)
+ return nullptr;
+
+ bool Template = Record[Idx++];
+ NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ // No associated value, and there can't be a prefix.
+ break;
+ }
+
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::SuperSpecifier(Context, RD);
+ break;
+ }
+ }
+ Prev = NNS;
+ }
+ return NNS;
+}
+
+NestedNameSpecifierLoc
+ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifierLocBuilder Builder;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ bool Template = Record[Idx++];
+ TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
+ if (!T)
+ return NestedNameSpecifierLoc();
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+
+ // FIXME: 'template' keyword location not saved anywhere, so we fake it.
+ Builder.Extend(Context,
+ Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
+ T->getTypeLoc(), ColonColonLoc);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ Builder.MakeGlobal(Context, ColonColonLoc);
+ break;
+ }
+
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd());
+ break;
+ }
+ }
+ }
+
+ return Builder.getWithLocInContext(Context);
+}
+
+SourceRange
+ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ SourceLocation beg = ReadSourceLocation(F, Record, Idx);
+ SourceLocation end = ReadSourceLocation(F, Record, Idx);
+ return SourceRange(beg, end);
+}
+
+/// \brief Read an integral value
+llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
+ unsigned BitWidth = Record[Idx++];
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+ llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
+ Idx += NumWords;
+ return Result;
+}
+
+/// \brief Read a signed integral value
+llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
+ bool isUnsigned = Record[Idx++];
+ return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
+}
+
+/// \brief Read a floating-point value
+llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record,
+ const llvm::fltSemantics &Sem,
+ unsigned &Idx) {
+ return llvm::APFloat(Sem, ReadAPInt(Record, Idx));
+}
+
+// \brief Read a string
+std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
+ unsigned Len = Record[Idx++];
+ std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
+ Idx += Len;
+ return Result;
+}
+
+std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ std::string Filename = ReadString(Record, Idx);
+ ResolveImportedPath(F, Filename);
+ return Filename;
+}
+
+VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
+ unsigned &Idx) {
+ unsigned Major = Record[Idx++];
+ unsigned Minor = Record[Idx++];
+ unsigned Subminor = Record[Idx++];
+ if (Minor == 0)
+ return VersionTuple(Major);
+ if (Subminor == 0)
+ return VersionTuple(Major, Minor - 1);
+ return VersionTuple(Major, Minor - 1, Subminor - 1);
+}
+
+CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
+ return CXXTemporary::Create(Context, Decl);
+}
+
+DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
+ return Diag(CurrentImportLoc, DiagID);
+}
+
+DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(Loc, DiagID);
+}
+
+/// \brief Retrieve the identifier table associated with the
+/// preprocessor.
+IdentifierTable &ASTReader::getIdentifierTable() {
+ return PP.getIdentifierTable();
+}
+
+/// \brief Record that the given ID maps to the given switch-case
+/// statement.
+void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
+ assert((*CurrSwitchCaseStmts)[ID] == nullptr &&
+ "Already have a SwitchCase with this ID");
+ (*CurrSwitchCaseStmts)[ID] = SC;
+}
+
+/// \brief Retrieve the switch-case statement with the given ID.
+SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) {
+ assert((*CurrSwitchCaseStmts)[ID] != nullptr && "No SwitchCase with this ID");
+ return (*CurrSwitchCaseStmts)[ID];
+}
+
+void ASTReader::ClearSwitchCaseIDs() {
+ CurrSwitchCaseStmts->clear();
+}
+
+void ASTReader::ReadComments() {
+ std::vector<RawComment *> Comments;
+ for (SmallVectorImpl<std::pair<BitstreamCursor,
+ serialization::ModuleFile *> >::iterator
+ I = CommentsCursors.begin(),
+ E = CommentsCursors.end();
+ I != E; ++I) {
+ Comments.clear();
+ BitstreamCursor &Cursor = I->first;
+ serialization::ModuleFile &F = *I->second;
+ SavedStreamPosition SavedPosition(Cursor);
+
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry Entry =
+ Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) {
+ case COMMENTS_RAW_COMMENT: {
+ unsigned Idx = 0;
+ SourceRange SR = ReadSourceRange(F, Record, Idx);
+ RawComment::CommentKind Kind =
+ (RawComment::CommentKind) Record[Idx++];
+ bool IsTrailingComment = Record[Idx++];
+ bool IsAlmostTrailingComment = Record[Idx++];
+ Comments.push_back(new (Context) RawComment(
+ SR, Kind, IsTrailingComment, IsAlmostTrailingComment,
+ Context.getLangOpts().CommentOpts.ParseAllComments));
+ break;
+ }
+ }
+ }
+ NextCursor:
+ Context.Comments.addDeserializedComments(Comments);
+ }
+}
+
+void ASTReader::getInputFiles(ModuleFile &F,
+ SmallVectorImpl<serialization::InputFile> &Files) {
+ for (unsigned I = 0, E = F.InputFilesLoaded.size(); I != E; ++I) {
+ unsigned ID = I+1;
+ Files.push_back(getInputFile(F, ID));
+ }
+}
+
+std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
+ // If we know the owning module, use it.
+ if (Module *M = D->getImportedOwningModule())
+ return M->getFullModuleName();
+
+ // Otherwise, use the name of the top-level module the decl is within.
+ if (ModuleFile *M = getOwningModuleFile(D))
+ return M->ModuleName;
+
+ // Not from a module.
+ return "";
+}
+
+void ASTReader::finishPendingActions() {
+ while (!PendingIdentifierInfos.empty() ||
+ !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
+ !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
+ !PendingUpdateRecords.empty()) {
+ // If any identifiers with corresponding top-level declarations have
+ // been loaded, load those declarations now.
+ typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
+ TopLevelDeclsMap;
+ TopLevelDeclsMap TopLevelDecls;
+
+ while (!PendingIdentifierInfos.empty()) {
+ IdentifierInfo *II = PendingIdentifierInfos.back().first;
+ SmallVector<uint32_t, 4> DeclIDs =
+ std::move(PendingIdentifierInfos.back().second);
+ PendingIdentifierInfos.pop_back();
+
+ SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
+ }
+
+ // For each decl chain that we wanted to complete while deserializing, mark
+ // it as "still needs to be completed".
+ for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) {
+ markIncompleteDeclChain(PendingIncompleteDeclChains[I]);
+ }
+ PendingIncompleteDeclChains.clear();
+
+ // Load pending declaration chains.
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
+ PendingDeclChainsKnown.erase(PendingDeclChains[I]);
+ loadPendingDeclChain(PendingDeclChains[I]);
+ }
+ assert(PendingDeclChainsKnown.empty());
+ PendingDeclChains.clear();
+
+ // Make the most recent of the top-level declarations visible.
+ for (TopLevelDeclsMap::iterator TLD = TopLevelDecls.begin(),
+ TLDEnd = TopLevelDecls.end(); TLD != TLDEnd; ++TLD) {
+ IdentifierInfo *II = TLD->first;
+ for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) {
+ pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II);
+ }
+ }
+
+ // Load any pending macro definitions.
+ for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
+ IdentifierInfo *II = PendingMacroIDs.begin()[I].first;
+ SmallVector<PendingMacroInfo, 2> GlobalIDs;
+ GlobalIDs.swap(PendingMacroIDs.begin()[I].second);
+ // Initialize the macro history from chained-PCHs ahead of module imports.
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ const PendingMacroInfo &Info = GlobalIDs[IDIdx];
+ if (Info.M->Kind != MK_ImplicitModule &&
+ Info.M->Kind != MK_ExplicitModule)
+ resolvePendingMacro(II, Info);
+ }
+ // Handle module imports.
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ const PendingMacroInfo &Info = GlobalIDs[IDIdx];
+ if (Info.M->Kind == MK_ImplicitModule ||
+ Info.M->Kind == MK_ExplicitModule)
+ resolvePendingMacro(II, Info);
+ }
+ }
+ PendingMacroIDs.clear();
+
+ // Wire up the DeclContexts for Decls that we delayed setting until
+ // recursive loading is completed.
+ while (!PendingDeclContextInfos.empty()) {
+ PendingDeclContextInfo Info = PendingDeclContextInfos.front();
+ PendingDeclContextInfos.pop_front();
+ DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC));
+ DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
+ Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
+ }
+
+ // Perform any pending declaration updates.
+ while (!PendingUpdateRecords.empty()) {
+ auto Update = PendingUpdateRecords.pop_back_val();
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+ loadDeclUpdateRecords(Update.first, Update.second);
+ }
+ }
+
+ // At this point, all update records for loaded decls are in place, so any
+ // fake class definitions should have become real.
+ assert(PendingFakeDefinitionData.empty() &&
+ "faked up a class definition but never saw the real one");
+
+ // If we deserialized any C++ or Objective-C class definitions, any
+ // Objective-C protocol definitions, or any redeclarable templates, make sure
+ // that all redeclarations point to the definitions. Note that this can only
+ // happen now, after the redeclaration chains have been fully wired.
+ for (Decl *D : PendingDefinitions) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->getTypeForDecl())) {
+ // Make sure that the TagType points at the definition.
+ const_cast<TagType*>(TagT)->decl = TD;
+ }
+
+ if (auto RD = dyn_cast<CXXRecordDecl>(D)) {
+ for (auto *R = getMostRecentExistingDecl(RD); R;
+ R = R->getPreviousDecl()) {
+ assert((R == D) ==
+ cast<CXXRecordDecl>(R)->isThisDeclarationADefinition() &&
+ "declaration thinks it's the definition but it isn't");
+ cast<CXXRecordDecl>(R)->DefinitionData = RD->DefinitionData;
+ }
+ }
+
+ continue;
+ }
+
+ if (auto ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ // Make sure that the ObjCInterfaceType points at the definition.
+ const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
+ ->Decl = ID;
+
+ for (auto *R = getMostRecentExistingDecl(ID); R; R = R->getPreviousDecl())
+ cast<ObjCInterfaceDecl>(R)->Data = ID->Data;
+
+ continue;
+ }
+
+ if (auto PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ for (auto *R = getMostRecentExistingDecl(PD); R; R = R->getPreviousDecl())
+ cast<ObjCProtocolDecl>(R)->Data = PD->Data;
+
+ continue;
+ }
+
+ auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
+ for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
+ cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
+ }
+ PendingDefinitions.clear();
+
+ // Load the bodies of any functions or methods we've encountered. We do
+ // this now (delayed) so that we can be sure that the declaration chains
+ // have been fully wired up.
+ // FIXME: There seems to be no point in delaying this, it does not depend
+ // on the redecl chains having been wired up.
+ for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
+ PBEnd = PendingBodies.end();
+ PB != PBEnd; ++PB) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
+ // FIXME: Check for =delete/=default?
+ // FIXME: Complain about ODR violations here?
+ if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ FD->setLazyBody(PB->second);
+ continue;
+ }
+
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
+ if (!getContext().getLangOpts().Modules || !MD->hasBody())
+ MD->setLazyBody(PB->second);
+ }
+ PendingBodies.clear();
+
+ // Do some cleanup.
+ for (auto *ND : PendingMergedDefinitionsToDeduplicate)
+ getContext().deduplicateMergedDefinitonsFor(ND);
+ PendingMergedDefinitionsToDeduplicate.clear();
+}
+
+void ASTReader::diagnoseOdrViolations() {
+ if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty())
+ return;
+
+ // Trigger the import of the full definition of each class that had any
+ // odr-merging problems, so we can produce better diagnostics for them.
+ // These updates may in turn find and diagnose some ODR failures, so take
+ // ownership of the set first.
+ auto OdrMergeFailures = std::move(PendingOdrMergeFailures);
+ PendingOdrMergeFailures.clear();
+ for (auto &Merge : OdrMergeFailures) {
+ Merge.first->buildLookup();
+ Merge.first->decls_begin();
+ Merge.first->bases_begin();
+ Merge.first->vbases_begin();
+ for (auto *RD : Merge.second) {
+ RD->decls_begin();
+ RD->bases_begin();
+ RD->vbases_begin();
+ }
+ }
+
+ // For each declaration from a merged context, check that the canonical
+ // definition of that context also contains a declaration of the same
+ // entity.
+ //
+ // Caution: this loop does things that might invalidate iterators into
+ // PendingOdrMergeChecks. Don't turn this into a range-based for loop!
+ while (!PendingOdrMergeChecks.empty()) {
+ NamedDecl *D = PendingOdrMergeChecks.pop_back_val();
+
+ // FIXME: Skip over implicit declarations for now. This matters for things
+ // like implicitly-declared special member functions. This isn't entirely
+ // correct; we can end up with multiple unmerged declarations of the same
+ // implicit entity.
+ if (D->isImplicit())
+ continue;
+
+ DeclContext *CanonDef = D->getDeclContext();
+
+ bool Found = false;
+ const Decl *DCanon = D->getCanonicalDecl();
+
+ for (auto RI : D->redecls()) {
+ if (RI->getLexicalDeclContext() == CanonDef) {
+ Found = true;
+ break;
+ }
+ }
+ if (Found)
+ continue;
+
+ llvm::SmallVector<const NamedDecl*, 4> Candidates;
+ DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
+ !Found && I != E; ++I) {
+ for (auto RI : (*I)->redecls()) {
+ if (RI->getLexicalDeclContext() == CanonDef) {
+ // This declaration is present in the canonical definition. If it's
+ // in the same redecl chain, it's the one we're looking for.
+ if (RI->getCanonicalDecl() == DCanon)
+ Found = true;
+ else
+ Candidates.push_back(cast<NamedDecl>(RI));
+ break;
+ }
+ }
+ }
+
+ if (!Found) {
+ // The AST doesn't like TagDecls becoming invalid after they've been
+ // completed. We only really need to mark FieldDecls as invalid here.
+ if (!isa<TagDecl>(D))
+ D->setInvalidDecl();
+
+ // Ensure we don't accidentally recursively enter deserialization while
+ // we're producing our diagnostic.
+ Deserializing RecursionGuard(this);
+
+ std::string CanonDefModule =
+ getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
+ Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
+ << D << getOwningModuleNameForDiagnostic(D)
+ << CanonDef << CanonDefModule.empty() << CanonDefModule;
+
+ if (Candidates.empty())
+ Diag(cast<Decl>(CanonDef)->getLocation(),
+ diag::note_module_odr_violation_no_possible_decls) << D;
+ else {
+ for (unsigned I = 0, N = Candidates.size(); I != N; ++I)
+ Diag(Candidates[I]->getLocation(),
+ diag::note_module_odr_violation_possible_decl)
+ << Candidates[I];
+ }
+
+ DiagnosedOdrMergeFailures.insert(CanonDef);
+ }
+ }
+
+ if (OdrMergeFailures.empty())
+ return;
+
+ // Ensure we don't accidentally recursively enter deserialization while
+ // we're producing our diagnostics.
+ Deserializing RecursionGuard(this);
+
+ // Issue any pending ODR-failure diagnostics.
+ for (auto &Merge : OdrMergeFailures) {
+ // If we've already pointed out a specific problem with this class, don't
+ // bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
+ continue;
+
+ bool Diagnosed = false;
+ for (auto *RD : Merge.second) {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (Merge.first != RD) {
+ // FIXME: Walk the definition, figure out what's different,
+ // and diagnose that.
+ if (!Diagnosed) {
+ std::string Module = getOwningModuleNameForDiagnostic(Merge.first);
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << Merge.first << Module.empty() << Module;
+ Diagnosed = true;
+ }
+
+ Diag(RD->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << getOwningModuleNameForDiagnostic(RD);
+ }
+ }
+
+ if (!Diagnosed) {
+ // All definitions are updates to the same declaration. This happens if a
+ // module instantiates the declaration of a class template specialization
+ // and two or more other modules instantiate its definition.
+ //
+ // FIXME: Indicate which modules had instantiations of this definition.
+ // FIXME: How can this even happen?
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_instantiations)
+ << Merge.first;
+ }
+ }
+}
+
+void ASTReader::FinishedDeserializing() {
+ assert(NumCurrentElementsDeserializing &&
+ "FinishedDeserializing not paired with StartedDeserializing");
+ if (NumCurrentElementsDeserializing == 1) {
+ // We decrease NumCurrentElementsDeserializing only after pending actions
+ // are finished, to avoid recursively re-calling finishPendingActions().
+ finishPendingActions();
+ }
+ --NumCurrentElementsDeserializing;
+
+ if (NumCurrentElementsDeserializing == 0) {
+ // Propagate exception specification updates along redeclaration chains.
+ while (!PendingExceptionSpecUpdates.empty()) {
+ auto Updates = std::move(PendingExceptionSpecUpdates);
+ PendingExceptionSpecUpdates.clear();
+ for (auto Update : Updates) {
+ auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
+ SemaObj->UpdateExceptionSpec(Update.second,
+ FPT->getExtProtoInfo().ExceptionSpec);
+ }
+ }
+
+ diagnoseOdrViolations();
+
+ // We are not in recursive loading, so it's safe to pass the "interesting"
+ // decls to the consumer.
+ if (Consumer)
+ PassInterestingDeclsToConsumer();
+ }
+}
+
+void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ // Remove any fake results before adding any real ones.
+ auto It = PendingFakeLookupResults.find(II);
+ if (It != PendingFakeLookupResults.end()) {
+ for (auto *ND : PendingFakeLookupResults[II])
+ SemaObj->IdResolver.RemoveDecl(ND);
+ // FIXME: this works around module+PCH performance issue.
+ // Rather than erase the result from the map, which is O(n), just clear
+ // the vector of NamedDecls.
+ It->second.clear();
+ }
+ }
+
+ if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
+ SemaObj->TUScope->AddDecl(D);
+ } else if (SemaObj->TUScope) {
+ // Adding the decl to IdResolver may have failed because it was already in
+ // (even though it was not added in scope). If it is already in, make sure
+ // it gets in the scope as well.
+ if (std::find(SemaObj->IdResolver.begin(Name),
+ SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end())
+ SemaObj->TUScope->AddDecl(D);
+ }
+}
+
+ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot,
+ bool DisableValidation, bool AllowASTWithCompilerErrors,
+ bool AllowConfigurationMismatch, bool ValidateSystemInputs,
+ bool UseGlobalIndex)
+ : Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr),
+ OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()),
+ FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
+ SemaObj(nullptr), PP(PP), Context(Context), Consumer(nullptr),
+ ModuleMgr(PP.getFileManager()), isysroot(isysroot),
+ DisableValidation(DisableValidation),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ AllowConfigurationMismatch(AllowConfigurationMismatch),
+ ValidateSystemInputs(ValidateSystemInputs),
+ UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
+ CurrSwitchCaseStmts(&SwitchCaseStmts),
+ NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0),
+ TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0),
+ NumIdentifierLookups(0), NumIdentifierLookupHits(0), NumSelectorsRead(0),
+ NumMethodPoolEntriesRead(0), NumMethodPoolLookups(0),
+ NumMethodPoolHits(0), NumMethodPoolTableLookups(0),
+ NumMethodPoolTableHits(0), TotalNumMethodPoolEntries(0),
+ NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
+ NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
+ TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
+ PassingDeclsToConsumer(false), ReadingKind(Read_None) {
+ SourceMgr.setExternalSLocEntrySource(this);
+}
+
+ASTReader::~ASTReader() {
+ if (OwnsDeserializationListener)
+ delete DeserializationListener;
+
+ for (DeclContextVisibleUpdatesPending::iterator
+ I = PendingVisibleUpdates.begin(),
+ E = PendingVisibleUpdates.end();
+ I != E; ++I) {
+ for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
+ F = I->second.end();
+ J != F; ++J)
+ delete J->first;
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
new file mode 100644
index 0000000..02273ed
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -0,0 +1,3875 @@
+//===--- ASTReaderDecl.cpp - Decl Deserialization ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ASTReader::ReadDeclRecord method, which is the
+// entrypoint for loading a decl.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTReader.h"
+#include "ASTCommon.h"
+#include "ASTReaderInternals.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/Support/SaveAndRestore.h"
+using namespace clang;
+using namespace clang::serialization;
+
+//===----------------------------------------------------------------------===//
+// Declaration deserialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
+ ASTReader &Reader;
+ ModuleFile &F;
+ const DeclID ThisDeclID;
+ const unsigned RawLocation;
+ typedef ASTReader::RecordData RecordData;
+ const RecordData &Record;
+ unsigned &Idx;
+ TypeID TypeIDForTypeDecl;
+ unsigned AnonymousDeclNumber;
+ GlobalDeclID NamedDeclForTagDecl;
+ IdentifierInfo *TypedefNameForLinkage;
+
+ bool HasPendingBody;
+
+ uint64_t GetCurrentCursorOffset();
+
+ SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
+ return Reader.ReadSourceLocation(F, R, I);
+ }
+
+ SourceRange ReadSourceRange(const RecordData &R, unsigned &I) {
+ return Reader.ReadSourceRange(F, R, I);
+ }
+
+ TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) {
+ return Reader.GetTypeSourceInfo(F, R, I);
+ }
+
+ serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclID(F, R, I);
+ }
+
+ void ReadDeclIDList(SmallVectorImpl<DeclID> &IDs) {
+ for (unsigned I = 0, Size = Record[Idx++]; I != Size; ++I)
+ IDs.push_back(ReadDeclID(Record, Idx));
+ }
+
+ Decl *ReadDecl(const RecordData &R, unsigned &I) {
+ return Reader.ReadDecl(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclAs<T>(F, R, I);
+ }
+
+ void ReadQualifierInfo(QualifierInfo &Info,
+ const RecordData &R, unsigned &I) {
+ Reader.ReadQualifierInfo(F, Info, R, I);
+ }
+
+ void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name,
+ const RecordData &R, unsigned &I) {
+ Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I);
+ }
+
+ void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo,
+ const RecordData &R, unsigned &I) {
+ Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
+ }
+
+ serialization::SubmoduleID readSubmoduleID(const RecordData &R,
+ unsigned &I) {
+ if (I >= R.size())
+ return 0;
+
+ return Reader.getGlobalSubmoduleID(F, R[I++]);
+ }
+
+ Module *readModule(const RecordData &R, unsigned &I) {
+ return Reader.getSubmodule(readSubmoduleID(R, I));
+ }
+
+ void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
+ void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
+ const RecordData &R, unsigned &I);
+ void MergeDefinitionData(CXXRecordDecl *D,
+ struct CXXRecordDecl::DefinitionData &&NewDD);
+
+ static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC,
+ unsigned Index);
+ static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC,
+ unsigned Index, NamedDecl *D);
+
+ /// \brief RAII class used to capture the first ID within a redeclaration
+ /// chain and to introduce it into the list of pending redeclaration chains
+ /// on destruction.
+ class RedeclarableResult {
+ ASTReader &Reader;
+ GlobalDeclID FirstID;
+ Decl *MergeWith;
+ mutable bool Owning;
+ Decl::Kind DeclKind;
+
+ void operator=(RedeclarableResult &) = delete;
+
+ public:
+ RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID,
+ Decl *MergeWith, Decl::Kind DeclKind)
+ : Reader(Reader), FirstID(FirstID), MergeWith(MergeWith),
+ Owning(true), DeclKind(DeclKind) {}
+
+ RedeclarableResult(RedeclarableResult &&Other)
+ : Reader(Other.Reader), FirstID(Other.FirstID),
+ MergeWith(Other.MergeWith), Owning(Other.Owning),
+ DeclKind(Other.DeclKind) {
+ Other.Owning = false;
+ }
+
+ ~RedeclarableResult() {
+ if (FirstID && Owning && isRedeclarableDeclKind(DeclKind)) {
+ auto Canon = Reader.GetDecl(FirstID)->getCanonicalDecl();
+ if (Reader.PendingDeclChainsKnown.insert(Canon).second)
+ Reader.PendingDeclChains.push_back(Canon);
+ }
+ }
+
+ /// \brief Retrieve the first ID.
+ GlobalDeclID getFirstID() const { return FirstID; }
+
+ /// \brief Get a known declaration that this should be merged with, if
+ /// any.
+ Decl *getKnownMergeTarget() const { return MergeWith; }
+ };
+
+ /// \brief Class used to capture the result of searching for an existing
+ /// declaration of a specific kind and name, along with the ability
+ /// to update the place where this result was found (the declaration
+ /// chain hanging off an identifier or the DeclContext we searched in)
+ /// if requested.
+ class FindExistingResult {
+ ASTReader &Reader;
+ NamedDecl *New;
+ NamedDecl *Existing;
+ mutable bool AddResult;
+
+ unsigned AnonymousDeclNumber;
+ IdentifierInfo *TypedefNameForLinkage;
+
+ void operator=(FindExistingResult&) = delete;
+
+ public:
+ FindExistingResult(ASTReader &Reader)
+ : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false),
+ AnonymousDeclNumber(0), TypedefNameForLinkage(0) {}
+
+ FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing,
+ unsigned AnonymousDeclNumber,
+ IdentifierInfo *TypedefNameForLinkage)
+ : Reader(Reader), New(New), Existing(Existing), AddResult(true),
+ AnonymousDeclNumber(AnonymousDeclNumber),
+ TypedefNameForLinkage(TypedefNameForLinkage) {}
+
+ FindExistingResult(const FindExistingResult &Other)
+ : Reader(Other.Reader), New(Other.New), Existing(Other.Existing),
+ AddResult(Other.AddResult),
+ AnonymousDeclNumber(Other.AnonymousDeclNumber),
+ TypedefNameForLinkage(Other.TypedefNameForLinkage) {
+ Other.AddResult = false;
+ }
+
+ ~FindExistingResult();
+
+ /// \brief Suppress the addition of this result into the known set of
+ /// names.
+ void suppress() { AddResult = false; }
+
+ operator NamedDecl*() const { return Existing; }
+
+ template<typename T>
+ operator T*() const { return dyn_cast_or_null<T>(Existing); }
+ };
+
+ static DeclContext *getPrimaryContextForMerging(ASTReader &Reader,
+ DeclContext *DC);
+ FindExistingResult findExisting(NamedDecl *D);
+
+ public:
+ ASTDeclReader(ASTReader &Reader, ModuleFile &F, DeclID thisDeclID,
+ unsigned RawLocation, const RecordData &Record, unsigned &Idx)
+ : Reader(Reader), F(F), ThisDeclID(thisDeclID),
+ RawLocation(RawLocation), Record(Record), Idx(Idx),
+ TypeIDForTypeDecl(0), NamedDeclForTagDecl(0),
+ TypedefNameForLinkage(nullptr), HasPendingBody(false) {}
+
+ template <typename DeclT>
+ static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
+ static Decl *getMostRecentDeclImpl(...);
+ static Decl *getMostRecentDecl(Decl *D);
+
+ template <typename DeclT>
+ static void attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<DeclT> *D, Decl *Previous,
+ Decl *Canon);
+ static void attachPreviousDeclImpl(ASTReader &Reader, ...);
+ static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
+ Decl *Canon);
+
+ template <typename DeclT>
+ static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
+ static void attachLatestDeclImpl(...);
+ static void attachLatestDecl(Decl *D, Decl *latest);
+
+ template <typename DeclT>
+ static void markIncompleteDeclChainImpl(Redeclarable<DeclT> *D);
+ static void markIncompleteDeclChainImpl(...);
+
+ /// \brief Determine whether this declaration has a pending body.
+ bool hasPendingBody() const { return HasPendingBody; }
+
+ void Visit(Decl *D);
+
+ void UpdateDecl(Decl *D, ModuleFile &ModuleFile,
+ const RecordData &Record);
+
+ static void setNextObjCCategory(ObjCCategoryDecl *Cat,
+ ObjCCategoryDecl *Next) {
+ Cat->NextClassCategory = Next;
+ }
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+ void VisitNamedDecl(NamedDecl *ND);
+ void VisitLabelDecl(LabelDecl *LD);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitTypeDecl(TypeDecl *TD);
+ RedeclarableResult VisitTypedefNameDecl(TypedefNameDecl *TD);
+ void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitTypeAliasDecl(TypeAliasDecl *TD);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ RedeclarableResult VisitTagDecl(TagDecl *TD);
+ void VisitEnumDecl(EnumDecl *ED);
+ RedeclarableResult VisitRecordDeclImpl(RecordDecl *RD);
+ void VisitRecordDecl(RecordDecl *RD) { VisitRecordDeclImpl(RD); }
+ RedeclarableResult VisitCXXRecordDeclImpl(CXXRecordDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D) { VisitCXXRecordDeclImpl(D); }
+ RedeclarableResult VisitClassTemplateSpecializationDeclImpl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDeclImpl(D);
+ }
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D);
+ RedeclarableResult
+ VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDeclImpl(D);
+ }
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ void VisitValueDecl(ValueDecl *VD);
+ void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ void VisitDeclaratorDecl(DeclaratorDecl *DD);
+ void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
+ void VisitFieldDecl(FieldDecl *FD);
+ void VisitMSPropertyDecl(MSPropertyDecl *FD);
+ void VisitIndirectFieldDecl(IndirectFieldDecl *FD);
+ RedeclarableResult VisitVarDeclImpl(VarDecl *D);
+ void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); }
+ void VisitImplicitParamDecl(ImplicitParamDecl *PD);
+ void VisitParmVarDecl(ParmVarDecl *PD);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ DeclID VisitTemplateDecl(TemplateDecl *D);
+ RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
+ void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitImportDecl(ImportDecl *D);
+ void VisitAccessSpecDecl(AccessSpecDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
+ void VisitBlockDecl(BlockDecl *BD);
+ void VisitCapturedDecl(CapturedDecl *CD);
+ void VisitEmptyDecl(EmptyDecl *D);
+
+ std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+
+ template<typename T>
+ RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
+
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
+
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
+
+ template<typename T>
+ void mergeMergeable(Mergeable<T> *D);
+
+ void mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID);
+
+ // FIXME: Reorder according to DeclNodes.td?
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+ };
+}
+
+uint64_t ASTDeclReader::GetCurrentCursorOffset() {
+ return F.DeclsCursor.GetCurrentBitNo() + F.GlobalBitOffset;
+}
+
+void ASTDeclReader::Visit(Decl *D) {
+ DeclVisitor<ASTDeclReader, void>::Visit(D);
+
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (DD->DeclInfo) {
+ DeclaratorDecl::ExtInfo *Info =
+ DD->DeclInfo.get<DeclaratorDecl::ExtInfo *>();
+ Info->TInfo =
+ GetTypeSourceInfo(Record, Idx);
+ }
+ else {
+ DD->DeclInfo = GetTypeSourceInfo(Record, Idx);
+ }
+ }
+
+ if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
+ // We have a fully initialized TypeDecl. Read its type now.
+ TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
+
+ // If this is a tag declaration with a typedef name for linkage, it's safe
+ // to load that typedef now.
+ if (NamedDeclForTagDecl)
+ cast<TagDecl>(D)->NamedDeclOrQualifier =
+ cast<NamedDecl>(Reader.GetDecl(NamedDeclForTagDecl));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ // if we have a fully initialized TypeDecl, we can safely read its type now.
+ ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // FunctionDecl's body was written last after all other Stmts/Exprs.
+ // We only read it if FD doesn't already have a body (e.g., from another
+ // module).
+ // FIXME: Can we diagnose ODR violations somehow?
+ if (Record[Idx++]) {
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ CD->NumCtorInitializers = Record[Idx++];
+ if (CD->NumCtorInitializers)
+ CD->CtorInitializers =
+ Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
+ }
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ }
+ }
+}
+
+void ASTDeclReader::VisitDecl(Decl *D) {
+ if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
+ isa<ParmVarDecl>(D)) {
+ // We don't want to deserialize the DeclContext of a template
+ // parameter or of a parameter of a function template immediately. These
+ // entities might be used in the formulation of its DeclContext (for
+ // example, a function parameter can be used in decltype() in trailing
+ // return type of the function). Use the translation unit DeclContext as a
+ // placeholder.
+ GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ Reader.addPendingDeclContextInfo(D,
+ SemaDCIDForTemplateParmDecl,
+ LexicalDCIDForTemplateParmDecl);
+ D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
+ } else {
+ DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
+ // Avoid calling setLexicalDeclContext() directly because it uses
+ // Decl::getASTContext() internally which is unsafe during derialization.
+ D->setDeclContextsImpl(MergedSemaDC ? MergedSemaDC : SemaDC, LexicalDC,
+ Reader.getContext());
+ }
+ D->setLocation(Reader.ReadSourceLocation(F, RawLocation));
+ D->setInvalidDecl(Record[Idx++]);
+ if (Record[Idx++]) { // hasAttrs
+ AttrVec Attrs;
+ Reader.ReadAttributes(F, Attrs, Record, Idx);
+ // Avoid calling setAttrs() directly because it uses Decl::getASTContext()
+ // internally which is unsafe during derialization.
+ D->setAttrsImpl(Attrs, Reader.getContext());
+ }
+ D->setImplicit(Record[Idx++]);
+ D->Used = Record[Idx++];
+ D->setReferenced(Record[Idx++]);
+ D->setTopLevelDeclInObjCContainer(Record[Idx++]);
+ D->setAccess((AccessSpecifier)Record[Idx++]);
+ D->FromASTFile = true;
+ D->setModulePrivate(Record[Idx++]);
+ D->Hidden = D->isModulePrivate();
+
+ // Determine whether this declaration is part of a (sub)module. If so, it
+ // may not yet be visible.
+ if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+ // Store the owning submodule ID in the declaration.
+ D->setOwningModuleID(SubmoduleID);
+
+ if (D->Hidden) {
+ // Module-private declarations are never visible, so there is no work to do.
+ } else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ // If local visibility is being tracked, this declaration will become
+ // hidden and visible as the owning module does. Inform Sema that this
+ // declaration might not be visible.
+ D->Hidden = true;
+ } else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
+ if (Owner->NameVisibility != Module::AllVisible) {
+ // The owning module is not visible. Mark this declaration as hidden.
+ D->Hidden = true;
+
+ // Note that this declaration was hidden because its owning module is
+ // not yet visible.
+ Reader.HiddenNamesMap[Owner].push_back(D);
+ }
+ }
+ }
+}
+
+void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ llvm_unreachable("Translation units are not serialized");
+}
+
+void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
+ VisitDecl(ND);
+ ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx));
+ AnonymousDeclNumber = Record[Idx++];
+}
+
+void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
+ VisitNamedDecl(TD);
+ TD->setLocStart(ReadSourceLocation(Record, Idx));
+ // Delay type reading until after we have fully initialized the decl.
+ TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
+ VisitTypeDecl(TD);
+ TypeSourceInfo *TInfo = GetTypeSourceInfo(Record, Idx);
+ if (Record[Idx++]) { // isModed
+ QualType modedT = Reader.readType(F, Record, Idx);
+ TD->setModedTypeSourceInfo(TInfo, modedT);
+ } else
+ TD->setTypeSourceInfo(TInfo);
+ return Redecl;
+}
+
+void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ RedeclarableResult Redecl = VisitTypedefNameDecl(TD);
+ mergeRedeclarable(TD, Redecl);
+}
+
+void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
+ RedeclarableResult Redecl = VisitTypedefNameDecl(TD);
+ if (auto *Template = ReadDeclAs<TypeAliasTemplateDecl>(Record, Idx))
+ // Merged when we merge the template.
+ TD->setDescribedAliasTemplate(Template);
+ else
+ mergeRedeclarable(TD, Redecl);
+}
+
+ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
+ VisitTypeDecl(TD);
+
+ TD->IdentifierNamespace = Record[Idx++];
+ TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
+ if (!isa<CXXRecordDecl>(TD))
+ TD->setCompleteDefinition(Record[Idx++]);
+ TD->setEmbeddedInDeclarator(Record[Idx++]);
+ TD->setFreeStanding(Record[Idx++]);
+ TD->setCompleteDefinitionRequired(Record[Idx++]);
+ TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
+
+ switch (Record[Idx++]) {
+ case 0:
+ break;
+ case 1: { // ExtInfo
+ TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
+ ReadQualifierInfo(*Info, Record, Idx);
+ TD->NamedDeclOrQualifier = Info;
+ break;
+ }
+ case 2: // TypedefNameForAnonDecl
+ NamedDeclForTagDecl = ReadDeclID(Record, Idx);
+ TypedefNameForLinkage = Reader.GetIdentifierInfo(F, Record, Idx);
+ break;
+ case 3: // DeclaratorForAnonDecl
+ NamedDeclForTagDecl = ReadDeclID(Record, Idx);
+ break;
+ default:
+ llvm_unreachable("unexpected tag info kind");
+ }
+
+ if (!isa<CXXRecordDecl>(TD))
+ mergeRedeclarable(TD, Redecl);
+ return Redecl;
+}
+
+void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
+ VisitTagDecl(ED);
+ if (TypeSourceInfo *TI = Reader.GetTypeSourceInfo(F, Record, Idx))
+ ED->setIntegerTypeSourceInfo(TI);
+ else
+ ED->setIntegerType(Reader.readType(F, Record, Idx));
+ ED->setPromotionType(Reader.readType(F, Record, Idx));
+ ED->setNumPositiveBits(Record[Idx++]);
+ ED->setNumNegativeBits(Record[Idx++]);
+ ED->IsScoped = Record[Idx++];
+ ED->IsScopedUsingClassTag = Record[Idx++];
+ ED->IsFixed = Record[Idx++];
+
+ // If this is a definition subject to the ODR, and we already have a
+ // definition, merge this one into it.
+ if (ED->IsCompleteDefinition &&
+ Reader.getContext().getLangOpts().Modules &&
+ Reader.getContext().getLangOpts().CPlusPlus) {
+ if (EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]) {
+ Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef));
+ ED->IsCompleteDefinition = false;
+ } else {
+ OldDef = ED;
+ }
+ }
+
+ if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+ ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK);
+ ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ }
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
+ RedeclarableResult Redecl = VisitTagDecl(RD);
+ RD->setHasFlexibleArrayMember(Record[Idx++]);
+ RD->setAnonymousStructOrUnion(Record[Idx++]);
+ RD->setHasObjectMember(Record[Idx++]);
+ RD->setHasVolatileMember(Record[Idx++]);
+ return Redecl;
+}
+
+void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
+ VisitNamedDecl(VD);
+ VD->setType(Reader.readType(F, Record, Idx));
+}
+
+void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
+ VisitValueDecl(ECD);
+ if (Record[Idx++])
+ ECD->setInitExpr(Reader.ReadExpr(F));
+ ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
+ mergeMergeable(ECD);
+}
+
+void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
+ VisitValueDecl(DD);
+ DD->setInnerLocStart(ReadSourceLocation(Record, Idx));
+ if (Record[Idx++]) { // hasExtInfo
+ DeclaratorDecl::ExtInfo *Info
+ = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
+ ReadQualifierInfo(*Info, Record, Idx);
+ DD->DeclInfo = Info;
+ }
+}
+
+void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
+ RedeclarableResult Redecl = VisitRedeclarable(FD);
+ VisitDeclaratorDecl(FD);
+
+ ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
+ FD->IdentifierNamespace = Record[Idx++];
+
+ // FunctionDecl's body is handled last at ASTDeclReader::Visit,
+ // after everything else is read.
+
+ FD->SClass = (StorageClass)Record[Idx++];
+ FD->IsInline = Record[Idx++];
+ FD->IsInlineSpecified = Record[Idx++];
+ FD->IsVirtualAsWritten = Record[Idx++];
+ FD->IsPure = Record[Idx++];
+ FD->HasInheritedPrototype = Record[Idx++];
+ FD->HasWrittenPrototype = Record[Idx++];
+ FD->IsDeleted = Record[Idx++];
+ FD->IsTrivial = Record[Idx++];
+ FD->IsDefaulted = Record[Idx++];
+ FD->IsExplicitlyDefaulted = Record[Idx++];
+ FD->HasImplicitReturnZero = Record[Idx++];
+ FD->IsConstexpr = Record[Idx++];
+ FD->HasSkippedBody = Record[Idx++];
+ FD->IsLateTemplateParsed = Record[Idx++];
+ FD->setCachedLinkage(Linkage(Record[Idx++]));
+ FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
+
+ switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
+ case FunctionDecl::TK_NonTemplate:
+ mergeRedeclarable(FD, Redecl);
+ break;
+ case FunctionDecl::TK_FunctionTemplate:
+ // Merged when we merge the template.
+ FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
+ Idx));
+ break;
+ case FunctionDecl::TK_MemberSpecialization: {
+ FunctionDecl *InstFD = ReadDeclAs<FunctionDecl>(Record, Idx);
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+ FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
+ FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ mergeRedeclarable(FD, Redecl);
+ break;
+ }
+ case FunctionDecl::TK_FunctionTemplateSpecialization: {
+ FunctionTemplateDecl *Template = ReadDeclAs<FunctionTemplateDecl>(Record,
+ Idx);
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+
+ // Template arguments.
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+
+ // Template args as written.
+ SmallVector<TemplateArgumentLoc, 8> TemplArgLocs;
+ SourceLocation LAngleLoc, RAngleLoc;
+ bool HasTemplateArgumentsAsWritten = Record[Idx++];
+ if (HasTemplateArgumentsAsWritten) {
+ unsigned NumTemplateArgLocs = Record[Idx++];
+ TemplArgLocs.reserve(NumTemplateArgLocs);
+ for (unsigned i=0; i != NumTemplateArgLocs; ++i)
+ TemplArgLocs.push_back(
+ Reader.ReadTemplateArgumentLoc(F, Record, Idx));
+
+ LAngleLoc = ReadSourceLocation(Record, Idx);
+ RAngleLoc = ReadSourceLocation(Record, Idx);
+ }
+
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+
+ ASTContext &C = Reader.getContext();
+ TemplateArgumentList *TemplArgList
+ = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size());
+ TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
+ for (unsigned i=0, e = TemplArgLocs.size(); i != e; ++i)
+ TemplArgsInfo.addArgument(TemplArgLocs[i]);
+ FunctionTemplateSpecializationInfo *FTInfo
+ = FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK,
+ TemplArgList,
+ HasTemplateArgumentsAsWritten ? &TemplArgsInfo
+ : nullptr,
+ POI);
+ FD->TemplateOrSpecialization = FTInfo;
+
+ if (FD->isCanonicalDecl()) { // if canonical add to template's set.
+ // The template that contains the specializations set. It's not safe to
+ // use getCanonicalDecl on Template since it may still be initializing.
+ FunctionTemplateDecl *CanonTemplate
+ = ReadDeclAs<FunctionTemplateDecl>(Record, Idx);
+ // Get the InsertPos by FindNodeOrInsertPos() instead of calling
+ // InsertNode(FTInfo) directly to avoid the getASTContext() call in
+ // FunctionTemplateSpecializationInfo's Profile().
+ // We avoid getASTContext because a decl in the parent hierarchy may
+ // be initializing.
+ llvm::FoldingSetNodeID ID;
+ FunctionTemplateSpecializationInfo::Profile(ID, TemplArgs, C);
+ void *InsertPos = nullptr;
+ FunctionTemplateDecl::Common *CommonPtr = CanonTemplate->getCommonPtr();
+ CommonPtr->Specializations.FindNodeOrInsertPos(ID, InsertPos);
+ if (InsertPos)
+ CommonPtr->Specializations.InsertNode(FTInfo, InsertPos);
+ else {
+ assert(Reader.getContext().getLangOpts().Modules &&
+ "already deserialized this template specialization");
+ // FIXME: This specialization is a redeclaration of one from another
+ // module. Merge it.
+ }
+ }
+ break;
+ }
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+ // Templates.
+ UnresolvedSet<8> TemplDecls;
+ unsigned NumTemplates = Record[Idx++];
+ while (NumTemplates--)
+ TemplDecls.addDecl(ReadDeclAs<NamedDecl>(Record, Idx));
+
+ // Templates args.
+ TemplateArgumentListInfo TemplArgs;
+ unsigned NumArgs = Record[Idx++];
+ while (NumArgs--)
+ TemplArgs.addArgument(Reader.ReadTemplateArgumentLoc(F, Record, Idx));
+ TemplArgs.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TemplArgs.setRAngleLoc(ReadSourceLocation(Record, Idx));
+
+ FD->setDependentTemplateSpecialization(Reader.getContext(),
+ TemplDecls, TemplArgs);
+
+ // FIXME: Merging.
+ break;
+ }
+ }
+
+ // Read in the parameters.
+ unsigned NumParams = Record[Idx++];
+ SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ FD->setParams(Reader.getContext(), Params);
+}
+
+void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ VisitNamedDecl(MD);
+ if (Record[Idx++]) {
+ // Load the body on-demand. Most clients won't care, because method
+ // definitions rarely show up in headers.
+ Reader.PendingBodies[MD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ }
+ MD->setInstanceMethod(Record[Idx++]);
+ MD->setVariadic(Record[Idx++]);
+ MD->setPropertyAccessor(Record[Idx++]);
+ MD->setDefined(Record[Idx++]);
+ MD->IsOverriding = Record[Idx++];
+ MD->HasSkippedBody = Record[Idx++];
+
+ MD->IsRedeclaration = Record[Idx++];
+ MD->HasRedeclaration = Record[Idx++];
+ if (MD->HasRedeclaration)
+ Reader.getContext().setObjCMethodRedeclaration(MD,
+ ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+
+ MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
+ MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->SetRelatedResultType(Record[Idx++]);
+ MD->setReturnType(Reader.readType(F, Record, Idx));
+ MD->setReturnTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ MD->DeclEndLoc = ReadSourceLocation(Record, Idx);
+ unsigned NumParams = Record[Idx++];
+ SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+
+ MD->SelLocsKind = Record[Idx++];
+ unsigned NumStoredSelLocs = Record[Idx++];
+ SmallVector<SourceLocation, 16> SelLocs;
+ SelLocs.reserve(NumStoredSelLocs);
+ for (unsigned i = 0; i != NumStoredSelLocs; ++i)
+ SelLocs.push_back(ReadSourceLocation(Record, Idx));
+
+ MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
+}
+
+void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
+ VisitNamedDecl(CD);
+ CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
+ CD->setAtEndRange(ReadSourceRange(Record, Idx));
+}
+
+void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
+ RedeclarableResult Redecl = VisitRedeclarable(ID);
+ VisitObjCContainerDecl(ID);
+ TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
+ mergeRedeclarable(ID, Redecl);
+
+ if (Record[Idx++]) {
+ // Read the definition.
+ ID->allocateDefinitionData();
+
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ ID->getCanonicalDecl()->Data = ID->Data;
+
+ ObjCInterfaceDecl::DefinitionData &Data = ID->data();
+
+ // Read the superclass.
+ Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+ Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
+
+ Data.EndLoc = ReadSourceLocation(Record, Idx);
+ Data.HasDesignatedInitializers = Record[Idx++];
+
+ // Read the directly referenced protocols and their SourceLocations.
+ unsigned NumProtocols = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> Protocols;
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
+ Reader.getContext());
+
+ // Read the transitive closure of protocols referenced by this class.
+ NumProtocols = Record[Idx++];
+ Protocols.clear();
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ ID->data().AllReferencedProtocols.set(Protocols.data(), NumProtocols,
+ Reader.getContext());
+
+ // We will rebuild this list lazily.
+ ID->setIvarList(nullptr);
+
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(ID);
+
+ // Note that we've loaded this Objective-C class.
+ Reader.ObjCClassesLoaded.push_back(ID);
+ } else {
+ ID->Data = ID->getCanonicalDecl()->Data;
+ }
+}
+
+void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
+ VisitFieldDecl(IVD);
+ IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]);
+ // This field will be built lazily.
+ IVD->setNextIvar(nullptr);
+ bool synth = Record[Idx++];
+ IVD->setSynthesize(synth);
+}
+
+void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ RedeclarableResult Redecl = VisitRedeclarable(PD);
+ VisitObjCContainerDecl(PD);
+ mergeRedeclarable(PD, Redecl);
+
+ if (Record[Idx++]) {
+ // Read the definition.
+ PD->allocateDefinitionData();
+
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ PD->getCanonicalDecl()->Data = PD->Data;
+
+ unsigned NumProtoRefs = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ Reader.getContext());
+
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(PD);
+ } else {
+ PD->Data = PD->getCanonicalDecl()->Data;
+ }
+}
+
+void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
+ VisitFieldDecl(FD);
+}
+
+void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
+ VisitObjCContainerDecl(CD);
+ CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx));
+ CD->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
+ CD->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
+
+ // Note that this category has been deserialized. We do this before
+ // deserializing the interface declaration, so that it will consider this
+ /// category.
+ Reader.CategoriesDeserialized.insert(CD);
+
+ CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+ unsigned NumProtoRefs = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ Reader.getContext());
+}
+
+void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
+ VisitNamedDecl(CAD);
+ CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+}
+
+void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ D->setAtLoc(ReadSourceLocation(Record, Idx));
+ D->setLParenLoc(ReadSourceLocation(Record, Idx));
+ D->setType(GetTypeSourceInfo(Record, Idx));
+ // FIXME: stable encoding
+ D->setPropertyAttributes(
+ (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);
+ D->setPropertyAttributesAsWritten(
+ (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);
+ // FIXME: stable encoding
+ D->setPropertyImplementation(
+ (ObjCPropertyDecl::PropertyControl)Record[Idx++]);
+ D->setGetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector());
+ D->setSetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector());
+ D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+ D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+ D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
+}
+
+void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitObjCContainerDecl(D);
+ D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+}
+
+void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setIdentifier(Reader.GetIdentifierInfo(F, Record, Idx));
+ D->CategoryNameLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+ D->SuperLoc = ReadSourceLocation(Record, Idx);
+ D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
+ D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
+ D->setHasNonZeroConstructors(Record[Idx++]);
+ D->setHasDestructors(Record[Idx++]);
+ D->NumIvarInitializers = Record[Idx++];
+ if (D->NumIvarInitializers)
+ D->IvarInitializers = Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
+}
+
+
+void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ D->setAtLoc(ReadSourceLocation(Record, Idx));
+ D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>(Record, Idx));
+ D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(Record, Idx);
+ D->IvarLoc = ReadSourceLocation(Record, Idx);
+ D->setGetterCXXConstructor(Reader.ReadExpr(F));
+ D->setSetterCXXAssignment(Reader.ReadExpr(F));
+}
+
+void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
+ VisitDeclaratorDecl(FD);
+ FD->Mutable = Record[Idx++];
+ if (int BitWidthOrInitializer = Record[Idx++]) {
+ FD->InitStorage.setInt(
+ static_cast<FieldDecl::InitStorageKind>(BitWidthOrInitializer - 1));
+ if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
+ // Read captured variable length array.
+ FD->InitStorage.setPointer(
+ Reader.readType(F, Record, Idx).getAsOpaquePtr());
+ } else {
+ FD->InitStorage.setPointer(Reader.ReadExpr(F));
+ }
+ }
+ if (!FD->getDeclName()) {
+ if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx))
+ Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
+ }
+ mergeMergeable(FD);
+}
+
+void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) {
+ VisitDeclaratorDecl(PD);
+ PD->GetterId = Reader.GetIdentifierInfo(F, Record, Idx);
+ PD->SetterId = Reader.GetIdentifierInfo(F, Record, Idx);
+}
+
+void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
+ VisitValueDecl(FD);
+
+ FD->ChainingSize = Record[Idx++];
+ assert(FD->ChainingSize >= 2 && "Anonymous chaining must be >= 2");
+ FD->Chaining = new (Reader.getContext())NamedDecl*[FD->ChainingSize];
+
+ for (unsigned I = 0; I != FD->ChainingSize; ++I)
+ FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx);
+}
+
+ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
+ RedeclarableResult Redecl = VisitRedeclarable(VD);
+ VisitDeclaratorDecl(VD);
+
+ VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
+ VD->VarDeclBits.TSCSpec = Record[Idx++];
+ VD->VarDeclBits.InitStyle = Record[Idx++];
+ if (!isa<ParmVarDecl>(VD)) {
+ VD->NonParmVarDeclBits.ExceptionVar = Record[Idx++];
+ VD->NonParmVarDeclBits.NRVOVariable = Record[Idx++];
+ VD->NonParmVarDeclBits.CXXForRangeDecl = Record[Idx++];
+ VD->NonParmVarDeclBits.ARCPseudoStrong = Record[Idx++];
+ VD->NonParmVarDeclBits.IsConstexpr = Record[Idx++];
+ VD->NonParmVarDeclBits.IsInitCapture = Record[Idx++];
+ VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record[Idx++];
+ }
+ Linkage VarLinkage = Linkage(Record[Idx++]);
+ VD->setCachedLinkage(VarLinkage);
+
+ // Reconstruct the one piece of the IdentifierNamespace that we need.
+ if (VD->getStorageClass() == SC_Extern && VarLinkage != NoLinkage &&
+ VD->getLexicalDeclContext()->isFunctionOrMethod())
+ VD->setLocalExternDecl();
+
+ if (uint64_t Val = Record[Idx++]) {
+ VD->setInit(Reader.ReadExpr(F));
+ if (Val > 1) {
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
+
+ enum VarKind {
+ VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+ };
+ switch ((VarKind)Record[Idx++]) {
+ case VarNotTemplate:
+ // Only true variables (not parameters or implicit parameters) can be merged
+ if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam &&
+ !isa<VarTemplateSpecializationDecl>(VD))
+ mergeRedeclarable(VD, Redecl);
+ break;
+ case VarTemplate:
+ // Merged when we merge the template.
+ VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
+ break;
+ case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
+ VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+ Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ mergeRedeclarable(VD, Redecl);
+ break;
+ }
+ }
+
+ return Redecl;
+}
+
+void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
+ VisitVarDecl(PD);
+}
+
+void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
+ VisitVarDecl(PD);
+ unsigned isObjCMethodParam = Record[Idx++];
+ unsigned scopeDepth = Record[Idx++];
+ unsigned scopeIndex = Record[Idx++];
+ unsigned declQualifier = Record[Idx++];
+ if (isObjCMethodParam) {
+ assert(scopeDepth == 0);
+ PD->setObjCMethodScopeInfo(scopeIndex);
+ PD->ParmVarDeclBits.ScopeDepthOrObjCQuals = declQualifier;
+ } else {
+ PD->setScopeInfo(scopeDepth, scopeIndex);
+ }
+ PD->ParmVarDeclBits.IsKNRPromoted = Record[Idx++];
+ PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++];
+ if (Record[Idx++]) // hasUninstantiatedDefaultArg.
+ PD->setUninstantiatedDefaultArg(Reader.ReadExpr(F));
+
+ // FIXME: If this is a redeclaration of a function from another module, handle
+ // inheritance of default arguments.
+}
+
+void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
+ VisitDecl(AD);
+ AD->setAsmString(cast<StringLiteral>(Reader.ReadExpr(F)));
+ AD->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
+ VisitDecl(BD);
+ BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadStmt(F)));
+ BD->setSignatureAsWritten(GetTypeSourceInfo(Record, Idx));
+ unsigned NumParams = Record[Idx++];
+ SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ BD->setParams(Params);
+
+ BD->setIsVariadic(Record[Idx++]);
+ BD->setBlockMissingReturnType(Record[Idx++]);
+ BD->setIsConversionFromLambda(Record[Idx++]);
+
+ bool capturesCXXThis = Record[Idx++];
+ unsigned numCaptures = Record[Idx++];
+ SmallVector<BlockDecl::Capture, 16> captures;
+ captures.reserve(numCaptures);
+ for (unsigned i = 0; i != numCaptures; ++i) {
+ VarDecl *decl = ReadDeclAs<VarDecl>(Record, Idx);
+ unsigned flags = Record[Idx++];
+ bool byRef = (flags & 1);
+ bool nested = (flags & 2);
+ Expr *copyExpr = ((flags & 4) ? Reader.ReadExpr(F) : nullptr);
+
+ captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr));
+ }
+ BD->setCaptures(Reader.getContext(), captures.begin(),
+ captures.end(), capturesCXXThis);
+}
+
+void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) {
+ VisitDecl(CD);
+ unsigned ContextParamPos = Record[Idx++];
+ CD->setNothrow(Record[Idx++] != 0);
+ // Body is set by VisitCapturedStmt.
+ for (unsigned I = 0; I < CD->NumParams; ++I) {
+ if (I != ContextParamPos)
+ CD->setParam(I, ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ else
+ CD->setContextParam(I, ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ }
+}
+
+void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
+ D->setExternLoc(ReadSourceLocation(Record, Idx));
+ D->setRBraceLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
+ VisitNamedDecl(D);
+ D->setLocStart(ReadSourceLocation(Record, Idx));
+}
+
+
+void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ D->setInline(Record[Idx++]);
+ D->LocStart = ReadSourceLocation(Record, Idx);
+ D->RBraceLoc = ReadSourceLocation(Record, Idx);
+
+ // Defer loading the anonymous namespace until we've finished merging
+ // this namespace; loading it might load a later declaration of the
+ // same namespace, and we have an invariant that older declarations
+ // get merged before newer ones try to merge.
+ GlobalDeclID AnonNamespace = 0;
+ if (Redecl.getFirstID() == ThisDeclID) {
+ AnonNamespace = ReadDeclID(Record, Idx);
+ } else {
+ // Link this namespace back to the first declaration, which has already
+ // been deserialized.
+ D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDecl());
+ }
+
+ mergeRedeclarable(D, Redecl);
+
+ if (AnonNamespace) {
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(AnonNamespace));
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule)
+ D->setAnonymousNamespace(Anon);
+ }
+}
+
+void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ D->NamespaceLoc = ReadSourceLocation(Record, Idx);
+ D->IdentLoc = ReadSourceLocation(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ D->Namespace = ReadDeclAs<NamedDecl>(Record, Idx);
+ mergeRedeclarable(D, Redecl);
+}
+
+void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
+ VisitNamedDecl(D);
+ D->setUsingLoc(ReadSourceLocation(Record, Idx));
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
+ D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>(Record, Idx));
+ D->setTypename(Record[Idx++]);
+ if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
+ Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
+ mergeMergeable(D);
+}
+
+void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ D->setTargetDecl(ReadDeclAs<NamedDecl>(Record, Idx));
+ D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(Record, Idx);
+ UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>(Record, Idx);
+ if (Pattern)
+ Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern);
+ mergeRedeclarable(D, Redecl);
+}
+
+void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ D->UsingLoc = ReadSourceLocation(Record, Idx);
+ D->NamespaceLoc = ReadSourceLocation(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ D->NominatedNamespace = ReadDeclAs<NamedDecl>(Record, Idx);
+ D->CommonAncestor = ReadDeclAs<DeclContext>(Record, Idx);
+}
+
+void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ D->setUsingLoc(ReadSourceLocation(Record, Idx));
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
+ mergeMergeable(D);
+}
+
+void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ D->TypenameLocation = ReadSourceLocation(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ mergeMergeable(D);
+}
+
+void ASTDeclReader::ReadCXXDefinitionData(
+ struct CXXRecordDecl::DefinitionData &Data,
+ const RecordData &Record, unsigned &Idx) {
+ // Note: the caller has deserialized the IsLambda bit already.
+ Data.UserDeclaredConstructor = Record[Idx++];
+ Data.UserDeclaredSpecialMembers = Record[Idx++];
+ Data.Aggregate = Record[Idx++];
+ Data.PlainOldData = Record[Idx++];
+ Data.Empty = Record[Idx++];
+ Data.Polymorphic = Record[Idx++];
+ Data.Abstract = Record[Idx++];
+ Data.IsStandardLayout = Record[Idx++];
+ Data.HasNoNonEmptyBases = Record[Idx++];
+ Data.HasPrivateFields = Record[Idx++];
+ Data.HasProtectedFields = Record[Idx++];
+ Data.HasPublicFields = Record[Idx++];
+ Data.HasMutableFields = Record[Idx++];
+ Data.HasVariantMembers = Record[Idx++];
+ Data.HasOnlyCMembers = Record[Idx++];
+ Data.HasInClassInitializer = Record[Idx++];
+ Data.HasUninitializedReferenceMember = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
+ Data.NeedOverloadResolutionForDestructor = Record[Idx++];
+ Data.DefaultedMoveConstructorIsDeleted = Record[Idx++];
+ Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
+ Data.DefaultedDestructorIsDeleted = Record[Idx++];
+ Data.HasTrivialSpecialMembers = Record[Idx++];
+ Data.DeclaredNonTrivialSpecialMembers = Record[Idx++];
+ Data.HasIrrelevantDestructor = Record[Idx++];
+ Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
+ Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
+ Data.HasConstexprDefaultConstructor = Record[Idx++];
+ Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
+ Data.ComputedVisibleConversions = Record[Idx++];
+ Data.UserProvidedDefaultConstructor = Record[Idx++];
+ Data.DeclaredSpecialMembers = Record[Idx++];
+ Data.ImplicitCopyConstructorHasConstParam = Record[Idx++];
+ Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
+ Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
+ Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
+
+ Data.NumBases = Record[Idx++];
+ if (Data.NumBases)
+ Data.Bases = Reader.readCXXBaseSpecifiers(F, Record, Idx);
+ Data.NumVBases = Record[Idx++];
+ if (Data.NumVBases)
+ Data.VBases = Reader.readCXXBaseSpecifiers(F, Record, Idx);
+
+ Reader.ReadUnresolvedSet(F, Data.Conversions, Record, Idx);
+ Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx);
+ assert(Data.Definition && "Data.Definition should be already set!");
+ Data.FirstFriend = ReadDeclID(Record, Idx);
+
+ if (Data.IsLambda) {
+ typedef LambdaCapture Capture;
+ CXXRecordDecl::LambdaDefinitionData &Lambda
+ = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
+ Lambda.Dependent = Record[Idx++];
+ Lambda.IsGenericLambda = Record[Idx++];
+ Lambda.CaptureDefault = Record[Idx++];
+ Lambda.NumCaptures = Record[Idx++];
+ Lambda.NumExplicitCaptures = Record[Idx++];
+ Lambda.ManglingNumber = Record[Idx++];
+ Lambda.ContextDecl = ReadDecl(Record, Idx);
+ Lambda.Captures
+ = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
+ Capture *ToCapture = Lambda.Captures;
+ Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
+ for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
+ SourceLocation Loc = ReadSourceLocation(Record, Idx);
+ bool IsImplicit = Record[Idx++];
+ LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
+ switch (Kind) {
+ case LCK_This:
+ case LCK_VLAType:
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation());
+ break;
+ case LCK_ByCopy:
+ case LCK_ByRef:
+ VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
+ SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
+ break;
+ }
+ }
+ }
+}
+
+void ASTDeclReader::MergeDefinitionData(
+ CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &&MergeDD) {
+ assert(D->DefinitionData.getNotUpdated() &&
+ "merging class definition into non-definition");
+ auto &DD = *D->DefinitionData.getNotUpdated();
+
+ // If the new definition has new special members, let the name lookup
+ // code know that it needs to look in the new definition too.
+ //
+ // FIXME: We only need to do this if the merged definition declares members
+ // that this definition did not declare, or if it defines members that this
+ // definition did not define.
+ if (DD.Definition != MergeDD.Definition) {
+ Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
+ DD.Definition->setHasExternalVisibleStorage();
+
+ if (DD.Definition->isHidden()) {
+ // If MergeDD is visible or becomes visible, make the definition visible.
+ if (!MergeDD.Definition->isHidden())
+ DD.Definition->Hidden = false;
+ else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ Reader.getContext().mergeDefinitionIntoModule(
+ DD.Definition, MergeDD.Definition->getImportedOwningModule(),
+ /*NotifyListeners*/ false);
+ Reader.PendingMergedDefinitionsToDeduplicate.insert(DD.Definition);
+ } else {
+ auto SubmoduleID = MergeDD.Definition->getOwningModuleID();
+ assert(SubmoduleID && "hidden definition in no module");
+ Reader.HiddenNamesMap[Reader.getSubmodule(SubmoduleID)].push_back(
+ DD.Definition);
+ }
+ }
+ }
+
+ auto PFDI = Reader.PendingFakeDefinitionData.find(&DD);
+ if (PFDI != Reader.PendingFakeDefinitionData.end() &&
+ PFDI->second == ASTReader::PendingFakeDefinitionKind::Fake) {
+ // We faked up this definition data because we found a class for which we'd
+ // not yet loaded the definition. Replace it with the real thing now.
+ assert(!DD.IsLambda && !MergeDD.IsLambda && "faked up lambda definition?");
+ PFDI->second = ASTReader::PendingFakeDefinitionKind::FakeLoaded;
+
+ // Don't change which declaration is the definition; that is required
+ // to be invariant once we select it.
+ auto *Def = DD.Definition;
+ DD = std::move(MergeDD);
+ DD.Definition = Def;
+ return;
+ }
+
+ // FIXME: Move this out into a .def file?
+ bool DetectedOdrViolation = false;
+#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
+#define MATCH_FIELD(Field) \
+ DetectedOdrViolation |= DD.Field != MergeDD.Field; \
+ OR_FIELD(Field)
+ MATCH_FIELD(UserDeclaredConstructor)
+ MATCH_FIELD(UserDeclaredSpecialMembers)
+ MATCH_FIELD(Aggregate)
+ MATCH_FIELD(PlainOldData)
+ MATCH_FIELD(Empty)
+ MATCH_FIELD(Polymorphic)
+ MATCH_FIELD(Abstract)
+ MATCH_FIELD(IsStandardLayout)
+ MATCH_FIELD(HasNoNonEmptyBases)
+ MATCH_FIELD(HasPrivateFields)
+ MATCH_FIELD(HasProtectedFields)
+ MATCH_FIELD(HasPublicFields)
+ MATCH_FIELD(HasMutableFields)
+ MATCH_FIELD(HasVariantMembers)
+ MATCH_FIELD(HasOnlyCMembers)
+ MATCH_FIELD(HasInClassInitializer)
+ MATCH_FIELD(HasUninitializedReferenceMember)
+ MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
+ MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
+ MATCH_FIELD(NeedOverloadResolutionForDestructor)
+ MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
+ MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
+ MATCH_FIELD(DefaultedDestructorIsDeleted)
+ OR_FIELD(HasTrivialSpecialMembers)
+ OR_FIELD(DeclaredNonTrivialSpecialMembers)
+ MATCH_FIELD(HasIrrelevantDestructor)
+ OR_FIELD(HasConstexprNonCopyMoveConstructor)
+ MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
+ OR_FIELD(HasConstexprDefaultConstructor)
+ MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
+ // ComputedVisibleConversions is handled below.
+ MATCH_FIELD(UserProvidedDefaultConstructor)
+ OR_FIELD(DeclaredSpecialMembers)
+ MATCH_FIELD(ImplicitCopyConstructorHasConstParam)
+ MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
+ OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
+ OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
+ MATCH_FIELD(IsLambda)
+#undef OR_FIELD
+#undef MATCH_FIELD
+
+ if (DD.NumBases != MergeDD.NumBases || DD.NumVBases != MergeDD.NumVBases)
+ DetectedOdrViolation = true;
+ // FIXME: Issue a diagnostic if the base classes don't match when we come
+ // to lazily load them.
+
+ // FIXME: Issue a diagnostic if the list of conversion functions doesn't
+ // match when we come to lazily load them.
+ if (MergeDD.ComputedVisibleConversions && !DD.ComputedVisibleConversions) {
+ DD.VisibleConversions = std::move(MergeDD.VisibleConversions);
+ DD.ComputedVisibleConversions = true;
+ }
+
+ // FIXME: Issue a diagnostic if FirstFriend doesn't match when we come to
+ // lazily load it.
+
+ if (DD.IsLambda) {
+ // FIXME: ODR-checking for merging lambdas (this happens, for instance,
+ // when they occur within the body of a function template specialization).
+ }
+
+ if (DetectedOdrViolation)
+ Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
+}
+
+void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
+ struct CXXRecordDecl::DefinitionData *DD;
+ ASTContext &C = Reader.getContext();
+
+ // Determine whether this is a lambda closure type, so that we can
+ // allocate the appropriate DefinitionData structure.
+ bool IsLambda = Record[Idx++];
+ if (IsLambda)
+ DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, nullptr, false, false,
+ LCD_None);
+ else
+ DD = new (C) struct CXXRecordDecl::DefinitionData(D);
+
+ ReadCXXDefinitionData(*DD, Record, Idx);
+
+ // We might already have a definition for this record. This can happen either
+ // because we're reading an update record, or because we've already done some
+ // merging. Either way, just merge into it.
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (auto *CanonDD = Canon->DefinitionData.getNotUpdated()) {
+ if (CanonDD->Definition != DD->Definition)
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(DD->Definition, CanonDD->Definition));
+ MergeDefinitionData(Canon, std::move(*DD));
+ D->DefinitionData = Canon->DefinitionData;
+ return;
+ }
+
+ // Propagate the DefinitionData pointer to the canonical declaration, so
+ // that all other deserialized declarations will see it.
+ if (Canon == D) {
+ D->DefinitionData = DD;
+ D->IsCompleteDefinition = true;
+
+ // If this is an update record, we can have redeclarations already. Make a
+ // note that we need to propagate the DefinitionData pointer onto them.
+ if (Update)
+ Reader.PendingDefinitions.insert(D);
+ } else if (auto *CanonDD = Canon->DefinitionData.getNotUpdated()) {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonDD->Definition));
+ D->DefinitionData = Canon->DefinitionData;
+ D->IsCompleteDefinition = false;
+ MergeDefinitionData(D, std::move(*DD));
+ } else {
+ Canon->DefinitionData = DD;
+ D->DefinitionData = Canon->DefinitionData;
+ D->IsCompleteDefinition = true;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ }
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
+ RedeclarableResult Redecl = VisitRecordDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+
+ enum CXXRecKind {
+ CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ };
+ switch ((CXXRecKind)Record[Idx++]) {
+ case CXXRecNotTemplate:
+ // Merged when we merge the folding set entry in the primary template.
+ if (!isa<ClassTemplateSpecializationDecl>(D))
+ mergeRedeclarable(D, Redecl);
+ break;
+ case CXXRecTemplate: {
+ // Merged when we merge the template.
+ ClassTemplateDecl *Template = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
+ D->TemplateOrInstantiation = Template;
+ if (!Template->getTemplatedDecl()) {
+ // We've not actually loaded the ClassTemplateDecl yet, because we're
+ // currently being loaded as its pattern. Rely on it to set up our
+ // TypeForDecl (see VisitClassTemplateDecl).
+ //
+ // Beware: we do not yet know our canonical declaration, and may still
+ // get merged once the surrounding class template has got off the ground.
+ TypeIDForTypeDecl = 0;
+ }
+ break;
+ }
+ case CXXRecMemberSpecialization: {
+ CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx);
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+ MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK);
+ MSI->setPointOfInstantiation(POI);
+ D->TemplateOrInstantiation = MSI;
+ mergeRedeclarable(D, Redecl);
+ break;
+ }
+ }
+
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition)
+ ReadCXXRecordDefinition(D, /*Update*/false);
+ else
+ // Propagate DefinitionData pointer from the canonical declaration.
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+
+ // Lazily load the key function to avoid deserializing every method so we can
+ // compute it.
+ if (WasDefinition) {
+ DeclID KeyFn = ReadDeclID(Record, Idx);
+ if (KeyFn && D->IsCompleteDefinition)
+ // FIXME: This is wrong for the ARM ABI, where some other module may have
+ // made this function no longer be a key function. We need an update
+ // record or similar for that case.
+ C.KeyFunctions[D] = KeyFn;
+ }
+
+ return Redecl;
+}
+
+void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ VisitFunctionDecl(D);
+
+ unsigned NumOverridenMethods = Record[Idx++];
+ if (D->isCanonicalDecl()) {
+ while (NumOverridenMethods--) {
+ // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
+ // MD may be initializing.
+ if (CXXMethodDecl *MD = ReadDeclAs<CXXMethodDecl>(Record, Idx))
+ Reader.getContext().addOverriddenMethod(D, MD->getCanonicalDecl());
+ }
+ } else {
+ // We don't care about which declarations this used to override; we get
+ // the relevant information from the canonical declaration.
+ Idx += NumOverridenMethods;
+ }
+}
+
+void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
+ if (D->isCanonicalDecl())
+ D->setInheritedConstructor(CD->getCanonicalDecl());
+ D->IsExplicitSpecified = Record[Idx++];
+}
+
+void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx)) {
+ auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!Canon->OperatorDelete)
+ Canon->OperatorDelete = OperatorDelete;
+ }
+}
+
+void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ VisitCXXMethodDecl(D);
+ D->IsExplicitSpecified = Record[Idx++];
+}
+
+void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
+ VisitDecl(D);
+ D->ImportedAndComplete.setPointer(readModule(Record, Idx));
+ D->ImportedAndComplete.setInt(Record[Idx++]);
+ SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1);
+ for (unsigned I = 0, N = Record.back(); I != N; ++I)
+ StoredLocs[I] = ReadSourceLocation(Record, Idx);
+ ++Idx; // The number of stored source locations.
+}
+
+void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
+ VisitDecl(D);
+ D->setColonLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
+ VisitDecl(D);
+ if (Record[Idx++]) // hasFriendDecl
+ D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
+ else
+ D->Friend = GetTypeSourceInfo(Record, Idx);
+ for (unsigned i = 0; i != D->NumTPLists; ++i)
+ D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->NextFriend = ReadDeclID(Record, Idx);
+ D->UnsupportedFriend = (Record[Idx++] != 0);
+ D->FriendLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ VisitDecl(D);
+ unsigned NumParams = Record[Idx++];
+ D->NumParams = NumParams;
+ D->Params = new TemplateParameterList*[NumParams];
+ for (unsigned i = 0; i != NumParams; ++i)
+ D->Params[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ if (Record[Idx++]) // HasFriendDecl
+ D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
+ else
+ D->Friend = GetTypeSourceInfo(Record, Idx);
+ D->FriendLoc = ReadSourceLocation(Record, Idx);
+}
+
+DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+ VisitNamedDecl(D);
+
+ DeclID PatternID = ReadDeclID(Record, Idx);
+ NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
+ TemplateParameterList* TemplateParams
+ = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->init(TemplatedDecl, TemplateParams);
+
+ // FIXME: If this is a redeclaration of a template from another module, handle
+ // inheritance of default template arguments.
+
+ return PatternID;
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+
+ // Make sure we've allocated the Common pointer first. We do this before
+ // VisitTemplateDecl so that getCommonPtr() can be used during initialization.
+ RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
+ if (!CanonD->Common) {
+ CanonD->Common = CanonD->newCommon(Reader.getContext());
+ Reader.PendingDefinitions.insert(CanonD);
+ }
+ D->Common = CanonD->Common;
+
+ // If this is the first declaration of the template, fill in the information
+ // for the 'common' pointer.
+ if (ThisDeclID == Redecl.getFirstID()) {
+ if (RedeclarableTemplateDecl *RTD
+ = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx)) {
+ assert(RTD->getKind() == D->getKind() &&
+ "InstantiatedFromMemberTemplate kind mismatch");
+ D->setInstantiatedFromMemberTemplate(RTD);
+ if (Record[Idx++])
+ D->setMemberSpecialization();
+ }
+ }
+
+ DeclID PatternID = VisitTemplateDecl(D);
+ D->IdentifierNamespace = Record[Idx++];
+
+ mergeRedeclarable(D, Redecl, PatternID);
+
+ // If we merged the template with a prior declaration chain, merge the common
+ // pointer.
+ // FIXME: Actually merge here, don't just overwrite.
+ D->Common = D->getCanonicalDecl()->Common;
+
+ return Redecl;
+}
+
+static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old,
+ SmallVectorImpl<DeclID> &IDs) {
+ assert(!IDs.empty() && "no IDs to add to list");
+ if (Old) {
+ IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
+ std::sort(IDs.begin(), IDs.end());
+ IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
+ }
+
+ auto *Result = new (Context) DeclID[1 + IDs.size()];
+ *Result = IDs.size();
+ std::copy(IDs.begin(), IDs.end(), Result + 1);
+ return Result;
+}
+
+void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+
+ if (ThisDeclID == Redecl.getFirstID()) {
+ // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
+ // the specializations.
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
+
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
+ }
+ }
+
+ if (D->getTemplatedDecl()->TemplateOrInstantiation) {
+ // We were loaded before our templated declaration was. We've not set up
+ // its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
+ // it now.
+ Reader.Context.getInjectedClassNameType(
+ D->getTemplatedDecl(), D->getInjectedClassNameSpecialization());
+ }
+}
+
+/// TODO: Unify with ClassTemplateDecl version?
+/// May require unifying ClassTemplateDecl and
+/// VarTemplateDecl beyond TemplateDecl...
+void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+
+ if (ThisDeclID == Redecl.getFirstID()) {
+ // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
+ // the specializations.
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
+
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
+ }
+ }
+}
+
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
+ ClassTemplateSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+ if (Decl *InstD = ReadDecl(Record, Idx)) {
+ if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(InstD)) {
+ D->SpecializedTemplate = CTD;
+ } else {
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ TemplateArgumentList *ArgList
+ = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
+ TemplArgs.size());
+ ClassTemplateSpecializationDecl::SpecializedPartialSpecialization *PS
+ = new (C) ClassTemplateSpecializationDecl::
+ SpecializedPartialSpecialization();
+ PS->PartialSpecialization
+ = cast<ClassTemplatePartialSpecializationDecl>(InstD);
+ PS->TemplateArgs = ArgList;
+ D->SpecializedTemplate = PS;
+ }
+ }
+
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
+ TemplArgs.size());
+ D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
+ D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
+ ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ // Set this as, or find, the canonical declaration for this specialization
+ ClassTemplateSpecializationDecl *CanonSpec;
+ if (ClassTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+ CanonSpec = CanonPattern->getCommonPtr()->PartialSpecializations
+ .GetOrInsertNode(Partial);
+ } else {
+ CanonSpec =
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ // If there was already a canonical specialization, merge into it.
+ if (CanonSpec != D) {
+ mergeRedeclarable<TagDecl>(D, CanonSpec, Redecl);
+
+ // This declaration might be a definition. Merge with any existing
+ // definition.
+ if (auto *DDD = D->DefinitionData.getNotUpdated()) {
+ if (auto *CanonDD = CanonSpec->DefinitionData.getNotUpdated()) {
+ MergeDefinitionData(CanonSpec, std::move(*DDD));
+ Reader.PendingDefinitions.erase(D);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonDD->Definition));
+ D->IsCompleteDefinition = false;
+ } else {
+ CanonSpec->DefinitionData = D->DefinitionData;
+ }
+ }
+ D->DefinitionData = CanonSpec->DefinitionData;
+ }
+ }
+ }
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
+ = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ return Redecl;
+}
+
+void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
+
+ D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->ArgsAsWritten = Reader.ReadASTTemplateArgumentListInfo(F, Record, Idx);
+
+ // These are read/set from/to the first declaration.
+ if (ThisDeclID == Redecl.getFirstID()) {
+ D->InstantiatedFromMember.setPointer(
+ ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx));
+ D->InstantiatedFromMember.setInt(Record[Idx++]);
+ }
+}
+
+void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D) {
+ VisitDecl(D);
+ D->Specialization = ReadDeclAs<CXXMethodDecl>(Record, Idx);
+}
+
+void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+
+ if (ThisDeclID == Redecl.getFirstID()) {
+ // This FunctionTemplateDecl owns a CommonPtr; read it.
+ SmallVector<serialization::DeclID, 32> SpecIDs;
+ ReadDeclIDList(SpecIDs);
+
+ if (!SpecIDs.empty()) {
+ auto *CommonPtr = D->getCommonPtr();
+ CommonPtr->LazySpecializations = newDeclIDList(
+ Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
+ }
+ }
+}
+
+/// TODO: Unify with ClassTemplateSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
+ VarTemplateSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarDeclImpl(D);
+
+ ASTContext &C = Reader.getContext();
+ if (Decl *InstD = ReadDecl(Record, Idx)) {
+ if (VarTemplateDecl *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
+ D->SpecializedTemplate = VTD;
+ } else {
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy(
+ C, TemplArgs.data(), TemplArgs.size());
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization *PS =
+ new (C)
+ VarTemplateSpecializationDecl::SpecializedPartialSpecialization();
+ PS->PartialSpecialization =
+ cast<VarTemplatePartialSpecializationDecl>(InstD);
+ PS->TemplateArgs = ArgList;
+ D->SpecializedTemplate = PS;
+ }
+ }
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ VarTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo =
+ new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ D->TemplateArgs =
+ TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size());
+ D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
+ D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
+ VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {
+ CanonPattern->getCommonPtr()->PartialSpecializations
+ .GetOrInsertNode(Partial);
+ } else {
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ }
+ }
+
+ return Redecl;
+}
+
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+/// May require unifying ClassTemplate(Partial)SpecializationDecl and
+/// VarTemplate(Partial)SpecializationDecl with a new data
+/// structure Template(Partial)SpecializationDecl, and
+/// using Template(Partial)SpecializationDecl as input type.
+void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
+
+ D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx);
+ D->ArgsAsWritten = Reader.ReadASTTemplateArgumentListInfo(F, Record, Idx);
+
+ // These are read/set from/to the first declaration.
+ if (ThisDeclID == Redecl.getFirstID()) {
+ D->InstantiatedFromMember.setPointer(
+ ReadDeclAs<VarTemplatePartialSpecializationDecl>(Record, Idx));
+ D->InstantiatedFromMember.setInt(Record[Idx++]);
+ }
+}
+
+void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ VisitTypeDecl(D);
+
+ D->setDeclaredWithTypename(Record[Idx++]);
+
+ bool Inherited = Record[Idx++];
+ TypeSourceInfo *DefArg = GetTypeSourceInfo(Record, Idx);
+ D->setDefaultArgument(DefArg, Inherited);
+}
+
+void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ VisitDeclaratorDecl(D);
+ // TemplateParmPosition.
+ D->setDepth(Record[Idx++]);
+ D->setPosition(Record[Idx++]);
+ if (D->isExpandedParameterPack()) {
+ void **Data = reinterpret_cast<void **>(D + 1);
+ for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
+ Data[2*I] = Reader.readType(F, Record, Idx).getAsOpaquePtr();
+ Data[2*I + 1] = GetTypeSourceInfo(Record, Idx);
+ }
+ } else {
+ // Rest of NonTypeTemplateParmDecl.
+ D->ParameterPack = Record[Idx++];
+ if (Record[Idx++]) {
+ Expr *DefArg = Reader.ReadExpr(F);
+ bool Inherited = Record[Idx++];
+ D->setDefaultArgument(DefArg, Inherited);
+ }
+ }
+}
+
+void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ VisitTemplateDecl(D);
+ // TemplateParmPosition.
+ D->setDepth(Record[Idx++]);
+ D->setPosition(Record[Idx++]);
+ if (D->isExpandedParameterPack()) {
+ void **Data = reinterpret_cast<void **>(D + 1);
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
+ bool IsInherited = Record[Idx++];
+ D->setDefaultArgument(Arg, IsInherited);
+ D->ParameterPack = Record[Idx++];
+ }
+}
+
+void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+}
+
+void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ VisitDecl(D);
+ D->AssertExprAndFailed.setPointer(Reader.ReadExpr(F));
+ D->AssertExprAndFailed.setInt(Record[Idx++]);
+ D->Message = cast<StringLiteral>(Reader.ReadExpr(F));
+ D->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+}
+
+std::pair<uint64_t, uint64_t>
+ASTDeclReader::VisitDeclContext(DeclContext *DC) {
+ uint64_t LexicalOffset = Record[Idx++];
+ uint64_t VisibleOffset = Record[Idx++];
+ return std::make_pair(LexicalOffset, VisibleOffset);
+}
+
+template <typename T>
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
+ Decl *MergeWith = nullptr;
+
+ // 0 indicates that this declaration was the only declaration of its entity,
+ // and is used for space optimization.
+ if (FirstDeclID == 0)
+ FirstDeclID = ThisDeclID;
+ else if (unsigned N = Record[Idx++]) {
+ // We have some declarations that must be before us in our redeclaration
+ // chain. Read them now, and remember that we ought to merge with one of
+ // them.
+ // FIXME: Provide a known merge target to the second and subsequent such
+ // declaration.
+ for (unsigned I = 0; I != N; ++I)
+ MergeWith = ReadDecl(Record, Idx/*, MergeWith*/);
+ }
+
+ T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
+ if (FirstDecl != D) {
+ // We delay loading of the redeclaration chain to avoid deeply nested calls.
+ // We temporarily set the first (canonical) declaration as the previous one
+ // which is the one that matters and mark the real previous DeclID to be
+ // loaded & attached later on.
+ D->RedeclLink = Redeclarable<T>::PreviousDeclLink(FirstDecl);
+ D->First = FirstDecl->getCanonicalDecl();
+ }
+
+ // Note that this declaration has been deserialized.
+ Reader.RedeclsDeserialized.insert(static_cast<T *>(D));
+
+ // The result structure takes care to note that we need to load the
+ // other declaration chains for this ID.
+ return RedeclarableResult(Reader, FirstDeclID, MergeWith,
+ static_cast<T *>(D)->getKind());
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
+ T *D = static_cast<T*>(DBase);
+
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
+ return;
+
+ // If we're not the canonical declaration, we don't need to merge.
+ if (!DBase->isFirstDecl())
+ return;
+
+ if (auto *Existing = Redecl.getKnownMergeTarget())
+ // We already know of an existing declaration we should merge with.
+ mergeRedeclarable(D, cast<T>(Existing), Redecl, TemplatePatternID);
+ else if (FindExistingResult ExistingRes = findExisting(D))
+ if (T *Existing = ExistingRes)
+ mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
+}
+
+/// \brief "Cast" to type T, asserting if we don't have an implicit conversion.
+/// We use this to put code in a template that will only be valid for certain
+/// instantiations.
+template<typename T> static T assert_cast(T t) { return t; }
+template<typename T> static T assert_cast(...) {
+ llvm_unreachable("bad assert_cast");
+}
+
+/// \brief Merge together the pattern declarations from two template
+/// declarations.
+void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID) {
+ auto *DPattern = D->getTemplatedDecl();
+ auto *ExistingPattern = Existing->getTemplatedDecl();
+ RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(),
+ /*MergeWith*/ExistingPattern, DPattern->getKind());
+
+ if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) {
+ // Merge with any existing definition.
+ // FIXME: This is duplicated in several places. Refactor.
+ auto *ExistingClass =
+ cast<CXXRecordDecl>(ExistingPattern)->getCanonicalDecl();
+ if (auto *DDD = DClass->DefinitionData.getNotUpdated()) {
+ if (auto *ExistingDD = ExistingClass->DefinitionData.getNotUpdated()) {
+ MergeDefinitionData(ExistingClass, std::move(*DDD));
+ Reader.PendingDefinitions.erase(DClass);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(DClass, ExistingDD->Definition));
+ DClass->IsCompleteDefinition = false;
+ } else {
+ ExistingClass->DefinitionData = DClass->DefinitionData;
+ Reader.PendingDefinitions.insert(DClass);
+ }
+ }
+ DClass->DefinitionData = ExistingClass->DefinitionData;
+
+ return mergeRedeclarable(DClass, cast<TagDecl>(ExistingPattern),
+ Result);
+ }
+ if (auto *DFunction = dyn_cast<FunctionDecl>(DPattern))
+ return mergeRedeclarable(DFunction, cast<FunctionDecl>(ExistingPattern),
+ Result);
+ if (auto *DVar = dyn_cast<VarDecl>(DPattern))
+ return mergeRedeclarable(DVar, cast<VarDecl>(ExistingPattern), Result);
+ if (auto *DAlias = dyn_cast<TypeAliasDecl>(DPattern))
+ return mergeRedeclarable(DAlias, cast<TypedefNameDecl>(ExistingPattern),
+ Result);
+ llvm_unreachable("merged an unknown kind of redeclarable template");
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
+ T *D = static_cast<T*>(DBase);
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = D->getCanonicalDecl();
+ if (ExistingCanon != DCanon) {
+ assert(DCanon->getGlobalID() == Redecl.getFirstID() &&
+ "already merged this declaration");
+
+ // Have our redeclaration link point back at the canonical declaration
+ // of the existing declaration, so that this declaration has the
+ // appropriate canonical declaration.
+ D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+ D->First = ExistingCanon;
+
+ // When we merge a namespace, update its pointer to the first namespace.
+ // We cannot have loaded any redeclarations of this declaration yet, so
+ // there's nothing else that needs to be updated.
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ assert_cast<NamespaceDecl*>(ExistingCanon));
+
+ // When we merge a template, merge its pattern.
+ if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
+ mergeTemplatePattern(
+ DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
+ TemplatePatternID);
+
+ // If this declaration was the canonical declaration, make a note of that.
+ if (DCanon == D) {
+ Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID());
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second)
+ Reader.PendingDeclChains.push_back(ExistingCanon);
+ }
+ }
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity, for the case where the entity is not actually
+/// redeclarable. This happens, for instance, when merging the fields of
+/// identical class definitions from two different modules.
+template<typename T>
+void ASTDeclReader::mergeMergeable(Mergeable<T> *D) {
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
+ return;
+
+ // ODR-based merging is only performed in C++. In C, identically-named things
+ // in different translation units are not redeclarations (but may still have
+ // compatible types).
+ if (!Reader.getContext().getLangOpts().CPlusPlus)
+ return;
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (T *Existing = ExistingRes)
+ Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D),
+ Existing->getCanonicalDecl());
+}
+
+void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ VisitDecl(D);
+ unsigned NumVars = D->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i) {
+ Vars.push_back(Reader.ReadExpr(F));
+ }
+ D->setVars(Vars);
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Reading
+//===----------------------------------------------------------------------===//
+
+/// \brief Reads attributes from the current stream position.
+void ASTReader::ReadAttributes(ModuleFile &F, AttrVec &Attrs,
+ const RecordData &Record, unsigned &Idx) {
+ for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) {
+ Attr *New = nullptr;
+ attr::Kind Kind = (attr::Kind)Record[Idx++];
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+
+#include "clang/Serialization/AttrPCHRead.inc"
+
+ assert(New && "Unable to decode attribute?");
+ Attrs.push_back(New);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// ASTReader Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Note that we have loaded the declaration with the given
+/// Index.
+///
+/// This routine notes that this declaration has already been loaded,
+/// so that future GetDecl calls will return this declaration rather
+/// than trying to load a new declaration.
+inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) {
+ assert(!DeclsLoaded[Index] && "Decl loaded twice?");
+ DeclsLoaded[Index] = D;
+}
+
+
+/// \brief Determine whether the consumer will be interested in seeing
+/// this declaration (via HandleTopLevelDecl).
+///
+/// This routine should return true for anything that might affect
+/// code generation, e.g., inline function definitions, Objective-C
+/// declarations with metadata, etc.
+static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
+ // An ObjCMethodDecl is never considered as "interesting" because its
+ // implementation container always is.
+
+ if (isa<FileScopeAsmDecl>(D) ||
+ isa<ObjCProtocolDecl>(D) ||
+ isa<ObjCImplDecl>(D) ||
+ isa<ImportDecl>(D) ||
+ isa<OMPThreadPrivateDecl>(D))
+ return true;
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->isFileVarDecl() &&
+ Var->isThisDeclarationADefinition() == VarDecl::Definition;
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
+ return Func->doesThisDeclarationHaveABody() || HasBody;
+
+ return false;
+}
+
+/// \brief Get the correct cursor and offset for loading a declaration.
+ASTReader::RecordLocation
+ASTReader::DeclCursorForID(DeclID ID, unsigned &RawLocation) {
+ // See if there's an override.
+ DeclReplacementMap::iterator It = ReplacedDecls.find(ID);
+ if (It != ReplacedDecls.end()) {
+ RawLocation = It->second.RawLoc;
+ return RecordLocation(It->second.Mod, It->second.Offset);
+ }
+
+ GlobalDeclMapType::iterator I = GlobalDeclMap.find(ID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *M = I->second;
+ const DeclOffset &
+ DOffs = M->DeclOffsets[ID - M->BaseDeclID - NUM_PREDEF_DECL_IDS];
+ RawLocation = DOffs.Loc;
+ return RecordLocation(M, DOffs.BitOffset);
+}
+
+ASTReader::RecordLocation ASTReader::getLocalBitOffset(uint64_t GlobalOffset) {
+ ContinuousRangeMap<uint64_t, ModuleFile*, 4>::iterator I
+ = GlobalBitOffsetsMap.find(GlobalOffset);
+
+ assert(I != GlobalBitOffsetsMap.end() && "Corrupted global bit offsets map");
+ return RecordLocation(I->second, GlobalOffset - I->second->GlobalBitOffset);
+}
+
+uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) {
+ return LocalOffset + M.GlobalBitOffset;
+}
+
+static bool isSameTemplateParameterList(const TemplateParameterList *X,
+ const TemplateParameterList *Y);
+
+/// \brief Determine whether two template parameters are similar enough
+/// that they may be used in declarations of the same template.
+static bool isSameTemplateParameter(const NamedDecl *X,
+ const NamedDecl *Y) {
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ if (const TemplateTypeParmDecl *TX = dyn_cast<TemplateTypeParmDecl>(X)) {
+ const TemplateTypeParmDecl *TY = cast<TemplateTypeParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack();
+ }
+
+ if (const NonTypeTemplateParmDecl *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
+ const NonTypeTemplateParmDecl *TY = cast<NonTypeTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ }
+
+ const TemplateTemplateParmDecl *TX = cast<TemplateTemplateParmDecl>(X);
+ const TemplateTemplateParmDecl *TY = cast<TemplateTemplateParmDecl>(Y);
+ return TX->isParameterPack() == TY->isParameterPack() &&
+ isSameTemplateParameterList(TX->getTemplateParameters(),
+ TY->getTemplateParameters());
+}
+
+static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
+ if (auto *NS = X->getAsNamespace())
+ return NS;
+ if (auto *NAS = X->getAsNamespaceAlias())
+ return NAS->getNamespace();
+ return nullptr;
+}
+
+static bool isSameQualifier(const NestedNameSpecifier *X,
+ const NestedNameSpecifier *Y) {
+ if (auto *NSX = getNamespace(X)) {
+ auto *NSY = getNamespace(Y);
+ if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
+ return false;
+ } else if (X->getKind() != Y->getKind())
+ return false;
+
+ // FIXME: For namespaces and types, we're permitted to check that the entity
+ // is named via the same tokens. We should probably do so.
+ switch (X->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (X->getAsIdentifier() != Y->getAsIdentifier())
+ return false;
+ break;
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ // We've already checked that we named the same namespace.
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (X->getAsType()->getCanonicalTypeInternal() !=
+ Y->getAsType()->getCanonicalTypeInternal())
+ return false;
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ return true;
+ }
+
+ // Recurse into earlier portion of NNS, if any.
+ auto *PX = X->getPrefix();
+ auto *PY = Y->getPrefix();
+ if (PX && PY)
+ return isSameQualifier(PX, PY);
+ return !PX && !PY;
+}
+
+/// \brief Determine whether two template parameter lists are similar enough
+/// that they may be used in declarations of the same template.
+static bool isSameTemplateParameterList(const TemplateParameterList *X,
+ const TemplateParameterList *Y) {
+ if (X->size() != Y->size())
+ return false;
+
+ for (unsigned I = 0, N = X->size(); I != N; ++I)
+ if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
+ return false;
+
+ return true;
+}
+
+/// \brief Determine whether the two declarations refer to the same entity.
+static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
+ assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
+
+ if (X == Y)
+ return true;
+
+ // Must be in the same context.
+ if (!X->getDeclContext()->getRedeclContext()->Equals(
+ Y->getDeclContext()->getRedeclContext()))
+ return false;
+
+ // Two typedefs refer to the same entity if they have the same underlying
+ // type.
+ if (TypedefNameDecl *TypedefX = dyn_cast<TypedefNameDecl>(X))
+ if (TypedefNameDecl *TypedefY = dyn_cast<TypedefNameDecl>(Y))
+ return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
+ TypedefY->getUnderlyingType());
+
+ // Must have the same kind.
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ // Objective-C classes and protocols with the same name always match.
+ if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
+ return true;
+
+ if (isa<ClassTemplateSpecializationDecl>(X)) {
+ // No need to handle these here: we merge them when adding them to the
+ // template.
+ return false;
+ }
+
+ // Compatible tags match.
+ if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
+ TagDecl *TagY = cast<TagDecl>(Y);
+ return (TagX->getTagKind() == TagY->getTagKind()) ||
+ ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
+ TagX->getTagKind() == TTK_Interface) &&
+ (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
+ TagY->getTagKind() == TTK_Interface));
+ }
+
+ // Functions with the same type and linkage match.
+ // FIXME: This needs to cope with merging of prototyped/non-prototyped
+ // functions, etc.
+ if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
+ FunctionDecl *FuncY = cast<FunctionDecl>(Y);
+ return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
+ FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
+ }
+
+ // Variables with the same type and linkage match.
+ if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
+ VarDecl *VarY = cast<VarDecl>(Y);
+ return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) &&
+ VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
+ }
+
+ // Namespaces with the same name and inlinedness match.
+ if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+ NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
+ return NamespaceX->isInline() == NamespaceY->isInline();
+ }
+
+ // Identical template names and kinds match if their template parameter lists
+ // and patterns match.
+ if (TemplateDecl *TemplateX = dyn_cast<TemplateDecl>(X)) {
+ TemplateDecl *TemplateY = cast<TemplateDecl>(Y);
+ return isSameEntity(TemplateX->getTemplatedDecl(),
+ TemplateY->getTemplatedDecl()) &&
+ isSameTemplateParameterList(TemplateX->getTemplateParameters(),
+ TemplateY->getTemplateParameters());
+ }
+
+ // Fields with the same name and the same type match.
+ if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
+ FieldDecl *FDY = cast<FieldDecl>(Y);
+ // FIXME: Also check the bitwidth is odr-equivalent, if any.
+ return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
+ }
+
+ // Enumerators with the same name match.
+ if (isa<EnumConstantDecl>(X))
+ // FIXME: Also check the value is odr-equivalent.
+ return true;
+
+ // Using shadow declarations with the same target match.
+ if (UsingShadowDecl *USX = dyn_cast<UsingShadowDecl>(X)) {
+ UsingShadowDecl *USY = cast<UsingShadowDecl>(Y);
+ return USX->getTargetDecl() == USY->getTargetDecl();
+ }
+
+ // Using declarations with the same qualifier match. (We already know that
+ // the name matches.)
+ if (auto *UX = dyn_cast<UsingDecl>(X)) {
+ auto *UY = cast<UsingDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->hasTypename() == UY->hasTypename() &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
+ auto *UY = cast<UnresolvedUsingValueDecl>(Y);
+ return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+ UX->isAccessDeclaration() == UY->isAccessDeclaration();
+ }
+ if (auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X))
+ return isSameQualifier(
+ UX->getQualifier(),
+ cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
+
+ // Namespace alias definitions with the same target match.
+ if (auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
+ auto *NAY = cast<NamespaceAliasDecl>(Y);
+ return NAX->getNamespace()->Equals(NAY->getNamespace());
+ }
+
+ // FIXME: Many other cases to implement.
+ return false;
+}
+
+/// Find the context in which we should search for previous declarations when
+/// looking for declarations to merge.
+DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
+ DeclContext *DC) {
+ if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ return ND->getOriginalNamespace();
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ // Try to dig out the definition.
+ auto *DD = RD->DefinitionData.getNotUpdated();
+ if (!DD)
+ DD = RD->getCanonicalDecl()->DefinitionData.getNotUpdated();
+
+ // If there's no definition yet, then DC's definition is added by an update
+ // record, but we've not yet loaded that update record. In this case, we
+ // commit to DC being the canonical definition now, and will fix this when
+ // we load the update record.
+ if (!DD) {
+ DD = new (Reader.Context) struct CXXRecordDecl::DefinitionData(RD);
+ RD->IsCompleteDefinition = true;
+ RD->DefinitionData = DD;
+ RD->getCanonicalDecl()->DefinitionData = DD;
+
+ // Track that we did this horrible thing so that we can fix it later.
+ Reader.PendingFakeDefinitionData.insert(
+ std::make_pair(DD, ASTReader::PendingFakeDefinitionKind::Fake));
+ }
+
+ return DD->Definition;
+ }
+
+ if (EnumDecl *ED = dyn_cast<EnumDecl>(DC))
+ return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition()
+ : nullptr;
+
+ // We can see the TU here only if we have no Sema object. In that case,
+ // there's no TU scope to look in, so using the DC alone is sufficient.
+ if (auto *TU = dyn_cast<TranslationUnitDecl>(DC))
+ return TU;
+
+ return nullptr;
+}
+
+ASTDeclReader::FindExistingResult::~FindExistingResult() {
+ // Record that we had a typedef name for linkage whether or not we merge
+ // with that declaration.
+ if (TypedefNameForLinkage) {
+ DeclContext *DC = New->getDeclContext()->getRedeclContext();
+ Reader.ImportedTypedefNamesForLinkage.insert(
+ std::make_pair(std::make_pair(DC, TypedefNameForLinkage), New));
+ return;
+ }
+
+ if (!AddResult || Existing)
+ return;
+
+ DeclarationName Name = New->getDeclName();
+ DeclContext *DC = New->getDeclContext()->getRedeclContext();
+ if (needsAnonymousDeclarationNumber(New)) {
+ setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
+ AnonymousDeclNumber, New);
+ } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+ !Reader.getContext().getLangOpts().CPlusPlus) {
+ if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name))
+ Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()]
+ .push_back(New);
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) {
+ // Add the declaration to its redeclaration context so later merging
+ // lookups will find it.
+ MergeDC->makeDeclVisibleInContextImpl(New, /*Internal*/true);
+ }
+}
+
+/// Find the declaration that should be merged into, given the declaration found
+/// by name lookup. If we're merging an anonymous declaration within a typedef,
+/// we need a matching typedef, and we merge with the type inside it.
+static NamedDecl *getDeclForMerging(NamedDecl *Found,
+ bool IsTypedefNameForLinkage) {
+ if (!IsTypedefNameForLinkage)
+ return Found;
+
+ // If we found a typedef declaration that gives a name to some other
+ // declaration, then we want that inner declaration. Declarations from
+ // AST files are handled via ImportedTypedefNamesForLinkage.
+ if (Found->isFromASTFile())
+ return 0;
+
+ if (auto *TND = dyn_cast<TypedefNameDecl>(Found))
+ return TND->getAnonDeclWithTypedefName();
+
+ return 0;
+}
+
+NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC,
+ unsigned Index) {
+ // If the lexical context has been merged, look into the now-canonical
+ // definition.
+ if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
+ DC = Merged;
+
+ // If we've seen this before, return the canonical declaration.
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ if (Index < Previous.size() && Previous[Index])
+ return Previous[Index];
+
+ // If this is the first time, but we have parsed a declaration of the context,
+ // build the anonymous declaration list from the parsed declaration.
+ if (!cast<Decl>(DC)->isFromASTFile()) {
+ numberAnonymousDeclsWithin(DC, [&](NamedDecl *ND, unsigned Number) {
+ if (Previous.size() == Number)
+ Previous.push_back(cast<NamedDecl>(ND->getCanonicalDecl()));
+ else
+ Previous[Number] = cast<NamedDecl>(ND->getCanonicalDecl());
+ });
+ }
+
+ return Index < Previous.size() ? Previous[Index] : nullptr;
+}
+
+void ASTDeclReader::setAnonymousDeclForMerging(ASTReader &Reader,
+ DeclContext *DC, unsigned Index,
+ NamedDecl *D) {
+ if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
+ DC = Merged;
+
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ if (Index >= Previous.size())
+ Previous.resize(Index + 1);
+ if (!Previous[Index])
+ Previous[Index] = D;
+}
+
+ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
+ DeclarationName Name = TypedefNameForLinkage ? TypedefNameForLinkage
+ : D->getDeclName();
+
+ if (!Name && !needsAnonymousDeclarationNumber(D)) {
+ // Don't bother trying to find unnamed declarations that are in
+ // unmergeable contexts.
+ FindExistingResult Result(Reader, D, /*Existing=*/nullptr,
+ AnonymousDeclNumber, TypedefNameForLinkage);
+ Result.suppress();
+ return Result;
+ }
+
+ // FIXME: Bail out for non-canonical declarations. We will have performed any
+ // necessary merging already.
+
+ DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ if (TypedefNameForLinkage) {
+ auto It = Reader.ImportedTypedefNamesForLinkage.find(
+ std::make_pair(DC, TypedefNameForLinkage));
+ if (It != Reader.ImportedTypedefNamesForLinkage.end())
+ if (isSameEntity(It->second, D))
+ return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ // Go on to check in other places in case an existing typedef name
+ // was not imported.
+ }
+
+ if (needsAnonymousDeclarationNumber(D)) {
+ // This is an anonymous declaration that we may need to merge. Look it up
+ // in its context by number.
+ if (auto *Existing = getAnonymousDeclForMerging(
+ Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+ !Reader.getContext().getLangOpts().CPlusPlus) {
+ IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
+
+ // Temporarily consider the identifier to be up-to-date. We don't want to
+ // cause additional lookups here.
+ class UpToDateIdentifierRAII {
+ IdentifierInfo *II;
+ bool WasOutToDate;
+
+ public:
+ explicit UpToDateIdentifierRAII(IdentifierInfo *II)
+ : II(II), WasOutToDate(false)
+ {
+ if (II) {
+ WasOutToDate = II->isOutOfDate();
+ if (WasOutToDate)
+ II->setOutOfDate(false);
+ }
+ }
+
+ ~UpToDateIdentifierRAII() {
+ if (WasOutToDate)
+ II->setOutOfDate(true);
+ }
+ } UpToDate(Name.getAsIdentifierInfo());
+
+ for (IdentifierResolver::iterator I = IdResolver.begin(Name),
+ IEnd = IdResolver.end();
+ I != IEnd; ++I) {
+ if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ }
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) {
+ DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage))
+ if (isSameEntity(Existing, D))
+ return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
+ TypedefNameForLinkage);
+ }
+ } else {
+ // Not in a mergeable context.
+ return FindExistingResult(Reader);
+ }
+
+ // If this declaration is from a merged context, make a note that we need to
+ // check that the canonical definition of that context contains the decl.
+ //
+ // FIXME: We should do something similar if we merge two definitions of the
+ // same template specialization into the same CXXRecordDecl.
+ auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
+ if (MergedDCIt != Reader.MergedDeclContexts.end() &&
+ MergedDCIt->second == D->getDeclContext())
+ Reader.PendingOdrMergeChecks.push_back(D);
+
+ return FindExistingResult(Reader, D, /*Existing=*/nullptr,
+ AnonymousDeclNumber, TypedefNameForLinkage);
+}
+
+template<typename DeclT>
+Decl *ASTDeclReader::getMostRecentDeclImpl(Redeclarable<DeclT> *D) {
+ return D->RedeclLink.getLatestNotUpdated();
+}
+Decl *ASTDeclReader::getMostRecentDeclImpl(...) {
+ llvm_unreachable("getMostRecentDecl on non-redeclarable declaration");
+}
+
+Decl *ASTDeclReader::getMostRecentDecl(Decl *D) {
+ assert(D);
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ return getMostRecentDeclImpl(cast<TYPE##Decl>(D));
+#include "clang/AST/DeclNodes.inc"
+ }
+ llvm_unreachable("unknown decl kind");
+}
+
+Decl *ASTReader::getMostRecentExistingDecl(Decl *D) {
+ return ASTDeclReader::getMostRecentDecl(D->getCanonicalDecl());
+}
+
+template<typename DeclT>
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<DeclT> *D,
+ Decl *Previous, Decl *Canon) {
+ D->RedeclLink.setPrevious(cast<DeclT>(Previous));
+ D->First = cast<DeclT>(Previous)->First;
+}
+namespace clang {
+template<>
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
+ Redeclarable<FunctionDecl> *D,
+ Decl *Previous, Decl *Canon) {
+ FunctionDecl *FD = static_cast<FunctionDecl*>(D);
+ FunctionDecl *PrevFD = cast<FunctionDecl>(Previous);
+
+ FD->RedeclLink.setPrevious(PrevFD);
+ FD->First = PrevFD->First;
+
+ // If the previous declaration is an inline function declaration, then this
+ // declaration is too.
+ if (PrevFD->IsInline != FD->IsInline) {
+ // FIXME: [dcl.fct.spec]p4:
+ // If a function with external linkage is declared inline in one
+ // translation unit, it shall be declared inline in all translation
+ // units in which it appears.
+ //
+ // Be careful of this case:
+ //
+ // module A:
+ // template<typename T> struct X { void f(); };
+ // template<typename T> inline void X<T>::f() {}
+ //
+ // module B instantiates the declaration of X<int>::f
+ // module C instantiates the definition of X<int>::f
+ //
+ // If module B and C are merged, we do not have a violation of this rule.
+ FD->IsInline = true;
+ }
+
+ // If we need to propagate an exception specification along the redecl
+ // chain, make a note of that so that we can do so later.
+ auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+ auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
+ if (FPT && PrevFPT) {
+ bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
+ bool WasUnresolved =
+ isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
+ if (IsUnresolved != WasUnresolved)
+ Reader.PendingExceptionSpecUpdates.insert(
+ std::make_pair(Canon, IsUnresolved ? PrevFD : FD));
+ }
+}
+}
+void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) {
+ llvm_unreachable("attachPreviousDecl on non-redeclarable declaration");
+}
+
+void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
+ Decl *Previous, Decl *Canon) {
+ assert(D && Previous);
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous, Canon); \
+ break;
+#include "clang/AST/DeclNodes.inc"
+ }
+
+ // If the declaration was visible in one module, a redeclaration of it in
+ // another module remains visible even if it wouldn't be visible by itself.
+ //
+ // FIXME: In this case, the declaration should only be visible if a module
+ // that makes it visible has been imported.
+ D->IdentifierNamespace |=
+ Previous->IdentifierNamespace &
+ (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
+
+ // If the previous declaration is marked as used, then this declaration should
+ // be too.
+ if (Previous->Used)
+ D->Used = true;
+}
+
+template<typename DeclT>
+void ASTDeclReader::attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest) {
+ D->RedeclLink.setLatest(cast<DeclT>(Latest));
+}
+void ASTDeclReader::attachLatestDeclImpl(...) {
+ llvm_unreachable("attachLatestDecl on non-redeclarable declaration");
+}
+
+void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
+ assert(D && Latest);
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachLatestDeclImpl(cast<TYPE##Decl>(D), Latest); \
+ break;
+#include "clang/AST/DeclNodes.inc"
+ }
+}
+
+template<typename DeclT>
+void ASTDeclReader::markIncompleteDeclChainImpl(Redeclarable<DeclT> *D) {
+ D->RedeclLink.markIncomplete();
+}
+void ASTDeclReader::markIncompleteDeclChainImpl(...) {
+ llvm_unreachable("markIncompleteDeclChain on non-redeclarable declaration");
+}
+
+void ASTReader::markIncompleteDeclChain(Decl *D) {
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ ASTDeclReader::markIncompleteDeclChainImpl(cast<TYPE##Decl>(D)); \
+ break;
+#include "clang/AST/DeclNodes.inc"
+ }
+}
+
+/// \brief Read the declaration at the given offset from the AST file.
+Decl *ASTReader::ReadDeclRecord(DeclID ID) {
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+ unsigned RawLocation = 0;
+ RecordLocation Loc = DeclCursorForID(ID, RawLocation);
+ llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this declaration.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+
+ // Note that we are loading a declaration record.
+ Deserializing ADecl(this);
+
+ DeclsCursor.JumpToBit(Loc.Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned Idx = 0;
+ ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
+
+ Decl *D = nullptr;
+ switch ((DeclCode)DeclsCursor.readRecord(Code, Record)) {
+ case DECL_CONTEXT_LEXICAL:
+ case DECL_CONTEXT_VISIBLE:
+ llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
+ case DECL_TYPEDEF:
+ D = TypedefDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_TYPEALIAS:
+ D = TypeAliasDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_ENUM:
+ D = EnumDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_RECORD:
+ D = RecordDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_ENUM_CONSTANT:
+ D = EnumConstantDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_FUNCTION:
+ D = FunctionDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_LINKAGE_SPEC:
+ D = LinkageSpecDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_LABEL:
+ D = LabelDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_NAMESPACE:
+ D = NamespaceDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_NAMESPACE_ALIAS:
+ D = NamespaceAliasDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_USING:
+ D = UsingDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_USING_SHADOW:
+ D = UsingShadowDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_USING_DIRECTIVE:
+ D = UsingDirectiveDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_UNRESOLVED_USING_VALUE:
+ D = UnresolvedUsingValueDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_UNRESOLVED_USING_TYPENAME:
+ D = UnresolvedUsingTypenameDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CXX_RECORD:
+ D = CXXRecordDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CXX_METHOD:
+ D = CXXMethodDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CXX_CONSTRUCTOR:
+ D = CXXConstructorDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CXX_DESTRUCTOR:
+ D = CXXDestructorDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CXX_CONVERSION:
+ D = CXXConversionDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_ACCESS_SPEC:
+ D = AccessSpecDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_FRIEND:
+ D = FriendDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_FRIEND_TEMPLATE:
+ D = FriendTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CLASS_TEMPLATE:
+ D = ClassTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CLASS_TEMPLATE_SPECIALIZATION:
+ D = ClassTemplateSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
+ D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE:
+ D = VarTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_SPECIALIZATION:
+ D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION:
+ D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
+ D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_FUNCTION_TEMPLATE:
+ D = FunctionTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_TEMPLATE_TYPE_PARM:
+ D = TemplateTypeParmDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_NON_TYPE_TEMPLATE_PARM:
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_TEMPLATE_TEMPLATE_PARM:
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
+ Record[Idx++]);
+ break;
+ case DECL_TYPE_ALIAS_TEMPLATE:
+ D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_STATIC_ASSERT:
+ D = StaticAssertDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_METHOD:
+ D = ObjCMethodDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_INTERFACE:
+ D = ObjCInterfaceDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_IVAR:
+ D = ObjCIvarDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_PROTOCOL:
+ D = ObjCProtocolDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_AT_DEFS_FIELD:
+ D = ObjCAtDefsFieldDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_CATEGORY:
+ D = ObjCCategoryDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_CATEGORY_IMPL:
+ D = ObjCCategoryImplDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_IMPLEMENTATION:
+ D = ObjCImplementationDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_COMPATIBLE_ALIAS:
+ D = ObjCCompatibleAliasDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_PROPERTY:
+ D = ObjCPropertyDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_OBJC_PROPERTY_IMPL:
+ D = ObjCPropertyImplDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_FIELD:
+ D = FieldDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_INDIRECTFIELD:
+ D = IndirectFieldDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_VAR:
+ D = VarDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_IMPLICIT_PARAM:
+ D = ImplicitParamDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_PARM_VAR:
+ D = ParmVarDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_FILE_SCOPE_ASM:
+ D = FileScopeAsmDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_BLOCK:
+ D = BlockDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_MS_PROPERTY:
+ D = MSPropertyDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_CAPTURED:
+ D = CapturedDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_CXX_BASE_SPECIFIERS:
+ Error("attempt to read a C++ base-specifier record as a declaration");
+ return nullptr;
+ case DECL_CXX_CTOR_INITIALIZERS:
+ Error("attempt to read a C++ ctor initializer record as a declaration");
+ return nullptr;
+ case DECL_IMPORT:
+ // Note: last entry of the ImportDecl record is the number of stored source
+ // locations.
+ D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
+ break;
+ case DECL_OMP_THREADPRIVATE:
+ D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_EMPTY:
+ D = EmptyDecl::CreateDeserialized(Context, ID);
+ break;
+ }
+
+ assert(D && "Unknown declaration reading AST file");
+ LoadedDecl(Index, D);
+ // Set the DeclContext before doing any deserialization, to make sure internal
+ // calls to Decl::getASTContext() by Decl's methods will find the
+ // TranslationUnitDecl without crashing.
+ D->setDeclContext(Context.getTranslationUnitDecl());
+ Reader.Visit(D);
+
+ // If this declaration is also a declaration context, get the
+ // offsets for its tables of lexical and visible declarations.
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ // FIXME: This should really be
+ // DeclContext *LookupDC = DC->getPrimaryContext();
+ // but that can walk the redeclaration chain, which might not work yet.
+ DeclContext *LookupDC = DC;
+ if (isa<NamespaceDecl>(DC))
+ LookupDC = DC->getPrimaryContext();
+ std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
+ if (Offsets.first || Offsets.second) {
+ if (Offsets.first != 0)
+ DC->setHasExternalLexicalStorage(true);
+ if (Offsets.second != 0)
+ LookupDC->setHasExternalVisibleStorage(true);
+ if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
+ Loc.F->DeclContextInfos[DC]))
+ return nullptr;
+ }
+
+ // Now add the pending visible updates for this decl context, if it has any.
+ DeclContextVisibleUpdatesPending::iterator I =
+ PendingVisibleUpdates.find(ID);
+ if (I != PendingVisibleUpdates.end()) {
+ // There are updates. This means the context has external visible
+ // storage, even if the original stored version didn't.
+ LookupDC->setHasExternalVisibleStorage(true);
+ for (const auto &Update : I->second) {
+ DeclContextInfo &Info = Update.second->DeclContextInfos[DC];
+ delete Info.NameLookupTableData;
+ Info.NameLookupTableData = Update.first;
+ }
+ PendingVisibleUpdates.erase(I);
+ }
+ }
+ assert(Idx == Record.size());
+
+ // Load any relevant update records.
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
+
+ // Load the categories after recursive loading is finished.
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
+ if (Class->isThisDeclarationADefinition())
+ loadObjCCategories(ID, Class);
+
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, queue it.
+ // We don't pass it to the consumer immediately because we may be in recursive
+ // loading, and some declarations may still be initializing.
+ if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
+ InterestingDecls.push_back(D);
+
+ return D;
+}
+
+void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
+ // The declaration may have been modified by files later in the chain.
+ // If this is the case, read the record containing the updates from each file
+ // and pass it to ASTDeclReader to make the modifications.
+ DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
+ if (UpdI != DeclUpdateOffsets.end()) {
+ FileOffsetsTy &UpdateOffsets = UpdI->second;
+ bool WasInteresting = isConsumerInterestedIn(D, false);
+ for (FileOffsetsTy::iterator
+ I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
+ ModuleFile *F = I->first;
+ uint64_t Offset = I->second;
+ llvm::BitstreamCursor &Cursor = F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record);
+ (void)RecCode;
+ assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
+
+ unsigned Idx = 0;
+ ASTDeclReader Reader(*this, *F, ID, 0, Record, Idx);
+ Reader.UpdateDecl(D, *F, Record);
+
+ // We might have made this declaration interesting. If so, remember that
+ // we need to hand it off to the consumer.
+ if (!WasInteresting &&
+ isConsumerInterestedIn(D, Reader.hasPendingBody())) {
+ InterestingDecls.push_back(D);
+ WasInteresting = true;
+ }
+ }
+ }
+}
+
+namespace {
+ /// \brief Module visitor class that finds all of the redeclarations of a
+ /// redeclarable declaration.
+ class RedeclChainVisitor {
+ ASTReader &Reader;
+ SmallVectorImpl<DeclID> &SearchDecls;
+ llvm::SmallPtrSetImpl<Decl *> &Deserialized;
+ GlobalDeclID CanonID;
+ SmallVector<Decl *, 4> Chain;
+
+ public:
+ RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
+ llvm::SmallPtrSetImpl<Decl *> &Deserialized,
+ GlobalDeclID CanonID)
+ : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
+ CanonID(CanonID) {
+ // Ensure that the canonical ID goes at the start of the chain.
+ addToChain(Reader.GetDecl(CanonID));
+ }
+
+ static ModuleManager::DFSPreorderControl
+ visitPreorder(ModuleFile &M, void *UserData) {
+ return static_cast<RedeclChainVisitor *>(UserData)->visitPreorder(M);
+ }
+
+ static bool visitPostorder(ModuleFile &M, void *UserData) {
+ return static_cast<RedeclChainVisitor *>(UserData)->visitPostorder(M);
+ }
+
+ void addToChain(Decl *D) {
+ if (!D)
+ return;
+
+ if (Deserialized.erase(D))
+ Chain.push_back(D);
+ }
+
+ void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
+ // Map global ID of the first declaration down to the local ID
+ // used in this module file.
+ DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
+ if (!ID)
+ return;
+
+ // If the search decl was from this module, add it to the chain before any
+ // of its redeclarations in this module or users of it, and after any from
+ // imported modules.
+ if (CanonID != GlobalID && Reader.isDeclIDFromModule(GlobalID, M))
+ addToChain(Reader.GetDecl(GlobalID));
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const LocalRedeclarationsInfo Compare = { ID, 0 };
+ const LocalRedeclarationsInfo *Result
+ = std::lower_bound(M.RedeclarationsMap,
+ M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
+ Compare);
+ if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
+ Result->FirstID != ID) {
+ // If we have a previously-canonical singleton declaration that was
+ // merged into another redeclaration chain, create a trivial chain
+ // for this single declaration so that it will get wired into the
+ // complete redeclaration chain.
+ if (GlobalID != CanonID &&
+ GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID &&
+ GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) {
+ addToChain(Reader.GetDecl(GlobalID));
+ }
+
+ return;
+ }
+
+ // Dig out all of the redeclarations.
+ unsigned Offset = Result->Offset;
+ unsigned N = M.RedeclarationChains[Offset];
+ M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
+ }
+
+ bool needsToVisitImports(ModuleFile &M, GlobalDeclID GlobalID) {
+ DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
+ if (!ID)
+ return false;
+
+ const LocalRedeclarationsInfo Compare = {ID, 0};
+ const LocalRedeclarationsInfo *Result = std::lower_bound(
+ M.RedeclarationsMap,
+ M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare);
+ if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
+ Result->FirstID != ID) {
+ return true;
+ }
+ unsigned Offset = Result->Offset;
+ unsigned N = M.RedeclarationChains[Offset];
+ // We don't need to visit a module or any of its imports if we've already
+ // deserialized the redecls from this module.
+ return N != 0;
+ }
+
+ ModuleManager::DFSPreorderControl visitPreorder(ModuleFile &M) {
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) {
+ if (needsToVisitImports(M, SearchDecls[I]))
+ return ModuleManager::Continue;
+ }
+ return ModuleManager::SkipImports;
+ }
+
+ bool visitPostorder(ModuleFile &M) {
+ // Visit each of the declarations.
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
+ searchForID(M, SearchDecls[I]);
+ // FIXME: If none of the SearchDecls had local IDs in this module, can
+ // we avoid searching any ancestor module files?
+ return false;
+ }
+
+ ArrayRef<Decl *> getChain() const {
+ return Chain;
+ }
+ };
+}
+
+void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
+ // The decl might have been merged into something else after being added to
+ // our list. If it was, just skip it.
+ if (!CanonDecl->isCanonicalDecl())
+ return;
+
+ // Determine the set of declaration IDs we'll be searching for.
+ SmallVector<DeclID, 16> SearchDecls;
+ GlobalDeclID CanonID = CanonDecl->getGlobalID();
+ if (CanonID)
+ SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first.
+ MergedDeclsMap::iterator MergedPos = MergedDecls.find(CanonDecl);
+ if (MergedPos != MergedDecls.end())
+ SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
+
+ // Build up the list of redeclarations.
+ RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
+ ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visitPreorder,
+ &RedeclChainVisitor::visitPostorder, &Visitor);
+
+ // Retrieve the chains.
+ ArrayRef<Decl *> Chain = Visitor.getChain();
+ if (Chain.empty() || (Chain.size() == 1 && Chain[0] == CanonDecl))
+ return;
+
+ // Hook up the chains.
+ //
+ // FIXME: We have three different dispatches on decl kind here; maybe
+ // we should instead generate one loop per kind and dispatch up-front?
+ Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl);
+ if (!MostRecent)
+ MostRecent = CanonDecl;
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (Chain[I] == CanonDecl)
+ continue;
+
+ ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl);
+ MostRecent = Chain[I];
+ }
+ ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
+}
+
+namespace {
+ /// \brief Given an ObjC interface, goes through the modules and links to the
+ /// interface all the categories for it.
+ class ObjCCategoriesVisitor {
+ ASTReader &Reader;
+ serialization::GlobalDeclID InterfaceID;
+ ObjCInterfaceDecl *Interface;
+ llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized;
+ unsigned PreviousGeneration;
+ ObjCCategoryDecl *Tail;
+ llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;
+
+ void add(ObjCCategoryDecl *Cat) {
+ // Only process each category once.
+ if (!Deserialized.erase(Cat))
+ return;
+
+ // Check for duplicate categories.
+ if (Cat->getDeclName()) {
+ ObjCCategoryDecl *&Existing = NameCategoryMap[Cat->getDeclName()];
+ if (Existing &&
+ Reader.getOwningModuleFile(Existing)
+ != Reader.getOwningModuleFile(Cat)) {
+ // FIXME: We should not warn for duplicates in diamond:
+ //
+ // MT //
+ // / \ //
+ // ML MR //
+ // \ / //
+ // MB //
+ //
+ // If there are duplicates in ML/MR, there will be warning when
+ // creating MB *and* when importing MB. We should not warn when
+ // importing.
+ Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
+ << Interface->getDeclName() << Cat->getDeclName();
+ Reader.Diag(Existing->getLocation(), diag::note_previous_definition);
+ } else if (!Existing) {
+ // Record this category.
+ Existing = Cat;
+ }
+ }
+
+ // Add this category to the end of the chain.
+ if (Tail)
+ ASTDeclReader::setNextObjCCategory(Tail, Cat);
+ else
+ Interface->setCategoryListRaw(Cat);
+ Tail = Cat;
+ }
+
+ public:
+ ObjCCategoriesVisitor(ASTReader &Reader,
+ serialization::GlobalDeclID InterfaceID,
+ ObjCInterfaceDecl *Interface,
+ llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized,
+ unsigned PreviousGeneration)
+ : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
+ Deserialized(Deserialized), PreviousGeneration(PreviousGeneration),
+ Tail(nullptr)
+ {
+ // Populate the name -> category map with the set of known categories.
+ for (auto *Cat : Interface->known_categories()) {
+ if (Cat->getDeclName())
+ NameCategoryMap[Cat->getDeclName()] = Cat;
+
+ // Keep track of the tail of the category list.
+ Tail = Cat;
+ }
+ }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ return static_cast<ObjCCategoriesVisitor *>(UserData)->visit(M);
+ }
+
+ bool visit(ModuleFile &M) {
+ // If we've loaded all of the category information we care about from
+ // this module file, we're done.
+ if (M.Generation <= PreviousGeneration)
+ return true;
+
+ // Map global ID of the definition down to the local ID used in this
+ // module file. If there is no such mapping, we'll find nothing here
+ // (or in any module it imports).
+ DeclID LocalID = Reader.mapGlobalIDToModuleFileGlobalID(M, InterfaceID);
+ if (!LocalID)
+ return true;
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const ObjCCategoriesInfo Compare = { LocalID, 0 };
+ const ObjCCategoriesInfo *Result
+ = std::lower_bound(M.ObjCCategoriesMap,
+ M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap,
+ Compare);
+ if (Result == M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap ||
+ Result->DefinitionID != LocalID) {
+ // We didn't find anything. If the class definition is in this module
+ // file, then the module files it depends on cannot have any categories,
+ // so suppress further lookup.
+ return Reader.isDeclIDFromModule(InterfaceID, M);
+ }
+
+ // We found something. Dig out all of the categories.
+ unsigned Offset = Result->Offset;
+ unsigned N = M.ObjCCategories[Offset];
+ M.ObjCCategories[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ add(cast_or_null<ObjCCategoryDecl>(
+ Reader.GetLocalDecl(M, M.ObjCCategories[Offset++])));
+ return true;
+ }
+ };
+}
+
+void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID,
+ ObjCInterfaceDecl *D,
+ unsigned PreviousGeneration) {
+ ObjCCategoriesVisitor Visitor(*this, ID, D, CategoriesDeserialized,
+ PreviousGeneration);
+ ModuleMgr.visit(ObjCCategoriesVisitor::visit, &Visitor);
+}
+
+namespace {
+/// Iterator over the redeclarations of a declaration that have already
+/// been merged into the same redeclaration chain.
+template<typename DeclT>
+class MergedRedeclIterator {
+ DeclT *Start, *Canonical, *Current;
+public:
+ MergedRedeclIterator() : Current(nullptr) {}
+ MergedRedeclIterator(DeclT *Start)
+ : Start(Start), Canonical(nullptr), Current(Start) {}
+
+ DeclT *operator*() { return Current; }
+
+ MergedRedeclIterator &operator++() {
+ if (Current->isFirstDecl()) {
+ Canonical = Current;
+ Current = Current->getMostRecentDecl();
+ } else
+ Current = Current->getPreviousDecl();
+
+ // If we started in the merged portion, we'll reach our start position
+ // eventually. Otherwise, we'll never reach it, but the second declaration
+ // we reached was the canonical declaration, so stop when we see that one
+ // again.
+ if (Current == Start || Current == Canonical)
+ Current = nullptr;
+ return *this;
+ }
+
+ friend bool operator!=(const MergedRedeclIterator &A,
+ const MergedRedeclIterator &B) {
+ return A.Current != B.Current;
+ }
+};
+}
+template<typename DeclT>
+llvm::iterator_range<MergedRedeclIterator<DeclT>> merged_redecls(DeclT *D) {
+ return llvm::iterator_range<MergedRedeclIterator<DeclT>>(
+ MergedRedeclIterator<DeclT>(D),
+ MergedRedeclIterator<DeclT>());
+}
+
+template<typename DeclT, typename Fn>
+static void forAllLaterRedecls(DeclT *D, Fn F) {
+ F(D);
+
+ // Check whether we've already merged D into its redeclaration chain.
+ // MostRecent may or may not be nullptr if D has not been merged. If
+ // not, walk the merged redecl chain and see if it's there.
+ auto *MostRecent = D->getMostRecentDecl();
+ bool Found = false;
+ for (auto *Redecl = MostRecent; Redecl && !Found;
+ Redecl = Redecl->getPreviousDecl())
+ Found = (Redecl == D);
+
+ // If this declaration is merged, apply the functor to all later decls.
+ if (Found) {
+ for (auto *Redecl = MostRecent; Redecl != D;
+ Redecl = Redecl->getPreviousDecl())
+ F(Redecl);
+ }
+}
+
+void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
+ const RecordData &Record) {
+ while (Idx < Record.size()) {
+ switch ((DeclUpdateKind)Record[Idx++]) {
+ case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ // FIXME: If we also have an update record for instantiating the
+ // definition of D, we need that to happen before we get here.
+ Decl *MD = Reader.ReadDecl(ModuleFile, Record, Idx);
+ assert(MD && "couldn't read decl from update record");
+ // FIXME: We should call addHiddenDecl instead, to add the member
+ // to its DeclContext.
+ RD->addedMember(MD);
+
+ // If we've added a new special member to a class definition that is not
+ // the canonical definition, then we need special member lookups in the
+ // canonical definition to also look into our class.
+ auto *DD = RD->DefinitionData.getNotUpdated();
+ if (DD && DD->Definition != RD) {
+ auto &Merged = Reader.MergedLookups[DD->Definition];
+ // FIXME: Avoid the linear-time scan here.
+ if (std::find(Merged.begin(), Merged.end(), RD) == Merged.end())
+ Merged.push_back(RD);
+ }
+ break;
+ }
+
+ case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
+ // It will be added to the template's specializations set when loaded.
+ (void)Reader.ReadDecl(ModuleFile, Record, Idx);
+ break;
+
+ case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
+ NamespaceDecl *Anon
+ = Reader.ReadDeclAs<NamespaceDecl>(ModuleFile, Record, Idx);
+
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ if (ModuleFile.Kind != MK_ImplicitModule &&
+ ModuleFile.Kind != MK_ExplicitModule) {
+ if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
+ TU->setAnonymousNamespace(Anon);
+ else
+ cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon);
+ }
+ break;
+ }
+
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
+ Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ break;
+
+ case UPD_CXX_ADDED_FUNCTION_DEFINITION: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (Reader.PendingBodies[FD]) {
+ // FIXME: Maybe check for ODR violations.
+ // It's safe to stop now because this update record is always last.
+ return;
+ }
+
+ if (Record[Idx++]) {
+ // Maintain AST consistency: any later redeclarations of this function
+ // are inline if this one is. (We might have merged another declaration
+ // into this one.)
+ forAllLaterRedecls(FD, [](FunctionDecl *FD) {
+ FD->setImplicitlyInline();
+ });
+ }
+ FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ CD->NumCtorInitializers = Record[Idx++];
+ if (CD->NumCtorInitializers)
+ CD->CtorInitializers =
+ Reader.ReadCXXCtorInitializersRef(F, Record, Idx);
+ }
+ // Store the offset of the body so we can lazily load it later.
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ assert(Idx == Record.size() && "lazy body must be last");
+ break;
+ }
+
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ auto *OldDD = RD->DefinitionData.getNotUpdated();
+ bool HadRealDefinition =
+ OldDD && (OldDD->Definition != RD ||
+ !Reader.PendingFakeDefinitionData.count(OldDD));
+ ReadCXXRecordDefinition(RD, /*Update*/true);
+
+ // Visible update is handled separately.
+ uint64_t LexicalOffset = Record[Idx++];
+ if (!HadRealDefinition && LexicalOffset) {
+ RD->setHasExternalLexicalStorage(true);
+ Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor,
+ std::make_pair(LexicalOffset, 0),
+ ModuleFile.DeclContextInfos[RD]);
+ Reader.PendingFakeDefinitionData.erase(OldDD);
+ }
+
+ auto TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(ModuleFile, Record, Idx);
+ if (MemberSpecializationInfo *MSInfo =
+ RD->getMemberSpecializationInfo()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ MSInfo->setPointOfInstantiation(POI);
+ } else {
+ ClassTemplateSpecializationDecl *Spec =
+ cast<ClassTemplateSpecializationDecl>(RD);
+ Spec->setTemplateSpecializationKind(TSK);
+ Spec->setPointOfInstantiation(POI);
+
+ if (Record[Idx++]) {
+ auto PartialSpec =
+ ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx);
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ auto *TemplArgList = TemplateArgumentList::CreateCopy(
+ Reader.getContext(), TemplArgs.data(), TemplArgs.size());
+
+ // FIXME: If we already have a partial specialization set,
+ // check that it matches.
+ if (!Spec->getSpecializedTemplateOrPartial()
+ .is<ClassTemplatePartialSpecializationDecl *>())
+ Spec->setInstantiationOf(PartialSpec, TemplArgList);
+ }
+ }
+
+ RD->setTagKind((TagTypeKind)Record[Idx++]);
+ RD->setLocation(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setRBraceLoc(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+
+ if (Record[Idx++]) {
+ AttrVec Attrs;
+ Reader.ReadAttributes(F, Attrs, Record, Idx);
+ D->setAttrsImpl(Attrs, Reader.getContext());
+ }
+ break;
+ }
+
+ case UPD_CXX_RESOLVED_DTOR_DELETE: {
+ // Set the 'operator delete' directly to avoid emitting another update
+ // record.
+ auto *Del = Reader.ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!First->OperatorDelete)
+ First->OperatorDelete = Del;
+ break;
+ }
+
+ case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
+ FunctionProtoType::ExceptionSpecInfo ESI;
+ SmallVector<QualType, 8> ExceptionStorage;
+ Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx);
+
+ // Update this declaration's exception specification, if needed.
+ auto *FD = cast<FunctionDecl>(D);
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ // FIXME: If the exception specification is already present, check that it
+ // matches.
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ FD->setType(Reader.Context.getFunctionType(
+ FPT->getReturnType(), FPT->getParamTypes(),
+ FPT->getExtProtoInfo().withExceptionSpec(ESI)));
+
+ // When we get to the end of deserializing, see if there are other decls
+ // that we need to propagate this exception specification onto.
+ Reader.PendingExceptionSpecUpdates.insert(
+ std::make_pair(FD->getCanonicalDecl(), FD));
+ }
+ break;
+ }
+
+ case UPD_CXX_DEDUCED_RETURN_TYPE: {
+ // FIXME: Also do this when merging redecls.
+ QualType DeducedResultType = Reader.readType(ModuleFile, Record, Idx);
+ for (auto *Redecl : merged_redecls(D)) {
+ // FIXME: If the return type is already deduced, check that it matches.
+ FunctionDecl *FD = cast<FunctionDecl>(Redecl);
+ Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType);
+ }
+ break;
+ }
+
+ case UPD_DECL_MARKED_USED: {
+ // FIXME: This doesn't send the right notifications if there are
+ // ASTMutationListeners other than an ASTWriter.
+
+ // Maintain AST consistency: any later redeclarations are used too.
+ forAllLaterRedecls(D, [](Decl *D) { D->Used = true; });
+ break;
+ }
+
+ case UPD_MANGLING_NUMBER:
+ Reader.Context.setManglingNumber(cast<NamedDecl>(D), Record[Idx++]);
+ break;
+
+ case UPD_STATIC_LOCAL_NUMBER:
+ Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
+ break;
+
+ case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
+ D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
+ Reader.Context, ReadSourceRange(Record, Idx)));
+ break;
+
+ case UPD_DECL_EXPORTED:
+ unsigned SubmoduleID = readSubmoduleID(Record, Idx);
+ Module *Owner = SubmoduleID ? Reader.getSubmodule(SubmoduleID) : nullptr;
+ if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ // FIXME: This doesn't send the right notifications if there are
+ // ASTMutationListeners other than an ASTWriter.
+ Reader.getContext().mergeDefinitionIntoModule(cast<NamedDecl>(D), Owner,
+ /*NotifyListeners*/false);
+ Reader.PendingMergedDefinitionsToDeduplicate.insert(cast<NamedDecl>(D));
+ } else if (Owner && Owner->NameVisibility != Module::AllVisible) {
+ // If Owner is made visible at some later point, make this declaration
+ // visible too.
+ Reader.HiddenNamesMap[Owner].push_back(D);
+ } else {
+ // The declaration is now visible.
+ D->Hidden = false;
+ }
+ break;
+ }
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h
new file mode 100644
index 0000000..d1b032b
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h
@@ -0,0 +1,249 @@
+//===--- ASTReaderInternals.h - AST Reader Internals ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides internal definitions used in the AST reader.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H
+#define LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include <utility>
+
+namespace clang {
+
+class ASTReader;
+class HeaderSearch;
+struct HeaderFileInfo;
+class FileEntry;
+
+namespace serialization {
+
+class ModuleFile;
+
+namespace reader {
+
+/// \brief Class that performs name lookup into a DeclContext stored
+/// in an AST file.
+class ASTDeclContextNameLookupTrait {
+ ASTReader &Reader;
+ ModuleFile &F;
+
+public:
+ /// \brief Pair of begin/end iterators for DeclIDs.
+ ///
+ /// Note that these declaration IDs are local to the module that contains this
+ /// particular lookup t
+ typedef llvm::support::ulittle32_t LE32DeclID;
+ typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ /// \brief Special internal key for declaration names.
+ /// The hash table creates keys for comparison; we do not create
+ /// a DeclarationName for the internal key to avoid deserializing types.
+ struct DeclNameKey {
+ DeclarationName::NameKind Kind;
+ uint64_t Data;
+ DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { }
+ };
+
+ typedef DeclarationName external_key_type;
+ typedef DeclNameKey internal_key_type;
+
+ explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F)
+ : Reader(Reader), F(F) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a.Kind == b.Kind && a.Data == b.Data;
+ }
+
+ hash_value_type ComputeHash(const DeclNameKey &Key) const;
+ internal_key_type GetInternalKey(const external_key_type& Name) const;
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ internal_key_type ReadKey(const unsigned char* d, unsigned);
+
+ data_type ReadData(internal_key_type, const unsigned char* d,
+ unsigned DataLen);
+};
+
+/// \brief Base class for the trait describing the on-disk hash table for the
+/// identifiers in an AST file.
+///
+/// This class is not useful by itself; rather, it provides common
+/// functionality for accessing the on-disk hash table of identifiers
+/// in an AST file. Different subclasses customize that functionality
+/// based on what information they are interested in. Those subclasses
+/// must provide the \c data_type typedef and the ReadData operation,
+/// only.
+class ASTIdentifierLookupTraitBase {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
+ return a == b;
+ }
+
+ static hash_value_type ComputeHash(const internal_key_type& a);
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n);
+};
+
+/// \brief Class that performs lookup for an identifier stored in an AST file.
+class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
+ ASTReader &Reader;
+ ModuleFile &F;
+
+ // 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 AST file was read.
+ IdentifierInfo *KnownII;
+
+public:
+ typedef IdentifierInfo * data_type;
+
+ ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F,
+ IdentifierInfo *II = nullptr)
+ : Reader(Reader), F(F), KnownII(II) { }
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen);
+
+ ASTReader &getReader() const { return Reader; }
+};
+
+/// \brief The on-disk hash table used to contain information about
+/// all of the identifiers in the program.
+typedef llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>
+ ASTIdentifierLookupTable;
+
+/// \brief Class that performs lookup for a selector's entries in the global
+/// method pool stored in an AST file.
+class ASTSelectorLookupTrait {
+ ASTReader &Reader;
+ ModuleFile &F;
+
+public:
+ struct data_type {
+ SelectorID ID;
+ unsigned InstanceBits;
+ unsigned FactoryBits;
+ bool InstanceHasMoreThanOneDecl;
+ bool FactoryHasMoreThanOneDecl;
+ SmallVector<ObjCMethodDecl *, 2> Instance;
+ SmallVector<ObjCMethodDecl *, 2> Factory;
+ };
+
+ typedef Selector external_key_type;
+ typedef external_key_type internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F)
+ : Reader(Reader), F(F) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a == b;
+ }
+
+ static hash_value_type ComputeHash(Selector Sel);
+
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ internal_key_type ReadKey(const unsigned char* d, unsigned);
+ data_type ReadData(Selector, const unsigned char* d, unsigned DataLen);
+};
+
+/// \brief The on-disk hash table used for the global method pool.
+typedef llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>
+ ASTSelectorLookupTable;
+
+/// \brief Trait class used to search the on-disk hash table containing all of
+/// the header search information.
+///
+/// The on-disk hash table contains a mapping from each header path to
+/// information about that header (how many times it has been included, its
+/// controlling macro, etc.). Note that we actually hash based on the size
+/// and mtime, and support "deep" comparisons of file names based on current
+/// inode numbers, so that the search can cope with non-normalized path names
+/// and symlinks.
+class HeaderFileInfoTrait {
+ ASTReader &Reader;
+ ModuleFile &M;
+ HeaderSearch *HS;
+ const char *FrameworkStrings;
+
+public:
+ typedef const FileEntry *external_key_type;
+
+ struct internal_key_type {
+ off_t Size;
+ time_t ModTime;
+ const char *Filename;
+ bool Imported;
+ };
+ typedef const internal_key_type &internal_key_ref;
+
+ typedef HeaderFileInfo data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
+ const char *FrameworkStrings)
+ : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
+
+ static hash_value_type ComputeHash(internal_key_ref ikey);
+ static internal_key_type GetInternalKey(const FileEntry *FE);
+ bool EqualKey(internal_key_ref a, internal_key_ref b);
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ static internal_key_type ReadKey(const unsigned char *d, unsigned);
+
+ data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);
+};
+
+/// \brief The on-disk hash table used for known header files.
+typedef llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>
+ HeaderFileInfoLookupTable;
+
+} // end namespace clang::serialization::reader
+} // end namespace clang::serialization
+} // end namespace clang
+
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
new file mode 100644
index 0000000..d1ecd46
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -0,0 +1,3058 @@
+//===--- ASTReaderStmt.cpp - Stmt/Expr Deserialization ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Statement/expression deserialization. This implements the
+// ASTReader::ReadStmt method.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTReader.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Token.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+using namespace clang::serialization;
+
+namespace clang {
+
+ class ASTStmtReader : public StmtVisitor<ASTStmtReader> {
+ friend class OMPClauseReader;
+ typedef ASTReader::RecordData RecordData;
+
+ ASTReader &Reader;
+ ModuleFile &F;
+ llvm::BitstreamCursor &DeclsCursor;
+ const ASTReader::RecordData &Record;
+ unsigned &Idx;
+
+ Token ReadToken(const RecordData &R, unsigned &I) {
+ return Reader.ReadToken(F, R, I);
+ }
+
+ SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
+ return Reader.ReadSourceLocation(F, R, I);
+ }
+
+ SourceRange ReadSourceRange(const RecordData &R, unsigned &I) {
+ return Reader.ReadSourceRange(F, R, I);
+ }
+
+ std::string ReadString(const RecordData &R, unsigned &I) {
+ return Reader.ReadString(R, I);
+ }
+
+ TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) {
+ return Reader.GetTypeSourceInfo(F, R, I);
+ }
+
+ serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclID(F, R, I);
+ }
+
+ Decl *ReadDecl(const RecordData &R, unsigned &I) {
+ return Reader.ReadDecl(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const RecordData &R, unsigned &I) {
+ return Reader.ReadDeclAs<T>(F, R, I);
+ }
+
+ void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name,
+ const ASTReader::RecordData &R, unsigned &I) {
+ Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I);
+ }
+
+ void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo,
+ const ASTReader::RecordData &R, unsigned &I) {
+ Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
+ }
+
+ public:
+ ASTStmtReader(ASTReader &Reader, ModuleFile &F,
+ llvm::BitstreamCursor &Cursor,
+ const ASTReader::RecordData &Record, unsigned &Idx)
+ : Reader(Reader), F(F), DeclsCursor(Cursor), Record(Record), Idx(Idx) { }
+
+ /// \brief The number of record fields required for the Stmt class
+ /// itself.
+ static const unsigned NumStmtFields = 0;
+
+ /// \brief The number of record fields required for the Expr class
+ /// itself.
+ static const unsigned NumExprFields = NumStmtFields + 7;
+
+ /// \brief Read and initialize a ExplicitTemplateArgumentList structure.
+ void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ unsigned NumTemplateArgs);
+ /// \brief Read and initialize a ExplicitTemplateArgumentList structure.
+ void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
+ unsigned NumTemplateArgs);
+
+ void VisitStmt(Stmt *S);
+#define STMT(Type, Base) \
+ void Visit##Type(Type *);
+#include "clang/AST/StmtNodes.inc"
+ };
+}
+
+void ASTStmtReader::
+ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ unsigned NumTemplateArgs) {
+ SourceLocation TemplateKWLoc = ReadSourceLocation(Record, Idx);
+ TemplateArgumentListInfo ArgInfo;
+ ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ ArgInfo.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ ArgInfo.addArgument(
+ Reader.ReadTemplateArgumentLoc(F, Record, Idx));
+ Args.initializeFrom(TemplateKWLoc, ArgInfo);
+}
+
+void ASTStmtReader::VisitStmt(Stmt *S) {
+ assert(Idx == NumStmtFields && "Incorrect statement field count");
+}
+
+void ASTStmtReader::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ S->setSemiLoc(ReadSourceLocation(Record, Idx));
+ S->HasLeadingEmptyMacro = Record[Idx++];
+}
+
+void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ SmallVector<Stmt *, 16> Stmts;
+ unsigned NumStmts = Record[Idx++];
+ while (NumStmts--)
+ Stmts.push_back(Reader.ReadSubStmt());
+ S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size());
+ S->LBraceLoc = ReadSourceLocation(Record, Idx);
+ S->RBraceLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Reader.RecordSwitchCaseID(S, Record[Idx++]);
+ S->setKeywordLoc(ReadSourceLocation(Record, Idx));
+ S->setColonLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ S->setLHS(Reader.ReadSubExpr());
+ S->setRHS(Reader.ReadSubExpr());
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setEllipsisLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ S->setSubStmt(Reader.ReadSubStmt());
+}
+
+void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ LabelDecl *LD = ReadDeclAs<LabelDecl>(Record, Idx);
+ LD->setStmt(S);
+ S->setDecl(LD);
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setIdentLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
+ VisitStmt(S);
+ uint64_t NumAttrs = Record[Idx++];
+ AttrVec Attrs;
+ Reader.ReadAttributes(F, Attrs, Record, Idx);
+ (void)NumAttrs;
+ assert(NumAttrs == S->NumAttrs);
+ assert(NumAttrs == Attrs.size());
+ std::copy(Attrs.begin(), Attrs.end(), S->getAttrArrayPtr());
+ S->SubStmt = Reader.ReadSubStmt();
+ S->AttrLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
+ S->setCond(Reader.ReadSubExpr());
+ S->setThen(Reader.ReadSubStmt());
+ S->setElse(Reader.ReadSubStmt());
+ S->setIfLoc(ReadSourceLocation(Record, Idx));
+ S->setElseLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setSwitchLoc(ReadSourceLocation(Record, Idx));
+ if (Record[Idx++])
+ S->setAllEnumCasesCovered();
+
+ SwitchCase *PrevSC = nullptr;
+ for (unsigned N = Record.size(); Idx != N; ++Idx) {
+ SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
+ if (PrevSC)
+ PrevSC->setNextSwitchCase(SC);
+ else
+ S->setSwitchCaseList(SC);
+
+ PrevSC = SC;
+ }
+}
+
+void ASTStmtReader::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
+
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setWhileLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setDoLoc(ReadSourceLocation(Record, Idx));
+ S->setWhileLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ S->setInit(Reader.ReadSubStmt());
+ S->setCond(Reader.ReadSubExpr());
+ S->setConditionVariable(Reader.getContext(),
+ ReadDeclAs<VarDecl>(Record, Idx));
+ S->setInc(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setForLoc(ReadSourceLocation(Record, Idx));
+ S->setLParenLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ S->setLabel(ReadDeclAs<LabelDecl>(Record, Idx));
+ S->setGotoLoc(ReadSourceLocation(Record, Idx));
+ S->setLabelLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ S->setGotoLoc(ReadSourceLocation(Record, Idx));
+ S->setStarLoc(ReadSourceLocation(Record, Idx));
+ S->setTarget(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ S->setContinueLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ S->setBreakLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ S->setRetValue(Reader.ReadSubExpr());
+ S->setReturnLoc(ReadSourceLocation(Record, Idx));
+ S->setNRVOCandidate(ReadDeclAs<VarDecl>(Record, Idx));
+}
+
+void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ S->setStartLoc(ReadSourceLocation(Record, Idx));
+ S->setEndLoc(ReadSourceLocation(Record, Idx));
+
+ if (Idx + 1 == Record.size()) {
+ // Single declaration
+ S->setDeclGroup(DeclGroupRef(ReadDecl(Record, Idx)));
+ } else {
+ SmallVector<Decl *, 16> Decls;
+ Decls.reserve(Record.size() - Idx);
+ for (unsigned N = Record.size(); Idx != N; )
+ Decls.push_back(ReadDecl(Record, Idx));
+ S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Reader.getContext(),
+ Decls.data(),
+ Decls.size())));
+ }
+}
+
+void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ S->NumOutputs = Record[Idx++];
+ S->NumInputs = Record[Idx++];
+ S->NumClobbers = Record[Idx++];
+ S->setAsmLoc(ReadSourceLocation(Record, Idx));
+ S->setVolatile(Record[Idx++]);
+ S->setSimple(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
+ VisitAsmStmt(S);
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+ S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+
+ unsigned NumOutputs = S->getNumOutputs();
+ unsigned NumInputs = S->getNumInputs();
+ unsigned NumClobbers = S->getNumClobbers();
+
+ // Outputs and inputs
+ SmallVector<IdentifierInfo *, 16> Names;
+ SmallVector<StringLiteral*, 16> Constraints;
+ SmallVector<Stmt*, 16> Exprs;
+ for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
+ Names.push_back(Reader.GetIdentifierInfo(F, Record, Idx));
+ Constraints.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+ Exprs.push_back(Reader.ReadSubStmt());
+ }
+
+ // Constraints
+ SmallVector<StringLiteral*, 16> Clobbers;
+ for (unsigned I = 0; I != NumClobbers; ++I)
+ Clobbers.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+
+ S->setOutputsAndInputsAndClobbers(Reader.getContext(),
+ Names.data(), Constraints.data(),
+ Exprs.data(), NumOutputs, NumInputs,
+ Clobbers.data(), NumClobbers);
+}
+
+void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
+ VisitAsmStmt(S);
+ S->LBraceLoc = ReadSourceLocation(Record, Idx);
+ S->EndLoc = ReadSourceLocation(Record, Idx);
+ S->NumAsmToks = Record[Idx++];
+ std::string AsmStr = ReadString(Record, Idx);
+
+ // Read the tokens.
+ SmallVector<Token, 16> AsmToks;
+ AsmToks.reserve(S->NumAsmToks);
+ for (unsigned i = 0, e = S->NumAsmToks; i != e; ++i) {
+ AsmToks.push_back(ReadToken(Record, Idx));
+ }
+
+ // The calls to reserve() for the FooData vectors are mandatory to
+ // prevent dead StringRefs in the Foo vectors.
+
+ // Read the clobbers.
+ SmallVector<std::string, 16> ClobbersData;
+ SmallVector<StringRef, 16> Clobbers;
+ ClobbersData.reserve(S->NumClobbers);
+ Clobbers.reserve(S->NumClobbers);
+ for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) {
+ ClobbersData.push_back(ReadString(Record, Idx));
+ Clobbers.push_back(ClobbersData.back());
+ }
+
+ // Read the operands.
+ unsigned NumOperands = S->NumOutputs + S->NumInputs;
+ SmallVector<Expr*, 16> Exprs;
+ SmallVector<std::string, 16> ConstraintsData;
+ SmallVector<StringRef, 16> Constraints;
+ Exprs.reserve(NumOperands);
+ ConstraintsData.reserve(NumOperands);
+ Constraints.reserve(NumOperands);
+ for (unsigned i = 0; i != NumOperands; ++i) {
+ Exprs.push_back(cast<Expr>(Reader.ReadSubStmt()));
+ ConstraintsData.push_back(ReadString(Record, Idx));
+ Constraints.push_back(ConstraintsData.back());
+ }
+
+ S->initialize(Reader.getContext(), AsmStr, AsmToks,
+ Constraints, Exprs, Clobbers);
+}
+
+void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
+ VisitStmt(S);
+ ++Idx;
+ S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx));
+ S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++]));
+ S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx));
+
+ // Capture inits
+ for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(),
+ E = S->capture_init_end();
+ I != E; ++I)
+ *I = Reader.ReadSubExpr();
+
+ // Body
+ S->setCapturedStmt(Reader.ReadSubStmt());
+ S->getCapturedDecl()->setBody(S->getCapturedStmt());
+
+ // Captures
+ for (auto &I : S->captures()) {
+ I.VarAndKind.setPointer(ReadDeclAs<VarDecl>(Record, Idx));
+ I.VarAndKind
+ .setInt(static_cast<CapturedStmt::VariableCaptureKind>(Record[Idx++]));
+ I.Loc = ReadSourceLocation(Record, Idx);
+ }
+}
+
+void ASTStmtReader::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ E->setType(Reader.readType(F, Record, Idx));
+ E->setTypeDependent(Record[Idx++]);
+ E->setValueDependent(Record[Idx++]);
+ E->setInstantiationDependent(Record[Idx++]);
+ E->ExprBits.ContainsUnexpandedParameterPack = Record[Idx++];
+ E->setValueKind(static_cast<ExprValueKind>(Record[Idx++]));
+ E->setObjectKind(static_cast<ExprObjectKind>(Record[Idx++]));
+ assert(Idx == NumExprFields && "Incorrect expression field count");
+}
+
+void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->Type = (PredefinedExpr::IdentType)Record[Idx++];
+ E->FnName = cast_or_null<StringLiteral>(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+
+ E->DeclRefExprBits.HasQualifier = Record[Idx++];
+ E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
+ E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record[Idx++];
+ E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++];
+ E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record[Idx++];
+ unsigned NumTemplateArgs = 0;
+ if (E->hasTemplateKWAndArgsInfo())
+ NumTemplateArgs = Record[Idx++];
+
+ if (E->hasQualifier())
+ E->getInternalQualifierLoc()
+ = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+
+ if (E->hasFoundDecl())
+ E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx);
+
+ if (E->hasTemplateKWAndArgsInfo())
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ NumTemplateArgs);
+
+ E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx));
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record, Idx);
+}
+
+void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setValue(Reader.getContext(), Reader.ReadAPInt(Record, Idx));
+}
+
+void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record[Idx++]));
+ E->setExact(Record[Idx++]);
+ E->setValue(Reader.getContext(),
+ Reader.ReadAPFloat(Record, E->getSemantics(), Idx));
+ E->setLocation(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ unsigned Len = Record[Idx++];
+ assert(Record[Idx] == E->getNumConcatenated() &&
+ "Wrong number of concatenated tokens!");
+ ++Idx;
+ StringLiteral::StringKind kind =
+ static_cast<StringLiteral::StringKind>(Record[Idx++]);
+ bool isPascal = Record[Idx++];
+
+ // Read string data
+ SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setString(Reader.getContext(), Str, kind, isPascal);
+ Idx += Len;
+
+ // Read source locations
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ E->setStrTokenLoc(I, ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record[Idx++]));
+}
+
+void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ E->setLParen(ReadSourceLocation(Record, Idx));
+ E->setRParen(ReadSourceLocation(Record, Idx));
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
+ VisitExpr(E);
+ unsigned NumExprs = Record[Idx++];
+ E->Exprs = new (Reader.getContext()) Stmt*[NumExprs];
+ for (unsigned i = 0; i != NumExprs; ++i)
+ E->Exprs[i] = Reader.ReadSubStmt();
+ E->NumExprs = NumExprs;
+ E->LParenLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setOpcode((UnaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ VisitExpr(E);
+ assert(E->getNumComponents() == Record[Idx]);
+ ++Idx;
+ assert(E->getNumExpressions() == Record[Idx]);
+ ++Idx;
+ E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+ SourceLocation Start = ReadSourceLocation(Record, Idx);
+ SourceLocation End = ReadSourceLocation(Record, Idx);
+ switch (Kind) {
+ case Node::Array:
+ E->setComponent(I, Node(Start, Record[Idx++], End));
+ break;
+
+ case Node::Field:
+ E->setComponent(I, Node(Start, ReadDeclAs<FieldDecl>(Record, Idx), End));
+ break;
+
+ case Node::Identifier:
+ E->setComponent(I,
+ Node(Start,
+ Reader.GetIdentifierInfo(F, Record, Idx),
+ End));
+ break;
+
+ case Node::Base: {
+ CXXBaseSpecifier *Base = new (Reader.getContext()) CXXBaseSpecifier();
+ *Base = Reader.ReadCXXBaseSpecifier(F, Record, Idx);
+ E->setComponent(I, Node(Base));
+ break;
+ }
+ }
+ }
+
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ E->setIndexExpr(I, Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
+ VisitExpr(E);
+ E->setKind(static_cast<UnaryExprOrTypeTrait>(Record[Idx++]));
+ if (Record[Idx] == 0) {
+ E->setArgument(Reader.ReadSubExpr());
+ ++Idx;
+ } else {
+ E->setArgument(GetTypeSourceInfo(Record, Idx));
+ }
+ E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setRBracketLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ E->setNumArgs(Reader.getContext(), Record[Idx++]);
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setCallee(Reader.ReadSubExpr());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ VisitCallExpr(E);
+}
+
+void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
+ // Don't call VisitExpr, this is fully initialized at creation.
+ assert(E->getStmtClass() == Stmt::MemberExprClass &&
+ "It's a subclass, we must advance Idx!");
+}
+
+void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ E->setBase(Reader.ReadSubExpr());
+ E->setIsaMemberLoc(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
+ E->setArrow(Record[Idx++]);
+}
+
+void ASTStmtReader::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ VisitExpr(E);
+ E->Operand = Reader.ReadSubExpr();
+ E->setShouldCopy(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->LParenLoc = ReadSourceLocation(Record, Idx);
+ E->BridgeKeywordLoc = ReadSourceLocation(Record, Idx);
+ E->Kind = Record[Idx++];
+}
+
+void ASTStmtReader::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ unsigned NumBaseSpecs = Record[Idx++];
+ assert(NumBaseSpecs == E->path_size());
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setCastKind((CastKind)Record[Idx++]);
+ CastExpr::path_iterator BaseI = E->path_begin();
+ while (NumBaseSpecs--) {
+ CXXBaseSpecifier *BaseSpec = new (Reader.getContext()) CXXBaseSpecifier;
+ *BaseSpec = Reader.ReadCXXBaseSpecifier(F, Record, Idx);
+ *BaseI++ = BaseSpec;
+ }
+}
+
+void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->setFPContractable((bool)Record[Idx++]);
+}
+
+void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ E->setComputationLHSType(Reader.readType(F, Record, Idx));
+ E->setComputationResultType(Reader.readType(F, Record, Idx));
+}
+
+void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ E->SubExprs[ConditionalOperator::COND] = Reader.ReadSubExpr();
+ E->SubExprs[ConditionalOperator::LHS] = Reader.ReadSubExpr();
+ E->SubExprs[ConditionalOperator::RHS] = Reader.ReadSubExpr();
+ E->QuestionLoc = ReadSourceLocation(Record, Idx);
+ E->ColonLoc = ReadSourceLocation(Record, Idx);
+}
+
+void
+ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ VisitExpr(E);
+ E->OpaqueValue = cast<OpaqueValueExpr>(Reader.ReadSubExpr());
+ E->SubExprs[BinaryConditionalOperator::COMMON] = Reader.ReadSubExpr();
+ E->SubExprs[BinaryConditionalOperator::COND] = Reader.ReadSubExpr();
+ E->SubExprs[BinaryConditionalOperator::LHS] = Reader.ReadSubExpr();
+ E->SubExprs[BinaryConditionalOperator::RHS] = Reader.ReadSubExpr();
+ E->QuestionLoc = ReadSourceLocation(Record, Idx);
+ E->ColonLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+}
+
+void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setTypeInfoAsWritten(GetTypeSourceInfo(Record, Idx));
+}
+
+void ASTStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
+ E->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ E->setInitializer(Reader.ReadSubExpr());
+ E->setFileScope(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ E->setBase(Reader.ReadSubExpr());
+ E->setAccessor(Reader.GetIdentifierInfo(F, Record, Idx));
+ E->setAccessorLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ if (InitListExpr *SyntForm = cast_or_null<InitListExpr>(Reader.ReadSubStmt()))
+ E->setSyntacticForm(SyntForm);
+ E->setLBraceLoc(ReadSourceLocation(Record, Idx));
+ E->setRBraceLoc(ReadSourceLocation(Record, Idx));
+ bool isArrayFiller = Record[Idx++];
+ Expr *filler = nullptr;
+ if (isArrayFiller) {
+ filler = Reader.ReadSubExpr();
+ E->ArrayFillerOrUnionFieldInit = filler;
+ } else
+ E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx);
+ E->sawArrayRangeDesignator(Record[Idx++]);
+ unsigned NumInits = Record[Idx++];
+ E->reserveInits(Reader.getContext(), NumInits);
+ if (isArrayFiller) {
+ for (unsigned I = 0; I != NumInits; ++I) {
+ Expr *init = Reader.ReadSubExpr();
+ E->updateInit(Reader.getContext(), I, init ? init : filler);
+ }
+ } else {
+ for (unsigned I = 0; I != NumInits; ++I)
+ E->updateInit(Reader.getContext(), I, Reader.ReadSubExpr());
+ }
+}
+
+void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ typedef DesignatedInitExpr::Designator Designator;
+
+ VisitExpr(E);
+ unsigned NumSubExprs = Record[Idx++];
+ assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs");
+ for (unsigned I = 0; I != NumSubExprs; ++I)
+ E->setSubExpr(I, Reader.ReadSubExpr());
+ E->setEqualOrColonLoc(ReadSourceLocation(Record, Idx));
+ E->setGNUSyntax(Record[Idx++]);
+
+ SmallVector<Designator, 4> Designators;
+ while (Idx < Record.size()) {
+ switch ((DesignatorTypes)Record[Idx++]) {
+ case DESIG_FIELD_DECL: {
+ FieldDecl *Field = ReadDeclAs<FieldDecl>(Record, Idx);
+ SourceLocation DotLoc
+ = ReadSourceLocation(Record, Idx);
+ SourceLocation FieldLoc
+ = ReadSourceLocation(Record, Idx);
+ Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
+ FieldLoc));
+ Designators.back().setField(Field);
+ break;
+ }
+
+ case DESIG_FIELD_NAME: {
+ const IdentifierInfo *Name = Reader.GetIdentifierInfo(F, Record, Idx);
+ SourceLocation DotLoc
+ = ReadSourceLocation(Record, Idx);
+ SourceLocation FieldLoc
+ = ReadSourceLocation(Record, Idx);
+ Designators.push_back(Designator(Name, DotLoc, FieldLoc));
+ break;
+ }
+
+ case DESIG_ARRAY: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = ReadSourceLocation(Record, Idx);
+ SourceLocation RBracketLoc
+ = ReadSourceLocation(Record, Idx);
+ Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc));
+ break;
+ }
+
+ case DESIG_ARRAY_RANGE: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = ReadSourceLocation(Record, Idx);
+ SourceLocation EllipsisLoc
+ = ReadSourceLocation(Record, Idx);
+ SourceLocation RBracketLoc
+ = ReadSourceLocation(Record, Idx);
+ Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc,
+ RBracketLoc));
+ break;
+ }
+ }
+ }
+ E->setDesignators(Reader.getContext(),
+ Designators.data(), Designators.size());
+}
+
+void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+}
+
+void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setWrittenTypeInfo(GetTypeSourceInfo(Record, Idx));
+ E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ E->setAmpAmpLoc(ReadSourceLocation(Record, Idx));
+ E->setLabelLoc(ReadSourceLocation(Record, Idx));
+ E->setLabel(ReadDeclAs<LabelDecl>(Record, Idx));
+}
+
+void ASTStmtReader::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setSubStmt(cast_or_null<CompoundStmt>(Reader.ReadSubStmt()));
+}
+
+void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ E->setCond(Reader.ReadSubExpr());
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setIsConditionTrue(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ E->setTokenLocation(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ SmallVector<Expr *, 16> Exprs;
+ unsigned NumExprs = Record[Idx++];
+ while (NumExprs--)
+ Exprs.push_back(Reader.ReadSubExpr());
+ E->setExprs(Reader.getContext(), Exprs);
+ E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+ VisitExpr(E);
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->TInfo = GetTypeSourceInfo(Record, Idx);
+ E->SrcExpr = Reader.ReadSubExpr();
+}
+
+void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
+}
+
+void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ E->NumAssocs = Record[Idx++];
+ E->AssocTypes = new (Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
+ E->SubExprs =
+ new(Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
+
+ E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr();
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ E->AssocTypes[I] = GetTypeSourceInfo(Record, Idx);
+ E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Reader.ReadSubExpr();
+ }
+ E->ResultIndex = Record[Idx++];
+
+ E->GenericLoc = ReadSourceLocation(Record, Idx);
+ E->DefaultLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ VisitExpr(E);
+ unsigned numSemanticExprs = Record[Idx++];
+ assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
+ E->PseudoObjectExprBits.ResultIndex = Record[Idx++];
+
+ // Read the syntactic expression.
+ E->getSubExprsBuffer()[0] = Reader.ReadSubExpr();
+
+ // Read all the semantic expressions.
+ for (unsigned i = 0; i != numSemanticExprs; ++i) {
+ Expr *subExpr = Reader.ReadSubExpr();
+ E->getSubExprsBuffer()[i+1] = subExpr;
+ }
+}
+
+void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ E->Op = AtomicExpr::AtomicOp(Record[Idx++]);
+ E->NumSubExprs = AtomicExpr::getNumSubExprs(E->Op);
+ for (unsigned I = 0; I != E->NumSubExprs; ++I)
+ E->SubExprs[I] = Reader.ReadSubExpr();
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements
+
+void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ E->setString(cast<StringLiteral>(Reader.ReadSubStmt()));
+ E->setAtLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
+ VisitExpr(E);
+ // could be one of several IntegerLiteral, FloatLiteral, etc.
+ E->SubExpr = Reader.ReadSubStmt();
+ E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ VisitExpr(E);
+ unsigned NumElements = Record[Idx++];
+ assert(NumElements == E->getNumElements() && "Wrong number of elements");
+ Expr **Elements = E->getElements();
+ for (unsigned I = 0, N = NumElements; I != N; ++I)
+ Elements[I] = Reader.ReadSubExpr();
+ E->ArrayWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ VisitExpr(E);
+ unsigned NumElements = Record[Idx++];
+ assert(NumElements == E->getNumElements() && "Wrong number of elements");
+ bool HasPackExpansions = Record[Idx++];
+ assert(HasPackExpansions == E->HasPackExpansions &&"Pack expansion mismatch");
+ ObjCDictionaryLiteral::KeyValuePair *KeyValues = E->getKeyValues();
+ ObjCDictionaryLiteral::ExpansionData *Expansions = E->getExpansionData();
+ for (unsigned I = 0; I != NumElements; ++I) {
+ KeyValues[I].Key = Reader.ReadSubExpr();
+ KeyValues[I].Value = Reader.ReadSubExpr();
+ if (HasPackExpansions) {
+ Expansions[I].EllipsisLoc = ReadSourceLocation(Record, Idx);
+ Expansions[I].NumExpansionsPlusOne = Record[Idx++];
+ }
+ }
+ E->DictWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ E->setEncodedTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ E->setAtLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ E->setSelector(Reader.ReadSelector(F, Record, Idx));
+ E->setAtLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ E->setProtocol(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ E->setAtLoc(ReadSourceLocation(Record, Idx));
+ E->ProtoLoc = ReadSourceLocation(Record, Idx);
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
+ E->setBase(Reader.ReadSubExpr());
+ E->setIsArrow(Record[Idx++]);
+ E->setIsFreeIvar(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ unsigned MethodRefFlags = Record[Idx++];
+ bool Implicit = Record[Idx++] != 0;
+ if (Implicit) {
+ ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ ObjCMethodDecl *Setter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->setImplicitProperty(Getter, Setter, MethodRefFlags);
+ } else {
+ E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx),
+ MethodRefFlags);
+ }
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setReceiverLocation(ReadSourceLocation(Record, Idx));
+ switch (Record[Idx++]) {
+ case 0:
+ E->setBase(Reader.ReadSubExpr());
+ break;
+ case 1:
+ E->setSuperReceiver(Reader.readType(F, Record, Idx));
+ break;
+ case 2:
+ E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+ break;
+ }
+}
+
+void ASTStmtReader::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
+ VisitExpr(E);
+ E->setRBracket(ReadSourceLocation(Record, Idx));
+ E->setBaseExpr(Reader.ReadSubExpr());
+ E->setKeyExpr(Reader.ReadSubExpr());
+ E->GetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->SetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ assert(Record[Idx] == E->getNumArgs());
+ ++Idx;
+ unsigned NumStoredSelLocs = Record[Idx++];
+ E->SelLocsKind = Record[Idx++];
+ E->setDelegateInitCall(Record[Idx++]);
+ E->IsImplicit = Record[Idx++];
+ ObjCMessageExpr::ReceiverKind Kind
+ = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
+ switch (Kind) {
+ case ObjCMessageExpr::Instance:
+ E->setInstanceReceiver(Reader.ReadSubExpr());
+ break;
+
+ case ObjCMessageExpr::Class:
+ E->setClassReceiver(GetTypeSourceInfo(Record, Idx));
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance: {
+ QualType T = Reader.readType(F, Record, Idx);
+ SourceLocation SuperLoc = ReadSourceLocation(Record, Idx);
+ E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
+ break;
+ }
+ }
+
+ assert(Kind == E->getReceiverKind());
+
+ if (Record[Idx++])
+ E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx));
+ else
+ E->setSelector(Reader.ReadSelector(F, Record, Idx));
+
+ E->LBracLoc = ReadSourceLocation(Record, Idx);
+ E->RBracLoc = ReadSourceLocation(Record, Idx);
+
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+
+ SourceLocation *Locs = E->getStoredSelLocs();
+ for (unsigned I = 0; I != NumStoredSelLocs; ++I)
+ Locs[I] = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ S->setElement(Reader.ReadSubStmt());
+ S->setCollection(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setForLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ VisitStmt(S);
+ S->setCatchBody(Reader.ReadSubStmt());
+ S->setCatchParamDecl(ReadDeclAs<VarDecl>(Record, Idx));
+ S->setAtCatchLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ VisitStmt(S);
+ S->setFinallyBody(Reader.ReadSubStmt());
+ S->setAtFinallyLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ VisitStmt(S);
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setAtLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ VisitStmt(S);
+ assert(Record[Idx] == S->getNumCatchStmts());
+ ++Idx;
+ bool HasFinally = Record[Idx++];
+ S->setTryBody(Reader.ReadSubStmt());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(Reader.ReadSubStmt()));
+
+ if (HasFinally)
+ S->setFinallyStmt(Reader.ReadSubStmt());
+ S->setAtTryLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ VisitStmt(S);
+ S->setSynchExpr(Reader.ReadSubStmt());
+ S->setSynchBody(Reader.ReadSubStmt());
+ S->setAtSynchronizedLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ VisitStmt(S);
+ S->setThrowExpr(Reader.ReadSubStmt());
+ S->setThrowLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements
+//===----------------------------------------------------------------------===//
+
+void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ VisitStmt(S);
+ S->CatchLoc = ReadSourceLocation(Record, Idx);
+ S->ExceptionDecl = ReadDeclAs<VarDecl>(Record, Idx);
+ S->HandlerBlock = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
+ VisitStmt(S);
+ assert(Record[Idx] == S->getNumHandlers() && "NumStmtFields is wrong ?");
+ ++Idx;
+ S->TryLoc = ReadSourceLocation(Record, Idx);
+ S->getStmts()[0] = Reader.ReadSubStmt();
+ for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i)
+ S->getStmts()[i + 1] = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+ S->setForLoc(ReadSourceLocation(Record, Idx));
+ S->setColonLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+ S->setRangeStmt(Reader.ReadSubStmt());
+ S->setBeginEndStmt(Reader.ReadSubStmt());
+ S->setCond(Reader.ReadSubExpr());
+ S->setInc(Reader.ReadSubExpr());
+ S->setLoopVarStmt(Reader.ReadSubStmt());
+ S->setBody(Reader.ReadSubStmt());
+}
+
+void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ VisitStmt(S);
+ S->KeywordLoc = ReadSourceLocation(Record, Idx);
+ S->IsIfExists = Record[Idx++];
+ S->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ ReadDeclarationNameInfo(S->NameInfo, Record, Idx);
+ S->SubStmt = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ VisitCallExpr(E);
+ E->Operator = (OverloadedOperatorKind)Record[Idx++];
+ E->Range = Reader.ReadSourceRange(F, Record, Idx);
+ E->setFPContractable((bool)Record[Idx++]);
+}
+
+void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ E->NumArgs = Record[Idx++];
+ if (E->NumArgs)
+ E->Args = new (Reader.getContext()) Stmt*[E->NumArgs];
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+ E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx));
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setElidable(Record[Idx++]);
+ E->setHadMultipleCandidates(Record[Idx++]);
+ E->setListInitialization(Record[Idx++]);
+ E->setStdInitListInitialization(Record[Idx++]);
+ E->setRequiresZeroInitialization(Record[Idx++]);
+ E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
+ E->ParenOrBraceRange = ReadSourceRange(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+ VisitCXXConstructExpr(E);
+ E->Type = GetTypeSourceInfo(Record, Idx);
+}
+
+void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ unsigned NumCaptures = Record[Idx++];
+ assert(NumCaptures == E->NumCaptures);(void)NumCaptures;
+ unsigned NumArrayIndexVars = Record[Idx++];
+ E->IntroducerRange = ReadSourceRange(Record, Idx);
+ E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record[Idx++]);
+ E->CaptureDefaultLoc = ReadSourceLocation(Record, Idx);
+ E->ExplicitParams = Record[Idx++];
+ E->ExplicitResultType = Record[Idx++];
+ E->ClosingBrace = ReadSourceLocation(Record, Idx);
+
+ // Read capture initializers.
+ for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(),
+ CEnd = E->capture_init_end();
+ C != CEnd; ++C)
+ *C = Reader.ReadSubExpr();
+
+ // Read array capture index variables.
+ if (NumArrayIndexVars > 0) {
+ unsigned *ArrayIndexStarts = E->getArrayIndexStarts();
+ for (unsigned I = 0; I != NumCaptures + 1; ++I)
+ ArrayIndexStarts[I] = Record[Idx++];
+
+ VarDecl **ArrayIndexVars = E->getArrayIndexVars();
+ for (unsigned I = 0; I != NumArrayIndexVars; ++I)
+ ArrayIndexVars[I] = ReadDeclAs<VarDecl>(Record, Idx);
+ }
+}
+
+void
+ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ E->SubExpr = Reader.ReadSubExpr();
+}
+
+void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ SourceRange R = ReadSourceRange(Record, Idx);
+ E->Loc = R.getBegin();
+ E->RParenLoc = R.getEnd();
+ R = ReadSourceRange(Record, Idx);
+ E->AngleBrackets = R;
+}
+
+void ASTStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void ASTStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void ASTStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ E->UDSuffixLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ E->setSourceRange(ReadSourceRange(Record, Idx));
+ if (E->isTypeOperand()) { // typeid(int)
+ E->setTypeOperandSourceInfo(
+ GetTypeSourceInfo(Record, Idx));
+ return;
+ }
+
+ // typeid(42+2)
+ E->setExprOperand(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setImplicit(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ E->ThrowLoc = ReadSourceLocation(Record, Idx);
+ E->Op = Reader.ReadSubExpr();
+ E->IsThrownVariableInScope = Record[Idx++];
+}
+
+void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+
+ assert((bool)Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
+ ++Idx; // HasOtherExprStored and SubExpr was handled during creation.
+ E->Param.setPointer(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ E->Loc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ VisitExpr(E);
+ E->Field = ReadDeclAs<FieldDecl>(Record, Idx);
+ E->Loc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx));
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+ VisitExpr(E);
+ E->TypeInfo = GetTypeSourceInfo(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ E->GlobalNew = Record[Idx++];
+ bool isArray = Record[Idx++];
+ E->UsualArrayDeleteWantsSize = Record[Idx++];
+ unsigned NumPlacementArgs = Record[Idx++];
+ E->StoredInitializationStyle = Record[Idx++];
+ E->setOperatorNew(ReadDeclAs<FunctionDecl>(Record, Idx));
+ E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
+ E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
+ E->TypeIdParens = ReadSourceRange(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+ E->DirectInitRange = ReadSourceRange(Record, Idx);
+
+ E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
+ E->StoredInitializationStyle != 0);
+
+ // Install all the subexpressions.
+ for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end();
+ I != e; ++I)
+ *I = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ VisitExpr(E);
+ E->GlobalDelete = Record[Idx++];
+ E->ArrayForm = Record[Idx++];
+ E->ArrayFormAsWritten = Record[Idx++];
+ E->UsualArrayDeleteWantsSize = Record[Idx++];
+ E->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
+ E->Argument = Reader.ReadSubExpr();
+ E->Loc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ VisitExpr(E);
+
+ E->Base = Reader.ReadSubExpr();
+ E->IsArrow = Record[Idx++];
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ E->ScopeType = GetTypeSourceInfo(Record, Idx);
+ E->ColonColonLoc = ReadSourceLocation(Record, Idx);
+ E->TildeLoc = ReadSourceLocation(Record, Idx);
+
+ IdentifierInfo *II = Reader.GetIdentifierInfo(F, Record, Idx);
+ if (II)
+ E->setDestroyedType(II, ReadSourceLocation(Record, Idx));
+ else
+ E->setDestroyedType(GetTypeSourceInfo(Record, Idx));
+}
+
+void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
+ VisitExpr(E);
+
+ unsigned NumObjects = Record[Idx++];
+ assert(NumObjects == E->getNumObjects());
+ for (unsigned i = 0; i != NumObjects; ++i)
+ E->getObjectsBuffer()[i] = ReadDeclAs<BlockDecl>(Record, Idx);
+
+ E->SubExpr = Reader.ReadSubExpr();
+}
+
+void
+ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
+ VisitExpr(E);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
+
+ E->Base = Reader.ReadSubExpr();
+ E->BaseType = Reader.readType(F, Record, Idx);
+ E->IsArrow = Record[Idx++];
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ E->FirstQualifierFoundInScope = ReadDeclAs<NamedDecl>(Record, Idx);
+ ReadDeclarationNameInfo(E->MemberNameInfo, Record, Idx);
+}
+
+void
+ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ VisitExpr(E);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
+
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
+}
+
+void
+ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
+ VisitExpr(E);
+ assert(Record[Idx] == E->arg_size() && "Read wrong record during creation ?");
+ ++Idx; // NumArgs;
+ for (unsigned I = 0, N = E->arg_size(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+ E->Type = GetTypeSourceInfo(Record, Idx);
+ E->setLParenLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
+ VisitExpr(E);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
+
+ unsigned NumDecls = Record[Idx++];
+ UnresolvedSet<8> Decls;
+ for (unsigned i = 0; i != NumDecls; ++i) {
+ NamedDecl *D = ReadDeclAs<NamedDecl>(Record, Idx);
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ Decls.addDecl(D, AS);
+ }
+ E->initializeResults(Reader.getContext(), Decls.begin(), Decls.end());
+
+ ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+}
+
+void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
+ VisitOverloadExpr(E);
+ E->IsArrow = Record[Idx++];
+ E->HasUnresolvedUsing = Record[Idx++];
+ E->Base = Reader.ReadSubExpr();
+ E->BaseType = Reader.readType(F, Record, Idx);
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+ VisitOverloadExpr(E);
+ E->RequiresADL = Record[Idx++];
+ E->Overloaded = Record[Idx++];
+ E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
+}
+
+void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ VisitExpr(E);
+ E->TypeTraitExprBits.NumArgs = Record[Idx++];
+ E->TypeTraitExprBits.Kind = Record[Idx++];
+ E->TypeTraitExprBits.Value = Record[Idx++];
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->Loc = Range.getBegin();
+ E->RParenLoc = Range.getEnd();
+
+ TypeSourceInfo **Args = E->getTypeSourceInfos();
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Args[I] = GetTypeSourceInfo(Record, Idx);
+}
+
+void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ VisitExpr(E);
+ E->ATT = (ArrayTypeTrait)Record[Idx++];
+ E->Value = (unsigned int)Record[Idx++];
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->Loc = Range.getBegin();
+ E->RParen = Range.getEnd();
+ E->QueriedType = GetTypeSourceInfo(Record, Idx);
+}
+
+void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ VisitExpr(E);
+ E->ET = (ExpressionTrait)Record[Idx++];
+ E->Value = (bool)Record[Idx++];
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->QueriedExpression = Reader.ReadSubExpr();
+ E->Loc = Range.getBegin();
+ E->RParen = Range.getEnd();
+}
+
+void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
+ VisitExpr(E);
+ E->Value = (bool)Record[Idx++];
+ E->Range = ReadSourceRange(Record, Idx);
+ E->Operand = Reader.ReadSubExpr();
+}
+
+void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
+ VisitExpr(E);
+ E->EllipsisLoc = ReadSourceLocation(Record, Idx);
+ E->NumExpansions = Record[Idx++];
+ E->Pattern = Reader.ReadSubExpr();
+}
+
+void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+ VisitExpr(E);
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+ E->PackLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->Length = Record[Idx++];
+ E->Pack = ReadDeclAs<NamedDecl>(Record, Idx);
+}
+
+void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ VisitExpr(E);
+ E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx);
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ E->Replacement = Reader.ReadSubExpr();
+}
+
+void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
+ SubstNonTypeTemplateParmPackExpr *E) {
+ VisitExpr(E);
+ E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx);
+ TemplateArgument ArgPack = Reader.ReadTemplateArgument(F, Record, Idx);
+ if (ArgPack.getKind() != TemplateArgument::Pack)
+ return;
+
+ E->Arguments = ArgPack.pack_begin();
+ E->NumArguments = ArgPack.pack_size();
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ E->NumParameters = Record[Idx++];
+ E->ParamPack = ReadDeclAs<ParmVarDecl>(Record, Idx);
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1);
+ for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
+ Parms[i] = ReadDeclAs<ParmVarDecl>(Record, Idx);
+}
+
+void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+ VisitExpr(E);
+ E->State = Reader.ReadSubExpr();
+ auto VD = ReadDeclAs<ValueDecl>(Record, Idx);
+ unsigned ManglingNumber = Record[Idx++];
+ E->setExtendingDecl(VD, ManglingNumber);
+}
+
+void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
+ VisitExpr(E);
+ E->LParenLoc = ReadSourceLocation(Record, Idx);
+ E->EllipsisLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->SubExprs[0] = Reader.ReadSubExpr();
+ E->SubExprs[1] = Reader.ReadSubExpr();
+ E->Opcode = (BinaryOperatorKind)Record[Idx++];
+}
+
+void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ VisitExpr(E);
+ E->SourceExpr = Reader.ReadSubExpr();
+ E->Loc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitTypoExpr(TypoExpr *E) {
+ llvm_unreachable("Cannot read TypoExpr nodes");
+}
+
+//===----------------------------------------------------------------------===//
+// Microsoft Expressions and Statements
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
+ VisitExpr(E);
+ E->IsArrow = (Record[Idx++] != 0);
+ E->BaseExpr = Reader.ReadSubExpr();
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ E->MemberLoc = ReadSourceLocation(Record, Idx);
+ E->TheDecl = ReadDeclAs<MSPropertyDecl>(Record, Idx);
+}
+
+void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+ VisitExpr(E);
+ E->setSourceRange(ReadSourceRange(Record, Idx));
+ if (E->isTypeOperand()) { // __uuidof(ComType)
+ E->setTypeOperandSourceInfo(
+ GetTypeSourceInfo(Record, Idx));
+ return;
+ }
+
+ // __uuidof(expr)
+ E->setExprOperand(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
+ VisitStmt(S);
+ S->setLeaveLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+ S->Loc = ReadSourceLocation(Record, Idx);
+ S->Children[SEHExceptStmt::FILTER_EXPR] = Reader.ReadSubStmt();
+ S->Children[SEHExceptStmt::BLOCK] = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+ S->Loc = ReadSourceLocation(Record, Idx);
+ S->Block = Reader.ReadSubStmt();
+}
+
+void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+ S->IsCXXTry = Record[Idx++];
+ S->TryLoc = ReadSourceLocation(Record, Idx);
+ S->Children[SEHTryStmt::TRY] = Reader.ReadSubStmt();
+ S->Children[SEHTryStmt::HANDLER] = Reader.ReadSubStmt();
+}
+
+//===----------------------------------------------------------------------===//
+// CUDA Expressions and Statements
+//===----------------------------------------------------------------------===//
+
+void ASTStmtReader::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
+ VisitCallExpr(E);
+ E->setConfig(cast<CallExpr>(Reader.ReadSubExpr()));
+}
+
+//===----------------------------------------------------------------------===//
+// OpenCL Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
+ VisitExpr(E);
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+ E->SrcExpr = Reader.ReadSubExpr();
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Clauses.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+class OMPClauseReader : public OMPClauseVisitor<OMPClauseReader> {
+ ASTStmtReader *Reader;
+ ASTContext &Context;
+ const ASTReader::RecordData &Record;
+ unsigned &Idx;
+public:
+ OMPClauseReader(ASTStmtReader *R, ASTContext &C,
+ const ASTReader::RecordData &Record, unsigned &Idx)
+ : Reader(R), Context(C), Record(Record), Idx(Idx) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+ OMPClause *readClause();
+};
+}
+
+OMPClause *OMPClauseReader::readClause() {
+ OMPClause *C;
+ switch (Record[Idx++]) {
+ case OMPC_if:
+ C = new (Context) OMPIfClause();
+ break;
+ case OMPC_final:
+ C = new (Context) OMPFinalClause();
+ break;
+ case OMPC_num_threads:
+ C = new (Context) OMPNumThreadsClause();
+ break;
+ case OMPC_safelen:
+ C = new (Context) OMPSafelenClause();
+ break;
+ case OMPC_collapse:
+ C = new (Context) OMPCollapseClause();
+ break;
+ case OMPC_default:
+ C = new (Context) OMPDefaultClause();
+ break;
+ case OMPC_proc_bind:
+ C = new (Context) OMPProcBindClause();
+ break;
+ case OMPC_schedule:
+ C = new (Context) OMPScheduleClause();
+ break;
+ case OMPC_ordered:
+ C = new (Context) OMPOrderedClause();
+ break;
+ case OMPC_nowait:
+ C = new (Context) OMPNowaitClause();
+ break;
+ case OMPC_untied:
+ C = new (Context) OMPUntiedClause();
+ break;
+ case OMPC_mergeable:
+ C = new (Context) OMPMergeableClause();
+ break;
+ case OMPC_read:
+ C = new (Context) OMPReadClause();
+ break;
+ case OMPC_write:
+ C = new (Context) OMPWriteClause();
+ break;
+ case OMPC_update:
+ C = new (Context) OMPUpdateClause();
+ break;
+ case OMPC_capture:
+ C = new (Context) OMPCaptureClause();
+ break;
+ case OMPC_seq_cst:
+ C = new (Context) OMPSeqCstClause();
+ break;
+ case OMPC_private:
+ C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_firstprivate:
+ C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_lastprivate:
+ C = OMPLastprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_shared:
+ C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_reduction:
+ C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_linear:
+ C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_aligned:
+ C = OMPAlignedClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_copyin:
+ C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_copyprivate:
+ C = OMPCopyprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_flush:
+ C = OMPFlushClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ }
+ Visit(C);
+ C->setLocStart(Reader->ReadSourceLocation(Record, Idx));
+ C->setLocEnd(Reader->ReadSourceLocation(Record, Idx));
+
+ return C;
+}
+
+void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) {
+ C->setCondition(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
+ C->setCondition(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ C->setNumThreads(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) {
+ C->setSafelen(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ C->setNumForLoops(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ C->setDefaultKind(
+ static_cast<OpenMPDefaultClauseKind>(Record[Idx++]));
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
+ C->setProcBindKind(
+ static_cast<OpenMPProcBindClauseKind>(Record[Idx++]));
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setProcBindKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ C->setScheduleKind(
+ static_cast<OpenMPScheduleClauseKind>(Record[Idx++]));
+ C->setChunkSize(Reader->Reader.ReadSubExpr());
+ C->setHelperChunkSize(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *) {}
+
+void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {}
+
+void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {}
+
+void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *) {}
+
+void OMPClauseReader::VisitOMPReadClause(OMPReadClause *) {}
+
+void OMPClauseReader::VisitOMPWriteClause(OMPWriteClause *) {}
+
+void OMPClauseReader::VisitOMPUpdateClause(OMPUpdateClause *) {}
+
+void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
+void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+
+void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
+}
+
+void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setInits(Vars);
+}
+
+void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Vars);
+}
+
+void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ NestedNameSpecifierLoc NNSL =
+ Reader->Reader.ReadNestedNameSpecifierLoc(Reader->F, Record, Idx);
+ DeclarationNameInfo DNI;
+ Reader->ReadDeclarationNameInfo(DNI, Record, Idx);
+ C->setQualifierLoc(NNSL);
+ C->setNameInfo(DNI);
+
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setLHSExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setRHSExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setReductionOps(Vars);
+}
+
+void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setInits(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setUpdates(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setFinals(Vars);
+ C->setStep(Reader->Reader.ReadSubExpr());
+ C->setCalcStep(Reader->Reader.ReadSubExpr());
+}
+
+void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ C->setAlignment(Reader->Reader.ReadSubExpr());
+}
+
+void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Exprs;
+ Exprs.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Exprs);
+}
+
+void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Exprs;
+ Exprs.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Exprs);
+}
+
+void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Directives.
+//===----------------------------------------------------------------------===//
+void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
+ E->setLocStart(ReadSourceLocation(Record, Idx));
+ E->setLocEnd(ReadSourceLocation(Record, Idx));
+ OMPClauseReader ClauseReader(this, Reader.getContext(), Record, Idx);
+ SmallVector<OMPClause *, 5> Clauses;
+ for (unsigned i = 0; i < E->getNumClauses(); ++i)
+ Clauses.push_back(ClauseReader.readClause());
+ E->setClauses(Clauses);
+ if (E->hasAssociatedStmt())
+ E->setAssociatedStmt(Reader.ReadSubStmt());
+}
+
+void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
+ VisitStmt(D);
+ // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
+ Idx += 2;
+ VisitOMPExecutableDirective(D);
+ D->setIterationVariable(Reader.ReadSubExpr());
+ D->setLastIteration(Reader.ReadSubExpr());
+ D->setCalcLastIteration(Reader.ReadSubExpr());
+ D->setPreCond(Reader.ReadSubExpr());
+ auto Fst = Reader.ReadSubExpr();
+ auto Snd = Reader.ReadSubExpr();
+ D->setCond(Fst, Snd);
+ D->setInit(Reader.ReadSubExpr());
+ D->setInc(Reader.ReadSubExpr());
+ if (isOpenMPWorksharingDirective(D->getDirectiveKind())) {
+ D->setIsLastIterVariable(Reader.ReadSubExpr());
+ D->setLowerBoundVariable(Reader.ReadSubExpr());
+ D->setUpperBoundVariable(Reader.ReadSubExpr());
+ D->setStrideVariable(Reader.ReadSubExpr());
+ D->setEnsureUpperBound(Reader.ReadSubExpr());
+ D->setNextLowerBound(Reader.ReadSubExpr());
+ D->setNextUpperBound(Reader.ReadSubExpr());
+ }
+ SmallVector<Expr *, 4> Sub;
+ unsigned CollapsedNum = D->getCollapsedNumber();
+ Sub.reserve(CollapsedNum);
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setCounters(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setUpdates(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Reader.ReadSubExpr());
+ D->setFinals(Sub);
+}
+
+void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPForSimdDirective(OMPForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSectionDirective(OMPSectionDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSingleDirective(OMPSingleDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPMasterDirective(OMPMasterDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ ReadDeclarationNameInfo(D->DirName, Record, Idx);
+}
+
+void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPBarrierDirective(OMPBarrierDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPAtomicDirective(OMPAtomicDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+ D->setX(Reader.ReadSubExpr());
+ D->setV(Reader.ReadSubExpr());
+ D->setExpr(Reader.ReadSubExpr());
+ D->setUpdateExpr(Reader.ReadSubExpr());
+ D->IsXLHSInRHSPart = Record[Idx++] != 0;
+ D->IsPostfixUpdate = Record[Idx++] != 0;
+}
+
+void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTeamsDirective(OMPTeamsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+//===----------------------------------------------------------------------===//
+// ASTReader Implementation
+//===----------------------------------------------------------------------===//
+
+Stmt *ASTReader::ReadStmt(ModuleFile &F) {
+ switch (ReadingKind) {
+ case Read_None:
+ llvm_unreachable("should not call this when not reading anything");
+ case Read_Decl:
+ case Read_Type:
+ return ReadStmtFromStream(F);
+ case Read_Stmt:
+ return ReadSubStmt();
+ }
+
+ llvm_unreachable("ReadingKind not set ?");
+}
+
+Expr *ASTReader::ReadExpr(ModuleFile &F) {
+ return cast_or_null<Expr>(ReadStmt(F));
+}
+
+Expr *ASTReader::ReadSubExpr() {
+ return cast_or_null<Expr>(ReadSubStmt());
+}
+
+// Within the bitstream, expressions are stored in Reverse Polish
+// Notation, with each of the subexpressions preceding the
+// expression they are stored in. Subexpressions are stored from last to first.
+// To evaluate expressions, we continue reading expressions and placing them on
+// the stack, with expressions having operands removing those operands from the
+// stack. Evaluation terminates when we see a STMT_STOP record, and
+// the single remaining expression on the stack is our result.
+Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
+
+ ReadingKindTracker ReadingKind(Read_Stmt, *this);
+ llvm::BitstreamCursor &Cursor = F.DeclsCursor;
+
+ // Map of offset to previously deserialized stmt. The offset points
+ /// just after the stmt record.
+ llvm::DenseMap<uint64_t, Stmt *> StmtEntries;
+
+#ifndef NDEBUG
+ unsigned PrevNumStmts = StmtStack.size();
+#endif
+
+ RecordData Record;
+ unsigned Idx;
+ ASTStmtReader Reader(*this, F, Cursor, Record, Idx);
+ Stmt::EmptyShell Empty;
+
+ while (true) {
+ llvm::BitstreamEntry Entry = Cursor.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return nullptr;
+ case llvm::BitstreamEntry::EndBlock:
+ goto Done;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ Stmt *S = nullptr;
+ Idx = 0;
+ Record.clear();
+ bool Finished = false;
+ bool IsStmtReference = false;
+ switch ((StmtCode)Cursor.readRecord(Entry.ID, Record)) {
+ case STMT_STOP:
+ Finished = true;
+ break;
+
+ case STMT_REF_PTR:
+ IsStmtReference = true;
+ assert(StmtEntries.find(Record[0]) != StmtEntries.end() &&
+ "No stmt was recorded for this offset reference!");
+ S = StmtEntries[Record[Idx++]];
+ break;
+
+ case STMT_NULL_PTR:
+ S = nullptr;
+ break;
+
+ case STMT_NULL:
+ S = new (Context) NullStmt(Empty);
+ break;
+
+ case STMT_COMPOUND:
+ S = new (Context) CompoundStmt(Empty);
+ break;
+
+ case STMT_CASE:
+ S = new (Context) CaseStmt(Empty);
+ break;
+
+ case STMT_DEFAULT:
+ S = new (Context) DefaultStmt(Empty);
+ break;
+
+ case STMT_LABEL:
+ S = new (Context) LabelStmt(Empty);
+ break;
+
+ case STMT_ATTRIBUTED:
+ S = AttributedStmt::CreateEmpty(
+ Context,
+ /*NumAttrs*/Record[ASTStmtReader::NumStmtFields]);
+ break;
+
+ case STMT_IF:
+ S = new (Context) IfStmt(Empty);
+ break;
+
+ case STMT_SWITCH:
+ S = new (Context) SwitchStmt(Empty);
+ break;
+
+ case STMT_WHILE:
+ S = new (Context) WhileStmt(Empty);
+ break;
+
+ case STMT_DO:
+ S = new (Context) DoStmt(Empty);
+ break;
+
+ case STMT_FOR:
+ S = new (Context) ForStmt(Empty);
+ break;
+
+ case STMT_GOTO:
+ S = new (Context) GotoStmt(Empty);
+ break;
+
+ case STMT_INDIRECT_GOTO:
+ S = new (Context) IndirectGotoStmt(Empty);
+ break;
+
+ case STMT_CONTINUE:
+ S = new (Context) ContinueStmt(Empty);
+ break;
+
+ case STMT_BREAK:
+ S = new (Context) BreakStmt(Empty);
+ break;
+
+ case STMT_RETURN:
+ S = new (Context) ReturnStmt(Empty);
+ break;
+
+ case STMT_DECL:
+ S = new (Context) DeclStmt(Empty);
+ break;
+
+ case STMT_GCCASM:
+ S = new (Context) GCCAsmStmt(Empty);
+ break;
+
+ case STMT_MSASM:
+ S = new (Context) MSAsmStmt(Empty);
+ break;
+
+ case STMT_CAPTURED:
+ S = CapturedStmt::CreateDeserialized(Context,
+ Record[ASTStmtReader::NumStmtFields]);
+ break;
+
+ case EXPR_PREDEFINED:
+ S = new (Context) PredefinedExpr(Empty);
+ break;
+
+ case EXPR_DECL_REF:
+ S = DeclRefExpr::CreateEmpty(
+ Context,
+ /*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
+ /*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 2],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
+ Record[ASTStmtReader::NumExprFields + 5] : 0);
+ break;
+
+ case EXPR_INTEGER_LITERAL:
+ S = IntegerLiteral::Create(Context, Empty);
+ break;
+
+ case EXPR_FLOATING_LITERAL:
+ S = FloatingLiteral::Create(Context, Empty);
+ break;
+
+ case EXPR_IMAGINARY_LITERAL:
+ S = new (Context) ImaginaryLiteral(Empty);
+ break;
+
+ case EXPR_STRING_LITERAL:
+ S = StringLiteral::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields + 1]);
+ break;
+
+ case EXPR_CHARACTER_LITERAL:
+ S = new (Context) CharacterLiteral(Empty);
+ break;
+
+ case EXPR_PAREN:
+ S = new (Context) ParenExpr(Empty);
+ break;
+
+ case EXPR_PAREN_LIST:
+ S = new (Context) ParenListExpr(Empty);
+ break;
+
+ case EXPR_UNARY_OPERATOR:
+ S = new (Context) UnaryOperator(Empty);
+ break;
+
+ case EXPR_OFFSETOF:
+ S = OffsetOfExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields],
+ Record[ASTStmtReader::NumExprFields + 1]);
+ break;
+
+ case EXPR_SIZEOF_ALIGN_OF:
+ S = new (Context) UnaryExprOrTypeTraitExpr(Empty);
+ break;
+
+ case EXPR_ARRAY_SUBSCRIPT:
+ S = new (Context) ArraySubscriptExpr(Empty);
+ break;
+
+ case EXPR_CALL:
+ S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty);
+ break;
+
+ case EXPR_MEMBER: {
+ // We load everything here and fully initialize it at creation.
+ // That way we can use MemberExpr::Create and don't have to duplicate its
+ // logic with a MemberExpr::CreateEmpty.
+
+ assert(Idx == 0);
+ NestedNameSpecifierLoc QualifierLoc;
+ if (Record[Idx++]) { // HasQualifier.
+ QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
+ }
+
+ SourceLocation TemplateKWLoc;
+ TemplateArgumentListInfo ArgInfo;
+ bool HasTemplateKWAndArgsInfo = Record[Idx++];
+ if (HasTemplateKWAndArgsInfo) {
+ TemplateKWLoc = ReadSourceLocation(F, Record, Idx);
+ unsigned NumTemplateArgs = Record[Idx++];
+ ArgInfo.setLAngleLoc(ReadSourceLocation(F, Record, Idx));
+ ArgInfo.setRAngleLoc(ReadSourceLocation(F, Record, Idx));
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ ArgInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Idx));
+ }
+
+ bool HadMultipleCandidates = Record[Idx++];
+
+ NamedDecl *FoundD = ReadDeclAs<NamedDecl>(F, Record, Idx);
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS);
+
+ QualType T = readType(F, Record, Idx);
+ ExprValueKind VK = static_cast<ExprValueKind>(Record[Idx++]);
+ ExprObjectKind OK = static_cast<ExprObjectKind>(Record[Idx++]);
+ Expr *Base = ReadSubExpr();
+ ValueDecl *MemberD = ReadDeclAs<ValueDecl>(F, Record, Idx);
+ SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx);
+ DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc);
+ bool IsArrow = Record[Idx++];
+ SourceLocation OperatorLoc = ReadSourceLocation(F, Record, Idx);
+
+ S = MemberExpr::Create(Context, Base, IsArrow, OperatorLoc, QualifierLoc,
+ TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
+ HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr, T,
+ VK, OK);
+ ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
+ MemberD->getDeclName(), Record, Idx);
+ if (HadMultipleCandidates)
+ cast<MemberExpr>(S)->setHadMultipleCandidates(true);
+ break;
+ }
+
+ case EXPR_BINARY_OPERATOR:
+ S = new (Context) BinaryOperator(Empty);
+ break;
+
+ case EXPR_COMPOUND_ASSIGN_OPERATOR:
+ S = new (Context) CompoundAssignOperator(Empty);
+ break;
+
+ case EXPR_CONDITIONAL_OPERATOR:
+ S = new (Context) ConditionalOperator(Empty);
+ break;
+
+ case EXPR_BINARY_CONDITIONAL_OPERATOR:
+ S = new (Context) BinaryConditionalOperator(Empty);
+ break;
+
+ case EXPR_IMPLICIT_CAST:
+ S = ImplicitCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CSTYLE_CAST:
+ S = CStyleCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_COMPOUND_LITERAL:
+ S = new (Context) CompoundLiteralExpr(Empty);
+ break;
+
+ case EXPR_EXT_VECTOR_ELEMENT:
+ S = new (Context) ExtVectorElementExpr(Empty);
+ break;
+
+ case EXPR_INIT_LIST:
+ S = new (Context) InitListExpr(Empty);
+ break;
+
+ case EXPR_DESIGNATED_INIT:
+ S = DesignatedInitExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields] - 1);
+
+ break;
+
+ case EXPR_IMPLICIT_VALUE_INIT:
+ S = new (Context) ImplicitValueInitExpr(Empty);
+ break;
+
+ case EXPR_VA_ARG:
+ S = new (Context) VAArgExpr(Empty);
+ break;
+
+ case EXPR_ADDR_LABEL:
+ S = new (Context) AddrLabelExpr(Empty);
+ break;
+
+ case EXPR_STMT:
+ S = new (Context) StmtExpr(Empty);
+ break;
+
+ case EXPR_CHOOSE:
+ S = new (Context) ChooseExpr(Empty);
+ break;
+
+ case EXPR_GNU_NULL:
+ S = new (Context) GNUNullExpr(Empty);
+ break;
+
+ case EXPR_SHUFFLE_VECTOR:
+ S = new (Context) ShuffleVectorExpr(Empty);
+ break;
+
+ case EXPR_CONVERT_VECTOR:
+ S = new (Context) ConvertVectorExpr(Empty);
+ break;
+
+ case EXPR_BLOCK:
+ S = new (Context) BlockExpr(Empty);
+ break;
+
+ case EXPR_GENERIC_SELECTION:
+ S = new (Context) GenericSelectionExpr(Empty);
+ break;
+
+ case EXPR_OBJC_STRING_LITERAL:
+ S = new (Context) ObjCStringLiteral(Empty);
+ break;
+ case EXPR_OBJC_BOXED_EXPRESSION:
+ S = new (Context) ObjCBoxedExpr(Empty);
+ break;
+ case EXPR_OBJC_ARRAY_LITERAL:
+ S = ObjCArrayLiteral::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+ case EXPR_OBJC_DICTIONARY_LITERAL:
+ S = ObjCDictionaryLiteral::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields],
+ Record[ASTStmtReader::NumExprFields + 1]);
+ break;
+ case EXPR_OBJC_ENCODE:
+ S = new (Context) ObjCEncodeExpr(Empty);
+ break;
+ case EXPR_OBJC_SELECTOR_EXPR:
+ S = new (Context) ObjCSelectorExpr(Empty);
+ break;
+ case EXPR_OBJC_PROTOCOL_EXPR:
+ S = new (Context) ObjCProtocolExpr(Empty);
+ break;
+ case EXPR_OBJC_IVAR_REF_EXPR:
+ S = new (Context) ObjCIvarRefExpr(Empty);
+ break;
+ case EXPR_OBJC_PROPERTY_REF_EXPR:
+ S = new (Context) ObjCPropertyRefExpr(Empty);
+ break;
+ case EXPR_OBJC_SUBSCRIPT_REF_EXPR:
+ S = new (Context) ObjCSubscriptRefExpr(Empty);
+ break;
+ case EXPR_OBJC_KVC_REF_EXPR:
+ llvm_unreachable("mismatching AST file");
+ case EXPR_OBJC_MESSAGE_EXPR:
+ S = ObjCMessageExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields],
+ Record[ASTStmtReader::NumExprFields + 1]);
+ break;
+ case EXPR_OBJC_ISA:
+ S = new (Context) ObjCIsaExpr(Empty);
+ break;
+ case EXPR_OBJC_INDIRECT_COPY_RESTORE:
+ S = new (Context) ObjCIndirectCopyRestoreExpr(Empty);
+ break;
+ case EXPR_OBJC_BRIDGED_CAST:
+ S = new (Context) ObjCBridgedCastExpr(Empty);
+ break;
+ case STMT_OBJC_FOR_COLLECTION:
+ S = new (Context) ObjCForCollectionStmt(Empty);
+ break;
+ case STMT_OBJC_CATCH:
+ S = new (Context) ObjCAtCatchStmt(Empty);
+ break;
+ case STMT_OBJC_FINALLY:
+ S = new (Context) ObjCAtFinallyStmt(Empty);
+ break;
+ case STMT_OBJC_AT_TRY:
+ S = ObjCAtTryStmt::CreateEmpty(Context,
+ Record[ASTStmtReader::NumStmtFields],
+ Record[ASTStmtReader::NumStmtFields + 1]);
+ break;
+ case STMT_OBJC_AT_SYNCHRONIZED:
+ S = new (Context) ObjCAtSynchronizedStmt(Empty);
+ break;
+ case STMT_OBJC_AT_THROW:
+ S = new (Context) ObjCAtThrowStmt(Empty);
+ break;
+ case STMT_OBJC_AUTORELEASE_POOL:
+ S = new (Context) ObjCAutoreleasePoolStmt(Empty);
+ break;
+ case EXPR_OBJC_BOOL_LITERAL:
+ S = new (Context) ObjCBoolLiteralExpr(Empty);
+ break;
+ case STMT_SEH_LEAVE:
+ S = new (Context) SEHLeaveStmt(Empty);
+ break;
+ case STMT_SEH_EXCEPT:
+ S = new (Context) SEHExceptStmt(Empty);
+ break;
+ case STMT_SEH_FINALLY:
+ S = new (Context) SEHFinallyStmt(Empty);
+ break;
+ case STMT_SEH_TRY:
+ S = new (Context) SEHTryStmt(Empty);
+ break;
+ case STMT_CXX_CATCH:
+ S = new (Context) CXXCatchStmt(Empty);
+ break;
+
+ case STMT_CXX_TRY:
+ S = CXXTryStmt::Create(Context, Empty,
+ /*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]);
+ break;
+
+ case STMT_CXX_FOR_RANGE:
+ S = new (Context) CXXForRangeStmt(Empty);
+ break;
+
+ case STMT_MS_DEPENDENT_EXISTS:
+ S = new (Context) MSDependentExistsStmt(SourceLocation(), true,
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(),
+ nullptr);
+ break;
+
+ case STMT_OMP_PARALLEL_DIRECTIVE:
+ S =
+ OMPParallelDirective::CreateEmpty(Context,
+ Record[ASTStmtReader::NumStmtFields],
+ Empty);
+ break;
+
+ case STMT_OMP_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_FOR_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPForDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
+ case STMT_OMP_FOR_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPForSimdDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
+ case STMT_OMP_SECTIONS_DIRECTIVE:
+ S = OMPSectionsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_SECTION_DIRECTIVE:
+ S = OMPSectionDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_SINGLE_DIRECTIVE:
+ S = OMPSingleDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_MASTER_DIRECTIVE:
+ S = OMPMasterDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_CRITICAL_DIRECTIVE:
+ S = OMPCriticalDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_PARALLEL_FOR_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelForDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelForSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE:
+ S = OMPParallelSectionsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TASK_DIRECTIVE:
+ S = OMPTaskDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TASKYIELD_DIRECTIVE:
+ S = OMPTaskyieldDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_BARRIER_DIRECTIVE:
+ S = OMPBarrierDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_TASKWAIT_DIRECTIVE:
+ S = OMPTaskwaitDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_FLUSH_DIRECTIVE:
+ S = OMPFlushDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_ORDERED_DIRECTIVE:
+ S = OMPOrderedDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_ATOMIC_DIRECTIVE:
+ S = OMPAtomicDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TARGET_DIRECTIVE:
+ S = OMPTargetDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TEAMS_DIRECTIVE:
+ S = OMPTeamsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case EXPR_CXX_OPERATOR_CALL:
+ S = new (Context) CXXOperatorCallExpr(Context, Empty);
+ break;
+
+ case EXPR_CXX_MEMBER_CALL:
+ S = new (Context) CXXMemberCallExpr(Context, Empty);
+ break;
+
+ case EXPR_CXX_CONSTRUCT:
+ S = new (Context) CXXConstructExpr(Empty);
+ break;
+
+ case EXPR_CXX_TEMPORARY_OBJECT:
+ S = new (Context) CXXTemporaryObjectExpr(Empty);
+ break;
+
+ case EXPR_CXX_STATIC_CAST:
+ S = CXXStaticCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CXX_DYNAMIC_CAST:
+ S = CXXDynamicCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CXX_REINTERPRET_CAST:
+ S = CXXReinterpretCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CXX_CONST_CAST:
+ S = CXXConstCastExpr::CreateEmpty(Context);
+ break;
+
+ case EXPR_CXX_FUNCTIONAL_CAST:
+ S = CXXFunctionalCastExpr::CreateEmpty(Context,
+ /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_USER_DEFINED_LITERAL:
+ S = new (Context) UserDefinedLiteral(Context, Empty);
+ break;
+
+ case EXPR_CXX_STD_INITIALIZER_LIST:
+ S = new (Context) CXXStdInitializerListExpr(Empty);
+ break;
+
+ case EXPR_CXX_BOOL_LITERAL:
+ S = new (Context) CXXBoolLiteralExpr(Empty);
+ break;
+
+ case EXPR_CXX_NULL_PTR_LITERAL:
+ S = new (Context) CXXNullPtrLiteralExpr(Empty);
+ break;
+ case EXPR_CXX_TYPEID_EXPR:
+ S = new (Context) CXXTypeidExpr(Empty, true);
+ break;
+ case EXPR_CXX_TYPEID_TYPE:
+ S = new (Context) CXXTypeidExpr(Empty, false);
+ break;
+ case EXPR_CXX_UUIDOF_EXPR:
+ S = new (Context) CXXUuidofExpr(Empty, true);
+ break;
+ case EXPR_CXX_PROPERTY_REF_EXPR:
+ S = new (Context) MSPropertyRefExpr(Empty);
+ break;
+ case EXPR_CXX_UUIDOF_TYPE:
+ S = new (Context) CXXUuidofExpr(Empty, false);
+ break;
+ case EXPR_CXX_THIS:
+ S = new (Context) CXXThisExpr(Empty);
+ break;
+ case EXPR_CXX_THROW:
+ S = new (Context) CXXThrowExpr(Empty);
+ break;
+ case EXPR_CXX_DEFAULT_ARG: {
+ bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields];
+ if (HasOtherExprStored) {
+ Expr *SubExpr = ReadSubExpr();
+ S = CXXDefaultArgExpr::Create(Context, SourceLocation(), nullptr,
+ SubExpr);
+ } else
+ S = new (Context) CXXDefaultArgExpr(Empty);
+ break;
+ }
+ case EXPR_CXX_DEFAULT_INIT:
+ S = new (Context) CXXDefaultInitExpr(Empty);
+ break;
+ case EXPR_CXX_BIND_TEMPORARY:
+ S = new (Context) CXXBindTemporaryExpr(Empty);
+ break;
+
+ case EXPR_CXX_SCALAR_VALUE_INIT:
+ S = new (Context) CXXScalarValueInitExpr(Empty);
+ break;
+ case EXPR_CXX_NEW:
+ S = new (Context) CXXNewExpr(Empty);
+ break;
+ case EXPR_CXX_DELETE:
+ S = new (Context) CXXDeleteExpr(Empty);
+ break;
+ case EXPR_CXX_PSEUDO_DESTRUCTOR:
+ S = new (Context) CXXPseudoDestructorExpr(Empty);
+ break;
+
+ case EXPR_EXPR_WITH_CLEANUPS:
+ S = ExprWithCleanups::Create(Context, Empty,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
+ S = CXXDependentScopeMemberExpr::CreateEmpty(Context,
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
+ ? Record[ASTStmtReader::NumExprFields + 1]
+ : 0);
+ break;
+
+ case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:
+ S = DependentScopeDeclRefExpr::CreateEmpty(Context,
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
+ ? Record[ASTStmtReader::NumExprFields + 1]
+ : 0);
+ break;
+
+ case EXPR_CXX_UNRESOLVED_CONSTRUCT:
+ S = CXXUnresolvedConstructExpr::CreateEmpty(Context,
+ /*NumArgs=*/Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_CXX_UNRESOLVED_MEMBER:
+ S = UnresolvedMemberExpr::CreateEmpty(Context,
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
+ ? Record[ASTStmtReader::NumExprFields + 1]
+ : 0);
+ break;
+
+ case EXPR_CXX_UNRESOLVED_LOOKUP:
+ S = UnresolvedLookupExpr::CreateEmpty(Context,
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
+ ? Record[ASTStmtReader::NumExprFields + 1]
+ : 0);
+ break;
+
+ case EXPR_TYPE_TRAIT:
+ S = TypeTraitExpr::CreateDeserialized(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_ARRAY_TYPE_TRAIT:
+ S = new (Context) ArrayTypeTraitExpr(Empty);
+ break;
+
+ case EXPR_CXX_EXPRESSION_TRAIT:
+ S = new (Context) ExpressionTraitExpr(Empty);
+ break;
+
+ case EXPR_CXX_NOEXCEPT:
+ S = new (Context) CXXNoexceptExpr(Empty);
+ break;
+
+ case EXPR_PACK_EXPANSION:
+ S = new (Context) PackExpansionExpr(Empty);
+ break;
+
+ case EXPR_SIZEOF_PACK:
+ S = new (Context) SizeOfPackExpr(Empty);
+ break;
+
+ case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
+ S = new (Context) SubstNonTypeTemplateParmExpr(Empty);
+ break;
+
+ case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK:
+ S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
+ break;
+
+ case EXPR_FUNCTION_PARM_PACK:
+ S = FunctionParmPackExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+
+ case EXPR_MATERIALIZE_TEMPORARY:
+ S = new (Context) MaterializeTemporaryExpr(Empty);
+ break;
+
+ case EXPR_CXX_FOLD:
+ S = new (Context) CXXFoldExpr(Empty);
+ break;
+
+ case EXPR_OPAQUE_VALUE:
+ S = new (Context) OpaqueValueExpr(Empty);
+ break;
+
+ case EXPR_CUDA_KERNEL_CALL:
+ S = new (Context) CUDAKernelCallExpr(Context, Empty);
+ break;
+
+ case EXPR_ASTYPE:
+ S = new (Context) AsTypeExpr(Empty);
+ break;
+
+ case EXPR_PSEUDO_OBJECT: {
+ unsigned numSemanticExprs = Record[ASTStmtReader::NumExprFields];
+ S = PseudoObjectExpr::Create(Context, Empty, numSemanticExprs);
+ break;
+ }
+
+ case EXPR_ATOMIC:
+ S = new (Context) AtomicExpr(Empty);
+ break;
+
+ case EXPR_LAMBDA: {
+ unsigned NumCaptures = Record[ASTStmtReader::NumExprFields];
+ unsigned NumArrayIndexVars = Record[ASTStmtReader::NumExprFields + 1];
+ S = LambdaExpr::CreateDeserialized(Context, NumCaptures,
+ NumArrayIndexVars);
+ break;
+ }
+ }
+
+ // We hit a STMT_STOP, so we're done with this expression.
+ if (Finished)
+ break;
+
+ ++NumStatementsRead;
+
+ if (S && !IsStmtReference) {
+ Reader.Visit(S);
+ StmtEntries[Cursor.GetCurrentBitNo()] = S;
+ }
+
+
+ assert(Idx == Record.size() && "Invalid deserialization of statement");
+ StmtStack.push_back(S);
+ }
+Done:
+ assert(StmtStack.size() > PrevNumStmts && "Read too many sub-stmts!");
+ assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!");
+ return StmtStack.pop_back_val();
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
new file mode 100644
index 0000000..e689234
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
@@ -0,0 +1,5769 @@
+//===--- ASTWriter.cpp - AST File Writer ----------------------------------===//
+//
+// 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 ASTWriter class, which writes AST files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTWriter.h"
+#include "ASTCommon.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclLookups.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemStatCache.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/Version.h"
+#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include <algorithm>
+#include <cstdio>
+#include <string.h>
+#include <utility>
+using namespace clang;
+using namespace clang::serialization;
+
+template <typename T, typename Allocator>
+static StringRef bytes(const std::vector<T, Allocator> &v) {
+ if (v.empty()) return StringRef();
+ return StringRef(reinterpret_cast<const char*>(&v[0]),
+ sizeof(T) * v.size());
+}
+
+template <typename T>
+static StringRef bytes(const SmallVectorImpl<T> &v) {
+ return StringRef(reinterpret_cast<const char*>(v.data()),
+ sizeof(T) * v.size());
+}
+
+//===----------------------------------------------------------------------===//
+// Type serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class ASTTypeWriter {
+ ASTWriter &Writer;
+ ASTWriter::RecordDataImpl &Record;
+
+ public:
+ /// \brief Type code that corresponds to the record generated.
+ TypeCode Code;
+ /// \brief Abbreviation to use for the record, if any.
+ unsigned AbbrevToUse;
+
+ ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
+ : Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { }
+
+ void VisitArrayType(const ArrayType *T);
+ void VisitFunctionType(const FunctionType *T);
+ void VisitTagType(const TagType *T);
+
+#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
+ llvm_unreachable("Built-in types are never serialized");
+}
+
+void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Code = TYPE_COMPLEX;
+}
+
+void ASTTypeWriter::VisitPointerType(const PointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = TYPE_POINTER;
+}
+
+void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
+ Writer.AddTypeRef(T->getOriginalType(), Record);
+ Code = TYPE_DECAYED;
+}
+
+void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) {
+ Writer.AddTypeRef(T->getOriginalType(), Record);
+ Writer.AddTypeRef(T->getAdjustedType(), Record);
+ Code = TYPE_ADJUSTED;
+}
+
+void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = TYPE_BLOCK_POINTER;
+}
+
+void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
+ Record.push_back(T->isSpelledAsLValue());
+ Code = TYPE_LVALUE_REFERENCE;
+}
+
+void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
+ Code = TYPE_RVALUE_REFERENCE;
+}
+
+void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
+ Code = TYPE_MEMBER_POINTER;
+}
+
+void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getSizeModifier()); // FIXME: stable values
+ Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
+}
+
+void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddAPInt(T->getSize(), Record);
+ Code = TYPE_CONSTANT_ARRAY;
+}
+
+void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ VisitArrayType(T);
+ Code = TYPE_INCOMPLETE_ARRAY;
+}
+
+void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddSourceLocation(T->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(T->getRBracketLoc(), Record);
+ Writer.AddStmt(T->getSizeExpr());
+ Code = TYPE_VARIABLE_ARRAY;
+}
+
+void ASTTypeWriter::VisitVectorType(const VectorType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getNumElements());
+ Record.push_back(T->getVectorKind());
+ Code = TYPE_VECTOR;
+}
+
+void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
+ VisitVectorType(T);
+ Code = TYPE_EXT_VECTOR;
+}
+
+void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
+ Writer.AddTypeRef(T->getReturnType(), Record);
+ FunctionType::ExtInfo C = T->getExtInfo();
+ Record.push_back(C.getNoReturn());
+ Record.push_back(C.getHasRegParm());
+ Record.push_back(C.getRegParm());
+ // FIXME: need to stabilize encoding of calling convention...
+ Record.push_back(C.getCC());
+ Record.push_back(C.getProducesResult());
+
+ if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
+ AbbrevToUse = 0;
+}
+
+void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ VisitFunctionType(T);
+ Code = TYPE_FUNCTION_NO_PROTO;
+}
+
+static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T,
+ ASTWriter::RecordDataImpl &Record) {
+ Record.push_back(T->getExceptionSpecType());
+ if (T->getExceptionSpecType() == EST_Dynamic) {
+ Record.push_back(T->getNumExceptions());
+ for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
+ Writer.AddTypeRef(T->getExceptionType(I), Record);
+ } else if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+ Writer.AddStmt(T->getNoexceptExpr());
+ } else if (T->getExceptionSpecType() == EST_Uninstantiated) {
+ Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
+ Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record);
+ } else if (T->getExceptionSpecType() == EST_Unevaluated) {
+ Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
+ }
+}
+
+void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
+ VisitFunctionType(T);
+
+ Record.push_back(T->isVariadic());
+ Record.push_back(T->hasTrailingReturn());
+ Record.push_back(T->getTypeQuals());
+ Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
+ addExceptionSpec(Writer, T, Record);
+
+ Record.push_back(T->getNumParams());
+ for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
+ Writer.AddTypeRef(T->getParamType(I), Record);
+
+ if (T->isVariadic() || T->hasTrailingReturn() || T->getTypeQuals() ||
+ T->getRefQualifier() || T->getExceptionSpecType() != EST_None)
+ AbbrevToUse = 0;
+
+ Code = TYPE_FUNCTION_PROTO;
+}
+
+void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = TYPE_UNRESOLVED_USING;
+}
+
+void ASTTypeWriter::VisitTypedefType(const TypedefType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
+ Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record);
+ Code = TYPE_TYPEDEF;
+}
+
+void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = TYPE_TYPEOF_EXPR;
+}
+
+void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Code = TYPE_TYPEOF;
+}
+
+void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = TYPE_DECLTYPE;
+}
+
+void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Record.push_back(T->getUTTKind());
+ Code = TYPE_UNARY_TRANSFORM;
+}
+
+void ASTTypeWriter::VisitAutoType(const AutoType *T) {
+ Writer.AddTypeRef(T->getDeducedType(), Record);
+ Record.push_back(T->isDecltypeAuto());
+ if (T->getDeducedType().isNull())
+ Record.push_back(T->isDependentType());
+ Code = TYPE_AUTO;
+}
+
+void ASTTypeWriter::VisitTagType(const TagType *T) {
+ Record.push_back(T->isDependentType());
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
+ assert(!T->isBeingDefined() &&
+ "Cannot serialize in the middle of a type definition");
+}
+
+void ASTTypeWriter::VisitRecordType(const RecordType *T) {
+ VisitTagType(T);
+ Code = TYPE_RECORD;
+}
+
+void ASTTypeWriter::VisitEnumType(const EnumType *T) {
+ VisitTagType(T);
+ Code = TYPE_ENUM;
+}
+
+void ASTTypeWriter::VisitAttributedType(const AttributedType *T) {
+ Writer.AddTypeRef(T->getModifiedType(), Record);
+ Writer.AddTypeRef(T->getEquivalentType(), Record);
+ Record.push_back(T->getAttrKind());
+ Code = TYPE_ATTRIBUTED;
+}
+
+void
+ASTTypeWriter::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
+ Writer.AddTypeRef(T->getReplacementType(), Record);
+ Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
+}
+
+void
+ASTTypeWriter::VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
+ Writer.AddTemplateArgument(T->getArgumentPack(), Record);
+ Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK;
+}
+
+void
+ASTTypeWriter::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ Record.push_back(T->isDependentType());
+ Writer.AddTemplateName(T->getTemplateName(), Record);
+ Record.push_back(T->getNumArgs());
+ for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
+ ArgI != ArgE; ++ArgI)
+ Writer.AddTemplateArgument(*ArgI, Record);
+ Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
+ T->isCanonicalUnqualified() ? QualType()
+ : T->getCanonicalTypeInternal(),
+ Record);
+ Code = TYPE_TEMPLATE_SPECIALIZATION;
+}
+
+void
+ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddStmt(T->getSizeExpr());
+ Writer.AddSourceRange(T->getBracketsRange(), Record);
+ Code = TYPE_DEPENDENT_SIZED_ARRAY;
+}
+
+void
+ASTTypeWriter::VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ // FIXME: Serialize this type (C++ only)
+ llvm_unreachable("Cannot serialize dependent sized extended vector types");
+}
+
+void
+ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ Record.push_back(T->getDepth());
+ Record.push_back(T->getIndex());
+ Record.push_back(T->isParameterPack());
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = TYPE_TEMPLATE_TYPE_PARM;
+}
+
+void
+ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddIdentifierRef(T->getIdentifier(), Record);
+ Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+ : T->getCanonicalTypeInternal(),
+ Record);
+ Code = TYPE_DEPENDENT_NAME;
+}
+
+void
+ASTTypeWriter::VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddIdentifierRef(T->getIdentifier(), Record);
+ Record.push_back(T->getNumArgs());
+ for (DependentTemplateSpecializationType::iterator
+ I = T->begin(), E = T->end(); I != E; ++I)
+ Writer.AddTemplateArgument(*I, Record);
+ Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
+}
+
+void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
+ Writer.AddTypeRef(T->getPattern(), Record);
+ if (Optional<unsigned> NumExpansions = T->getNumExpansions())
+ Record.push_back(*NumExpansions + 1);
+ else
+ Record.push_back(0);
+ Code = TYPE_PACK_EXPANSION;
+}
+
+void ASTTypeWriter::VisitParenType(const ParenType *T) {
+ Writer.AddTypeRef(T->getInnerType(), Record);
+ Code = TYPE_PAREN;
+}
+
+void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddTypeRef(T->getNamedType(), Record);
+ Code = TYPE_ELABORATED;
+}
+
+void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
+ Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
+ Code = TYPE_INJECTED_CLASS_NAME;
+}
+
+void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
+ Code = TYPE_OBJC_INTERFACE;
+}
+
+void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Record.push_back(T->getNumProtocols());
+ for (const auto *I : T->quals())
+ Writer.AddDeclRef(I, Record);
+ Code = TYPE_OBJC_OBJECT;
+}
+
+void
+ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = TYPE_OBJC_OBJECT_POINTER;
+}
+
+void
+ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
+ Writer.AddTypeRef(T->getValueType(), Record);
+ Code = TYPE_ATOMIC;
+}
+
+namespace {
+
+class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
+ ASTWriter &Writer;
+ ASTWriter::RecordDataImpl &Record;
+
+public:
+ TypeLocWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
+ : Writer(Writer), Record(Record) { }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitArrayTypeLoc(ArrayTypeLoc TyLoc);
+ void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
+};
+
+}
+
+void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
+ if (TL.needsExtraLocalData()) {
+ Record.push_back(TL.getWrittenTypeSpec());
+ Record.push_back(TL.getWrittenSignSpec());
+ Record.push_back(TL.getWrittenWidthSpec());
+ Record.push_back(TL.hasModeAttr());
+ }
+}
+void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getCaretLoc(), Record);
+}
+void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getAmpLoc(), Record);
+}
+void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record);
+}
+void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record);
+}
+void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
+ Writer.AddSourceLocation(TL.getRBracketLoc(), Record);
+ Record.push_back(TL.getSizeExpr() ? 1 : 0);
+ if (TL.getSizeExpr())
+ Writer.AddStmt(TL.getSizeExpr());
+}
+void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
+ DependentSizedArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
+ DependentSizedExtVectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
+ for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i)
+ Writer.AddDeclRef(TL.getParam(i), Record);
+}
+void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+}
+void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
+}
+void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
+}
+void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getAttrNameLoc(), Record);
+ if (TL.hasAttrOperand()) {
+ SourceRange range = TL.getAttrOperandParensRange();
+ Writer.AddSourceLocation(range.getBegin(), Record);
+ Writer.AddSourceLocation(range.getEnd(), Record);
+ }
+ if (TL.hasAttrExprOperand()) {
+ Expr *operand = TL.getAttrExprOperand();
+ Record.push_back(operand ? 1 : 0);
+ if (operand) Writer.AddStmt(operand);
+ } else if (TL.hasAttrEnumOperand()) {
+ Writer.AddSourceLocation(TL.getAttrEnumOperandLoc(), Record);
+ }
+}
+void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
+ SubstTemplateTypeParmTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
+ SubstTemplateTypeParmPackTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(),
+ TL.getArgLoc(i).getLocInfo(), Record);
+}
+void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+}
+void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
+}
+void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
+ Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
+ TL.getArgLoc(I).getLocInfo(), Record);
+}
+void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getEllipsisLoc(), Record);
+}
+void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ Record.push_back(TL.hasBaseTypeAsWritten());
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
+ Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
+}
+void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+}
+
+void ASTWriter::WriteTypeAbbrevs() {
+ using namespace llvm;
+
+ BitCodeAbbrev *Abv;
+
+ // Abbreviation for TYPE_EXT_QUAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::TYPE_EXT_QUAL));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 3)); // Quals
+ TypeExtQualAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for TYPE_FUNCTION_PROTO
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::TYPE_FUNCTION_PROTO));
+ // FunctionType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ReturnType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // NoReturn
+ Abv->Add(BitCodeAbbrevOp(0)); // HasRegParm
+ Abv->Add(BitCodeAbbrevOp(0)); // RegParm
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC
+ Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult
+ // FunctionProtoType
+ Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic
+ Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn
+ Abv->Add(BitCodeAbbrevOp(0)); // TypeQuals
+ Abv->Add(BitCodeAbbrevOp(0)); // RefQualifier
+ Abv->Add(BitCodeAbbrevOp(EST_None)); // ExceptionSpec
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumParams
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Params
+ TypeFunctionProtoAbbrev = Stream.EmitAbbrev(Abv);
+}
+
+//===----------------------------------------------------------------------===//
+// ASTWriter Implementation
+//===----------------------------------------------------------------------===//
+
+static void EmitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ ASTWriter::RecordDataImpl &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (!Name || Name[0] == 0)
+ return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void EmitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ ASTWriter::RecordDataImpl &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
+ ASTWriter::RecordDataImpl &Record) {
+#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
+ RECORD(STMT_STOP);
+ RECORD(STMT_NULL_PTR);
+ RECORD(STMT_REF_PTR);
+ RECORD(STMT_NULL);
+ RECORD(STMT_COMPOUND);
+ RECORD(STMT_CASE);
+ RECORD(STMT_DEFAULT);
+ RECORD(STMT_LABEL);
+ RECORD(STMT_ATTRIBUTED);
+ RECORD(STMT_IF);
+ RECORD(STMT_SWITCH);
+ RECORD(STMT_WHILE);
+ RECORD(STMT_DO);
+ RECORD(STMT_FOR);
+ RECORD(STMT_GOTO);
+ RECORD(STMT_INDIRECT_GOTO);
+ RECORD(STMT_CONTINUE);
+ RECORD(STMT_BREAK);
+ RECORD(STMT_RETURN);
+ RECORD(STMT_DECL);
+ RECORD(STMT_GCCASM);
+ RECORD(STMT_MSASM);
+ RECORD(EXPR_PREDEFINED);
+ RECORD(EXPR_DECL_REF);
+ RECORD(EXPR_INTEGER_LITERAL);
+ RECORD(EXPR_FLOATING_LITERAL);
+ RECORD(EXPR_IMAGINARY_LITERAL);
+ RECORD(EXPR_STRING_LITERAL);
+ RECORD(EXPR_CHARACTER_LITERAL);
+ RECORD(EXPR_PAREN);
+ RECORD(EXPR_PAREN_LIST);
+ RECORD(EXPR_UNARY_OPERATOR);
+ RECORD(EXPR_SIZEOF_ALIGN_OF);
+ RECORD(EXPR_ARRAY_SUBSCRIPT);
+ RECORD(EXPR_CALL);
+ RECORD(EXPR_MEMBER);
+ RECORD(EXPR_BINARY_OPERATOR);
+ RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
+ RECORD(EXPR_CONDITIONAL_OPERATOR);
+ RECORD(EXPR_IMPLICIT_CAST);
+ RECORD(EXPR_CSTYLE_CAST);
+ RECORD(EXPR_COMPOUND_LITERAL);
+ RECORD(EXPR_EXT_VECTOR_ELEMENT);
+ RECORD(EXPR_INIT_LIST);
+ RECORD(EXPR_DESIGNATED_INIT);
+ RECORD(EXPR_IMPLICIT_VALUE_INIT);
+ RECORD(EXPR_VA_ARG);
+ RECORD(EXPR_ADDR_LABEL);
+ RECORD(EXPR_STMT);
+ RECORD(EXPR_CHOOSE);
+ RECORD(EXPR_GNU_NULL);
+ RECORD(EXPR_SHUFFLE_VECTOR);
+ RECORD(EXPR_BLOCK);
+ RECORD(EXPR_GENERIC_SELECTION);
+ RECORD(EXPR_OBJC_STRING_LITERAL);
+ RECORD(EXPR_OBJC_BOXED_EXPRESSION);
+ RECORD(EXPR_OBJC_ARRAY_LITERAL);
+ RECORD(EXPR_OBJC_DICTIONARY_LITERAL);
+ RECORD(EXPR_OBJC_ENCODE);
+ RECORD(EXPR_OBJC_SELECTOR_EXPR);
+ RECORD(EXPR_OBJC_PROTOCOL_EXPR);
+ RECORD(EXPR_OBJC_IVAR_REF_EXPR);
+ RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
+ RECORD(EXPR_OBJC_KVC_REF_EXPR);
+ RECORD(EXPR_OBJC_MESSAGE_EXPR);
+ RECORD(STMT_OBJC_FOR_COLLECTION);
+ RECORD(STMT_OBJC_CATCH);
+ RECORD(STMT_OBJC_FINALLY);
+ RECORD(STMT_OBJC_AT_TRY);
+ RECORD(STMT_OBJC_AT_SYNCHRONIZED);
+ RECORD(STMT_OBJC_AT_THROW);
+ RECORD(EXPR_OBJC_BOOL_LITERAL);
+ RECORD(STMT_CXX_CATCH);
+ RECORD(STMT_CXX_TRY);
+ RECORD(STMT_CXX_FOR_RANGE);
+ RECORD(EXPR_CXX_OPERATOR_CALL);
+ RECORD(EXPR_CXX_MEMBER_CALL);
+ RECORD(EXPR_CXX_CONSTRUCT);
+ RECORD(EXPR_CXX_TEMPORARY_OBJECT);
+ RECORD(EXPR_CXX_STATIC_CAST);
+ RECORD(EXPR_CXX_DYNAMIC_CAST);
+ RECORD(EXPR_CXX_REINTERPRET_CAST);
+ RECORD(EXPR_CXX_CONST_CAST);
+ RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_USER_DEFINED_LITERAL);
+ RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
+ RECORD(EXPR_CXX_BOOL_LITERAL);
+ RECORD(EXPR_CXX_NULL_PTR_LITERAL);
+ RECORD(EXPR_CXX_TYPEID_EXPR);
+ RECORD(EXPR_CXX_TYPEID_TYPE);
+ RECORD(EXPR_CXX_THIS);
+ RECORD(EXPR_CXX_THROW);
+ RECORD(EXPR_CXX_DEFAULT_ARG);
+ RECORD(EXPR_CXX_DEFAULT_INIT);
+ RECORD(EXPR_CXX_BIND_TEMPORARY);
+ RECORD(EXPR_CXX_SCALAR_VALUE_INIT);
+ RECORD(EXPR_CXX_NEW);
+ RECORD(EXPR_CXX_DELETE);
+ RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR);
+ RECORD(EXPR_EXPR_WITH_CLEANUPS);
+ RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER);
+ RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF);
+ RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT);
+ RECORD(EXPR_CXX_UNRESOLVED_MEMBER);
+ RECORD(EXPR_CXX_UNRESOLVED_LOOKUP);
+ RECORD(EXPR_CXX_EXPRESSION_TRAIT);
+ RECORD(EXPR_CXX_NOEXCEPT);
+ RECORD(EXPR_OPAQUE_VALUE);
+ RECORD(EXPR_BINARY_CONDITIONAL_OPERATOR);
+ RECORD(EXPR_TYPE_TRAIT);
+ RECORD(EXPR_ARRAY_TYPE_TRAIT);
+ RECORD(EXPR_PACK_EXPANSION);
+ RECORD(EXPR_SIZEOF_PACK);
+ RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM);
+ RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
+ RECORD(EXPR_FUNCTION_PARM_PACK);
+ RECORD(EXPR_MATERIALIZE_TEMPORARY);
+ RECORD(EXPR_CUDA_KERNEL_CALL);
+ RECORD(EXPR_CXX_UUIDOF_EXPR);
+ RECORD(EXPR_CXX_UUIDOF_TYPE);
+ RECORD(EXPR_LAMBDA);
+#undef RECORD
+}
+
+void ASTWriter::WriteBlockInfoBlock() {
+ RecordData Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
+
+ // Control Block.
+ BLOCK(CONTROL_BLOCK);
+ RECORD(METADATA);
+ RECORD(SIGNATURE);
+ RECORD(MODULE_NAME);
+ RECORD(MODULE_MAP_FILE);
+ RECORD(IMPORTS);
+ RECORD(KNOWN_MODULE_FILES);
+ RECORD(LANGUAGE_OPTIONS);
+ RECORD(TARGET_OPTIONS);
+ RECORD(ORIGINAL_FILE);
+ RECORD(ORIGINAL_PCH_DIR);
+ RECORD(ORIGINAL_FILE_ID);
+ RECORD(INPUT_FILE_OFFSETS);
+ RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(FILE_SYSTEM_OPTIONS);
+ RECORD(HEADER_SEARCH_OPTIONS);
+ RECORD(PREPROCESSOR_OPTIONS);
+
+ BLOCK(INPUT_FILES_BLOCK);
+ RECORD(INPUT_FILE);
+
+ // AST Top-Level Block.
+ BLOCK(AST_BLOCK);
+ RECORD(TYPE_OFFSET);
+ RECORD(DECL_OFFSET);
+ RECORD(IDENTIFIER_OFFSET);
+ RECORD(IDENTIFIER_TABLE);
+ RECORD(EAGERLY_DESERIALIZED_DECLS);
+ RECORD(SPECIAL_TYPES);
+ RECORD(STATISTICS);
+ RECORD(TENTATIVE_DEFINITIONS);
+ RECORD(UNUSED_FILESCOPED_DECLS);
+ RECORD(SELECTOR_OFFSETS);
+ RECORD(METHOD_POOL);
+ RECORD(PP_COUNTER_VALUE);
+ RECORD(SOURCE_LOCATION_OFFSETS);
+ RECORD(SOURCE_LOCATION_PRELOADS);
+ RECORD(EXT_VECTOR_DECLS);
+ RECORD(PPD_ENTITIES_OFFSETS);
+ RECORD(REFERENCED_SELECTOR_POOL);
+ RECORD(TU_UPDATE_LEXICAL);
+ RECORD(LOCAL_REDECLARATIONS_MAP);
+ RECORD(SEMA_DECL_REFS);
+ RECORD(WEAK_UNDECLARED_IDENTIFIERS);
+ RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
+ RECORD(DECL_REPLACEMENTS);
+ RECORD(UPDATE_VISIBLE);
+ RECORD(DECL_UPDATE_OFFSETS);
+ RECORD(DECL_UPDATES);
+ RECORD(CXX_BASE_SPECIFIER_OFFSETS);
+ RECORD(DIAG_PRAGMA_MAPPINGS);
+ RECORD(CUDA_SPECIAL_DECL_REFS);
+ RECORD(HEADER_SEARCH_TABLE);
+ RECORD(FP_PRAGMA_OPTIONS);
+ RECORD(OPENCL_EXTENSIONS);
+ RECORD(DELEGATING_CTORS);
+ RECORD(KNOWN_NAMESPACES);
+ RECORD(UNDEFINED_BUT_USED);
+ RECORD(MODULE_OFFSET_MAP);
+ RECORD(SOURCE_MANAGER_LINE_TABLE);
+ RECORD(OBJC_CATEGORIES_MAP);
+ RECORD(FILE_SORTED_DECLS);
+ RECORD(IMPORTED_MODULES);
+ RECORD(LOCAL_REDECLARATIONS);
+ RECORD(OBJC_CATEGORIES);
+ RECORD(MACRO_OFFSET);
+ RECORD(LATE_PARSED_TEMPLATE);
+ RECORD(OPTIMIZE_PRAGMA_OPTIONS);
+
+ // SourceManager Block.
+ BLOCK(SOURCE_MANAGER_BLOCK);
+ RECORD(SM_SLOC_FILE_ENTRY);
+ RECORD(SM_SLOC_BUFFER_ENTRY);
+ RECORD(SM_SLOC_BUFFER_BLOB);
+ RECORD(SM_SLOC_EXPANSION_ENTRY);
+
+ // Preprocessor Block.
+ BLOCK(PREPROCESSOR_BLOCK);
+ RECORD(PP_MACRO_DIRECTIVE_HISTORY);
+ RECORD(PP_MACRO_FUNCTION_LIKE);
+ RECORD(PP_MACRO_OBJECT_LIKE);
+ RECORD(PP_MODULE_MACRO);
+ RECORD(PP_TOKEN);
+
+ // Decls and Types block.
+ BLOCK(DECLTYPES_BLOCK);
+ RECORD(TYPE_EXT_QUAL);
+ RECORD(TYPE_COMPLEX);
+ RECORD(TYPE_POINTER);
+ RECORD(TYPE_BLOCK_POINTER);
+ RECORD(TYPE_LVALUE_REFERENCE);
+ RECORD(TYPE_RVALUE_REFERENCE);
+ RECORD(TYPE_MEMBER_POINTER);
+ RECORD(TYPE_CONSTANT_ARRAY);
+ RECORD(TYPE_INCOMPLETE_ARRAY);
+ RECORD(TYPE_VARIABLE_ARRAY);
+ RECORD(TYPE_VECTOR);
+ RECORD(TYPE_EXT_VECTOR);
+ RECORD(TYPE_FUNCTION_NO_PROTO);
+ RECORD(TYPE_FUNCTION_PROTO);
+ RECORD(TYPE_TYPEDEF);
+ RECORD(TYPE_TYPEOF_EXPR);
+ RECORD(TYPE_TYPEOF);
+ RECORD(TYPE_RECORD);
+ RECORD(TYPE_ENUM);
+ RECORD(TYPE_OBJC_INTERFACE);
+ RECORD(TYPE_OBJC_OBJECT_POINTER);
+ RECORD(TYPE_DECLTYPE);
+ RECORD(TYPE_ELABORATED);
+ RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM);
+ RECORD(TYPE_UNRESOLVED_USING);
+ RECORD(TYPE_INJECTED_CLASS_NAME);
+ RECORD(TYPE_OBJC_OBJECT);
+ RECORD(TYPE_TEMPLATE_TYPE_PARM);
+ RECORD(TYPE_TEMPLATE_SPECIALIZATION);
+ RECORD(TYPE_DEPENDENT_NAME);
+ RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION);
+ RECORD(TYPE_DEPENDENT_SIZED_ARRAY);
+ RECORD(TYPE_PAREN);
+ RECORD(TYPE_PACK_EXPANSION);
+ RECORD(TYPE_ATTRIBUTED);
+ RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
+ RECORD(TYPE_AUTO);
+ RECORD(TYPE_UNARY_TRANSFORM);
+ RECORD(TYPE_ATOMIC);
+ RECORD(TYPE_DECAYED);
+ RECORD(TYPE_ADJUSTED);
+ RECORD(DECL_TYPEDEF);
+ RECORD(DECL_TYPEALIAS);
+ RECORD(DECL_ENUM);
+ RECORD(DECL_RECORD);
+ RECORD(DECL_ENUM_CONSTANT);
+ RECORD(DECL_FUNCTION);
+ RECORD(DECL_OBJC_METHOD);
+ RECORD(DECL_OBJC_INTERFACE);
+ RECORD(DECL_OBJC_PROTOCOL);
+ RECORD(DECL_OBJC_IVAR);
+ RECORD(DECL_OBJC_AT_DEFS_FIELD);
+ RECORD(DECL_OBJC_CATEGORY);
+ RECORD(DECL_OBJC_CATEGORY_IMPL);
+ RECORD(DECL_OBJC_IMPLEMENTATION);
+ RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
+ RECORD(DECL_OBJC_PROPERTY);
+ RECORD(DECL_OBJC_PROPERTY_IMPL);
+ RECORD(DECL_FIELD);
+ RECORD(DECL_MS_PROPERTY);
+ RECORD(DECL_VAR);
+ RECORD(DECL_IMPLICIT_PARAM);
+ RECORD(DECL_PARM_VAR);
+ RECORD(DECL_FILE_SCOPE_ASM);
+ RECORD(DECL_BLOCK);
+ RECORD(DECL_CONTEXT_LEXICAL);
+ RECORD(DECL_CONTEXT_VISIBLE);
+ RECORD(DECL_NAMESPACE);
+ RECORD(DECL_NAMESPACE_ALIAS);
+ RECORD(DECL_USING);
+ RECORD(DECL_USING_SHADOW);
+ RECORD(DECL_USING_DIRECTIVE);
+ RECORD(DECL_UNRESOLVED_USING_VALUE);
+ RECORD(DECL_UNRESOLVED_USING_TYPENAME);
+ RECORD(DECL_LINKAGE_SPEC);
+ RECORD(DECL_CXX_RECORD);
+ RECORD(DECL_CXX_METHOD);
+ RECORD(DECL_CXX_CONSTRUCTOR);
+ RECORD(DECL_CXX_DESTRUCTOR);
+ RECORD(DECL_CXX_CONVERSION);
+ RECORD(DECL_ACCESS_SPEC);
+ RECORD(DECL_FRIEND);
+ RECORD(DECL_FRIEND_TEMPLATE);
+ RECORD(DECL_CLASS_TEMPLATE);
+ RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION);
+ RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE);
+ RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION);
+ RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION);
+ RECORD(DECL_FUNCTION_TEMPLATE);
+ RECORD(DECL_TEMPLATE_TYPE_PARM);
+ RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
+ RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
+ RECORD(DECL_STATIC_ASSERT);
+ RECORD(DECL_CXX_BASE_SPECIFIERS);
+ RECORD(DECL_INDIRECTFIELD);
+ RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
+
+ // Statements and Exprs can occur in the Decls and Types block.
+ AddStmtsExprs(Stream, Record);
+
+ BLOCK(PREPROCESSOR_DETAIL_BLOCK);
+ RECORD(PPD_MACRO_EXPANSION);
+ RECORD(PPD_MACRO_DEFINITION);
+ RECORD(PPD_INCLUSION_DIRECTIVE);
+
+#undef RECORD
+#undef BLOCK
+ Stream.ExitBlock();
+}
+
+/// \brief Prepares a path for being written to an AST file by converting it
+/// to an absolute path and removing nested './'s.
+///
+/// \return \c true if the path was changed.
+static bool cleanPathForOutput(FileManager &FileMgr,
+ SmallVectorImpl<char> &Path) {
+ bool Changed = false;
+
+ if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
+ llvm::sys::fs::make_absolute(Path);
+ Changed = true;
+ }
+
+ return Changed | FileMgr.removeDotPaths(Path);
+}
+
+/// \brief Adjusts the given filename to only write out the portion of the
+/// filename that is not part of the system root directory.
+///
+/// \param Filename the file name to adjust.
+///
+/// \param BaseDir When non-NULL, the PCH file is a relocatable AST file and
+/// the returned filename will be adjusted by this root directory.
+///
+/// \returns either the original filename (if it needs no adjustment) or the
+/// adjusted filename (which points into the @p Filename parameter).
+static const char *
+adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) {
+ assert(Filename && "No file name to adjust?");
+
+ if (BaseDir.empty())
+ return Filename;
+
+ // Verify that the filename and the system root have the same prefix.
+ unsigned Pos = 0;
+ for (; Filename[Pos] && Pos < BaseDir.size(); ++Pos)
+ if (Filename[Pos] != BaseDir[Pos])
+ return Filename; // Prefixes don't match.
+
+ // We hit the end of the filename before we hit the end of the system root.
+ if (!Filename[Pos])
+ return Filename;
+
+ // If there's not a path separator at the end of the base directory nor
+ // immediately after it, then this isn't within the base directory.
+ if (!llvm::sys::path::is_separator(Filename[Pos])) {
+ if (!llvm::sys::path::is_separator(BaseDir.back()))
+ return Filename;
+ } else {
+ // If the file name has a '/' at the current position, skip over the '/'.
+ // We distinguish relative paths from absolute paths by the
+ // absence of '/' at the beginning of relative paths.
+ //
+ // FIXME: This is wrong. We distinguish them by asking if the path is
+ // absolute, which isn't the same thing. And there might be multiple '/'s
+ // in a row. Use a better mechanism to indicate whether we have emitted an
+ // absolute or relative path.
+ ++Pos;
+ }
+
+ return Filename + Pos;
+}
+
+static ASTFileSignature getSignature() {
+ while (1) {
+ if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber())
+ return S;
+ // Rely on GetRandomNumber to eventually return non-zero...
+ }
+}
+
+/// \brief Write the control block.
+void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot,
+ const std::string &OutputFile) {
+ using namespace llvm;
+ Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
+ RecordData Record;
+
+ // Metadata
+ BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
+ MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev);
+ Record.push_back(METADATA);
+ Record.push_back(VERSION_MAJOR);
+ Record.push_back(VERSION_MINOR);
+ Record.push_back(CLANG_VERSION_MAJOR);
+ Record.push_back(CLANG_VERSION_MINOR);
+ assert((!WritingModule || isysroot.empty()) &&
+ "writing module as a relocatable PCH?");
+ Record.push_back(!isysroot.empty());
+ Record.push_back(ASTHasCompilerErrors);
+ Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
+ getClangFullRepositoryVersion());
+
+ if (WritingModule) {
+ // For implicit modules we output a signature that we can use to ensure
+ // duplicate module builds don't collide in the cache as their output order
+ // is non-deterministic.
+ // FIXME: Remove this when output is deterministic.
+ if (Context.getLangOpts().ImplicitModules) {
+ Record.clear();
+ Record.push_back(getSignature());
+ Stream.EmitRecord(SIGNATURE, Record);
+ }
+
+ // Module name
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ RecordData Record;
+ Record.push_back(MODULE_NAME);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
+ }
+
+ if (WritingModule && WritingModule->Directory) {
+ // Module directory.
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ RecordData Record;
+ Record.push_back(MODULE_DIRECTORY);
+
+ SmallString<128> BaseDir(WritingModule->Directory->getName());
+ cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir);
+
+ // Write out all other paths relative to the base directory if possible.
+ BaseDirectory.assign(BaseDir.begin(), BaseDir.end());
+ } else if (!isysroot.empty()) {
+ // Write out paths relative to the sysroot if possible.
+ BaseDirectory = isysroot;
+ }
+
+ // Module map file
+ if (WritingModule) {
+ Record.clear();
+
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+
+ // Primary module map file.
+ AddPath(Map.getModuleMapFileForUniquing(WritingModule)->getName(), Record);
+
+ // Additional module map files.
+ if (auto *AdditionalModMaps =
+ Map.getAdditionalModuleMapFiles(WritingModule)) {
+ Record.push_back(AdditionalModMaps->size());
+ for (const FileEntry *F : *AdditionalModMaps)
+ AddPath(F->getName(), Record);
+ } else {
+ Record.push_back(0);
+ }
+
+ Stream.EmitRecord(MODULE_MAP_FILE, Record);
+ }
+
+ // Imports
+ if (Chain) {
+ serialization::ModuleManager &Mgr = Chain->getModuleManager();
+ Record.clear();
+
+ for (auto *M : Mgr) {
+ // Skip modules that weren't directly imported.
+ if (!M->isDirectlyImported())
+ continue;
+
+ Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding
+ AddSourceLocation(M->ImportLoc, Record);
+ Record.push_back(M->File->getSize());
+ Record.push_back(M->File->getModificationTime());
+ Record.push_back(M->Signature);
+ AddPath(M->FileName, Record);
+ }
+ Stream.EmitRecord(IMPORTS, Record);
+
+ // Also emit a list of known module files that were not imported,
+ // but are made available by this module.
+ // FIXME: Should we also include a signature here?
+ Record.clear();
+ for (auto *E : Mgr.getAdditionalKnownModuleFiles())
+ AddPath(E->getName(), Record);
+ if (!Record.empty())
+ Stream.EmitRecord(KNOWN_MODULE_FILES, Record);
+ }
+
+ // Language options.
+ Record.clear();
+ const LangOptions &LangOpts = Context.getLangOpts();
+#define LANGOPT(Name, Bits, Default, Description) \
+ Record.push_back(LangOpts.Name);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
+#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) \
+ Record.push_back(LangOpts.Sanitize.has(SanitizerKind::ID));
+#include "clang/Basic/Sanitizers.def"
+
+ Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
+ AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
+
+ Record.push_back(LangOpts.CurrentModule.size());
+ Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
+
+ // Comment options.
+ Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = LangOpts.CommentOpts.BlockCommandNames.begin(),
+ IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
+ I != IEnd; ++I) {
+ AddString(*I, Record);
+ }
+ Record.push_back(LangOpts.CommentOpts.ParseAllComments);
+
+ Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
+
+ // Target options.
+ Record.clear();
+ const TargetInfo &Target = Context.getTargetInfo();
+ const TargetOptions &TargetOpts = Target.getTargetOpts();
+ AddString(TargetOpts.Triple, Record);
+ AddString(TargetOpts.CPU, Record);
+ AddString(TargetOpts.ABI, Record);
+ Record.push_back(TargetOpts.FeaturesAsWritten.size());
+ for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
+ AddString(TargetOpts.FeaturesAsWritten[I], Record);
+ }
+ Record.push_back(TargetOpts.Features.size());
+ for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
+ AddString(TargetOpts.Features[I], Record);
+ }
+ Stream.EmitRecord(TARGET_OPTIONS, Record);
+
+ // Diagnostic options.
+ Record.clear();
+ const DiagnosticOptions &DiagOpts
+ = Context.getDiagnostics().getDiagnosticOptions();
+#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
+#include "clang/Basic/DiagnosticOptions.def"
+ Record.push_back(DiagOpts.Warnings.size());
+ for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
+ AddString(DiagOpts.Warnings[I], Record);
+ Record.push_back(DiagOpts.Remarks.size());
+ for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
+ AddString(DiagOpts.Remarks[I], Record);
+ // Note: we don't serialize the log or serialization file names, because they
+ // are generally transient files and will almost always be overridden.
+ Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
+
+ // File system options.
+ Record.clear();
+ const FileSystemOptions &FSOpts
+ = Context.getSourceManager().getFileManager().getFileSystemOptions();
+ AddString(FSOpts.WorkingDir, Record);
+ Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record);
+
+ // Header search options.
+ Record.clear();
+ const HeaderSearchOptions &HSOpts
+ = PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ AddString(HSOpts.Sysroot, Record);
+
+ // Include entries.
+ Record.push_back(HSOpts.UserEntries.size());
+ for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
+ const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
+ AddString(Entry.Path, Record);
+ Record.push_back(static_cast<unsigned>(Entry.Group));
+ Record.push_back(Entry.IsFramework);
+ Record.push_back(Entry.IgnoreSysRoot);
+ }
+
+ // System header prefixes.
+ Record.push_back(HSOpts.SystemHeaderPrefixes.size());
+ for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
+ AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
+ Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
+ }
+
+ AddString(HSOpts.ResourceDir, Record);
+ AddString(HSOpts.ModuleCachePath, Record);
+ AddString(HSOpts.ModuleUserBuildPath, Record);
+ Record.push_back(HSOpts.DisableModuleHash);
+ Record.push_back(HSOpts.UseBuiltinIncludes);
+ Record.push_back(HSOpts.UseStandardSystemIncludes);
+ Record.push_back(HSOpts.UseStandardCXXIncludes);
+ Record.push_back(HSOpts.UseLibcxx);
+ // Write out the specific module cache path that contains the module files.
+ AddString(PP.getHeaderSearchInfo().getModuleCachePath(), Record);
+ Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record);
+
+ // Preprocessor options.
+ Record.clear();
+ const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts();
+
+ // Macro definitions.
+ Record.push_back(PPOpts.Macros.size());
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ AddString(PPOpts.Macros[I].first, Record);
+ Record.push_back(PPOpts.Macros[I].second);
+ }
+
+ // Includes
+ Record.push_back(PPOpts.Includes.size());
+ for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I)
+ AddString(PPOpts.Includes[I], Record);
+
+ // Macro includes
+ Record.push_back(PPOpts.MacroIncludes.size());
+ for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I)
+ AddString(PPOpts.MacroIncludes[I], Record);
+
+ Record.push_back(PPOpts.UsePredefines);
+ // Detailed record is important since it is used for the module cache hash.
+ Record.push_back(PPOpts.DetailedRecord);
+ AddString(PPOpts.ImplicitPCHInclude, Record);
+ AddString(PPOpts.ImplicitPTHInclude, Record);
+ Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary));
+ Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record);
+
+ // Original file name and file ID
+ SourceManager &SM = Context.getSourceManager();
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
+ FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
+
+ Record.clear();
+ Record.push_back(ORIGINAL_FILE);
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ EmitRecordWithPath(FileAbbrevCode, Record, MainFile->getName());
+ }
+
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+
+ // Original PCH directory
+ if (!OutputFile.empty() && OutputFile != "-") {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+ SmallString<128> OutputPath(OutputFile);
+
+ llvm::sys::fs::make_absolute(OutputPath);
+ StringRef origDir = llvm::sys::path::parent_path(OutputPath);
+
+ RecordData Record;
+ Record.push_back(ORIGINAL_PCH_DIR);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
+ }
+
+ WriteInputFiles(Context.SourceMgr,
+ PP.getHeaderSearchInfo().getHeaderSearchOpts(),
+ PP.getLangOpts().Modules);
+ Stream.ExitBlock();
+}
+
+namespace {
+ /// \brief An input file.
+ struct InputFileEntry {
+ const FileEntry *File;
+ bool IsSystemFile;
+ bool BufferOverridden;
+ };
+}
+
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts,
+ bool Modules) {
+ using namespace llvm;
+ Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
+ RecordData Record;
+
+ // Create input-file abbreviation.
+ BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
+ IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
+
+ // Get all ContentCache objects for files, sorted by whether the file is a
+ // system one or not. System files go at the back, users files at the front.
+ std::deque<InputFileEntry> SortedFiles;
+ for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
+ // Get this source location entry.
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
+ assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc);
+
+ // We only care about file entries that were not overridden.
+ if (!SLoc->isFile())
+ continue;
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (!Cache->OrigEntry)
+ continue;
+
+ InputFileEntry Entry;
+ Entry.File = Cache->OrigEntry;
+ Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.BufferOverridden = Cache->BufferOverridden;
+ if (Cache->IsSystemFile)
+ SortedFiles.push_back(Entry);
+ else
+ SortedFiles.push_front(Entry);
+ }
+
+ unsigned UserFilesNum = 0;
+ // Write out all of the input files.
+ std::vector<uint64_t> InputFileOffsets;
+ for (std::deque<InputFileEntry>::iterator
+ I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
+ const InputFileEntry &Entry = *I;
+
+ uint32_t &InputFileID = InputFileIDs[Entry.File];
+ if (InputFileID != 0)
+ continue; // already recorded this file.
+
+ // Record this entry's offset.
+ InputFileOffsets.push_back(Stream.GetCurrentBitNo());
+
+ InputFileID = InputFileOffsets.size();
+
+ if (!Entry.IsSystemFile)
+ ++UserFilesNum;
+
+ Record.clear();
+ Record.push_back(INPUT_FILE);
+ Record.push_back(InputFileOffsets.size());
+
+ // Emit size/modification time for this file.
+ Record.push_back(Entry.File->getSize());
+ Record.push_back(Entry.File->getModificationTime());
+
+ // Whether this file was overridden.
+ Record.push_back(Entry.BufferOverridden);
+
+ EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ }
+
+ Stream.ExitBlock();
+
+ // Create input file offsets abbreviation.
+ BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
+ // input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
+ unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
+
+ // Write input file offsets.
+ Record.clear();
+ Record.push_back(INPUT_FILE_OFFSETS);
+ Record.push_back(InputFileOffsets.size());
+ Record.push_back(UserFilesNum);
+ Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets));
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// file.
+static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ // FileEntry fields.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer.
+static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer's blob.
+static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a macro
+/// expansion.
+static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+namespace {
+ // Trait used for the on-disk hash table of header search information.
+ class HeaderFileInfoTrait {
+ ASTWriter &Writer;
+ const HeaderSearch &HS;
+
+ // Keep track of the framework names we've used during serialization.
+ SmallVector<char, 128> FrameworkStringData;
+ llvm::StringMap<unsigned> FrameworkNameOffset;
+
+ public:
+ HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
+ : Writer(Writer), HS(HS) { }
+
+ struct key_type {
+ const FileEntry *FE;
+ const char *Filename;
+ };
+ typedef const key_type &key_type_ref;
+
+ typedef HeaderFileInfo data_type;
+ typedef const data_type &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(key_type_ref key) {
+ // The hash is based only on size/time of the file, so that the reader can
+ // match even when symlinking or excess path elements ("foo/../", "../")
+ // change the form of the name. However, complete path is still the key.
+ //
+ // FIXME: Using the mtime here will cause problems for explicit module
+ // imports.
+ return llvm::hash_combine(key.FE->getSize(),
+ key.FE->getModificationTime());
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ using namespace llvm::support;
+ endian::Writer<little> Writer(Out);
+ unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
+ Writer.write<uint16_t>(KeyLen);
+ unsigned DataLen = 1 + 2 + 4 + 4;
+ if (Data.isModuleHeader)
+ DataLen += 4;
+ Writer.write<uint8_t>(DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ LE.write<uint64_t>(key.FE->getSize());
+ KeyLen -= 8;
+ LE.write<uint64_t>(key.FE->getModificationTime());
+ KeyLen -= 8;
+ Out.write(key.Filename, KeyLen);
+ }
+
+ void EmitData(raw_ostream &Out, key_type_ref key,
+ data_type_ref Data, unsigned DataLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint64_t Start = Out.tell(); (void)Start;
+
+ unsigned char Flags = (Data.HeaderRole << 6)
+ | (Data.isImport << 5)
+ | (Data.isPragmaOnce << 4)
+ | (Data.DirInfo << 2)
+ | (Data.Resolved << 1)
+ | Data.IndexHeaderMapHeader;
+ LE.write<uint8_t>(Flags);
+ LE.write<uint16_t>(Data.NumIncludes);
+
+ if (!Data.ControllingMacro)
+ LE.write<uint32_t>(Data.ControllingMacroID);
+ else
+ LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro));
+
+ unsigned Offset = 0;
+ if (!Data.Framework.empty()) {
+ // If this header refers into a framework, save the framework name.
+ llvm::StringMap<unsigned>::iterator Pos
+ = FrameworkNameOffset.find(Data.Framework);
+ if (Pos == FrameworkNameOffset.end()) {
+ Offset = FrameworkStringData.size() + 1;
+ FrameworkStringData.append(Data.Framework.begin(),
+ Data.Framework.end());
+ FrameworkStringData.push_back(0);
+
+ FrameworkNameOffset[Data.Framework] = Offset;
+ } else
+ Offset = Pos->second;
+ }
+ LE.write<uint32_t>(Offset);
+
+ if (Data.isModuleHeader) {
+ Module *Mod = HS.findModuleForHeader(key.FE).getModule();
+ LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod));
+ }
+
+ assert(Out.tell() - Start == DataLen && "Wrong data length");
+ }
+
+ const char *strings_begin() const { return FrameworkStringData.begin(); }
+ const char *strings_end() const { return FrameworkStringData.end(); }
+ };
+} // end anonymous namespace
+
+/// \brief Write the header search block for the list of files that
+///
+/// \param HS The header search structure to save.
+void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
+ SmallVector<const FileEntry *, 16> FilesByUID;
+ HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
+
+ if (FilesByUID.size() > HS.header_file_size())
+ FilesByUID.resize(HS.header_file_size());
+
+ HeaderFileInfoTrait GeneratorTrait(*this, HS);
+ llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
+ SmallVector<const char *, 4> SavedStrings;
+ unsigned NumHeaderSearchEntries = 0;
+ for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
+ const FileEntry *File = FilesByUID[UID];
+ if (!File)
+ continue;
+
+ // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo
+ // from the external source if it was not provided already.
+ HeaderFileInfo HFI;
+ if (!HS.tryGetFileInfo(File, HFI) ||
+ (HFI.External && Chain) ||
+ (HFI.isModuleHeader && !HFI.isCompilingModuleHeader))
+ continue;
+
+ // Massage the file path into an appropriate form.
+ const char *Filename = File->getName();
+ SmallString<128> FilenameTmp(Filename);
+ if (PreparePathForOutput(FilenameTmp)) {
+ // If we performed any translation on the file name at all, we need to
+ // save this string, since the generator will refer to it later.
+ Filename = strdup(FilenameTmp.c_str());
+ SavedStrings.push_back(Filename);
+ }
+
+ HeaderFileInfoTrait::key_type key = { File, Filename };
+ Generator.insert(key, HFI, GeneratorTrait);
+ ++NumHeaderSearchEntries;
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> TableData;
+ uint32_t BucketOffset;
+ {
+ using namespace llvm::support;
+ llvm::raw_svector_ostream Out(TableData);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ BucketOffset = Generator.Emit(Out, GeneratorTrait);
+ }
+
+ // Create a blob abbreviation
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the header search table
+ RecordData Record;
+ Record.push_back(HEADER_SEARCH_TABLE);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumHeaderSearchEntries);
+ Record.push_back(TableData.size());
+ TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
+ Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData);
+
+ // Free all of the strings we had to duplicate.
+ for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
+ free(const_cast<char *>(SavedStrings[I]));
+}
+
+/// \brief Writes the block containing the serialized form of the
+/// source manager.
+///
+/// TODO: We should probably use an on-disk hash table (stored in a
+/// blob), indexed based on the file name, so that we only create
+/// entries for files that we actually need. In the common case (no
+/// errors), we probably won't have to create file entries for any of
+/// the files in the AST.
+void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
+ const Preprocessor &PP) {
+ RecordData Record;
+
+ // Enter the source manager block.
+ Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 3);
+
+ // Abbreviations for the various kinds of source-location entries.
+ unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
+ unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
+ unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
+ unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream);
+
+ // Write out the source location entry table. We skip the first
+ // entry, which is always the same dummy entry.
+ std::vector<uint32_t> SLocEntryOffsets;
+ RecordData PreloadSLocs;
+ SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
+ for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
+ I != N; ++I) {
+ // Get this source location entry.
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
+ FileID FID = FileID::get(I);
+ assert(&SourceMgr.getSLocEntry(FID) == SLoc);
+
+ // Record the offset of this source-location entry.
+ SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
+
+ // Figure out which record code to use.
+ unsigned Code;
+ if (SLoc->isFile()) {
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (Cache->OrigEntry) {
+ Code = SM_SLOC_FILE_ENTRY;
+ } else
+ Code = SM_SLOC_BUFFER_ENTRY;
+ } else
+ Code = SM_SLOC_EXPANSION_ENTRY;
+ Record.clear();
+ Record.push_back(Code);
+
+ // Starting offset of this entry within this module, so skip the dummy.
+ Record.push_back(SLoc->getOffset() - 2);
+ if (SLoc->isFile()) {
+ const SrcMgr::FileInfo &File = SLoc->getFile();
+ Record.push_back(File.getIncludeLoc().getRawEncoding());
+ Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
+ Record.push_back(File.hasLineDirectives());
+
+ const SrcMgr::ContentCache *Content = File.getContentCache();
+ if (Content->OrigEntry) {
+ assert(Content->OrigEntry == Content->ContentsEntry &&
+ "Writing to AST an overridden file is not supported");
+
+ // The source location entry is a file. Emit input file ID.
+ assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
+ Record.push_back(InputFileIDs[Content->OrigEntry]);
+
+ Record.push_back(File.NumCreatedFIDs);
+
+ FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
+ if (FDI != FileDeclIDs.end()) {
+ Record.push_back(FDI->second->FirstDeclIndex);
+ Record.push_back(FDI->second->DeclIDs.size());
+ } else {
+ Record.push_back(0);
+ Record.push_back(0);
+ }
+
+ Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
+
+ if (Content->BufferOverridden) {
+ Record.clear();
+ Record.push_back(SM_SLOC_BUFFER_BLOB);
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
+ }
+ } else {
+ // The source location entry is a buffer. The blob associated
+ // with this entry contains the contents of the buffer.
+
+ // We add one to the size so that we capture the trailing NULL
+ // that is required by llvm::MemoryBuffer::getMemBuffer (on
+ // the reader side).
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ const char *Name = Buffer->getBufferIdentifier();
+ Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
+ StringRef(Name, strlen(Name) + 1));
+ Record.clear();
+ Record.push_back(SM_SLOC_BUFFER_BLOB);
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
+
+ if (strcmp(Name, "<built-in>") == 0) {
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ }
+ }
+ } else {
+ // The source location entry is a macro expansion.
+ const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion();
+ Record.push_back(Expansion.getSpellingLoc().getRawEncoding());
+ Record.push_back(Expansion.getExpansionLocStart().getRawEncoding());
+ Record.push_back(Expansion.isMacroArgExpansion() ? 0
+ : Expansion.getExpansionLocEnd().getRawEncoding());
+
+ // Compute the token length for this macro expansion.
+ unsigned NextOffset = SourceMgr.getNextLocalOffset();
+ if (I + 1 != N)
+ NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset();
+ Record.push_back(NextOffset - SLoc->getOffset() - 1);
+ Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
+ }
+ }
+
+ Stream.ExitBlock();
+
+ if (SLocEntryOffsets.empty())
+ return;
+
+ // Write the source-location offsets table into the AST block. This
+ // table is used for lazily loading source-location information.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
+ unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(SOURCE_LOCATION_OFFSETS);
+ Record.push_back(SLocEntryOffsets.size());
+ Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
+ Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets));
+
+ // Write the source location entry preloads array, telling the AST
+ // reader which source locations entries it should load eagerly.
+ Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
+
+ // Write the line table. It depends on remapping working, so it must come
+ // after the source location offsets.
+ if (SourceMgr.hasLineTable()) {
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ Record.clear();
+ // Emit the file names.
+ Record.push_back(LineTable.getNumFilenames());
+ for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I)
+ AddPath(LineTable.getFilename(I), Record);
+
+ // Emit the line entries
+ for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
+ L != LEnd; ++L) {
+ // Only emit entries for local files.
+ if (L->first.ID < 0)
+ continue;
+
+ // Emit the file ID
+ Record.push_back(L->first.ID);
+
+ // Emit the line entries
+ Record.push_back(L->second.size());
+ for (std::vector<LineEntry>::iterator LE = L->second.begin(),
+ LEEnd = L->second.end();
+ LE != LEEnd; ++LE) {
+ Record.push_back(LE->FileOffset);
+ Record.push_back(LE->LineNo);
+ Record.push_back(LE->FilenameID);
+ Record.push_back((unsigned)LE->FileKind);
+ Record.push_back(LE->IncludeOffset);
+ }
+ }
+ Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Serialization
+//===----------------------------------------------------------------------===//
+
+static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
+ const Preprocessor &PP) {
+ if (MacroInfo *MI = MD->getMacroInfo())
+ if (MI->isBuiltinMacro())
+ return true;
+
+ if (IsModule) {
+ SourceLocation Loc = MD->getLocation();
+ if (Loc.isInvalid())
+ return true;
+ if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID())
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Writes the block containing the serialized form of the
+/// preprocessor.
+///
+void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
+ PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+ if (PPRec)
+ WritePreprocessorDetail(*PPRec);
+
+ RecordData Record;
+ RecordData ModuleMacroRecord;
+
+ // If the preprocessor __COUNTER__ value has been bumped, remember it.
+ if (PP.getCounterValue() != 0) {
+ Record.push_back(PP.getCounterValue());
+ Stream.EmitRecord(PP_COUNTER_VALUE, Record);
+ Record.clear();
+ }
+
+ // Enter the preprocessor block.
+ Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
+
+ // If the AST file contains __DATE__ or __TIME__ emit a warning about this.
+ // FIXME: use diagnostics subsystem for localization etc.
+ if (PP.SawDateOrTime())
+ fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
+
+
+ // Loop over all the macro directives that are live at the end of the file,
+ // emitting each to the PP section.
+
+ // Construct the list of identifiers with macro directives that need to be
+ // serialized.
+ SmallVector<const IdentifierInfo *, 128> MacroIdentifiers;
+ for (auto &Id : PP.getIdentifierTable())
+ if (Id.second->hadMacroDefinition() &&
+ (!Id.second->isFromAST() ||
+ Id.second->hasChangedSinceDeserialization()))
+ MacroIdentifiers.push_back(Id.second);
+ // Sort the set of macro definitions that need to be serialized by the
+ // name of the macro, to provide a stable ordering.
+ std::sort(MacroIdentifiers.begin(), MacroIdentifiers.end(),
+ llvm::less_ptr<IdentifierInfo>());
+
+ // Emit the macro directives as a list and associate the offset with the
+ // identifier they belong to.
+ for (const IdentifierInfo *Name : MacroIdentifiers) {
+ MacroDirective *MD = PP.getLocalMacroDirectiveHistory(Name);
+ auto StartOffset = Stream.GetCurrentBitNo();
+
+ // Emit the macro directives in reverse source order.
+ for (; MD; MD = MD->getPrevious()) {
+ // Once we hit an ignored macro, we're done: the rest of the chain
+ // will all be ignored macros.
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ break;
+
+ AddSourceLocation(MD->getLocation(), Record);
+ Record.push_back(MD->getKind());
+ if (auto *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ Record.push_back(getMacroRef(DefMD->getInfo(), Name));
+ } else if (auto *VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ Record.push_back(VisMD->isPublic());
+ }
+ }
+
+ // Write out any exported module macros.
+ bool EmittedModuleMacros = false;
+ if (IsModule) {
+ auto Leafs = PP.getLeafModuleMacros(Name);
+ SmallVector<ModuleMacro*, 8> Worklist(Leafs.begin(), Leafs.end());
+ llvm::DenseMap<ModuleMacro*, unsigned> Visits;
+ while (!Worklist.empty()) {
+ auto *Macro = Worklist.pop_back_val();
+
+ // Emit a record indicating this submodule exports this macro.
+ ModuleMacroRecord.push_back(
+ getSubmoduleID(Macro->getOwningModule()));
+ ModuleMacroRecord.push_back(getMacroRef(Macro->getMacroInfo(), Name));
+ for (auto *M : Macro->overrides())
+ ModuleMacroRecord.push_back(getSubmoduleID(M->getOwningModule()));
+
+ Stream.EmitRecord(PP_MODULE_MACRO, ModuleMacroRecord);
+ ModuleMacroRecord.clear();
+
+ // Enqueue overridden macros once we've visited all their ancestors.
+ for (auto *M : Macro->overrides())
+ if (++Visits[M] == M->getNumOverridingMacros())
+ Worklist.push_back(M);
+
+ EmittedModuleMacros = true;
+ }
+ }
+
+ if (Record.empty() && !EmittedModuleMacros)
+ continue;
+
+ IdentMacroDirectivesOffsetMap[Name] = StartOffset;
+ Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
+ Record.clear();
+ }
+
+ /// \brief Offsets of each of the macros into the bitstream, indexed by
+ /// the local macro ID
+ ///
+ /// For each identifier that is associated with a macro, this map
+ /// provides the offset into the bitstream where that macro is
+ /// defined.
+ std::vector<uint32_t> MacroOffsets;
+
+ for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroInfosToEmit[I].Name;
+ MacroInfo *MI = MacroInfosToEmit[I].MI;
+ MacroID ID = MacroInfosToEmit[I].ID;
+
+ if (ID < FirstMacroID) {
+ assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?");
+ continue;
+ }
+
+ // Record the local offset of this macro.
+ unsigned Index = ID - FirstMacroID;
+ if (Index == MacroOffsets.size())
+ MacroOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > MacroOffsets.size())
+ MacroOffsets.resize(Index + 1);
+
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ AddIdentifierRef(Name, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
+ AddSourceLocation(MI->getDefinitionLoc(), Record);
+ AddSourceLocation(MI->getDefinitionEndLoc(), Record);
+ Record.push_back(MI->isUsed());
+ Record.push_back(MI->isUsedForHeaderGuard());
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = PP_MACRO_FUNCTION_LIKE;
+
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->hasCommaPasting());
+ Record.push_back(MI->getNumArgs());
+ for (const IdentifierInfo *Arg : MI->args())
+ AddIdentifierRef(Arg, Record);
+ }
+
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
+
+ Stream.EmitRecord(Code, Record);
+ Record.clear();
+
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't
+ // be in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+ AddToken(Tok, Record);
+ Stream.EmitRecord(PP_TOKEN, Record);
+ Record.clear();
+ }
+ ++NumMacros;
+ }
+
+ Stream.ExitBlock();
+
+ // Write the offsets table for macro IDs.
+ using namespace llvm;
+ auto *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+
+ unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(MACRO_OFFSET);
+ Record.push_back(MacroOffsets.size());
+ Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS);
+ Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record,
+ bytes(MacroOffsets));
+}
+
+void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
+ if (PPRec.local_begin() == PPRec.local_end())
+ return;
+
+ SmallVector<PPEntityOffset, 64> PreprocessedEntityOffsets;
+
+ // Enter the preprocessor block.
+ Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3);
+
+ // If the preprocessor has a preprocessing record, emit it.
+ unsigned NumPreprocessingRecords = 0;
+ using namespace llvm;
+
+ // Set up the abbreviation for
+ unsigned InclusionAbbrev = 0;
+ {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
+ }
+
+ unsigned FirstPreprocessorEntityID
+ = (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0)
+ + NUM_PREDEF_PP_ENTITY_IDS;
+ unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID;
+ RecordData Record;
+ for (PreprocessingRecord::iterator E = PPRec.local_begin(),
+ EEnd = PPRec.local_end();
+ E != EEnd;
+ (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) {
+ Record.clear();
+
+ PreprocessedEntityOffsets.push_back(
+ PPEntityOffset((*E)->getSourceRange(), Stream.GetCurrentBitNo()));
+
+ if (MacroDefinitionRecord *MD = dyn_cast<MacroDefinitionRecord>(*E)) {
+ // Record this macro definition's ID.
+ MacroDefinitions[MD] = NextPreprocessorEntityID;
+
+ AddIdentifierRef(MD->getName(), Record);
+ Stream.EmitRecord(PPD_MACRO_DEFINITION, Record);
+ continue;
+ }
+
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
+ Record.push_back(ME->isBuiltinMacro());
+ if (ME->isBuiltinMacro())
+ AddIdentifierRef(ME->getName(), Record);
+ else
+ Record.push_back(MacroDefinitions[ME->getDefinition()]);
+ Stream.EmitRecord(PPD_MACRO_EXPANSION, Record);
+ continue;
+ }
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+ Record.push_back(PPD_INCLUSION_DIRECTIVE);
+ Record.push_back(ID->getFileName().size());
+ Record.push_back(ID->wasInQuotes());
+ Record.push_back(static_cast<unsigned>(ID->getKind()));
+ Record.push_back(ID->importedModule());
+ SmallString<64> Buffer;
+ Buffer += ID->getFileName();
+ // Check that the FileEntry is not null because it was not resolved and
+ // we create a PCH even with compiler errors.
+ if (ID->getFile())
+ Buffer += ID->getFile()->getName();
+ Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
+ continue;
+ }
+
+ llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter");
+ }
+ Stream.ExitBlock();
+
+ // Write the offsets table for the preprocessing record.
+ if (NumPreprocessingRecords > 0) {
+ assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords);
+
+ // Write the offsets table for identifier IDs.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(PPD_ENTITIES_OFFSETS);
+ Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS);
+ Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record,
+ bytes(PreprocessedEntityOffsets));
+ }
+}
+
+unsigned ASTWriter::getSubmoduleID(Module *Mod) {
+ llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return SubmoduleIDs[Mod] = NextSubmoduleID++;
+}
+
+unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const {
+ if (!Mod)
+ return 0;
+
+ llvm::DenseMap<Module *, unsigned>::const_iterator
+ Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return 0;
+}
+
+/// \brief Compute the number of modules within the given tree (including the
+/// given module).
+static unsigned getNumberOfModules(Module *Mod) {
+ unsigned ChildModules = 0;
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub)
+ ChildModules += getNumberOfModules(*Sub);
+
+ return ChildModules + 1;
+}
+
+void ASTWriter::WriteSubmodules(Module *WritingModule) {
+ // Enter the submodule description block.
+ Stream.EnterSubblock(SUBMODULE_BLOCK_ID, /*bits for abbreviations*/5);
+
+ // Write the abbreviations needed for the submodules block.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // State
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
+ unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TEXTUAL_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned TextualHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_TEXTUAL_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned PrivateTextualHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
+ unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the submodule metadata block.
+ RecordData Record;
+ Record.push_back(getNumberOfModules(WritingModule));
+ Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS);
+ Stream.EmitRecord(SUBMODULE_METADATA, Record);
+
+ // Write all of the submodules.
+ std::queue<Module *> Q;
+ Q.push(WritingModule);
+ while (!Q.empty()) {
+ Module *Mod = Q.front();
+ Q.pop();
+ unsigned ID = getSubmoduleID(Mod);
+
+ // Emit the definition of the block.
+ Record.clear();
+ Record.push_back(SUBMODULE_DEFINITION);
+ Record.push_back(ID);
+ if (Mod->Parent) {
+ assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
+ Record.push_back(SubmoduleIDs[Mod->Parent]);
+ } else {
+ Record.push_back(0);
+ }
+ Record.push_back(Mod->IsFramework);
+ Record.push_back(Mod->IsExplicit);
+ Record.push_back(Mod->IsSystem);
+ Record.push_back(Mod->IsExternC);
+ Record.push_back(Mod->InferSubmodules);
+ Record.push_back(Mod->InferExplicitSubmodules);
+ Record.push_back(Mod->InferExportWildcard);
+ Record.push_back(Mod->ConfigMacrosExhaustive);
+ Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
+
+ // Emit the requirements.
+ for (unsigned I = 0, N = Mod->Requirements.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_REQUIRES);
+ Record.push_back(Mod->Requirements[I].second);
+ Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
+ Mod->Requirements[I].first);
+ }
+
+ // Emit the umbrella header, if there is one.
+ if (auto UmbrellaHeader = Mod->getUmbrellaHeader()) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA_HEADER);
+ Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
+ UmbrellaHeader.NameAsWritten);
+ } else if (auto UmbrellaDir = Mod->getUmbrellaDir()) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA_DIR);
+ Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,
+ UmbrellaDir.NameAsWritten);
+ }
+
+ // Emit the headers.
+ struct {
+ unsigned RecordKind;
+ unsigned Abbrev;
+ Module::HeaderKind HeaderKind;
+ } HeaderLists[] = {
+ {SUBMODULE_HEADER, HeaderAbbrev, Module::HK_Normal},
+ {SUBMODULE_TEXTUAL_HEADER, TextualHeaderAbbrev, Module::HK_Textual},
+ {SUBMODULE_PRIVATE_HEADER, PrivateHeaderAbbrev, Module::HK_Private},
+ {SUBMODULE_PRIVATE_TEXTUAL_HEADER, PrivateTextualHeaderAbbrev,
+ Module::HK_PrivateTextual},
+ {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded}
+ };
+ for (auto &HL : HeaderLists) {
+ Record.clear();
+ Record.push_back(HL.RecordKind);
+ for (auto &H : Mod->Headers[HL.HeaderKind])
+ Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten);
+ }
+
+ // Emit the top headers.
+ {
+ auto TopHeaders = Mod->getTopHeaders(PP->getFileManager());
+ Record.clear();
+ Record.push_back(SUBMODULE_TOPHEADER);
+ for (auto *H : TopHeaders)
+ Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName());
+ }
+
+ // Emit the imports.
+ if (!Mod->Imports.empty()) {
+ Record.clear();
+ for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
+ unsigned ImportedID = getSubmoduleID(Mod->Imports[I]);
+ assert(ImportedID && "Unknown submodule!");
+ Record.push_back(ImportedID);
+ }
+ Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
+ }
+
+ // Emit the exports.
+ if (!Mod->Exports.empty()) {
+ Record.clear();
+ for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
+ if (Module *Exported = Mod->Exports[I].getPointer()) {
+ unsigned ExportedID = getSubmoduleID(Exported);
+ Record.push_back(ExportedID);
+ } else {
+ Record.push_back(0);
+ }
+
+ Record.push_back(Mod->Exports[I].getInt());
+ }
+ Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
+ }
+
+ //FIXME: How do we emit the 'use'd modules? They may not be submodules.
+ // Might be unnecessary as use declarations are only used to build the
+ // module itself.
+
+ // Emit the link libraries.
+ for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_LINK_LIBRARY);
+ Record.push_back(Mod->LinkLibraries[I].IsFramework);
+ Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record,
+ Mod->LinkLibraries[I].Library);
+ }
+
+ // Emit the conflicts.
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFLICT);
+ unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other);
+ assert(OtherID && "Unknown submodule!");
+ Record.push_back(OtherID);
+ Stream.EmitRecordWithBlob(ConflictAbbrev, Record,
+ Mod->Conflicts[I].Message);
+ }
+
+ // Emit the configuration macros.
+ for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFIG_MACRO);
+ Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record,
+ Mod->ConfigMacros[I]);
+ }
+
+ // Queue up the submodules of this module.
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub)
+ Q.push(*Sub);
+ }
+
+ Stream.ExitBlock();
+
+ // FIXME: This can easily happen, if we have a reference to a submodule that
+ // did not result in us loading a module file for that submodule. For
+ // instance, a cross-top-level-module 'conflict' declaration will hit this.
+ assert((NextSubmoduleID - FirstSubmoduleID ==
+ getNumberOfModules(WritingModule)) &&
+ "Wrong # of submodules; found a reference to a non-local, "
+ "non-imported submodule?");
+}
+
+serialization::SubmoduleID
+ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
+ if (Loc.isInvalid() || !WritingModule)
+ return 0; // No submodule
+
+ // Find the module that owns this location.
+ ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
+ Module *OwningMod
+ = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager()));
+ if (!OwningMod)
+ return 0;
+
+ // Check whether this submodule is part of our own module.
+ if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
+ return 0;
+
+ return getSubmoduleID(OwningMod);
+}
+
+void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
+ bool isModule) {
+ // Make sure set diagnostic pragmas don't affect the translation unit that
+ // imports the module.
+ // FIXME: Make diagnostic pragma sections work properly with modules.
+ if (isModule)
+ return;
+
+ llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
+ DiagStateIDMap;
+ unsigned CurrID = 0;
+ DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one.
+ RecordData Record;
+ for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
+ I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
+ I != E; ++I) {
+ const DiagnosticsEngine::DiagStatePoint &point = *I;
+ if (point.Loc.isInvalid())
+ continue;
+
+ Record.push_back(point.Loc.getRawEncoding());
+ unsigned &DiagStateID = DiagStateIDMap[point.State];
+ Record.push_back(DiagStateID);
+
+ if (DiagStateID == 0) {
+ DiagStateID = ++CurrID;
+ for (DiagnosticsEngine::DiagState::const_iterator
+ I = point.State->begin(), E = point.State->end(); I != E; ++I) {
+ if (I->second.isPragma()) {
+ Record.push_back(I->first);
+ Record.push_back((unsigned)I->second.getSeverity());
+ }
+ }
+ Record.push_back(-1); // mark the end of the diag/map pairs for this
+ // location.
+ }
+ }
+
+ if (!Record.empty())
+ Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
+}
+
+void ASTWriter::WriteCXXCtorInitializersOffsets() {
+ if (CXXCtorInitializersOffsets.empty())
+ return;
+
+ RecordData Record;
+
+ // Create a blob abbreviation for the C++ ctor initializer offsets.
+ using namespace llvm;
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned CtorInitializersOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the base specifier offsets table.
+ Record.clear();
+ Record.push_back(CXX_CTOR_INITIALIZERS_OFFSETS);
+ Record.push_back(CXXCtorInitializersOffsets.size());
+ Stream.EmitRecordWithBlob(CtorInitializersOffsetAbbrev, Record,
+ bytes(CXXCtorInitializersOffsets));
+}
+
+void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
+ if (CXXBaseSpecifiersOffsets.empty())
+ return;
+
+ RecordData Record;
+
+ // Create a blob abbreviation for the C++ base specifiers offsets.
+ using namespace llvm;
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the base specifier offsets table.
+ Record.clear();
+ Record.push_back(CXX_BASE_SPECIFIER_OFFSETS);
+ Record.push_back(CXXBaseSpecifiersOffsets.size());
+ Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record,
+ bytes(CXXBaseSpecifiersOffsets));
+}
+
+//===----------------------------------------------------------------------===//
+// Type Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the representation of a type to the AST stream.
+void ASTWriter::WriteType(QualType T) {
+ TypeIdx &Idx = TypeIdxs[T];
+ if (Idx.getIndex() == 0) // we haven't seen this type before.
+ Idx = TypeIdx(NextTypeID++);
+
+ assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST");
+
+ // Record the offset for this type.
+ unsigned Index = Idx.getIndex() - FirstTypeID;
+ if (TypeOffsets.size() == Index)
+ TypeOffsets.push_back(Stream.GetCurrentBitNo());
+ else if (TypeOffsets.size() < Index) {
+ TypeOffsets.resize(Index + 1);
+ TypeOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ RecordData Record;
+
+ // Emit the type's representation.
+ ASTTypeWriter W(*this, Record);
+ W.AbbrevToUse = 0;
+
+ if (T.hasLocalNonFastQualifiers()) {
+ Qualifiers Qs = T.getLocalQualifiers();
+ AddTypeRef(T.getLocalUnqualifiedType(), Record);
+ Record.push_back(Qs.getAsOpaqueValue());
+ W.Code = TYPE_EXT_QUAL;
+ W.AbbrevToUse = TypeExtQualAbbrev;
+ } else {
+ switch (T->getTypeClass()) {
+ // For all of the concrete, non-dependent types, call the
+ // appropriate visitor function.
+#define TYPE(Class, Base) \
+ case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ // Emit the serialized record.
+ Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
+
+ // Flush any expressions that were written as part of this type.
+ FlushStmts();
+}
+
+//===----------------------------------------------------------------------===//
+// Declaration Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the block containing all of the declaration IDs
+/// lexically declared within the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the
+/// bistream, or 0 if no block was written.
+uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->decls_empty())
+ return 0;
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ Record.push_back(DECL_CONTEXT_LEXICAL);
+ SmallVector<KindDeclIDPair, 64> Decls;
+ for (const auto *D : DC->decls())
+ Decls.push_back(std::make_pair(D->getKind(), GetDeclRef(D)));
+
+ ++NumLexicalDeclContexts;
+ Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, bytes(Decls));
+ return Offset;
+}
+
+void ASTWriter::WriteTypeDeclOffsets() {
+ using namespace llvm;
+ RecordData Record;
+
+ // Write the type offsets array
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
+ unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(TYPE_OFFSET);
+ Record.push_back(TypeOffsets.size());
+ Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS);
+ Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets));
+
+ // Write the declaration offsets array
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
+ unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(DECL_OFFSET);
+ Record.push_back(DeclOffsets.size());
+ Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS);
+ Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets));
+}
+
+void ASTWriter::WriteFileDeclIDsMap() {
+ using namespace llvm;
+ RecordData Record;
+
+ SmallVector<std::pair<FileID, DeclIDInFileInfo *>, 64> SortedFileDeclIDs(
+ FileDeclIDs.begin(), FileDeclIDs.end());
+ std::sort(SortedFileDeclIDs.begin(), SortedFileDeclIDs.end(),
+ llvm::less_first());
+
+ // Join the vectors of DeclIDs from all files.
+ SmallVector<DeclID, 256> FileGroupedDeclIDs;
+ for (auto &FileDeclEntry : SortedFileDeclIDs) {
+ DeclIDInFileInfo &Info = *FileDeclEntry.second;
+ Info.FirstDeclIndex = FileGroupedDeclIDs.size();
+ for (auto &LocDeclEntry : Info.DeclIDs)
+ FileGroupedDeclIDs.push_back(LocDeclEntry.second);
+ }
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ Record.push_back(FILE_SORTED_DECLS);
+ Record.push_back(FileGroupedDeclIDs.size());
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileGroupedDeclIDs));
+}
+
+void ASTWriter::WriteComments() {
+ Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3);
+ ArrayRef<RawComment *> RawComments = Context->Comments.getComments();
+ RecordData Record;
+ for (ArrayRef<RawComment *>::iterator I = RawComments.begin(),
+ E = RawComments.end();
+ I != E; ++I) {
+ Record.clear();
+ AddSourceRange((*I)->getSourceRange(), Record);
+ Record.push_back((*I)->getKind());
+ Record.push_back((*I)->isTrailingComment());
+ Record.push_back((*I)->isAlmostTrailingComment());
+ Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);
+ }
+ Stream.ExitBlock();
+}
+
+//===----------------------------------------------------------------------===//
+// Global Method Pool and Selector Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table used in the method pool.
+class ASTMethodPoolTrait {
+ ASTWriter &Writer;
+
+public:
+ typedef Selector key_type;
+ typedef key_type key_type_ref;
+
+ struct data_type {
+ SelectorID ID;
+ ObjCMethodList Instance, Factory;
+ };
+ typedef const data_type& data_type_ref;
+
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { }
+
+ static hash_value_type ComputeHash(Selector Sel) {
+ return serialization::ComputeHash(Sel);
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, Selector Sel,
+ data_type_ref Methods) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
+ LE.write<uint16_t>(KeyLen);
+ unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts
+ for (const ObjCMethodList *Method = &Methods.Instance; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ DataLen += 4;
+ for (const ObjCMethodList *Method = &Methods.Factory; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ DataLen += 4;
+ LE.write<uint16_t>(DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, Selector Sel, unsigned) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint64_t Start = Out.tell();
+ assert((Start >> 32) == 0 && "Selector key offset too large");
+ Writer.SetSelectorOffset(Sel, Start);
+ unsigned N = Sel.getNumArgs();
+ LE.write<uint16_t>(N);
+ if (N == 0)
+ N = 1;
+ for (unsigned I = 0; I != N; ++I)
+ LE.write<uint32_t>(
+ Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
+ }
+
+ void EmitData(raw_ostream& Out, key_type_ref,
+ data_type_ref Methods, unsigned DataLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint64_t Start = Out.tell(); (void)Start;
+ LE.write<uint32_t>(Methods.ID);
+ unsigned NumInstanceMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.Instance; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ ++NumInstanceMethods;
+
+ unsigned NumFactoryMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.Factory; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ ++NumFactoryMethods;
+
+ unsigned InstanceBits = Methods.Instance.getBits();
+ assert(InstanceBits < 4);
+ unsigned InstanceHasMoreThanOneDeclBit =
+ Methods.Instance.hasMoreThanOneDecl();
+ unsigned FullInstanceBits = (NumInstanceMethods << 3) |
+ (InstanceHasMoreThanOneDeclBit << 2) |
+ InstanceBits;
+ unsigned FactoryBits = Methods.Factory.getBits();
+ assert(FactoryBits < 4);
+ unsigned FactoryHasMoreThanOneDeclBit =
+ Methods.Factory.hasMoreThanOneDecl();
+ unsigned FullFactoryBits = (NumFactoryMethods << 3) |
+ (FactoryHasMoreThanOneDeclBit << 2) |
+ FactoryBits;
+ LE.write<uint16_t>(FullInstanceBits);
+ LE.write<uint16_t>(FullFactoryBits);
+ for (const ObjCMethodList *Method = &Methods.Instance; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ LE.write<uint32_t>(Writer.getDeclID(Method->getMethod()));
+ for (const ObjCMethodList *Method = &Methods.Factory; Method;
+ Method = Method->getNext())
+ if (Method->getMethod())
+ LE.write<uint32_t>(Writer.getDeclID(Method->getMethod()));
+
+ assert(Out.tell() - Start == DataLen && "Data length is wrong");
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write ObjC data: selectors and the method pool.
+///
+/// The method pool contains both instance and factory methods, stored
+/// in an on-disk hash table indexed by the selector. The hash table also
+/// contains an empty entry for every other selector known to Sema.
+void ASTWriter::WriteSelectors(Sema &SemaRef) {
+ using namespace llvm;
+
+ // Do we have to do anything at all?
+ if (SemaRef.MethodPool.empty() && SelectorIDs.empty())
+ return;
+ unsigned NumTableEntries = 0;
+ // Create and write out the blob that contains selectors and the method pool.
+ {
+ llvm::OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
+ ASTMethodPoolTrait Trait(*this);
+
+ // Create the on-disk hash table representation. We walk through every
+ // selector we've seen and look it up in the method pool.
+ SelectorOffsets.resize(NextSelectorID - FirstSelectorID);
+ for (auto &SelectorAndID : SelectorIDs) {
+ Selector S = SelectorAndID.first;
+ SelectorID ID = SelectorAndID.second;
+ Sema::GlobalMethodPool::iterator F = SemaRef.MethodPool.find(S);
+ ASTMethodPoolTrait::data_type Data = {
+ ID,
+ ObjCMethodList(),
+ ObjCMethodList()
+ };
+ if (F != SemaRef.MethodPool.end()) {
+ Data.Instance = F->second.first;
+ Data.Factory = F->second.second;
+ }
+ // Only write this selector if it's not in an existing AST or something
+ // changed.
+ if (Chain && ID < FirstSelectorID) {
+ // Selector already exists. Did it change?
+ bool changed = false;
+ for (ObjCMethodList *M = &Data.Instance;
+ !changed && M && M->getMethod(); M = M->getNext()) {
+ if (!M->getMethod()->isFromASTFile())
+ changed = true;
+ }
+ for (ObjCMethodList *M = &Data.Factory; !changed && M && M->getMethod();
+ M = M->getNext()) {
+ if (!M->getMethod()->isFromASTFile())
+ changed = true;
+ }
+ if (!changed)
+ continue;
+ } else if (Data.Instance.getMethod() || Data.Factory.getMethod()) {
+ // A new method pool entry.
+ ++NumTableEntries;
+ }
+ Generator.insert(S, Data, Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> MethodPool;
+ uint32_t BucketOffset;
+ {
+ using namespace llvm::support;
+ ASTMethodPoolTrait Trait(*this);
+ llvm::raw_svector_ostream Out(MethodPool);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the method pool
+ RecordData Record;
+ Record.push_back(METHOD_POOL);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumTableEntries);
+ Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool);
+
+ // Create a blob abbreviation for the selector table offsets.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the selector offsets table.
+ Record.clear();
+ Record.push_back(SELECTOR_OFFSETS);
+ Record.push_back(SelectorOffsets.size());
+ Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS);
+ Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
+ bytes(SelectorOffsets));
+ }
+}
+
+/// \brief Write the selectors referenced in @selector expression into AST file.
+void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) {
+ using namespace llvm;
+ if (SemaRef.ReferencedSelectors.empty())
+ return;
+
+ RecordData Record;
+
+ // Note: this writes out all references even for a dependent AST. But it is
+ // very tricky to fix, and given that @selector shouldn't really appear in
+ // headers, probably not worth it. It's not a correctness issue.
+ for (auto &SelectorAndLocation : SemaRef.ReferencedSelectors) {
+ Selector Sel = SelectorAndLocation.first;
+ SourceLocation Loc = SelectorAndLocation.second;
+ AddSelectorRef(Sel, Record);
+ AddSourceLocation(Loc, Record);
+ }
+ Stream.EmitRecord(REFERENCED_SELECTOR_POOL, Record);
+}
+
+//===----------------------------------------------------------------------===//
+// Identifier Table Serialization
+//===----------------------------------------------------------------------===//
+
+/// Determine the declaration that should be put into the name lookup table to
+/// represent the given declaration in this module. This is usually D itself,
+/// but if D was imported and merged into a local declaration, we want the most
+/// recent local declaration instead. The chosen declaration will be the most
+/// recent declaration in any module that imports this one.
+static NamedDecl *getDeclForLocalLookup(const LangOptions &LangOpts,
+ NamedDecl *D) {
+ if (!LangOpts.Modules || !D->isFromASTFile())
+ return D;
+
+ if (Decl *Redecl = D->getPreviousDecl()) {
+ // For Redeclarable decls, a prior declaration might be local.
+ for (; Redecl; Redecl = Redecl->getPreviousDecl()) {
+ if (!Redecl->isFromASTFile())
+ return cast<NamedDecl>(Redecl);
+ // If we find a decl from a (chained-)PCH stop since we won't find a
+ // local one.
+ if (D->getOwningModuleID() == 0)
+ break;
+ }
+ } else if (Decl *First = D->getCanonicalDecl()) {
+ // For Mergeable decls, the first decl might be local.
+ if (!First->isFromASTFile())
+ return cast<NamedDecl>(First);
+ }
+
+ // All declarations are imported. Our most recent declaration will also be
+ // the most recent one in anyone who imports us.
+ return D;
+}
+
+namespace {
+class ASTIdentifierTableTrait {
+ ASTWriter &Writer;
+ Preprocessor &PP;
+ IdentifierResolver &IdResolver;
+
+ /// \brief Determines whether this is an "interesting" identifier that needs a
+ /// full IdentifierInfo structure written into the hash table. Notably, this
+ /// doesn't check whether the name has macros defined; use PublicMacroIterator
+ /// to check that.
+ bool isInterestingIdentifier(IdentifierInfo *II, uint64_t MacroOffset) {
+ if (MacroOffset ||
+ II->isPoisoned() ||
+ II->isExtensionToken() ||
+ II->getObjCOrBuiltinID() ||
+ II->hasRevertedTokenIDToIdentifier() ||
+ II->getFETokenInfo<void>())
+ return true;
+
+ return false;
+ }
+
+public:
+ typedef IdentifierInfo* key_type;
+ typedef key_type key_type_ref;
+
+ typedef IdentID data_type;
+ typedef data_type data_type_ref;
+
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,
+ IdentifierResolver &IdResolver)
+ : Writer(Writer), PP(PP), IdResolver(IdResolver) {}
+
+ static hash_value_type ComputeHash(const IdentifierInfo* II) {
+ return llvm::HashString(II->getName());
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
+ unsigned KeyLen = II->getLength() + 1;
+ unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
+ auto MacroOffset = Writer.getMacroDirectivesOffset(II);
+ if (isInterestingIdentifier(II, MacroOffset)) {
+ DataLen += 2; // 2 bytes for builtin ID
+ DataLen += 2; // 2 bytes for flags
+ if (MacroOffset)
+ DataLen += 4; // MacroDirectives offset.
+
+ for (IdentifierResolver::iterator D = IdResolver.begin(II),
+ DEnd = IdResolver.end();
+ D != DEnd; ++D)
+ DataLen += 4;
+ }
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+
+ assert((uint16_t)DataLen == DataLen && (uint16_t)KeyLen == KeyLen);
+ LE.write<uint16_t>(DataLen);
+ // We emit the key length after the data length so that every
+ // string is preceded by a 16-bit length. This matches the PTH
+ // format for storing identifiers.
+ LE.write<uint16_t>(KeyLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, const IdentifierInfo* II,
+ unsigned KeyLen) {
+ // Record the location of the key data. This is used when generating
+ // the mapping from persistent IDs to strings.
+ Writer.SetIdentifierOffset(II, Out.tell());
+ Out.write(II->getNameStart(), KeyLen);
+ }
+
+ void EmitData(raw_ostream& Out, IdentifierInfo* II,
+ IdentID ID, unsigned) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+
+ auto MacroOffset = Writer.getMacroDirectivesOffset(II);
+ if (!isInterestingIdentifier(II, MacroOffset)) {
+ LE.write<uint32_t>(ID << 1);
+ return;
+ }
+
+ LE.write<uint32_t>((ID << 1) | 0x01);
+ uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID();
+ assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
+ LE.write<uint16_t>(Bits);
+ Bits = 0;
+ bool HadMacroDefinition = MacroOffset != 0;
+ Bits = (Bits << 1) | unsigned(HadMacroDefinition);
+ Bits = (Bits << 1) | unsigned(II->isExtensionToken());
+ Bits = (Bits << 1) | unsigned(II->isPoisoned());
+ Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
+ Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
+ LE.write<uint16_t>(Bits);
+
+ if (HadMacroDefinition)
+ LE.write<uint32_t>(MacroOffset);
+
+ // Emit the declaration IDs in reverse order, because the
+ // IdentifierResolver provides the declarations as they would be
+ // visible (e.g., the function "stat" would come before the struct
+ // "stat"), but the ASTReader adds declarations to the end of the list
+ // (so we need to see the struct "stat" before the function "stat").
+ // Only emit declarations that aren't from a chained PCH, though.
+ SmallVector<NamedDecl *, 16> Decls(IdResolver.begin(II), IdResolver.end());
+ for (SmallVectorImpl<NamedDecl *>::reverse_iterator D = Decls.rbegin(),
+ DEnd = Decls.rend();
+ D != DEnd; ++D)
+ LE.write<uint32_t>(
+ Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D)));
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the identifier table into the AST file.
+///
+/// The identifier table consists of a blob containing string data
+/// (the actual identifiers themselves) and a separate "offsets" index
+/// that maps identifier IDs to locations within the blob.
+void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
+ IdentifierResolver &IdResolver,
+ bool IsModule) {
+ using namespace llvm;
+
+ // Create and write out the blob that contains the identifier
+ // strings.
+ {
+ llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
+ ASTIdentifierTableTrait Trait(*this, PP, IdResolver);
+
+ // Look for any identifiers that were named while processing the
+ // headers, but are otherwise not needed. We add these to the hash
+ // table to enable checking of the predefines buffer in the case
+ // where the user adds new macro definitions when building the AST
+ // file.
+ SmallVector<const IdentifierInfo *, 128> IIs;
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID)
+ IIs.push_back(ID->second);
+ // Sort the identifiers lexicographically before getting them references so
+ // that their order is stable.
+ std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());
+ for (const IdentifierInfo *II : IIs)
+ getIdentifierRef(II);
+
+ // Create the on-disk hash table representation. We only store offsets
+ // for identifiers that appear here for the first time.
+ IdentifierOffsets.resize(NextIdentID - FirstIdentID);
+ for (auto IdentIDPair : IdentifierIDs) {
+ IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first);
+ IdentID ID = IdentIDPair.second;
+ assert(II && "NULL identifier in identifier table");
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
+ Generator.insert(II, ID, Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ using namespace llvm::support;
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ RecordData Record;
+ Record.push_back(IDENTIFIER_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
+ }
+
+ // Write the offsets table for identifier IDs.
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+#ifndef NDEBUG
+ for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I)
+ assert(IdentifierOffsets[I] && "Missing identifier offset?");
+#endif
+
+ RecordData Record;
+ Record.push_back(IDENTIFIER_OFFSET);
+ Record.push_back(IdentifierOffsets.size());
+ Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS);
+ Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
+ bytes(IdentifierOffsets));
+}
+
+//===----------------------------------------------------------------------===//
+// DeclContext's Name Lookup Table Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table used in the method pool.
+class ASTDeclContextNameLookupTrait {
+ ASTWriter &Writer;
+
+public:
+ typedef DeclarationName key_type;
+ typedef key_type key_type_ref;
+
+ typedef DeclContext::lookup_result data_type;
+ typedef const data_type& data_type_ref;
+
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
+
+ hash_value_type ComputeHash(DeclarationName Name) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(Name.getNameKind());
+
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ ID.AddString(Name.getAsIdentifierInfo()->getName());
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector()));
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ break;
+ case DeclarationName::CXXOperatorName:
+ ID.AddInteger(Name.getCXXOverloadedOperator());
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ ID.AddString(Name.getCXXLiteralIdentifier()->getName());
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+
+ return ID.ComputeHash();
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, DeclarationName Name,
+ data_type_ref Lookup) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ unsigned KeyLen = 1;
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXLiteralOperatorName:
+ KeyLen += 4;
+ break;
+ case DeclarationName::CXXOperatorName:
+ KeyLen += 1;
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+ LE.write<uint16_t>(KeyLen);
+
+ // 2 bytes for num of decls and 4 for each DeclID.
+ unsigned DataLen = 2 + 4 * Lookup.size();
+ LE.write<uint16_t>(DataLen);
+
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ LE.write<uint8_t>(Name.getNameKind());
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ LE.write<uint32_t>(Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
+ return;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ LE.write<uint32_t>(Writer.getSelectorRef(Name.getObjCSelector()));
+ return;
+ case DeclarationName::CXXOperatorName:
+ assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS &&
+ "Invalid operator?");
+ LE.write<uint8_t>(Name.getCXXOverloadedOperator());
+ return;
+ case DeclarationName::CXXLiteralOperatorName:
+ LE.write<uint32_t>(Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
+ return;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ return;
+ }
+
+ llvm_unreachable("Invalid name kind?");
+ }
+
+ void EmitData(raw_ostream& Out, key_type_ref,
+ data_type Lookup, unsigned DataLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint64_t Start = Out.tell(); (void)Start;
+ LE.write<uint16_t>(Lookup.size());
+ for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
+ I != E; ++I)
+ LE.write<uint32_t>(
+ Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), *I)));
+
+ assert(Out.tell() - Start == DataLen && "Data length is wrong");
+ }
+};
+} // end anonymous namespace
+
+bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
+ DeclContext *DC) {
+ return Result.hasExternalDecls() && DC->NeedToReconcileExternalVisibleStorage;
+}
+
+bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,
+ DeclContext *DC) {
+ for (auto *D : Result.getLookupResult())
+ if (!getDeclForLocalLookup(getLangOpts(), D)->isFromASTFile())
+ return false;
+
+ return true;
+}
+
+uint32_t
+ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
+ llvm::SmallVectorImpl<char> &LookupTable) {
+ assert(!ConstDC->HasLazyLocalLexicalLookups &&
+ !ConstDC->HasLazyExternalLexicalLookups &&
+ "must call buildLookups first");
+
+ // FIXME: We need to build the lookups table, which is logically const.
+ DeclContext *DC = const_cast<DeclContext*>(ConstDC);
+ assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
+
+ // Create the on-disk hash table representation.
+ llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
+ Generator;
+ ASTDeclContextNameLookupTrait Trait(*this);
+
+ // The first step is to collect the declaration names which we need to
+ // serialize into the name lookup table, and to collect them in a stable
+ // order.
+ SmallVector<DeclarationName, 16> Names;
+
+ // We also build up small sets of the constructor and conversion function
+ // names which are visible.
+ llvm::SmallSet<DeclarationName, 8> ConstructorNameSet, ConversionNameSet;
+
+ for (auto &Lookup : *DC->buildLookup()) {
+ auto &Name = Lookup.first;
+ auto &Result = Lookup.second;
+
+ // If there are no local declarations in our lookup result, we don't
+ // need to write an entry for the name at all unless we're rewriting
+ // the decl context. If we can't write out a lookup set without
+ // performing more deserialization, just skip this entry.
+ if (isLookupResultExternal(Result, DC) && !isRewritten(cast<Decl>(DC)) &&
+ isLookupResultEntirelyExternal(Result, DC))
+ continue;
+
+ // We also skip empty results. If any of the results could be external and
+ // the currently available results are empty, then all of the results are
+ // external and we skip it above. So the only way we get here with an empty
+ // results is when no results could have been external *and* we have
+ // external results.
+ //
+ // FIXME: While we might want to start emitting on-disk entries for negative
+ // lookups into a decl context as an optimization, today we *have* to skip
+ // them because there are names with empty lookup results in decl contexts
+ // which we can't emit in any stable ordering: we lookup constructors and
+ // conversion functions in the enclosing namespace scope creating empty
+ // results for them. This in almost certainly a bug in Clang's name lookup,
+ // but that is likely to be hard or impossible to fix and so we tolerate it
+ // here by omitting lookups with empty results.
+ if (Lookup.second.getLookupResult().empty())
+ continue;
+
+ switch (Lookup.first.getNameKind()) {
+ default:
+ Names.push_back(Lookup.first);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ assert(isa<CXXRecordDecl>(DC) &&
+ "Cannot have a constructor name outside of a class!");
+ ConstructorNameSet.insert(Name);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ assert(isa<CXXRecordDecl>(DC) &&
+ "Cannot have a conversion function name outside of a class!");
+ ConversionNameSet.insert(Name);
+ break;
+ }
+ }
+
+ // Sort the names into a stable order.
+ std::sort(Names.begin(), Names.end());
+
+ if (auto *D = dyn_cast<CXXRecordDecl>(DC)) {
+ // We need to establish an ordering of constructor and conversion function
+ // names, and they don't have an intrinsic ordering.
+
+ // First we try the easy case by forming the current context's constructor
+ // name and adding that name first. This is a very useful optimization to
+ // avoid walking the lexical declarations in many cases, and it also
+ // handles the only case where a constructor name can come from some other
+ // lexical context -- when that name is an implicit constructor merged from
+ // another declaration in the redecl chain. Any non-implicit constructor or
+ // conversion function which doesn't occur in all the lexical contexts
+ // would be an ODR violation.
+ auto ImplicitCtorName = Context->DeclarationNames.getCXXConstructorName(
+ Context->getCanonicalType(Context->getRecordType(D)));
+ if (ConstructorNameSet.erase(ImplicitCtorName))
+ Names.push_back(ImplicitCtorName);
+
+ // If we still have constructors or conversion functions, we walk all the
+ // names in the decl and add the constructors and conversion functions
+ // which are visible in the order they lexically occur within the context.
+ if (!ConstructorNameSet.empty() || !ConversionNameSet.empty())
+ for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls())
+ if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
+ auto Name = ChildND->getDeclName();
+ switch (Name.getNameKind()) {
+ default:
+ continue;
+
+ case DeclarationName::CXXConstructorName:
+ if (ConstructorNameSet.erase(Name))
+ Names.push_back(Name);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ if (ConversionNameSet.erase(Name))
+ Names.push_back(Name);
+ break;
+ }
+
+ if (ConstructorNameSet.empty() && ConversionNameSet.empty())
+ break;
+ }
+
+ assert(ConstructorNameSet.empty() && "Failed to find all of the visible "
+ "constructors by walking all the "
+ "lexical members of the context.");
+ assert(ConversionNameSet.empty() && "Failed to find all of the visible "
+ "conversion functions by walking all "
+ "the lexical members of the context.");
+ }
+
+ // Next we need to do a lookup with each name into this decl context to fully
+ // populate any results from external sources. We don't actually use the
+ // results of these lookups because we only want to use the results after all
+ // results have been loaded and the pointers into them will be stable.
+ for (auto &Name : Names)
+ DC->lookup(Name);
+
+ // Now we need to insert the results for each name into the hash table. For
+ // constructor names and conversion function names, we actually need to merge
+ // all of the results for them into one list of results each and insert
+ // those.
+ SmallVector<NamedDecl *, 8> ConstructorDecls;
+ SmallVector<NamedDecl *, 8> ConversionDecls;
+
+ // Now loop over the names, either inserting them or appending for the two
+ // special cases.
+ for (auto &Name : Names) {
+ DeclContext::lookup_result Result = DC->noload_lookup(Name);
+
+ switch (Name.getNameKind()) {
+ default:
+ Generator.insert(Name, Result, Trait);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ ConstructorDecls.append(Result.begin(), Result.end());
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ ConversionDecls.append(Result.begin(), Result.end());
+ break;
+ }
+ }
+
+ // Handle our two special cases if we ended up having any. We arbitrarily use
+ // the first declaration's name here because the name itself isn't part of
+ // the key, only the kind of name is used.
+ if (!ConstructorDecls.empty())
+ Generator.insert(ConstructorDecls.front()->getDeclName(),
+ DeclContext::lookup_result(ConstructorDecls), Trait);
+ if (!ConversionDecls.empty())
+ Generator.insert(ConversionDecls.front()->getDeclName(),
+ DeclContext::lookup_result(ConversionDecls), Trait);
+
+ // Create the on-disk hash table in a buffer.
+ llvm::raw_svector_ostream Out(LookupTable);
+ // Make sure that no bucket is at offset 0
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ return Generator.Emit(Out, Trait);
+}
+
+/// \brief Write the block containing all of the declaration IDs
+/// visible from the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the
+/// bitstream, or 0 if no block was written.
+uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->getPrimaryContext() != DC)
+ return 0;
+
+ // Skip contexts which don't support name lookup.
+ if (!DC->isLookupContext())
+ return 0;
+
+ // If not in C++, we perform name lookup for the translation unit via the
+ // IdentifierInfo chains, don't bother to build a visible-declarations table.
+ if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
+ return 0;
+
+ // Serialize the contents of the mapping used for lookup. Note that,
+ // although we have two very different code paths, the serialized
+ // representation is the same for both cases: a declaration name,
+ // followed by a size, followed by references to the visible
+ // declarations that have that name.
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ StoredDeclsMap *Map = DC->buildLookup();
+ if (!Map || Map->empty())
+ return 0;
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> LookupTable;
+ uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
+
+ // Write the lookup table
+ RecordData Record;
+ Record.push_back(DECL_CONTEXT_VISIBLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
+ LookupTable);
+ ++NumVisibleDeclContexts;
+ return Offset;
+}
+
+/// \brief Write an UPDATE_VISIBLE block for the given context.
+///
+/// UPDATE_VISIBLE blocks contain the declarations that are added to an existing
+/// DeclContext in a dependent AST file. As such, they only exist for the TU
+/// (in C++), for namespaces, and for classes with forward-declared unscoped
+/// enumeration members (in C++11).
+void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
+ StoredDeclsMap *Map = DC->getLookupPtr();
+ if (!Map || Map->empty())
+ return;
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> LookupTable;
+ uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
+
+ // Write the lookup table
+ RecordData Record;
+ Record.push_back(UPDATE_VISIBLE);
+ Record.push_back(getDeclID(cast<Decl>(DC)));
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable);
+}
+
+/// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
+void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
+ RecordData Record;
+ Record.push_back(Opts.fp_contract);
+ Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);
+}
+
+/// \brief Write an OPENCL_EXTENSIONS block for the given OpenCLOptions.
+void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
+ if (!SemaRef.Context.getLangOpts().OpenCL)
+ return;
+
+ const OpenCLOptions &Opts = SemaRef.getOpenCLOptions();
+ RecordData Record;
+#define OPENCLEXT(nm) Record.push_back(Opts.nm);
+#include "clang/Basic/OpenCLExtensions.def"
+ Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
+}
+
+void ASTWriter::WriteRedeclarations() {
+ RecordData LocalRedeclChains;
+ SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
+
+ for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
+ Decl *First = Redeclarations[I];
+ assert(First->isFirstDecl() && "Not the first declaration?");
+
+ Decl *MostRecent = First->getMostRecentDecl();
+
+ // If we only have a single declaration, there is no point in storing
+ // a redeclaration chain.
+ if (First == MostRecent)
+ continue;
+
+ unsigned Offset = LocalRedeclChains.size();
+ unsigned Size = 0;
+ LocalRedeclChains.push_back(0); // Placeholder for the size.
+
+ // Collect the set of local redeclarations of this declaration.
+ for (Decl *Prev = MostRecent; Prev != First;
+ Prev = Prev->getPreviousDecl()) {
+ if (!Prev->isFromASTFile()) {
+ AddDeclRef(Prev, LocalRedeclChains);
+ ++Size;
+ }
+ }
+
+ LocalRedeclChains[Offset] = Size;
+
+ // Reverse the set of local redeclarations, so that we store them in
+ // order (since we found them in reverse order).
+ std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
+
+ // Add the mapping from the first ID from the AST to the set of local
+ // declarations.
+ LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
+ LocalRedeclsMap.push_back(Info);
+
+ assert(N == Redeclarations.size() &&
+ "Deserialized a declaration we shouldn't have");
+ }
+
+ if (LocalRedeclChains.empty())
+ return;
+
+ // Sort the local redeclarations map by the first declaration ID,
+ // since the reader will be performing binary searches on this information.
+ llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
+
+ // Emit the local redeclarations map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(LOCAL_REDECLARATIONS_MAP);
+ Record.push_back(LocalRedeclsMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(LocalRedeclsMap.data()),
+ LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
+
+ // Emit the redeclaration chains.
+ Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
+}
+
+void ASTWriter::WriteObjCCategories() {
+ SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
+ RecordData Categories;
+
+ for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
+ unsigned Size = 0;
+ unsigned StartIndex = Categories.size();
+
+ ObjCInterfaceDecl *Class = ObjCClassesWithCategories[I];
+
+ // Allocate space for the size.
+ Categories.push_back(0);
+
+ // Add the categories.
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat, ++Size) {
+ assert(getDeclID(*Cat) != 0 && "Bogus category");
+ AddDeclRef(*Cat, Categories);
+ }
+
+ // Update the size.
+ Categories[StartIndex] = Size;
+
+ // Record this interface -> category map.
+ ObjCCategoriesInfo CatInfo = { getDeclID(Class), StartIndex };
+ CategoriesMap.push_back(CatInfo);
+ }
+
+ // Sort the categories map by the definition ID, since the reader will be
+ // performing binary searches on this information.
+ llvm::array_pod_sort(CategoriesMap.begin(), CategoriesMap.end());
+
+ // Emit the categories map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(OBJC_CATEGORIES_MAP);
+ Record.push_back(CategoriesMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(CategoriesMap.data()),
+ CategoriesMap.size() * sizeof(ObjCCategoriesInfo));
+
+ // Emit the category lists.
+ Stream.EmitRecord(OBJC_CATEGORIES, Categories);
+}
+
+void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) {
+ Sema::LateParsedTemplateMapT &LPTMap = SemaRef.LateParsedTemplateMap;
+
+ if (LPTMap.empty())
+ return;
+
+ RecordData Record;
+ for (auto LPTMapEntry : LPTMap) {
+ const FunctionDecl *FD = LPTMapEntry.first;
+ LateParsedTemplate *LPT = LPTMapEntry.second;
+ AddDeclRef(FD, Record);
+ AddDeclRef(LPT->D, Record);
+ Record.push_back(LPT->Toks.size());
+
+ for (CachedTokens::iterator TokIt = LPT->Toks.begin(),
+ TokEnd = LPT->Toks.end();
+ TokIt != TokEnd; ++TokIt) {
+ AddToken(*TokIt, Record);
+ }
+ }
+ Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record);
+}
+
+/// \brief Write the state of 'pragma clang optimize' at the end of the module.
+void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) {
+ RecordData Record;
+ SourceLocation PragmaLoc = SemaRef.getOptimizeOffPragmaLocation();
+ AddSourceLocation(PragmaLoc, Record);
+ Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record);
+}
+
+//===----------------------------------------------------------------------===//
+// General Serialization Routines
+//===----------------------------------------------------------------------===//
+
+/// \brief Write a record containing the given attributes.
+void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs,
+ RecordDataImpl &Record) {
+ Record.push_back(Attrs.size());
+ for (ArrayRef<const Attr *>::iterator i = Attrs.begin(),
+ e = Attrs.end(); i != e; ++i){
+ const Attr *A = *i;
+ Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
+ AddSourceRange(A->getRange(), Record);
+
+#include "clang/Serialization/AttrPCHWrite.inc"
+
+ }
+}
+
+void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
+ AddSourceLocation(Tok.getLocation(), Record);
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer
+ // if it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+ // FIXME: Should translate token kind to a stable encoding.
+ Record.push_back(Tok.getKind());
+ // FIXME: Should translate token flags to a stable encoding.
+ Record.push_back(Tok.getFlags());
+}
+
+void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
+ Record.push_back(Str.size());
+ Record.insert(Record.end(), Str.begin(), Str.end());
+}
+
+bool ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) {
+ assert(Context && "should have context when outputting path");
+
+ bool Changed =
+ cleanPathForOutput(Context->getSourceManager().getFileManager(), Path);
+
+ // Remove a prefix to make the path relative, if relevant.
+ const char *PathBegin = Path.data();
+ const char *PathPtr =
+ adjustFilenameForRelocatableAST(PathBegin, BaseDirectory);
+ if (PathPtr != PathBegin) {
+ Path.erase(Path.begin(), Path.begin() + (PathPtr - PathBegin));
+ Changed = true;
+ }
+
+ return Changed;
+}
+
+void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) {
+ SmallString<128> FilePath(Path);
+ PreparePathForOutput(FilePath);
+ AddString(FilePath, Record);
+}
+
+void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record,
+ StringRef Path) {
+ SmallString<128> FilePath(Path);
+ PreparePathForOutput(FilePath);
+ Stream.EmitRecordWithBlob(Abbrev, Record, FilePath);
+}
+
+void ASTWriter::AddVersionTuple(const VersionTuple &Version,
+ RecordDataImpl &Record) {
+ Record.push_back(Version.getMajor());
+ if (Optional<unsigned> Minor = Version.getMinor())
+ Record.push_back(*Minor + 1);
+ else
+ Record.push_back(0);
+ if (Optional<unsigned> Subminor = Version.getSubminor())
+ Record.push_back(*Subminor + 1);
+ else
+ Record.push_back(0);
+}
+
+/// \brief Note that the identifier II occurs at the given offset
+/// within the identifier table.
+void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
+ IdentID ID = IdentifierIDs[II];
+ // Only store offsets new to this AST file. Other identifier names are looked
+ // up earlier in the chain and thus don't need an offset.
+ if (ID >= FirstIdentID)
+ IdentifierOffsets[ID - FirstIdentID] = Offset;
+}
+
+/// \brief Note that the selector Sel occurs at the given offset
+/// within the method pool/selector table.
+void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
+ unsigned ID = SelectorIDs[Sel];
+ assert(ID && "Unknown selector");
+ // Don't record offsets for selectors that are also available in a different
+ // file.
+ if (ID < FirstSelectorID)
+ return;
+ SelectorOffsets[ID - FirstSelectorID] = Offset;
+}
+
+ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
+ : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr),
+ WritingModule(nullptr), WritingAST(false),
+ DoneWritingDeclsAndTypes(false), ASTHasCompilerErrors(false),
+ FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
+ FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
+ FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
+ FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
+ NextSubmoduleID(FirstSubmoduleID),
+ FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
+ CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
+ NumLexicalDeclContexts(0), NumVisibleDeclContexts(0),
+ NextCXXBaseSpecifiersID(1), NextCXXCtorInitializersID(1),
+ TypeExtQualAbbrev(0),
+ TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0),
+ DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0),
+ UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0),
+ DeclVarAbbrev(0), DeclFieldAbbrev(0), DeclEnumAbbrev(0),
+ DeclObjCIvarAbbrev(0), DeclCXXMethodAbbrev(0), DeclRefExprAbbrev(0),
+ CharacterLiteralAbbrev(0), IntegerLiteralAbbrev(0),
+ ExprImplicitCastAbbrev(0) {}
+
+ASTWriter::~ASTWriter() {
+ llvm::DeleteContainerSeconds(FileDeclIDs);
+}
+
+const LangOptions &ASTWriter::getLangOpts() const {
+ assert(WritingAST && "can't determine lang opts when not writing AST");
+ return Context->getLangOpts();
+}
+
+void ASTWriter::WriteAST(Sema &SemaRef,
+ const std::string &OutputFile,
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors) {
+ WritingAST = true;
+
+ ASTHasCompilerErrors = hasErrors;
+
+ // Emit the file header.
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'P', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'H', 8);
+
+ WriteBlockInfoBlock();
+
+ Context = &SemaRef.Context;
+ PP = &SemaRef.PP;
+ this->WritingModule = WritingModule;
+ WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
+ Context = nullptr;
+ PP = nullptr;
+ this->WritingModule = nullptr;
+ this->BaseDirectory.clear();
+
+ WritingAST = false;
+}
+
+template<typename Vector>
+static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
+ ASTWriter::RecordData &Record) {
+ for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end();
+ I != E; ++I) {
+ Writer.AddDeclRef(*I, Record);
+ }
+}
+
+void ASTWriter::WriteASTCore(Sema &SemaRef,
+ StringRef isysroot,
+ const std::string &OutputFile,
+ Module *WritingModule) {
+ using namespace llvm;
+
+ bool isModule = WritingModule != nullptr;
+
+ // Make sure that the AST reader knows to finalize itself.
+ if (Chain)
+ Chain->finalizeForWriting();
+
+ ASTContext &Context = SemaRef.Context;
+ Preprocessor &PP = SemaRef.PP;
+
+ // Set up predefined declaration IDs.
+ DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID;
+ if (Context.ObjCIdDecl)
+ DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID;
+ if (Context.ObjCSelDecl)
+ DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID;
+ if (Context.ObjCClassDecl)
+ DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID;
+ if (Context.ObjCProtocolClassDecl)
+ DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID;
+ if (Context.Int128Decl)
+ DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
+ if (Context.UInt128Decl)
+ DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
+ if (Context.ObjCInstanceTypeDecl)
+ DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
+ if (Context.BuiltinVaListDecl)
+ DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID;
+ if (Context.ExternCContext)
+ DeclIDs[Context.ExternCContext] = PREDEF_DECL_EXTERN_C_CONTEXT_ID;
+
+ // Build a record containing all of the tentative definitions in this file, in
+ // TentativeDefinitions order. Generally, this record will be empty for
+ // headers.
+ RecordData TentativeDefinitions;
+ AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions);
+
+ // Build a record containing all of the file scoped decls in this file.
+ RecordData UnusedFileScopedDecls;
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
+ UnusedFileScopedDecls);
+
+ // Build a record containing all of the delegating constructors we still need
+ // to resolve.
+ RecordData DelegatingCtorDecls;
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
+
+ // Write the set of weak, undeclared identifiers. We always write the
+ // entire table, since later PCH files in a PCH chain are only interested in
+ // the results at the end of the chain.
+ RecordData WeakUndeclaredIdentifiers;
+ for (auto &WeakUndeclaredIdentifier : SemaRef.WeakUndeclaredIdentifiers) {
+ IdentifierInfo *II = WeakUndeclaredIdentifier.first;
+ WeakInfo &WI = WeakUndeclaredIdentifier.second;
+ AddIdentifierRef(II, WeakUndeclaredIdentifiers);
+ AddIdentifierRef(WI.getAlias(), WeakUndeclaredIdentifiers);
+ AddSourceLocation(WI.getLocation(), WeakUndeclaredIdentifiers);
+ WeakUndeclaredIdentifiers.push_back(WI.getUsed());
+ }
+
+ // Build a record containing all of the ext_vector declarations.
+ RecordData ExtVectorDecls;
+ AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
+
+ // Build a record containing all of the VTable uses information.
+ RecordData VTableUses;
+ if (!SemaRef.VTableUses.empty()) {
+ for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
+ AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
+ AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
+ VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
+ }
+ }
+
+ // Build a record containing all of the UnusedLocalTypedefNameCandidates.
+ RecordData UnusedLocalTypedefNameCandidates;
+ for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
+ AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
+
+ // Build a record containing all of pending implicit instantiations.
+ RecordData PendingInstantiations;
+ for (std::deque<Sema::PendingImplicitInstantiation>::iterator
+ I = SemaRef.PendingInstantiations.begin(),
+ N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
+ AddDeclRef(I->first, PendingInstantiations);
+ AddSourceLocation(I->second, PendingInstantiations);
+ }
+ assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
+ "There are local ones at end of translation unit!");
+
+ // Build a record containing some declaration references.
+ RecordData SemaDeclRefs;
+ if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
+ AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
+ AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
+ }
+
+ RecordData CUDASpecialDeclRefs;
+ if (Context.getcudaConfigureCallDecl()) {
+ AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
+ }
+
+ // Build a record containing all of the known namespaces.
+ RecordData KnownNamespaces;
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
+ I = SemaRef.KnownNamespaces.begin(),
+ IEnd = SemaRef.KnownNamespaces.end();
+ I != IEnd; ++I) {
+ if (!I->second)
+ AddDeclRef(I->first, KnownNamespaces);
+ }
+
+ // Build a record of all used, undefined objects that require definitions.
+ RecordData UndefinedButUsed;
+
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ SemaRef.getUndefinedButUsed(Undefined);
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ AddDeclRef(I->first, UndefinedButUsed);
+ AddSourceLocation(I->second, UndefinedButUsed);
+ }
+
+ // Build a record containing all delete-expressions that we would like to
+ // analyze later in AST.
+ RecordData DeleteExprsToAnalyze;
+
+ for (const auto &DeleteExprsInfo :
+ SemaRef.getMismatchingDeleteExpressions()) {
+ AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze);
+ DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size());
+ for (const auto &DeleteLoc : DeleteExprsInfo.second) {
+ AddSourceLocation(DeleteLoc.first, DeleteExprsToAnalyze);
+ DeleteExprsToAnalyze.push_back(DeleteLoc.second);
+ }
+ }
+
+ // Write the control block
+ WriteControlBlock(PP, Context, isysroot, OutputFile);
+
+ // Write the remaining AST contents.
+ RecordData Record;
+ Stream.EnterSubblock(AST_BLOCK_ID, 5);
+
+ // This is so that older clang versions, before the introduction
+ // of the control block, can read and reject the newer PCH format.
+ Record.clear();
+ Record.push_back(VERSION_MAJOR);
+ Stream.EmitRecord(METADATA_OLD_FORMAT, Record);
+
+ // Create a lexical update block containing all of the declarations in the
+ // translation unit that do not come from other AST files.
+ const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
+ SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
+ for (const auto *I : TU->noload_decls()) {
+ if (!I->isFromASTFile())
+ NewGlobalDecls.push_back(std::make_pair(I->getKind(), GetDeclRef(I)));
+ }
+
+ llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
+ Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
+ unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv);
+ Record.clear();
+ Record.push_back(TU_UPDATE_LEXICAL);
+ Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
+ bytes(NewGlobalDecls));
+
+ // And a visible updates block for the translation unit.
+ Abv = new llvm::BitCodeAbbrev();
+ Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
+ UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
+ WriteDeclContextVisibleUpdate(TU);
+
+ // If we have any extern "C" names, write out a visible update for them.
+ if (Context.ExternCContext)
+ WriteDeclContextVisibleUpdate(Context.ExternCContext);
+
+ // If the translation unit has an anonymous namespace, and we don't already
+ // have an update block for it, write it as an update block.
+ // FIXME: Why do we not do this if there's already an update block?
+ if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
+ ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
+ if (Record.empty())
+ Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS));
+ }
+
+ // Add update records for all mangling numbers and static local numbers.
+ // These aren't really update records, but this is a convenient way of
+ // tagging this rare extra data onto the declarations.
+ for (const auto &Number : Context.MangleNumbers)
+ if (!Number.first->isFromASTFile())
+ DeclUpdates[Number.first].push_back(DeclUpdate(UPD_MANGLING_NUMBER,
+ Number.second));
+ for (const auto &Number : Context.StaticLocalNumbers)
+ if (!Number.first->isFromASTFile())
+ DeclUpdates[Number.first].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER,
+ Number.second));
+
+ // Make sure visible decls, added to DeclContexts previously loaded from
+ // an AST file, are registered for serialization.
+ for (SmallVectorImpl<const Decl *>::iterator
+ I = UpdatingVisibleDecls.begin(),
+ E = UpdatingVisibleDecls.end(); I != E; ++I) {
+ GetDeclRef(*I);
+ }
+
+ // Make sure all decls associated with an identifier are registered for
+ // serialization.
+ llvm::SmallVector<const IdentifierInfo*, 256> IIs;
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID) {
+ const IdentifierInfo *II = ID->second;
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
+ IIs.push_back(II);
+ }
+ // Sort the identifiers to visit based on their name.
+ std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());
+ for (const IdentifierInfo *II : IIs) {
+ for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II),
+ DEnd = SemaRef.IdResolver.end();
+ D != DEnd; ++D) {
+ GetDeclRef(*D);
+ }
+ }
+
+ // Form the record of special types.
+ RecordData SpecialTypes;
+ AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
+ AddTypeRef(Context.getFILEType(), SpecialTypes);
+ AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.getucontext_tType(), SpecialTypes);
+
+ if (Chain) {
+ // Write the mapping information describing our module dependencies and how
+ // each of those modules were mapped into our own offset/ID space, so that
+ // the reader can build the appropriate mapping to its own offset/ID space.
+ // The map consists solely of a blob with the following format:
+ // *(module-name-len:i16 module-name:len*i8
+ // source-location-offset:i32
+ // identifier-id:i32
+ // preprocessed-entity-id:i32
+ // macro-definition-id:i32
+ // submodule-id:i32
+ // selector-id:i32
+ // declaration-id:i32
+ // c++-base-specifiers-id:i32
+ // type-id:i32)
+ //
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
+ SmallString<2048> Buffer;
+ {
+ llvm::raw_svector_ostream Out(Buffer);
+ for (ModuleFile *M : Chain->ModuleMgr) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ StringRef FileName = M->FileName;
+ LE.write<uint16_t>(FileName.size());
+ Out.write(FileName.data(), FileName.size());
+
+ // Note: if a base ID was uint max, it would not be possible to load
+ // another module after it or have more than one entity inside it.
+ uint32_t None = std::numeric_limits<uint32_t>::max();
+
+ auto writeBaseIDOrNone = [&](uint32_t BaseID, bool ShouldWrite) {
+ assert(BaseID < std::numeric_limits<uint32_t>::max() && "base id too high");
+ if (ShouldWrite)
+ LE.write<uint32_t>(BaseID);
+ else
+ LE.write<uint32_t>(None);
+ };
+
+ // These values should be unique within a chain, since they will be read
+ // as keys into ContinuousRangeMaps.
+ writeBaseIDOrNone(M->SLocEntryBaseOffset, M->LocalNumSLocEntries);
+ writeBaseIDOrNone(M->BaseIdentifierID, M->LocalNumIdentifiers);
+ writeBaseIDOrNone(M->BaseMacroID, M->LocalNumMacros);
+ writeBaseIDOrNone(M->BasePreprocessedEntityID,
+ M->NumPreprocessedEntities);
+ writeBaseIDOrNone(M->BaseSubmoduleID, M->LocalNumSubmodules);
+ writeBaseIDOrNone(M->BaseSelectorID, M->LocalNumSelectors);
+ writeBaseIDOrNone(M->BaseDeclID, M->LocalNumDecls);
+ writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes);
+ }
+ }
+ Record.clear();
+ Record.push_back(MODULE_OFFSET_MAP);
+ Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
+ Buffer.data(), Buffer.size());
+ }
+
+ RecordData DeclUpdatesOffsetsRecord;
+
+ // Keep writing types, declarations, and declaration update records
+ // until we've emitted all of them.
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);
+ WriteTypeAbbrevs();
+ WriteDeclAbbrevs();
+ for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
+ E = DeclsToRewrite.end();
+ I != E; ++I)
+ DeclTypesToEmit.push(const_cast<Decl*>(*I));
+ do {
+ WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord);
+ while (!DeclTypesToEmit.empty()) {
+ DeclOrType DOT = DeclTypesToEmit.front();
+ DeclTypesToEmit.pop();
+ if (DOT.isType())
+ WriteType(DOT.getType());
+ else
+ WriteDecl(Context, DOT.getDecl());
+ }
+ } while (!DeclUpdates.empty());
+ Stream.ExitBlock();
+
+ DoneWritingDeclsAndTypes = true;
+
+ // These things can only be done once we've written out decls and types.
+ WriteTypeDeclOffsets();
+ if (!DeclUpdatesOffsetsRecord.empty())
+ Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
+ WriteCXXBaseSpecifiersOffsets();
+ WriteCXXCtorInitializersOffsets();
+ WriteFileDeclIDsMap();
+ WriteSourceManagerBlock(Context.getSourceManager(), PP);
+
+ WriteComments();
+ WritePreprocessor(PP, isModule);
+ WriteHeaderSearch(PP.getHeaderSearchInfo());
+ WriteSelectors(SemaRef);
+ WriteReferencedSelectorsPool(SemaRef);
+ WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
+ WriteFPPragmaOptions(SemaRef.getFPOptions());
+ WriteOpenCLExtensions(SemaRef);
+ WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
+
+ // If we're emitting a module, write out the submodule information.
+ if (WritingModule)
+ WriteSubmodules(WritingModule);
+
+ Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
+
+ // Write the record containing external, unnamed definitions.
+ if (!EagerlyDeserializedDecls.empty())
+ Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
+
+ // Write the record containing tentative definitions.
+ if (!TentativeDefinitions.empty())
+ Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
+
+ // Write the record containing unused file scoped decls.
+ if (!UnusedFileScopedDecls.empty())
+ Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
+
+ // Write the record containing weak undeclared identifiers.
+ if (!WeakUndeclaredIdentifiers.empty())
+ Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
+ WeakUndeclaredIdentifiers);
+
+ // Write the record containing ext_vector type names.
+ if (!ExtVectorDecls.empty())
+ Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
+
+ // Write the record containing VTable uses information.
+ if (!VTableUses.empty())
+ Stream.EmitRecord(VTABLE_USES, VTableUses);
+
+ // Write the record containing potentially unused local typedefs.
+ if (!UnusedLocalTypedefNameCandidates.empty())
+ Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
+ UnusedLocalTypedefNameCandidates);
+
+ // Write the record containing pending implicit instantiations.
+ if (!PendingInstantiations.empty())
+ Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
+
+ // Write the record containing declaration references of Sema.
+ if (!SemaDeclRefs.empty())
+ Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
+
+ // Write the record containing CUDA-specific declaration references.
+ if (!CUDASpecialDeclRefs.empty())
+ Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
+
+ // Write the delegating constructors.
+ if (!DelegatingCtorDecls.empty())
+ Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
+
+ // Write the known namespaces.
+ if (!KnownNamespaces.empty())
+ Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
+ // Write the undefined internal functions and variables, and inline functions.
+ if (!UndefinedButUsed.empty())
+ Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
+
+ if (!DeleteExprsToAnalyze.empty())
+ Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze);
+
+ // Write the visible updates to DeclContexts.
+ for (auto *DC : UpdatedDeclContexts)
+ WriteDeclContextVisibleUpdate(DC);
+
+ if (!WritingModule) {
+ // Write the submodules that were imported, if any.
+ struct ModuleInfo {
+ uint64_t ID;
+ Module *M;
+ ModuleInfo(uint64_t ID, Module *M) : ID(ID), M(M) {}
+ };
+ llvm::SmallVector<ModuleInfo, 64> Imports;
+ for (const auto *I : Context.local_imports()) {
+ assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
+ Imports.push_back(ModuleInfo(SubmoduleIDs[I->getImportedModule()],
+ I->getImportedModule()));
+ }
+
+ if (!Imports.empty()) {
+ auto Cmp = [](const ModuleInfo &A, const ModuleInfo &B) {
+ return A.ID < B.ID;
+ };
+ auto Eq = [](const ModuleInfo &A, const ModuleInfo &B) {
+ return A.ID == B.ID;
+ };
+
+ // Sort and deduplicate module IDs.
+ std::sort(Imports.begin(), Imports.end(), Cmp);
+ Imports.erase(std::unique(Imports.begin(), Imports.end(), Eq),
+ Imports.end());
+
+ RecordData ImportedModules;
+ for (const auto &Import : Imports) {
+ ImportedModules.push_back(Import.ID);
+ // FIXME: If the module has macros imported then later has declarations
+ // imported, this location won't be the right one as a location for the
+ // declaration imports.
+ AddSourceLocation(PP.getModuleImportLoc(Import.M), ImportedModules);
+ }
+
+ Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
+ }
+ }
+
+ WriteDeclReplacementsBlock();
+ WriteRedeclarations();
+ WriteObjCCategories();
+ WriteLateParsedTemplates(SemaRef);
+ if(!WritingModule)
+ WriteOptimizePragmaOptions(SemaRef);
+
+ // Some simple statistics
+ Record.clear();
+ Record.push_back(NumStatements);
+ Record.push_back(NumMacros);
+ Record.push_back(NumLexicalDeclContexts);
+ Record.push_back(NumVisibleDeclContexts);
+ Stream.EmitRecord(STATISTICS, Record);
+ Stream.ExitBlock();
+}
+
+void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
+ if (DeclUpdates.empty())
+ return;
+
+ DeclUpdateMap LocalUpdates;
+ LocalUpdates.swap(DeclUpdates);
+
+ for (auto &DeclUpdate : LocalUpdates) {
+ const Decl *D = DeclUpdate.first;
+ if (isRewritten(D))
+ continue; // The decl will be written completely,no need to store updates.
+
+ bool HasUpdatedBody = false;
+ RecordData Record;
+ for (auto &Update : DeclUpdate.second) {
+ DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind();
+
+ Record.push_back(Kind);
+ switch (Kind) {
+ case UPD_CXX_ADDED_IMPLICIT_MEMBER:
+ case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
+ case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
+ assert(Update.getDecl() && "no decl to add?");
+ Record.push_back(GetDeclRef(Update.getDecl()));
+ break;
+
+ case UPD_CXX_ADDED_FUNCTION_DEFINITION:
+ // An updated body is emitted last, so that the reader doesn't need
+ // to skip over the lazy body to reach statements for other records.
+ Record.pop_back();
+ HasUpdatedBody = true;
+ break;
+
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ AddSourceLocation(Update.getLoc(), Record);
+ break;
+
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ UpdatedDeclContexts.insert(RD->getPrimaryContext());
+ AddCXXDefinitionData(RD, Record);
+ Record.push_back(WriteDeclContextLexicalBlock(
+ *Context, const_cast<CXXRecordDecl *>(RD)));
+
+ // This state is sometimes updated by template instantiation, when we
+ // switch from the specialization referring to the template declaration
+ // to it referring to the template definition.
+ if (auto *MSInfo = RD->getMemberSpecializationInfo()) {
+ Record.push_back(MSInfo->getTemplateSpecializationKind());
+ AddSourceLocation(MSInfo->getPointOfInstantiation(), Record);
+ } else {
+ auto *Spec = cast<ClassTemplateSpecializationDecl>(RD);
+ Record.push_back(Spec->getTemplateSpecializationKind());
+ AddSourceLocation(Spec->getPointOfInstantiation(), Record);
+
+ // The instantiation might have been resolved to a partial
+ // specialization. If so, record which one.
+ auto From = Spec->getInstantiatedFrom();
+ if (auto PartialSpec =
+ From.dyn_cast<ClassTemplatePartialSpecializationDecl*>()) {
+ Record.push_back(true);
+ AddDeclRef(PartialSpec, Record);
+ AddTemplateArgumentList(&Spec->getTemplateInstantiationArgs(),
+ Record);
+ } else {
+ Record.push_back(false);
+ }
+ }
+ Record.push_back(RD->getTagKind());
+ AddSourceLocation(RD->getLocation(), Record);
+ AddSourceLocation(RD->getLocStart(), Record);
+ AddSourceLocation(RD->getRBraceLoc(), Record);
+
+ // Instantiation may change attributes; write them all out afresh.
+ Record.push_back(D->hasAttrs());
+ if (Record.back())
+ WriteAttributes(llvm::makeArrayRef(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
+
+ // FIXME: Ensure we don't get here for explicit instantiations.
+ break;
+ }
+
+ case UPD_CXX_RESOLVED_DTOR_DELETE:
+ AddDeclRef(Update.getDecl(), Record);
+ break;
+
+ case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
+ addExceptionSpec(
+ *this,
+ cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(),
+ Record);
+ break;
+
+ case UPD_CXX_DEDUCED_RETURN_TYPE:
+ Record.push_back(GetOrCreateTypeID(Update.getType()));
+ break;
+
+ case UPD_DECL_MARKED_USED:
+ break;
+
+ case UPD_MANGLING_NUMBER:
+ case UPD_STATIC_LOCAL_NUMBER:
+ Record.push_back(Update.getNumber());
+ break;
+
+ case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
+ AddSourceRange(D->getAttr<OMPThreadPrivateDeclAttr>()->getRange(),
+ Record);
+ break;
+
+ case UPD_DECL_EXPORTED:
+ Record.push_back(getSubmoduleID(Update.getModule()));
+ break;
+ }
+ }
+
+ if (HasUpdatedBody) {
+ const FunctionDecl *Def = cast<FunctionDecl>(D);
+ Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
+ Record.push_back(Def->isInlined());
+ AddSourceLocation(Def->getInnerLocStart(), Record);
+ AddFunctionDefinition(Def, Record);
+ }
+
+ OffsetsRecord.push_back(GetDeclRef(D));
+ OffsetsRecord.push_back(Stream.GetCurrentBitNo());
+
+ Stream.EmitRecord(DECL_UPDATES, Record);
+
+ FlushPendingAfterDecl();
+ }
+}
+
+void ASTWriter::WriteDeclReplacementsBlock() {
+ if (ReplacedDecls.empty())
+ return;
+
+ RecordData Record;
+ for (SmallVectorImpl<ReplacedDeclInfo>::iterator
+ I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
+ Record.push_back(I->ID);
+ Record.push_back(I->Offset);
+ Record.push_back(I->Loc);
+ }
+ Stream.EmitRecord(DECL_REPLACEMENTS, Record);
+}
+
+void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) {
+ Record.push_back(Loc.getRawEncoding());
+}
+
+void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) {
+ AddSourceLocation(Range.getBegin(), Record);
+ AddSourceLocation(Range.getEnd(), Record);
+}
+
+void ASTWriter::AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record) {
+ Record.push_back(Value.getBitWidth());
+ const uint64_t *Words = Value.getRawData();
+ Record.append(Words, Words + Value.getNumWords());
+}
+
+void ASTWriter::AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record) {
+ Record.push_back(Value.isUnsigned());
+ AddAPInt(Value, Record);
+}
+
+void ASTWriter::AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record) {
+ AddAPInt(Value.bitcastToAPInt(), Record);
+}
+
+void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) {
+ Record.push_back(getIdentifierRef(II));
+}
+
+IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
+ if (!II)
+ return 0;
+
+ IdentID &ID = IdentifierIDs[II];
+ if (ID == 0)
+ ID = NextIdentID++;
+ return ID;
+}
+
+MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) {
+ // Don't emit builtin macros like __LINE__ to the AST file unless they
+ // have been redefined by the header (in which case they are not
+ // isBuiltinMacro).
+ if (!MI || MI->isBuiltinMacro())
+ return 0;
+
+ MacroID &ID = MacroIDs[MI];
+ if (ID == 0) {
+ ID = NextMacroID++;
+ MacroInfoToEmitData Info = { Name, MI, ID };
+ MacroInfosToEmit.push_back(Info);
+ }
+ return ID;
+}
+
+MacroID ASTWriter::getMacroID(MacroInfo *MI) {
+ if (!MI || MI->isBuiltinMacro())
+ return 0;
+
+ assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!");
+ return MacroIDs[MI];
+}
+
+uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) {
+ return IdentMacroDirectivesOffsetMap.lookup(Name);
+}
+
+void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
+ Record.push_back(getSelectorRef(SelRef));
+}
+
+SelectorID ASTWriter::getSelectorRef(Selector Sel) {
+ if (Sel.getAsOpaquePtr() == nullptr) {
+ return 0;
+ }
+
+ SelectorID SID = SelectorIDs[Sel];
+ if (SID == 0 && Chain) {
+ // This might trigger a ReadSelector callback, which will set the ID for
+ // this selector.
+ Chain->LoadSelector(Sel);
+ SID = SelectorIDs[Sel];
+ }
+ if (SID == 0) {
+ SID = NextSelectorID++;
+ SelectorIDs[Sel] = SID;
+ }
+ return SID;
+}
+
+void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record) {
+ AddDeclRef(Temp->getDestructor(), Record);
+}
+
+void ASTWriter::AddCXXCtorInitializersRef(ArrayRef<CXXCtorInitializer *> Inits,
+ RecordDataImpl &Record) {
+ assert(!Inits.empty() && "Empty ctor initializer sets are not recorded");
+ CXXCtorInitializersToWrite.push_back(
+ QueuedCXXCtorInitializers(NextCXXCtorInitializersID, Inits));
+ Record.push_back(NextCXXCtorInitializersID++);
+}
+
+void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases,
+ CXXBaseSpecifier const *BasesEnd,
+ RecordDataImpl &Record) {
+ assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded");
+ CXXBaseSpecifiersToWrite.push_back(
+ QueuedCXXBaseSpecifiers(NextCXXBaseSpecifiersID,
+ Bases, BasesEnd));
+ Record.push_back(NextCXXBaseSpecifiersID++);
+}
+
+void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
+ const TemplateArgumentLocInfo &Arg,
+ RecordDataImpl &Record) {
+ switch (Kind) {
+ case TemplateArgument::Expression:
+ AddStmt(Arg.getAsExpr());
+ break;
+ case TemplateArgument::Type:
+ AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record);
+ break;
+ case TemplateArgument::Template:
+ AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
+ AddSourceLocation(Arg.getTemplateNameLoc(), Record);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
+ AddSourceLocation(Arg.getTemplateNameLoc(), Record);
+ AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record);
+ break;
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Pack:
+ // FIXME: Is this right?
+ break;
+ }
+}
+
+void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
+ RecordDataImpl &Record) {
+ AddTemplateArgument(Arg.getArgument(), Record);
+
+ if (Arg.getArgument().getKind() == TemplateArgument::Expression) {
+ bool InfoHasSameExpr
+ = Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr();
+ Record.push_back(InfoHasSameExpr);
+ if (InfoHasSameExpr)
+ return; // Avoid storing the same expr twice.
+ }
+ AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(),
+ Record);
+}
+
+void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo,
+ RecordDataImpl &Record) {
+ if (!TInfo) {
+ AddTypeRef(QualType(), Record);
+ return;
+ }
+
+ AddTypeLoc(TInfo->getTypeLoc(), Record);
+}
+
+void ASTWriter::AddTypeLoc(TypeLoc TL, RecordDataImpl &Record) {
+ AddTypeRef(TL.getType(), Record);
+
+ TypeLocWriter TLW(*this, Record);
+ for (; !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLW.Visit(TL);
+}
+
+void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) {
+ Record.push_back(GetOrCreateTypeID(T));
+}
+
+TypeID ASTWriter::GetOrCreateTypeID(QualType T) {
+ assert(Context);
+ return MakeTypeID(*Context, T, [&](QualType T) -> TypeIdx {
+ if (T.isNull())
+ return TypeIdx();
+ assert(!T.getLocalFastQualifiers());
+
+ TypeIdx &Idx = TypeIdxs[T];
+ if (Idx.getIndex() == 0) {
+ if (DoneWritingDeclsAndTypes) {
+ assert(0 && "New type seen after serializing all the types to emit!");
+ return TypeIdx();
+ }
+
+ // We haven't seen this type before. Assign it a new ID and put it
+ // into the queue of types to emit.
+ Idx = TypeIdx(NextTypeID++);
+ DeclTypesToEmit.push(T);
+ }
+ return Idx;
+ });
+}
+
+TypeID ASTWriter::getTypeID(QualType T) const {
+ assert(Context);
+ return MakeTypeID(*Context, T, [&](QualType T) -> TypeIdx {
+ if (T.isNull())
+ return TypeIdx();
+ assert(!T.getLocalFastQualifiers());
+
+ TypeIdxMap::const_iterator I = TypeIdxs.find(T);
+ assert(I != TypeIdxs.end() && "Type not emitted!");
+ return I->second;
+ });
+}
+
+void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
+ Record.push_back(GetDeclRef(D));
+}
+
+DeclID ASTWriter::GetDeclRef(const Decl *D) {
+ assert(WritingAST && "Cannot request a declaration ID before AST writing");
+
+ if (!D) {
+ return 0;
+ }
+
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
+ assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
+ DeclID &ID = DeclIDs[D];
+ if (ID == 0) {
+ if (DoneWritingDeclsAndTypes) {
+ assert(0 && "New decl seen after serializing all the decls to emit!");
+ return 0;
+ }
+
+ // We haven't seen this declaration before. Give it a new ID and
+ // enqueue it in the list of declarations to emit.
+ ID = NextDeclID++;
+ DeclTypesToEmit.push(const_cast<Decl *>(D));
+ }
+
+ return ID;
+}
+
+DeclID ASTWriter::getDeclID(const Decl *D) {
+ if (!D)
+ return 0;
+
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
+ assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
+ return DeclIDs[D];
+}
+
+void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
+ assert(ID);
+ assert(D);
+
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isInvalid())
+ return;
+
+ // We only keep track of the file-level declarations of each file.
+ if (!D->getLexicalDeclContext()->isFileContext())
+ return;
+ // FIXME: ParmVarDecls that are part of a function type of a parameter of
+ // a function/objc method, should not have TU as lexical context.
+ if (isa<ParmVarDecl>(D))
+ return;
+
+ SourceManager &SM = Context->getSourceManager();
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ assert(SM.isLocalSourceLocation(FileLoc));
+ FileID FID;
+ unsigned Offset;
+ std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
+ if (FID.isInvalid())
+ return;
+ assert(SM.getSLocEntry(FID).isFile());
+
+ DeclIDInFileInfo *&Info = FileDeclIDs[FID];
+ if (!Info)
+ Info = new DeclIDInFileInfo();
+
+ std::pair<unsigned, serialization::DeclID> LocDecl(Offset, ID);
+ LocDeclIDsTy &Decls = Info->DeclIDs;
+
+ if (Decls.empty() || Decls.back().first <= Offset) {
+ Decls.push_back(LocDecl);
+ return;
+ }
+
+ LocDeclIDsTy::iterator I =
+ std::upper_bound(Decls.begin(), Decls.end(), LocDecl, llvm::less_first());
+
+ Decls.insert(I, LocDecl);
+}
+
+void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) {
+ // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
+ Record.push_back(Name.getNameKind());
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ AddIdentifierRef(Name.getAsIdentifierInfo(), Record);
+ break;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ AddSelectorRef(Name.getObjCSelector(), Record);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ AddTypeRef(Name.getCXXNameType(), Record);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ Record.push_back(Name.getCXXOverloadedOperator());
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record);
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ // No extra data to emit
+ break;
+ }
+}
+
+unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) {
+ assert(needsAnonymousDeclarationNumber(D) &&
+ "expected an anonymous declaration");
+
+ // Number the anonymous declarations within this context, if we've not
+ // already done so.
+ auto It = AnonymousDeclarationNumbers.find(D);
+ if (It == AnonymousDeclarationNumbers.end()) {
+ auto *DC = D->getLexicalDeclContext();
+ numberAnonymousDeclsWithin(DC, [&](const NamedDecl *ND, unsigned Number) {
+ AnonymousDeclarationNumbers[ND] = Number;
+ });
+
+ It = AnonymousDeclarationNumbers.find(D);
+ assert(It != AnonymousDeclarationNumbers.end() &&
+ "declaration not found within its lexical context");
+ }
+
+ return It->second;
+}
+
+void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
+ DeclarationName Name, RecordDataImpl &Record) {
+ switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ AddTypeSourceInfo(DNLoc.NamedType.TInfo, Record);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ AddSourceLocation(
+ SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.BeginOpNameLoc),
+ Record);
+ AddSourceLocation(
+ SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.EndOpNameLoc),
+ Record);
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ AddSourceLocation(
+ SourceLocation::getFromRawEncoding(DNLoc.CXXLiteralOperatorName.OpNameLoc),
+ Record);
+ break;
+
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+}
+
+void ASTWriter::AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
+ RecordDataImpl &Record) {
+ AddDeclarationName(NameInfo.getName(), Record);
+ AddSourceLocation(NameInfo.getLoc(), Record);
+ AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName(), Record);
+}
+
+void ASTWriter::AddQualifierInfo(const QualifierInfo &Info,
+ RecordDataImpl &Record) {
+ AddNestedNameSpecifierLoc(Info.QualifierLoc, Record);
+ Record.push_back(Info.NumTemplParamLists);
+ for (unsigned i=0, e=Info.NumTemplParamLists; i != e; ++i)
+ AddTemplateParameterList(Info.TemplParamLists[i], Record);
+}
+
+void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
+ RecordDataImpl &Record) {
+ // Nested name specifiers usually aren't too long. I think that 8 would
+ // typically accommodate the vast majority.
+ SmallVector<NestedNameSpecifier *, 8> NestedNames;
+
+ // Push each of the NNS's onto a stack for serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS->getPrefix();
+ }
+
+ Record.push_back(NestedNames.size());
+ while(!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier::SpecifierKind Kind = NNS->getKind();
+ Record.push_back(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierRef(NNS->getAsIdentifier(), Record);
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ AddDeclRef(NNS->getAsNamespace(), Record);
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDeclRef(NNS->getAsNamespaceAlias(), Record);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ AddTypeRef(QualType(NNS->getAsType(), 0), Record);
+ Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
+ break;
+
+ case NestedNameSpecifier::Global:
+ // Don't need to write an associated value.
+ break;
+
+ case NestedNameSpecifier::Super:
+ AddDeclRef(NNS->getAsRecordDecl(), Record);
+ break;
+ }
+ }
+}
+
+void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ RecordDataImpl &Record) {
+ // Nested name specifiers usually aren't too long. I think that 8 would
+ // typically accommodate the vast majority.
+ SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
+
+ // Push each of the nested-name-specifiers's onto a stack for
+ // serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS.getPrefix();
+ }
+
+ Record.push_back(NestedNames.size());
+ while(!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier::SpecifierKind Kind
+ = NNS.getNestedNameSpecifier()->getKind();
+ Record.push_back(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
+ AddTypeLoc(NNS.getTypeLoc(), Record);
+ AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
+ break;
+
+ case NestedNameSpecifier::Global:
+ AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
+ break;
+
+ case NestedNameSpecifier::Super:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+ }
+ }
+}
+
+void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) {
+ TemplateName::NameKind Kind = Name.getKind();
+ Record.push_back(Kind);
+ switch (Kind) {
+ case TemplateName::Template:
+ AddDeclRef(Name.getAsTemplateDecl(), Record);
+ break;
+
+ case TemplateName::OverloadedTemplate: {
+ OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();
+ Record.push_back(OvT->size());
+ for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end();
+ I != E; ++I)
+ AddDeclRef(*I, Record);
+ break;
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName();
+ AddNestedNameSpecifier(QualT->getQualifier(), Record);
+ Record.push_back(QualT->hasTemplateKeyword());
+ AddDeclRef(QualT->getTemplateDecl(), Record);
+ break;
+ }
+
+ case TemplateName::DependentTemplate: {
+ DependentTemplateName *DepT = Name.getAsDependentTemplateName();
+ AddNestedNameSpecifier(DepT->getQualifier(), Record);
+ Record.push_back(DepT->isIdentifier());
+ if (DepT->isIdentifier())
+ AddIdentifierRef(DepT->getIdentifier(), Record);
+ else
+ Record.push_back(DepT->getOperator());
+ break;
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *subst
+ = Name.getAsSubstTemplateTemplateParm();
+ AddDeclRef(subst->getParameter(), Record);
+ AddTemplateName(subst->getReplacement(), Record);
+ break;
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage *SubstPack
+ = Name.getAsSubstTemplateTemplateParmPack();
+ AddDeclRef(SubstPack->getParameterPack(), Record);
+ AddTemplateArgument(SubstPack->getArgumentPack(), Record);
+ break;
+ }
+ }
+}
+
+void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
+ RecordDataImpl &Record) {
+ Record.push_back(Arg.getKind());
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+ case TemplateArgument::Type:
+ AddTypeRef(Arg.getAsType(), Record);
+ break;
+ case TemplateArgument::Declaration:
+ AddDeclRef(Arg.getAsDecl(), Record);
+ AddTypeRef(Arg.getParamTypeForDecl(), Record);
+ break;
+ case TemplateArgument::NullPtr:
+ AddTypeRef(Arg.getNullPtrType(), Record);
+ break;
+ case TemplateArgument::Integral:
+ AddAPSInt(Arg.getAsIntegral(), Record);
+ AddTypeRef(Arg.getIntegralType(), Record);
+ break;
+ case TemplateArgument::Template:
+ AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+ if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+ Record.push_back(*NumExpansions + 1);
+ else
+ Record.push_back(0);
+ break;
+ case TemplateArgument::Expression:
+ AddStmt(Arg.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ Record.push_back(Arg.pack_size());
+ for (const auto &P : Arg.pack_elements())
+ AddTemplateArgument(P, Record);
+ break;
+ }
+}
+
+void
+ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams,
+ RecordDataImpl &Record) {
+ assert(TemplateParams && "No TemplateParams!");
+ AddSourceLocation(TemplateParams->getTemplateLoc(), Record);
+ AddSourceLocation(TemplateParams->getLAngleLoc(), Record);
+ AddSourceLocation(TemplateParams->getRAngleLoc(), Record);
+ Record.push_back(TemplateParams->size());
+ for (TemplateParameterList::const_iterator
+ P = TemplateParams->begin(), PEnd = TemplateParams->end();
+ P != PEnd; ++P)
+ AddDeclRef(*P, Record);
+}
+
+/// \brief Emit a template argument list.
+void
+ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
+ RecordDataImpl &Record) {
+ assert(TemplateArgs && "No TemplateArgs!");
+ Record.push_back(TemplateArgs->size());
+ for (int i=0, e = TemplateArgs->size(); i != e; ++i)
+ AddTemplateArgument(TemplateArgs->get(i), Record);
+}
+
+void
+ASTWriter::AddASTTemplateArgumentListInfo
+(const ASTTemplateArgumentListInfo *ASTTemplArgList, RecordDataImpl &Record) {
+ assert(ASTTemplArgList && "No ASTTemplArgList!");
+ AddSourceLocation(ASTTemplArgList->LAngleLoc, Record);
+ AddSourceLocation(ASTTemplArgList->RAngleLoc, Record);
+ Record.push_back(ASTTemplArgList->NumTemplateArgs);
+ const TemplateArgumentLoc *TemplArgs = ASTTemplArgList->getTemplateArgs();
+ for (int i=0, e = ASTTemplArgList->NumTemplateArgs; i != e; ++i)
+ AddTemplateArgumentLoc(TemplArgs[i], Record);
+}
+
+void
+ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) {
+ Record.push_back(Set.size());
+ for (ASTUnresolvedSet::const_iterator
+ I = Set.begin(), E = Set.end(); I != E; ++I) {
+ AddDeclRef(I.getDecl(), Record);
+ Record.push_back(I.getAccess());
+ }
+}
+
+void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
+ RecordDataImpl &Record) {
+ Record.push_back(Base.isVirtual());
+ Record.push_back(Base.isBaseOfClass());
+ Record.push_back(Base.getAccessSpecifierAsWritten());
+ Record.push_back(Base.getInheritConstructors());
+ AddTypeSourceInfo(Base.getTypeSourceInfo(), Record);
+ AddSourceRange(Base.getSourceRange(), Record);
+ AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc()
+ : SourceLocation(),
+ Record);
+}
+
+void ASTWriter::FlushCXXBaseSpecifiers() {
+ RecordData Record;
+ unsigned N = CXXBaseSpecifiersToWrite.size();
+ for (unsigned I = 0; I != N; ++I) {
+ Record.clear();
+
+ // Record the offset of this base-specifier set.
+ unsigned Index = CXXBaseSpecifiersToWrite[I].ID - 1;
+ if (Index == CXXBaseSpecifiersOffsets.size())
+ CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > CXXBaseSpecifiersOffsets.size())
+ CXXBaseSpecifiersOffsets.resize(Index + 1);
+ CXXBaseSpecifiersOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ const CXXBaseSpecifier *B = CXXBaseSpecifiersToWrite[I].Bases,
+ *BEnd = CXXBaseSpecifiersToWrite[I].BasesEnd;
+ Record.push_back(BEnd - B);
+ for (; B != BEnd; ++B)
+ AddCXXBaseSpecifier(*B, Record);
+ Stream.EmitRecord(serialization::DECL_CXX_BASE_SPECIFIERS, Record);
+
+ // Flush any expressions that were written as part of the base specifiers.
+ FlushStmts();
+ }
+
+ assert(N == CXXBaseSpecifiersToWrite.size() &&
+ "added more base specifiers while writing base specifiers");
+ CXXBaseSpecifiersToWrite.clear();
+}
+
+void ASTWriter::AddCXXCtorInitializers(
+ const CXXCtorInitializer * const *CtorInitializers,
+ unsigned NumCtorInitializers,
+ RecordDataImpl &Record) {
+ Record.push_back(NumCtorInitializers);
+ for (unsigned i=0; i != NumCtorInitializers; ++i) {
+ const CXXCtorInitializer *Init = CtorInitializers[i];
+
+ if (Init->isBaseInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_BASE);
+ AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
+ Record.push_back(Init->isBaseVirtual());
+ } else if (Init->isDelegatingInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_DELEGATING);
+ AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
+ } else if (Init->isMemberInitializer()){
+ Record.push_back(CTOR_INITIALIZER_MEMBER);
+ AddDeclRef(Init->getMember(), Record);
+ } else {
+ Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER);
+ AddDeclRef(Init->getIndirectMember(), Record);
+ }
+
+ AddSourceLocation(Init->getMemberLocation(), Record);
+ AddStmt(Init->getInit());
+ AddSourceLocation(Init->getLParenLoc(), Record);
+ AddSourceLocation(Init->getRParenLoc(), Record);
+ Record.push_back(Init->isWritten());
+ if (Init->isWritten()) {
+ Record.push_back(Init->getSourceOrder());
+ } else {
+ Record.push_back(Init->getNumArrayIndices());
+ for (unsigned i=0, e=Init->getNumArrayIndices(); i != e; ++i)
+ AddDeclRef(Init->getArrayIndex(i), Record);
+ }
+ }
+}
+
+void ASTWriter::FlushCXXCtorInitializers() {
+ RecordData Record;
+
+ unsigned N = CXXCtorInitializersToWrite.size();
+ (void)N; // Silence unused warning in non-assert builds.
+ for (auto &Init : CXXCtorInitializersToWrite) {
+ Record.clear();
+
+ // Record the offset of this mem-initializer list.
+ unsigned Index = Init.ID - 1;
+ if (Index == CXXCtorInitializersOffsets.size())
+ CXXCtorInitializersOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > CXXCtorInitializersOffsets.size())
+ CXXCtorInitializersOffsets.resize(Index + 1);
+ CXXCtorInitializersOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ AddCXXCtorInitializers(Init.Inits.data(), Init.Inits.size(), Record);
+ Stream.EmitRecord(serialization::DECL_CXX_CTOR_INITIALIZERS, Record);
+
+ // Flush any expressions that were written as part of the initializers.
+ FlushStmts();
+ }
+
+ assert(N == CXXCtorInitializersToWrite.size() &&
+ "added more ctor initializers while writing ctor initializers");
+ CXXCtorInitializersToWrite.clear();
+}
+
+void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
+ auto &Data = D->data();
+ Record.push_back(Data.IsLambda);
+ Record.push_back(Data.UserDeclaredConstructor);
+ Record.push_back(Data.UserDeclaredSpecialMembers);
+ Record.push_back(Data.Aggregate);
+ Record.push_back(Data.PlainOldData);
+ Record.push_back(Data.Empty);
+ Record.push_back(Data.Polymorphic);
+ Record.push_back(Data.Abstract);
+ Record.push_back(Data.IsStandardLayout);
+ Record.push_back(Data.HasNoNonEmptyBases);
+ Record.push_back(Data.HasPrivateFields);
+ Record.push_back(Data.HasProtectedFields);
+ Record.push_back(Data.HasPublicFields);
+ Record.push_back(Data.HasMutableFields);
+ Record.push_back(Data.HasVariantMembers);
+ Record.push_back(Data.HasOnlyCMembers);
+ Record.push_back(Data.HasInClassInitializer);
+ Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
+ Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
+ Record.push_back(Data.NeedOverloadResolutionForDestructor);
+ Record.push_back(Data.DefaultedMoveConstructorIsDeleted);
+ Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
+ Record.push_back(Data.DefaultedDestructorIsDeleted);
+ Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.DeclaredNonTrivialSpecialMembers);
+ Record.push_back(Data.HasIrrelevantDestructor);
+ Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
+ Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
+ Record.push_back(Data.HasConstexprDefaultConstructor);
+ Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
+ Record.push_back(Data.ComputedVisibleConversions);
+ Record.push_back(Data.UserProvidedDefaultConstructor);
+ Record.push_back(Data.DeclaredSpecialMembers);
+ Record.push_back(Data.ImplicitCopyConstructorHasConstParam);
+ Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
+ Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
+ Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+ // IsLambda bit is already saved.
+
+ Record.push_back(Data.NumBases);
+ if (Data.NumBases > 0)
+ AddCXXBaseSpecifiersRef(Data.getBases(), Data.getBases() + Data.NumBases,
+ Record);
+
+ // FIXME: Make VBases lazily computed when needed to avoid storing them.
+ Record.push_back(Data.NumVBases);
+ if (Data.NumVBases > 0)
+ AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases,
+ Record);
+
+ AddUnresolvedSet(Data.Conversions.get(*Context), Record);
+ AddUnresolvedSet(Data.VisibleConversions.get(*Context), Record);
+ // Data.Definition is the owning decl, no need to write it.
+ AddDeclRef(D->getFirstFriend(), Record);
+
+ // Add lambda-specific data.
+ if (Data.IsLambda) {
+ auto &Lambda = D->getLambdaData();
+ Record.push_back(Lambda.Dependent);
+ Record.push_back(Lambda.IsGenericLambda);
+ Record.push_back(Lambda.CaptureDefault);
+ Record.push_back(Lambda.NumCaptures);
+ Record.push_back(Lambda.NumExplicitCaptures);
+ Record.push_back(Lambda.ManglingNumber);
+ AddDeclRef(Lambda.ContextDecl, Record);
+ AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
+ for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
+ const LambdaCapture &Capture = Lambda.Captures[I];
+ AddSourceLocation(Capture.getLocation(), Record);
+ Record.push_back(Capture.isImplicit());
+ Record.push_back(Capture.getCaptureKind());
+ switch (Capture.getCaptureKind()) {
+ case LCK_This:
+ case LCK_VLAType:
+ break;
+ case LCK_ByCopy:
+ case LCK_ByRef:
+ VarDecl *Var =
+ Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr;
+ AddDeclRef(Var, Record);
+ AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
+ : SourceLocation(),
+ Record);
+ break;
+ }
+ }
+ }
+}
+
+void ASTWriter::ReaderInitialized(ASTReader *Reader) {
+ assert(Reader && "Cannot remove chain");
+ assert((!Chain || Chain == Reader) && "Cannot replace chain");
+ assert(FirstDeclID == NextDeclID &&
+ FirstTypeID == NextTypeID &&
+ FirstIdentID == NextIdentID &&
+ FirstMacroID == NextMacroID &&
+ FirstSubmoduleID == NextSubmoduleID &&
+ FirstSelectorID == NextSelectorID &&
+ "Setting chain after writing has started.");
+
+ Chain = Reader;
+
+ // Note, this will get called multiple times, once one the reader starts up
+ // and again each time it's done reading a PCH or module.
+ FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
+ FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
+ FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
+ FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros();
+ FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
+ FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
+ NextDeclID = FirstDeclID;
+ NextTypeID = FirstTypeID;
+ NextIdentID = FirstIdentID;
+ NextMacroID = FirstMacroID;
+ NextSelectorID = FirstSelectorID;
+ NextSubmoduleID = FirstSubmoduleID;
+}
+
+void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ IdentID &StoredID = IdentifierIDs[II];
+ if (ID > StoredID)
+ StoredID = ID;
+}
+
+void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ MacroID &StoredID = MacroIDs[MI];
+ if (ID > StoredID)
+ StoredID = ID;
+}
+
+void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
+ // Always take the highest-numbered type index. This copes with an interesting
+ // case for chained AST writing where we schedule writing the type and then,
+ // later, deserialize the type from another AST. In this case, we want to
+ // keep the higher-numbered entry so that we can properly write it out to
+ // the AST file.
+ TypeIdx &StoredIdx = TypeIdxs[T];
+ if (Idx.getIndex() >= StoredIdx.getIndex())
+ StoredIdx = Idx;
+}
+
+void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ SelectorID &StoredID = SelectorIDs[S];
+ if (ID > StoredID)
+ StoredID = ID;
+}
+
+void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
+ MacroDefinitionRecord *MD) {
+ assert(MacroDefinitions.find(MD) == MacroDefinitions.end());
+ MacroDefinitions[MD] = ID;
+}
+
+void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
+ assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
+ SubmoduleIDs[Mod] = ID;
+}
+
+void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
+ assert(D->isCompleteDefinition());
+ assert(!WritingAST && "Already writing the AST!");
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ // We are interested when a PCH decl is modified.
+ if (RD->isFromASTFile()) {
+ // A forward reference was mutated into a definition. Rewrite it.
+ // FIXME: This happens during template instantiation, should we
+ // have created a new definition decl instead ?
+ assert(isTemplateInstantiation(RD->getTemplateSpecializationKind()) &&
+ "completed a tag from another module but not by instantiation?");
+ DeclUpdates[RD].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_CLASS_DEFINITION));
+ }
+ }
+}
+
+void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
+ // TU and namespaces are handled elsewhere.
+ if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))
+ return;
+
+ if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
+ return; // Not a source decl added to a DeclContext from PCH.
+
+ assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
+ assert(!WritingAST && "Already writing the AST!");
+ UpdatedDeclContexts.insert(DC);
+ UpdatingVisibleDecls.push_back(D);
+}
+
+void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
+ assert(D->isImplicit());
+ if (!(!D->isFromASTFile() && RD->isFromASTFile()))
+ return; // Not a source member added to a class from PCH.
+ if (!isa<CXXMethodDecl>(D))
+ return; // We are interested in lazily declared implicit methods.
+
+ // A decl coming from PCH was modified.
+ assert(RD->isCompleteDefinition());
+ assert(!WritingAST && "Already writing the AST!");
+ DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D));
+}
+
+void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
+ const ClassTemplateSpecializationDecl *D) {
+ // The specializations set is kept in the canonical template.
+ TD = TD->getCanonicalDecl();
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
+ return; // Not a source specialization added to a template from PCH.
+
+ assert(!WritingAST && "Already writing the AST!");
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
+}
+
+void ASTWriter::AddedCXXTemplateSpecialization(
+ const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) {
+ // The specializations set is kept in the canonical template.
+ TD = TD->getCanonicalDecl();
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
+ return; // Not a source specialization added to a template from PCH.
+
+ assert(!WritingAST && "Already writing the AST!");
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
+}
+
+void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D) {
+ // The specializations set is kept in the canonical template.
+ TD = TD->getCanonicalDecl();
+ if (!(!D->isFromASTFile() && TD->isFromASTFile()))
+ return; // Not a source specialization added to a template from PCH.
+
+ assert(!WritingAST && "Already writing the AST!");
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
+}
+
+void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
+ assert(!DoneWritingDeclsAndTypes && "Already done writing updates!");
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+ // If we don't already know the exception specification for this redecl
+ // chain, add an update record for it.
+ if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D)
+ ->getType()
+ ->castAs<FunctionProtoType>()
+ ->getExceptionSpecType()))
+ DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
+ });
+}
+
+void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
+ });
+}
+
+void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) {
+ assert(!WritingAST && "Already writing the AST!");
+ assert(Delete && "Not given an operator delete");
+ if (!Chain) return;
+ Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) {
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
+ });
+}
+
+void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return; // Declaration not imported from PCH.
+
+ // Implicit function decl from a PCH was defined.
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
+}
+
+void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
+}
+
+void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ // Since the actual instantiation is delayed, this really means that we need
+ // to update the instantiation location.
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+ D->getMemberSpecializationInfo()->getPointOfInstantiation()));
+}
+
+void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!IFD->isFromASTFile())
+ return; // Declaration not imported from PCH.
+
+ assert(IFD->getDefinition() && "Category on a class without a definition?");
+ ObjCClassesWithCategories.insert(
+ const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));
+}
+
+
+void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt) {
+ const ObjCInterfaceDecl *D = ClassExt->getClassInterface();
+ if (!D)
+ return;
+
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return; // Declaration not imported from PCH.
+
+ RewriteDecl(D);
+}
+
+void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED));
+}
+
+void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
+}
+
+void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
+ assert(!WritingAST && "Already writing the AST!");
+ assert(D->isHidden() && "expected a hidden declaration");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M));
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
new file mode 100644
index 0000000..0fa4f93
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -0,0 +1,2100 @@
+//===--- ASTWriterDecl.cpp - Declaration Serialization --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements serialization for Declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTWriter.h"
+#include "ASTCommon.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+using namespace serialization;
+
+//===----------------------------------------------------------------------===//
+// Declaration serialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class ASTDeclWriter : public DeclVisitor<ASTDeclWriter, void> {
+
+ ASTWriter &Writer;
+ ASTContext &Context;
+ typedef ASTWriter::RecordData RecordData;
+ RecordData &Record;
+
+ public:
+ serialization::DeclCode Code;
+ unsigned AbbrevToUse;
+
+ ASTDeclWriter(ASTWriter &Writer, ASTContext &Context, RecordData &Record)
+ : Writer(Writer), Context(Context), Record(Record) {
+ }
+
+ void Visit(Decl *D);
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitLabelDecl(LabelDecl *LD);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefNameDecl(TypedefNameDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTypeAliasDecl(TypeAliasDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitEnumDecl(EnumDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ void VisitValueDecl(ValueDecl *D);
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ void VisitDeclaratorDecl(DeclaratorDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitMSPropertyDecl(MSPropertyDecl *D);
+ void VisitIndirectFieldDecl(IndirectFieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitImplicitParamDecl(ImplicitParamDecl *D);
+ void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitVarTemplateDecl(VarTemplateDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
+ void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitImportDecl(ImportDecl *D);
+ void VisitAccessSpecDecl(AccessSpecDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
+ void VisitBlockDecl(BlockDecl *D);
+ void VisitCapturedDecl(CapturedDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
+
+ void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset);
+ template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
+
+
+ // FIXME: Put in the same order is DeclNodes.td?
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+
+ void AddFunctionDefinition(const FunctionDecl *FD) {
+ assert(FD->doesThisDeclarationHaveABody());
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ Record.push_back(CD->NumCtorInitializers);
+ if (CD->NumCtorInitializers)
+ Writer.AddCXXCtorInitializersRef(
+ llvm::makeArrayRef(CD->init_begin(), CD->init_end()), Record);
+ }
+ Writer.AddStmt(FD->getBody());
+ }
+
+ /// Get the specialization decl from an entry in the specialization list.
+ template <typename EntryType>
+ typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
+ getSpecializationDecl(EntryType &T) {
+ return RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::getDecl(&T);
+ }
+
+ /// Get the list of partial specializations from a template's common ptr.
+ template<typename T>
+ decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
+ return Common->PartialSpecializations;
+ }
+ ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
+ return None;
+ }
+
+ template<typename Decl>
+ void AddTemplateSpecializations(Decl *D) {
+ auto *Common = D->getCommonPtr();
+
+ // If we have any lazy specializations, and the external AST source is
+ // our chained AST reader, we can just write out the DeclIDs. Otherwise,
+ // we need to resolve them to actual declarations.
+ if (Writer.Chain != Writer.Context->getExternalSource() &&
+ Common->LazySpecializations) {
+ D->LoadLazySpecializations();
+ assert(!Common->LazySpecializations);
+ }
+
+ auto &Specializations = Common->Specializations;
+ auto &&PartialSpecializations = getPartialSpecializations(Common);
+ ArrayRef<DeclID> LazySpecializations;
+ if (auto *LS = Common->LazySpecializations)
+ LazySpecializations = ArrayRef<DeclID>(LS + 1, LS + 1 + LS[0]);
+
+ Record.push_back(Specializations.size() +
+ PartialSpecializations.size() +
+ LazySpecializations.size());
+ for (auto &Entry : Specializations) {
+ auto *D = getSpecializationDecl(Entry);
+ assert(D->isCanonicalDecl() && "non-canonical decl in set");
+ Writer.AddDeclRef(D, Record);
+ }
+ for (auto &Entry : PartialSpecializations) {
+ auto *D = getSpecializationDecl(Entry);
+ assert(D->isCanonicalDecl() && "non-canonical decl in set");
+ Writer.AddDeclRef(D, Record);
+ }
+ for (DeclID ID : LazySpecializations)
+ Record.push_back(ID);
+ }
+ };
+}
+
+void ASTDeclWriter::Visit(Decl *D) {
+ DeclVisitor<ASTDeclWriter>::Visit(D);
+
+ // Source locations require array (variable-length) abbreviations. The
+ // abbreviation infrastructure requires that arrays are encoded last, so
+ // we handle it here in the case of those classes derived from DeclaratorDecl
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)){
+ Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record);
+ }
+
+ // Handle FunctionDecl's body here and write it after all other Stmts/Exprs
+ // have been written. We want it last because we will not read it back when
+ // retrieving it from the AST, we'll just lazily set the offset.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Record.push_back(FD->doesThisDeclarationHaveABody());
+ if (FD->doesThisDeclarationHaveABody())
+ AddFunctionDefinition(FD);
+ }
+}
+
+void ASTDeclWriter::VisitDecl(Decl *D) {
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+ Record.push_back(D->isInvalidDecl());
+ Record.push_back(D->hasAttrs());
+ if (D->hasAttrs())
+ Writer.WriteAttributes(llvm::makeArrayRef(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
+ Record.push_back(D->isImplicit());
+ Record.push_back(D->isUsed(false));
+ Record.push_back(D->isReferenced());
+ Record.push_back(D->isTopLevelDeclInObjCContainer());
+ Record.push_back(D->getAccess());
+ Record.push_back(D->isModulePrivate());
+ Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
+
+ // If this declaration injected a name into a context different from its
+ // lexical context, and that context is an imported namespace, we need to
+ // update its visible declarations to include this name.
+ //
+ // This happens when we instantiate a class with a friend declaration or a
+ // function with a local extern declaration, for instance.
+ if (D->isOutOfLine()) {
+ auto *DC = D->getDeclContext();
+ while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) {
+ if (!NS->isFromASTFile())
+ break;
+ Writer.UpdatedDeclContexts.insert(NS->getPrimaryContext());
+ if (!NS->isInlineNamespace())
+ break;
+ DC = NS->getParent();
+ }
+ }
+}
+
+void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ llvm_unreachable("Translation units aren't directly serialized");
+}
+
+void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclarationName(D->getDeclName(), Record);
+ Record.push_back(needsAnonymousDeclarationNumber(D)
+ ? Writer.getAnonymousDeclarationNumber(D)
+ : 0);
+}
+
+void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+}
+
+void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
+ VisitRedeclarable(D);
+ VisitTypeDecl(D);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Record.push_back(D->isModed());
+ if (D->isModed())
+ Writer.AddTypeRef(D->getUnderlyingType(), Record);
+}
+
+void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitTypedefNameDecl(D);
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
+ !D->isInvalidDecl() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ !D->isModulePrivate() &&
+ !needsAnonymousDeclarationNumber(D) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclTypedefAbbrev();
+
+ Code = serialization::DECL_TYPEDEF;
+}
+
+void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ VisitTypedefNameDecl(D);
+ Writer.AddDeclRef(D->getDescribedAliasTemplate(), Record);
+ Code = serialization::DECL_TYPEALIAS;
+}
+
+void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
+ VisitRedeclarable(D);
+ VisitTypeDecl(D);
+ Record.push_back(D->getIdentifierNamespace());
+ Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
+ if (!isa<CXXRecordDecl>(D))
+ Record.push_back(D->isCompleteDefinition());
+ Record.push_back(D->isEmbeddedInDeclarator());
+ Record.push_back(D->isFreeStanding());
+ Record.push_back(D->isCompleteDefinitionRequired());
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
+
+ if (D->hasExtInfo()) {
+ Record.push_back(1);
+ Writer.AddQualifierInfo(*D->getExtInfo(), Record);
+ } else if (auto *TD = D->getTypedefNameForAnonDecl()) {
+ Record.push_back(2);
+ Writer.AddDeclRef(TD, Record);
+ Writer.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo(), Record);
+ } else if (auto *DD = D->getDeclaratorForAnonDecl()) {
+ Record.push_back(3);
+ Writer.AddDeclRef(DD, Record);
+ } else {
+ Record.push_back(0);
+ }
+}
+
+void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
+ VisitTagDecl(D);
+ Writer.AddTypeSourceInfo(D->getIntegerTypeSourceInfo(), Record);
+ if (!D->getIntegerTypeSourceInfo())
+ Writer.AddTypeRef(D->getIntegerType(), Record);
+ Writer.AddTypeRef(D->getPromotionType(), Record);
+ Record.push_back(D->getNumPositiveBits());
+ Record.push_back(D->getNumNegativeBits());
+ Record.push_back(D->isScoped());
+ Record.push_back(D->isScopedUsingClassTag());
+ Record.push_back(D->isFixed());
+ if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
+ Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MemberInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
+ } else {
+ Writer.AddDeclRef(nullptr, Record);
+ }
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->hasExtInfo() &&
+ !D->getTypedefNameForAnonDecl() &&
+ !D->getDeclaratorForAnonDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ !D->getIntegerTypeSourceInfo() &&
+ !D->getMemberSpecializationInfo() &&
+ !needsAnonymousDeclarationNumber(D) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclEnumAbbrev();
+
+ Code = serialization::DECL_ENUM;
+}
+
+void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
+ VisitTagDecl(D);
+ Record.push_back(D->hasFlexibleArrayMember());
+ Record.push_back(D->isAnonymousStructOrUnion());
+ Record.push_back(D->hasObjectMember());
+ Record.push_back(D->hasVolatileMember());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->hasExtInfo() &&
+ !D->getTypedefNameForAnonDecl() &&
+ !D->getDeclaratorForAnonDecl() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ !needsAnonymousDeclarationNumber(D) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclRecordAbbrev();
+
+ Code = serialization::DECL_RECORD;
+}
+
+void ASTDeclWriter::VisitValueDecl(ValueDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(D->getType(), Record);
+}
+
+void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->getInitExpr()? 1 : 0);
+ if (D->getInitExpr())
+ Writer.AddStmt(D->getInitExpr());
+ Writer.AddAPSInt(D->getInitVal(), Record);
+
+ Code = serialization::DECL_ENUM_CONSTANT;
+}
+
+void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
+ VisitValueDecl(D);
+ Writer.AddSourceLocation(D->getInnerLocStart(), Record);
+ Record.push_back(D->hasExtInfo());
+ if (D->hasExtInfo())
+ Writer.AddQualifierInfo(*D->getExtInfo(), Record);
+}
+
+void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
+ VisitRedeclarable(D);
+ VisitDeclaratorDecl(D);
+ Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
+ Record.push_back(D->getIdentifierNamespace());
+
+ // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
+ // after everything else is written.
+
+ Record.push_back((int)D->SClass); // FIXME: stable encoding
+ Record.push_back(D->IsInline);
+ Record.push_back(D->IsInlineSpecified);
+ Record.push_back(D->IsVirtualAsWritten);
+ Record.push_back(D->IsPure);
+ Record.push_back(D->HasInheritedPrototype);
+ Record.push_back(D->HasWrittenPrototype);
+ Record.push_back(D->IsDeleted);
+ Record.push_back(D->IsTrivial);
+ Record.push_back(D->IsDefaulted);
+ Record.push_back(D->IsExplicitlyDefaulted);
+ Record.push_back(D->HasImplicitReturnZero);
+ Record.push_back(D->IsConstexpr);
+ Record.push_back(D->HasSkippedBody);
+ Record.push_back(D->IsLateTemplateParsed);
+ Record.push_back(D->getLinkageInternal());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+
+ Record.push_back(D->getTemplatedKind());
+ switch (D->getTemplatedKind()) {
+ case FunctionDecl::TK_NonTemplate:
+ break;
+ case FunctionDecl::TK_FunctionTemplate:
+ Writer.AddDeclRef(D->getDescribedFunctionTemplate(), Record);
+ break;
+ case FunctionDecl::TK_MemberSpecialization: {
+ MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo();
+ Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MemberInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
+ break;
+ }
+ case FunctionDecl::TK_FunctionTemplateSpecialization: {
+ FunctionTemplateSpecializationInfo *
+ FTSInfo = D->getTemplateSpecializationInfo();
+ Writer.AddDeclRef(FTSInfo->getTemplate(), Record);
+ Record.push_back(FTSInfo->getTemplateSpecializationKind());
+
+ // Template arguments.
+ Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record);
+
+ // Template args as written.
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
+ if (FTSInfo->TemplateArgumentsAsWritten) {
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs);
+ for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs;
+ i!=e; ++i)
+ Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i],
+ Record);
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc,
+ Record);
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc,
+ Record);
+ }
+
+ Writer.AddSourceLocation(FTSInfo->getPointOfInstantiation(), Record);
+
+ if (D->isCanonicalDecl()) {
+ // Write the template that contains the specializations set. We will
+ // add a FunctionTemplateSpecializationInfo to it when reading.
+ Writer.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl(), Record);
+ }
+ break;
+ }
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+ DependentFunctionTemplateSpecializationInfo *
+ DFTSInfo = D->getDependentSpecializationInfo();
+
+ // Templates.
+ Record.push_back(DFTSInfo->getNumTemplates());
+ for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i)
+ Writer.AddDeclRef(DFTSInfo->getTemplate(i), Record);
+
+ // Templates args.
+ Record.push_back(DFTSInfo->getNumTemplateArgs());
+ for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i)
+ Writer.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i), Record);
+ Writer.AddSourceLocation(DFTSInfo->getLAngleLoc(), Record);
+ Writer.AddSourceLocation(DFTSInfo->getRAngleLoc(), Record);
+ break;
+ }
+ }
+
+ Record.push_back(D->param_size());
+ for (auto P : D->params())
+ Writer.AddDeclRef(P, Record);
+ Code = serialization::DECL_FUNCTION;
+}
+
+void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ VisitNamedDecl(D);
+ // FIXME: convert to LazyStmtPtr?
+ // Unlike C/C++, method bodies will never be in header files.
+ bool HasBodyStuff = D->getBody() != nullptr ||
+ D->getSelfDecl() != nullptr || D->getCmdDecl() != nullptr;
+ Record.push_back(HasBodyStuff);
+ if (HasBodyStuff) {
+ Writer.AddStmt(D->getBody());
+ Writer.AddDeclRef(D->getSelfDecl(), Record);
+ Writer.AddDeclRef(D->getCmdDecl(), Record);
+ }
+ Record.push_back(D->isInstanceMethod());
+ Record.push_back(D->isVariadic());
+ Record.push_back(D->isPropertyAccessor());
+ Record.push_back(D->isDefined());
+ Record.push_back(D->IsOverriding);
+ Record.push_back(D->HasSkippedBody);
+
+ Record.push_back(D->IsRedeclaration);
+ Record.push_back(D->HasRedeclaration);
+ if (D->HasRedeclaration) {
+ assert(Context.getObjCMethodRedeclaration(D));
+ Writer.AddDeclRef(Context.getObjCMethodRedeclaration(D), Record);
+ }
+
+ // FIXME: stable encoding for @required/@optional
+ Record.push_back(D->getImplementationControl());
+ // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
+ Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->hasRelatedResultType());
+ Writer.AddTypeRef(D->getReturnType(), Record);
+ Writer.AddTypeSourceInfo(D->getReturnTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(D->param_size());
+ for (const auto *P : D->params())
+ Writer.AddDeclRef(P, Record);
+
+ Record.push_back(D->SelLocsKind);
+ unsigned NumStoredSelLocs = D->getNumStoredSelLocs();
+ SourceLocation *SelLocs = D->getStoredSelLocs();
+ Record.push_back(NumStoredSelLocs);
+ for (unsigned i = 0; i != NumStoredSelLocs; ++i)
+ Writer.AddSourceLocation(SelLocs[i], Record);
+
+ Code = serialization::DECL_OBJC_METHOD;
+}
+
+void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtStartLoc(), Record);
+ Writer.AddSourceRange(D->getAtEndRange(), Record);
+ // Abstract class (no need to define a stable serialization::DECL code).
+}
+
+void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ VisitRedeclarable(D);
+ VisitObjCContainerDecl(D);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
+ // Write the DefinitionData
+ ObjCInterfaceDecl::DefinitionData &Data = D->data();
+
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+ Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record);
+ Record.push_back(Data.HasDesignatedInitializers);
+
+ // Write out the protocols that are directly referenced by the @interface.
+ Record.push_back(Data.ReferencedProtocols.size());
+ for (const auto *P : D->protocols())
+ Writer.AddDeclRef(P, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
+
+ // Write out the protocols that are transitively referenced.
+ Record.push_back(Data.AllReferencedProtocols.size());
+ for (ObjCList<ObjCProtocolDecl>::iterator
+ P = Data.AllReferencedProtocols.begin(),
+ PEnd = Data.AllReferencedProtocols.end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+
+
+ if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) {
+ // Ensure that we write out the set of categories for this class.
+ Writer.ObjCClassesWithCategories.insert(D);
+
+ // Make sure that the categories get serialized.
+ for (; Cat; Cat = Cat->getNextClassCategoryRaw())
+ (void)Writer.GetDeclRef(Cat);
+ }
+ }
+
+ Code = serialization::DECL_OBJC_INTERFACE;
+}
+
+void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
+ VisitFieldDecl(D);
+ // FIXME: stable encoding for @public/@private/@protected/@package
+ Record.push_back(D->getAccessControl());
+ Record.push_back(D->getSynthesize());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ !D->isModulePrivate() &&
+ !D->getBitWidth() &&
+ !D->hasExtInfo() &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclObjCIvarAbbrev();
+
+ Code = serialization::DECL_OBJC_IVAR;
+}
+
+void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ VisitRedeclarable(D);
+ VisitObjCContainerDecl(D);
+
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
+ Record.push_back(D->protocol_size());
+ for (const auto *I : D->protocols())
+ Writer.AddDeclRef(I, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
+ }
+
+ Code = serialization::DECL_OBJC_PROTOCOL;
+}
+
+void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
+ VisitFieldDecl(D);
+ Code = serialization::DECL_OBJC_AT_DEFS_FIELD;
+}
+
+void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Record.push_back(D->protocol_size());
+ for (const auto *I : D->protocols())
+ Writer.AddDeclRef(I, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
+ Code = serialization::DECL_OBJC_CATEGORY;
+}
+
+void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Code = serialization::DECL_OBJC_COMPATIBLE_ALIAS;
+}
+
+void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtLoc(), Record);
+ Writer.AddSourceLocation(D->getLParenLoc(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyAttributes());
+ Record.push_back((unsigned)D->getPropertyAttributesAsWritten());
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyImplementation());
+ Writer.AddDeclarationName(D->getGetterName(), Record);
+ Writer.AddDeclarationName(D->getSetterName(), Record);
+ Writer.AddDeclRef(D->getGetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getSetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ Code = serialization::DECL_OBJC_PROPERTY;
+}
+
+void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ // Abstract class (no need to define a stable serialization::DECL code).
+}
+
+void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddIdentifierRef(D->getIdentifier(), Record);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
+ Code = serialization::DECL_OBJC_CATEGORY_IMPL;
+}
+
+void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
+ Record.push_back(D->hasNonZeroConstructors());
+ Record.push_back(D->hasDestructors());
+ Record.push_back(D->NumIvarInitializers);
+ if (D->NumIvarInitializers)
+ Writer.AddCXXCtorInitializersRef(
+ llvm::makeArrayRef(D->init_begin(), D->init_end()), Record);
+ Code = serialization::DECL_OBJC_IMPLEMENTATION;
+}
+
+void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddDeclRef(D->getPropertyDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ Writer.AddSourceLocation(D->getPropertyIvarDeclLoc(), Record);
+ Writer.AddStmt(D->getGetterCXXConstructor());
+ Writer.AddStmt(D->getSetterCXXAssignment());
+ Code = serialization::DECL_OBJC_PROPERTY_IMPL;
+}
+
+void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
+ VisitDeclaratorDecl(D);
+ Record.push_back(D->isMutable());
+ if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing &&
+ D->InitStorage.getPointer() == nullptr) {
+ Record.push_back(0);
+ } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
+ Record.push_back(D->InitStorage.getInt() + 1);
+ Writer.AddTypeRef(
+ QualType(static_cast<Type *>(D->InitStorage.getPointer()), 0),
+ Record);
+ } else {
+ Record.push_back(D->InitStorage.getInt() + 1);
+ Writer.AddStmt(static_cast<Expr *>(D->InitStorage.getPointer()));
+ }
+ if (!D->getDeclName())
+ Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ !D->isModulePrivate() &&
+ !D->getBitWidth() &&
+ !D->hasInClassInitializer() &&
+ !D->hasExtInfo() &&
+ !ObjCIvarDecl::classofKind(D->getKind()) &&
+ !ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclFieldAbbrev();
+
+ Code = serialization::DECL_FIELD;
+}
+
+void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) {
+ VisitDeclaratorDecl(D);
+ Writer.AddIdentifierRef(D->getGetterId(), Record);
+ Writer.AddIdentifierRef(D->getSetterId(), Record);
+ Code = serialization::DECL_MS_PROPERTY;
+}
+
+void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->getChainingSize());
+
+ for (const auto *P : D->chain())
+ Writer.AddDeclRef(P, Record);
+ Code = serialization::DECL_INDIRECTFIELD;
+}
+
+void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
+ VisitRedeclarable(D);
+ VisitDeclaratorDecl(D);
+ Record.push_back(D->getStorageClass());
+ Record.push_back(D->getTSCSpec());
+ Record.push_back(D->getInitStyle());
+ if (!isa<ParmVarDecl>(D)) {
+ Record.push_back(D->isExceptionVariable());
+ Record.push_back(D->isNRVOVariable());
+ Record.push_back(D->isCXXForRangeDecl());
+ Record.push_back(D->isARCPseudoStrong());
+ Record.push_back(D->isConstexpr());
+ Record.push_back(D->isInitCapture());
+ Record.push_back(D->isPreviousDeclInSameBlockScope());
+ }
+ Record.push_back(D->getLinkageInternal());
+
+ if (D->getInit()) {
+ Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
+ Writer.AddStmt(D->getInit());
+ } else {
+ Record.push_back(0);
+ }
+
+ enum {
+ VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
+ };
+ if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) {
+ Record.push_back(VarTemplate);
+ Writer.AddDeclRef(TemplD, Record);
+ } else if (MemberSpecializationInfo *SpecInfo
+ = D->getMemberSpecializationInfo()) {
+ Record.push_back(StaticDataMemberSpecialization);
+ Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
+ Record.push_back(SpecInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
+ } else {
+ Record.push_back(VarNotTemplate);
+ }
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
+ !needsAnonymousDeclarationNumber(D) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ !D->hasExtInfo() &&
+ D->getFirstDecl() == D->getMostRecentDecl() &&
+ D->getInitStyle() == VarDecl::CInit &&
+ D->getInit() == nullptr &&
+ !isa<ParmVarDecl>(D) &&
+ !isa<VarTemplateSpecializationDecl>(D) &&
+ !D->isConstexpr() &&
+ !D->isInitCapture() &&
+ !D->isPreviousDeclInSameBlockScope() &&
+ !D->getMemberSpecializationInfo())
+ AbbrevToUse = Writer.getDeclVarAbbrev();
+
+ Code = serialization::DECL_VAR;
+}
+
+void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
+ VisitVarDecl(D);
+ Code = serialization::DECL_IMPLICIT_PARAM;
+}
+
+void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
+ VisitVarDecl(D);
+ Record.push_back(D->isObjCMethodParameter());
+ Record.push_back(D->getFunctionScopeDepth());
+ Record.push_back(D->getFunctionScopeIndex());
+ Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
+ Record.push_back(D->isKNRPromoted());
+ Record.push_back(D->hasInheritedDefaultArg());
+ Record.push_back(D->hasUninstantiatedDefaultArg());
+ if (D->hasUninstantiatedDefaultArg())
+ Writer.AddStmt(D->getUninstantiatedDefaultArg());
+ Code = serialization::DECL_PARM_VAR;
+
+ assert(!D->isARCPseudoStrong()); // can be true of ImplicitParamDecl
+
+ // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
+ // we dynamically check for the properties that we optimize for, but don't
+ // know are true of all PARM_VAR_DECLs.
+ if (!D->hasAttrs() &&
+ !D->hasExtInfo() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
+ D->getStorageClass() == 0 &&
+ D->getInitStyle() == VarDecl::CInit && // Can params have anything else?
+ D->getFunctionScopeDepth() == 0 &&
+ D->getObjCDeclQualifier() == 0 &&
+ !D->isKNRPromoted() &&
+ !D->hasInheritedDefaultArg() &&
+ D->getInit() == nullptr &&
+ !D->hasUninstantiatedDefaultArg()) // No default expr.
+ AbbrevToUse = Writer.getDeclParmVarAbbrev();
+
+ // Check things we know are true of *every* PARM_VAR_DECL, which is more than
+ // just us assuming it.
+ assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS");
+ assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
+ assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
+ assert(D->getPreviousDecl() == nullptr && "PARM_VAR_DECL can't be redecl");
+ assert(!D->isStaticDataMember() &&
+ "PARM_VAR_DECL can't be static data member");
+}
+
+void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getAsmString());
+ Writer.AddSourceLocation(D->getRParenLoc(), Record);
+ Code = serialization::DECL_FILE_SCOPE_ASM;
+}
+
+void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+ Code = serialization::DECL_EMPTY;
+}
+
+void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getBody());
+ Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record);
+ Record.push_back(D->param_size());
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Record.push_back(D->isVariadic());
+ Record.push_back(D->blockMissingReturnType());
+ Record.push_back(D->isConversionFromLambda());
+ Record.push_back(D->capturesCXXThis());
+ Record.push_back(D->getNumCaptures());
+ for (const auto &capture : D->captures()) {
+ Writer.AddDeclRef(capture.getVariable(), Record);
+
+ unsigned flags = 0;
+ if (capture.isByRef()) flags |= 1;
+ if (capture.isNested()) flags |= 2;
+ if (capture.hasCopyExpr()) flags |= 4;
+ Record.push_back(flags);
+
+ if (capture.hasCopyExpr()) Writer.AddStmt(capture.getCopyExpr());
+ }
+
+ Code = serialization::DECL_BLOCK;
+}
+
+void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) {
+ Record.push_back(CD->getNumParams());
+ VisitDecl(CD);
+ Record.push_back(CD->getContextParamPosition());
+ Record.push_back(CD->isNothrow() ? 1 : 0);
+ // Body is stored by VisitCapturedStmt.
+ for (unsigned I = 0; I < CD->getNumParams(); ++I)
+ Writer.AddDeclRef(CD->getParam(I), Record);
+ Code = serialization::DECL_CAPTURED;
+}
+
+void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->getLanguage());
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
+ Code = serialization::DECL_LINKAGE_SPEC;
+}
+
+void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Code = serialization::DECL_LABEL;
+}
+
+
+void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ Record.push_back(D->isInline());
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
+
+ if (D->isOriginalNamespace())
+ Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
+ Code = serialization::DECL_NAMESPACE;
+
+ if (Writer.hasChain() && !D->isOriginalNamespace() &&
+ D->getOriginalNamespace()->isFromASTFile()) {
+ NamespaceDecl *NS = D->getOriginalNamespace();
+ Writer.UpdatedDeclContexts.insert(NS);
+
+ // Make sure all visible decls are written. They will be recorded later. We
+ // do this using a side data structure so we can sort the names into
+ // a deterministic order.
+ StoredDeclsMap *Map = NS->buildLookup();
+ SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16>
+ LookupResults;
+ LookupResults.reserve(Map->size());
+ for (auto &Entry : *Map)
+ LookupResults.push_back(
+ std::make_pair(Entry.first, Entry.second.getLookupResult()));
+
+ std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first());
+ for (auto &NameAndResult : LookupResults) {
+ DeclarationName Name = NameAndResult.first;
+ DeclContext::lookup_result Result = NameAndResult.second;
+ if (Name.getNameKind() == DeclarationName::CXXConstructorName ||
+ Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
+ // We have to work around a name lookup bug here where negative lookup
+ // results for these names get cached in namespace lookup tables.
+ assert(Result.empty() && "Cannot have a constructor or conversion "
+ "function name in a namespace!");
+ continue;
+ }
+
+ for (NamedDecl *ND : Result)
+ Writer.GetDeclRef(ND);
+ }
+ }
+
+ if (Writer.hasChain() && D->isAnonymousNamespace() &&
+ D == D->getMostRecentDecl()) {
+ // This is a most recent reopening of the anonymous namespace. If its parent
+ // is in a previous PCH (or is the TU), mark that parent for update, because
+ // the original namespace always points to the latest re-opening of its
+ // anonymous namespace.
+ Decl *Parent = cast<Decl>(
+ D->getParent()->getRedeclContext()->getPrimaryContext());
+ if (Parent->isFromASTFile() || isa<TranslationUnitDecl>(Parent)) {
+ Writer.DeclUpdates[Parent].push_back(
+ ASTWriter::DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, D));
+ }
+ }
+}
+
+void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getNamespaceLoc(), Record);
+ Writer.AddSourceLocation(D->getTargetNameLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
+ Writer.AddDeclRef(D->getNamespace(), Record);
+ Code = serialization::DECL_NAMESPACE_ALIAS;
+}
+
+void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
+ Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
+ Writer.AddDeclRef(D->FirstUsingShadow.getPointer(), Record);
+ Record.push_back(D->hasTypename());
+ Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record);
+ Code = serialization::DECL_USING;
+}
+
+void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ VisitRedeclarable(D);
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getTargetDecl(), Record);
+ Writer.AddDeclRef(D->UsingOrNextShadow, Record);
+ Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record);
+ Code = serialization::DECL_USING_SHADOW;
+}
+
+void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
+ Writer.AddDeclRef(D->getNominatedNamespace(), Record);
+ Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
+ Code = serialization::DECL_USING_DIRECTIVE;
+}
+
+void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
+ Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
+ Code = serialization::DECL_UNRESOLVED_USING_VALUE;
+}
+
+void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddSourceLocation(D->getTypenameLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
+ Code = serialization::DECL_UNRESOLVED_USING_TYPENAME;
+}
+
+void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ VisitRecordDecl(D);
+
+ enum {
+ CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ };
+ if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) {
+ Record.push_back(CXXRecTemplate);
+ Writer.AddDeclRef(TemplD, Record);
+ } else if (MemberSpecializationInfo *MSInfo
+ = D->getMemberSpecializationInfo()) {
+ Record.push_back(CXXRecMemberSpecialization);
+ Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MSInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record);
+ } else {
+ Record.push_back(CXXRecNotTemplate);
+ }
+
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
+ Writer.AddCXXDefinitionData(D, Record);
+
+ // Store (what we currently believe to be) the key function to avoid
+ // deserializing every method so we can compute it.
+ if (D->IsCompleteDefinition)
+ Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record);
+
+ Code = serialization::DECL_CXX_RECORD;
+}
+
+void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ VisitFunctionDecl(D);
+ if (D->isCanonicalDecl()) {
+ Record.push_back(D->size_overridden_methods());
+ for (CXXMethodDecl::method_iterator
+ I = D->begin_overridden_methods(), E = D->end_overridden_methods();
+ I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ } else {
+ // We only need to record overridden methods once for the canonical decl.
+ Record.push_back(0);
+ }
+
+ if (D->getFirstDecl() == D->getMostRecentDecl() &&
+ !D->isInvalidDecl() &&
+ !D->hasAttrs() &&
+ !D->isTopLevelDeclInObjCContainer() &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ !D->hasExtInfo() &&
+ !D->hasInheritedPrototype() &&
+ D->hasWrittenPrototype())
+ AbbrevToUse = Writer.getDeclCXXMethodAbbrev();
+
+ Code = serialization::DECL_CXX_METHOD;
+}
+
+void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ Writer.AddDeclRef(D->getInheritedConstructor(), Record);
+ Record.push_back(D->IsExplicitSpecified);
+
+ Code = serialization::DECL_CXX_CONSTRUCTOR;
+}
+
+void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ Writer.AddDeclRef(D->getOperatorDelete(), Record);
+
+ Code = serialization::DECL_CXX_DESTRUCTOR;
+}
+
+void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ VisitCXXMethodDecl(D);
+ Record.push_back(D->IsExplicitSpecified);
+ Code = serialization::DECL_CXX_CONVERSION;
+}
+
+void ASTDeclWriter::VisitImportDecl(ImportDecl *D) {
+ VisitDecl(D);
+ Record.push_back(Writer.getSubmoduleID(D->getImportedModule()));
+ ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs();
+ Record.push_back(!IdentifierLocs.empty());
+ if (IdentifierLocs.empty()) {
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(1);
+ } else {
+ for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I)
+ Writer.AddSourceLocation(IdentifierLocs[I], Record);
+ Record.push_back(IdentifierLocs.size());
+ }
+ // Note: the number of source locations must always be the last element in
+ // the record.
+ Code = serialization::DECL_IMPORT;
+}
+
+void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
+ VisitDecl(D);
+ Writer.AddSourceLocation(D->getColonLoc(), Record);
+ Code = serialization::DECL_ACCESS_SPEC;
+}
+
+void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
+ // Record the number of friend type template parameter lists here
+ // so as to simplify memory allocation during deserialization.
+ Record.push_back(D->NumTPLists);
+ VisitDecl(D);
+ bool hasFriendDecl = D->Friend.is<NamedDecl*>();
+ Record.push_back(hasFriendDecl);
+ if (hasFriendDecl)
+ Writer.AddDeclRef(D->getFriendDecl(), Record);
+ else
+ Writer.AddTypeSourceInfo(D->getFriendType(), Record);
+ for (unsigned i = 0; i < D->NumTPLists; ++i)
+ Writer.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i),
+ Record);
+ Writer.AddDeclRef(D->getNextFriend(), Record);
+ Record.push_back(D->UnsupportedFriend);
+ Writer.AddSourceLocation(D->FriendLoc, Record);
+ Code = serialization::DECL_FRIEND;
+}
+
+void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->getNumTemplateParameters());
+ for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i)
+ Writer.AddTemplateParameterList(D->getTemplateParameterList(i), Record);
+ Record.push_back(D->getFriendDecl() != nullptr);
+ if (D->getFriendDecl())
+ Writer.AddDeclRef(D->getFriendDecl(), Record);
+ else
+ Writer.AddTypeSourceInfo(D->getFriendType(), Record);
+ Writer.AddSourceLocation(D->getFriendLoc(), Record);
+ Code = serialization::DECL_FRIEND_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
+ VisitNamedDecl(D);
+
+ Writer.AddDeclRef(D->getTemplatedDecl(), Record);
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+}
+
+void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ VisitRedeclarable(D);
+
+ // Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
+ // getCommonPtr() can be used while this is still initializing.
+ if (D->isFirstDecl()) {
+ // This declaration owns the 'common' pointer, so serialize that data now.
+ Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
+ if (D->getInstantiatedFromMemberTemplate())
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ VisitTemplateDecl(D);
+ Record.push_back(D->getIdentifierNamespace());
+}
+
+void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
+ Code = serialization::DECL_CLASS_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *> InstFrom
+ = D->getSpecializedTemplateOrPartial();
+ if (Decl *InstFromD = InstFrom.dyn_cast<ClassTemplateDecl *>()) {
+ Writer.AddDeclRef(InstFromD, Record);
+ } else {
+ Writer.AddDeclRef(InstFrom.get<ClassTemplatePartialSpecializationDecl *>(),
+ Record);
+ Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
+ }
+
+ Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
+ Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
+ Record.push_back(D->getSpecializationKind());
+ Record.push_back(D->isCanonicalDecl());
+
+ if (D->isCanonicalDecl()) {
+ // When reading, we'll add it to the folding set of the following template.
+ Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
+ }
+
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
+ Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+ Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDecl() == nullptr) {
+ Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
+ Code = serialization::DECL_VAR_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ VisitVarDecl(D);
+
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ InstFrom = D->getSpecializedTemplateOrPartial();
+ if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
+ Writer.AddDeclRef(InstFromD, Record);
+ } else {
+ Writer.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>(),
+ Record);
+ Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
+ }
+
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
+ Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
+ Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
+ Record.push_back(D->getSpecializationKind());
+ Record.push_back(D->isCanonicalDecl());
+
+ if (D->isCanonicalDecl()) {
+ // When reading, we'll add it to the folding set of the following template.
+ Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
+ }
+
+ Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ VisitVarTemplateSpecializationDecl(D);
+
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+ Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDecl() == nullptr) {
+ Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
+}
+
+void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
+ ClassScopeFunctionSpecializationDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclRef(D->getSpecialization(), Record);
+ Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION;
+}
+
+
+void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+
+ if (D->isFirstDecl())
+ AddTemplateSpecializations(D);
+ Code = serialization::DECL_FUNCTION_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ VisitTypeDecl(D);
+
+ Record.push_back(D->wasDeclaredWithTypename());
+ Record.push_back(D->defaultArgumentWasInherited());
+ Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record);
+
+ Code = serialization::DECL_TEMPLATE_TYPE_PARM;
+}
+
+void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ // For an expanded parameter pack, record the number of expansion types here
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
+ if (D->isExpandedParameterPack())
+ Record.push_back(D->getNumExpansionTypes());
+
+ VisitDeclaratorDecl(D);
+ // TemplateParmPosition.
+ Record.push_back(D->getDepth());
+ Record.push_back(D->getPosition());
+
+ if (D->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
+ Writer.AddTypeRef(D->getExpansionType(I), Record);
+ Writer.AddTypeSourceInfo(D->getExpansionTypeSourceInfo(I), Record);
+ }
+
+ Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
+ } else {
+ // Rest of NonTypeTemplateParmDecl.
+ Record.push_back(D->isParameterPack());
+ Record.push_back(D->getDefaultArgument() != nullptr);
+ if (D->getDefaultArgument()) {
+ Writer.AddStmt(D->getDefaultArgument());
+ Record.push_back(D->defaultArgumentWasInherited());
+ }
+ Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM;
+ }
+}
+
+void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ // For an expanded parameter pack, record the number of expansion types here
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
+ if (D->isExpandedParameterPack())
+ Record.push_back(D->getNumExpansionTemplateParameters());
+
+ VisitTemplateDecl(D);
+ // TemplateParmPosition.
+ Record.push_back(D->getDepth());
+ Record.push_back(D->getPosition());
+
+ if (D->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I),
+ Record);
+ Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
+ Record.push_back(D->defaultArgumentWasInherited());
+ Record.push_back(D->isParameterPack());
+ Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+ }
+}
+
+void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+ Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
+}
+
+void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getAssertExpr());
+ Record.push_back(D->isFailed());
+ Writer.AddStmt(D->getMessage());
+ Writer.AddSourceLocation(D->getRParenLoc(), Record);
+ Code = serialization::DECL_STATIC_ASSERT;
+}
+
+/// \brief Emit the DeclContext part of a declaration context decl.
+///
+/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations stored within this context.
+///
+/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations visible from this context. Note
+/// that this value will not be emitted for non-primary declaration
+/// contexts.
+void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset) {
+ Record.push_back(LexicalOffset);
+ Record.push_back(VisibleOffset);
+}
+
+template <typename T>
+void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
+ T *First = D->getFirstDecl();
+ T *MostRecent = First->getMostRecentDecl();
+ if (MostRecent != First) {
+ assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
+ "Not considered redeclarable?");
+
+ // There is more than one declaration of this entity, so we will need to
+ // write a redeclaration chain.
+ Writer.AddDeclRef(First, Record);
+ Writer.Redeclarations.insert(First);
+
+ auto *Previous = D->getPreviousDecl();
+
+ // In a modules build, we can have imported declarations after a local
+ // canonical declaration. If this is the first local declaration, emit
+ // a list of all such imported declarations so that we can ensure they
+ // are loaded before we are. This allows us to rebuild the redecl chain
+ // in the right order on reload (all declarations imported by a module
+ // should be before all declarations provided by that module).
+ bool EmitImportedMergedCanonicalDecls = false;
+ if (Context.getLangOpts().Modules && Writer.Chain) {
+ auto *PreviousLocal = Previous;
+ while (PreviousLocal && PreviousLocal->isFromASTFile())
+ PreviousLocal = PreviousLocal->getPreviousDecl();
+ if (!PreviousLocal)
+ EmitImportedMergedCanonicalDecls = true;
+ }
+ if (EmitImportedMergedCanonicalDecls) {
+ llvm::SmallMapVector<ModuleFile*, Decl*, 16> FirstInModule;
+ for (auto *Redecl = MostRecent; Redecl;
+ Redecl = Redecl->getPreviousDecl())
+ if (Redecl->isFromASTFile())
+ FirstInModule[Writer.Chain->getOwningModuleFile(Redecl)] = Redecl;
+ // FIXME: If FirstInModule has entries for modules A and B, and B imports
+ // A (directly or indirectly), we don't need to write the entry for A.
+ Record.push_back(FirstInModule.size());
+ for (auto I = FirstInModule.rbegin(), E = FirstInModule.rend();
+ I != E; ++I)
+ Writer.AddDeclRef(I->second, Record);
+ } else
+ Record.push_back(0);
+
+ // Make sure that we serialize both the previous and the most-recent
+ // declarations, which (transitively) ensures that all declarations in the
+ // chain get serialized.
+ //
+ // FIXME: This is not correct; when we reach an imported declaration we
+ // won't emit its previous declaration.
+ (void)Writer.GetDeclRef(Previous);
+ (void)Writer.GetDeclRef(MostRecent);
+ } else {
+ // We use the sentinel value 0 to indicate an only declaration.
+ Record.push_back(0);
+ }
+}
+
+void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ Record.push_back(D->varlist_size());
+ VisitDecl(D);
+ for (auto *I : D->varlists())
+ Writer.AddStmt(I);
+ Code = serialization::DECL_OMP_THREADPRIVATE;
+}
+
+//===----------------------------------------------------------------------===//
+// ASTWriter Implementation
+//===----------------------------------------------------------------------===//
+
+void ASTWriter::WriteDeclAbbrevs() {
+ using namespace llvm;
+
+ BitCodeAbbrev *Abv;
+
+ // Abbreviation for DECL_FIELD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclFieldAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_OBJC_IVAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // ObjC Ivar
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclObjCIvarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_ENUM
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
+ // EnumDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumPositiveBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumNegativeBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclEnumAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_RECORD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind
+ // RecordDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclRecordAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_PARM_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // getTSCSpec
+ Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(0)); // Linkage
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInit
+ Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
+ // ParmVarDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsObjCMethodParameter
+ Abv->Add(BitCodeAbbrevOp(0)); // ScopeDepth
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex
+ Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+ Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
+ Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclParmVarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_TYPEDEF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // TypedefDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclTypedefAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTSCSpec
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
+ Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
+ Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclVarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_CXX_METHOD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_CXX_METHOD));
+ // RedeclarableDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(0)); // Invalid
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Implicit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Used
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Referenced
+ Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
+ Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
+ Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
+ // FunctionDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
+ Abv->Add(BitCodeAbbrevOp(1)); // HasWrittenProto
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Deleted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Trivial
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind
+ // This Array slurps the rest of the record. Fortunately we want to encode
+ // (nearly) all the remaining (variable number of) fields in the same way.
+ //
+ // This is the function template information if any, then
+ // NumParams and Params[] from FunctionDecl, and
+ // NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
+ //
+ // Add an AbbrevOp for 'size then elements' and use it here.
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ DeclCXXMethodAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_DECL_REF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //DeclRefExpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+ 1)); // RefersToEnclosingVariableOrCapture
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_INTEGER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Integer Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value
+ IntegerLiteralAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_CHARACTER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Character Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
+ CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_IMPLICIT_CAST
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_IMPLICIT_CAST));
+ // Stmt
+ // Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ // CastExpr
+ Abv->Add(BitCodeAbbrevOp(0)); // PathSize
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // CastKind
+ // ImplicitCastExpr
+ ExprImplicitCastAbbrev = Stream.EmitAbbrev(Abv);
+
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ DeclContextLexicalAbbrev = Stream.EmitAbbrev(Abv);
+
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(Abv);
+}
+
+/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
+/// consumers of the AST.
+///
+/// Such decls will always be deserialized from the AST file, so we would like
+/// this to be as restrictive as possible. Currently the predicate is driven by
+/// code generation requirements, if other clients have a different notion of
+/// what is "required" then we may have to consider an alternate scheme where
+/// clients can iterate over the top-level decls and get information on them,
+/// without necessary deserializing them. We could explicitly require such
+/// clients to use a separate API call to "realize" the decl. This should be
+/// relatively painless since they would presumably only do it for top-level
+/// decls.
+static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
+ // An ObjCMethodDecl is never considered as "required" because its
+ // implementation container always is.
+
+ // File scoped assembly or obj-c implementation must be seen. ImportDecl is
+ // used by codegen to determine the set of imported modules to search for
+ // inputs for automatic linking.
+ if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D) || isa<ImportDecl>(D))
+ return true;
+
+ return Context.DeclMustBeEmitted(D);
+}
+
+void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
+ // Switch case IDs are per Decl.
+ ClearSwitchCaseIDs();
+
+ RecordData Record;
+ ASTDeclWriter W(*this, Context, Record);
+
+ // Determine the ID for this declaration.
+ serialization::DeclID ID;
+ if (D->isFromASTFile()) {
+ assert(isRewritten(D) && "should not be emitting imported decl");
+ ID = getDeclID(D);
+ } else {
+ serialization::DeclID &IDR = DeclIDs[D];
+ if (IDR == 0)
+ IDR = NextDeclID++;
+
+ ID= IDR;
+ }
+
+ bool isReplacingADecl = ID < FirstDeclID;
+
+ // If this declaration is also a DeclContext, write blocks for the
+ // declarations that lexically stored inside its context and those
+ // declarations that are visible from its context. These blocks
+ // are written before the declaration itself so that we can put
+ // their offsets into the record for the declaration.
+ uint64_t LexicalOffset = 0;
+ uint64_t VisibleOffset = 0;
+ DeclContext *DC = dyn_cast<DeclContext>(D);
+ if (DC) {
+ if (isReplacingADecl) {
+ // It is replacing a decl from a chained PCH; make sure that the
+ // DeclContext is fully loaded.
+ if (DC->hasExternalLexicalStorage())
+ DC->LoadLexicalDeclsFromExternalStorage();
+ if (DC->hasExternalVisibleStorage())
+ Chain->completeVisibleDeclsMap(DC);
+ }
+ LexicalOffset = WriteDeclContextLexicalBlock(Context, DC);
+ VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
+ }
+
+ if (isReplacingADecl) {
+ // We're replacing a decl in a previous file.
+ ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(),
+ D->getLocation()));
+ } else {
+ unsigned Index = ID - FirstDeclID;
+
+ // Record the offset for this declaration
+ SourceLocation Loc = D->getLocation();
+ if (DeclOffsets.size() == Index)
+ DeclOffsets.push_back(DeclOffset(Loc, Stream.GetCurrentBitNo()));
+ else if (DeclOffsets.size() < Index) {
+ DeclOffsets.resize(Index+1);
+ DeclOffsets[Index].setLocation(Loc);
+ DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo();
+ }
+
+ SourceManager &SM = Context.getSourceManager();
+ if (Loc.isValid() && SM.isLocalSourceLocation(Loc))
+ associateDeclWithFile(D, ID);
+ }
+
+ // Build and emit a record for this declaration
+ Record.clear();
+ W.Code = (serialization::DeclCode)0;
+ W.AbbrevToUse = 0;
+ W.Visit(D);
+ if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
+
+ if (!W.Code)
+ llvm::report_fatal_error(StringRef("unexpected declaration kind '") +
+ D->getDeclKindName() + "'");
+ Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
+
+ // Flush any expressions, base specifiers, and ctor initializers that
+ // were written as part of this declaration.
+ FlushPendingAfterDecl();
+
+ // Note declarations that should be deserialized eagerly so that we can add
+ // them to a record in the AST file later.
+ if (isRequiredDecl(D, Context))
+ EagerlyDeserializedDecls.push_back(ID);
+}
+
+void ASTWriter::AddFunctionDefinition(const FunctionDecl *FD,
+ RecordData &Record) {
+ ClearSwitchCaseIDs();
+
+ ASTDeclWriter W(*this, FD->getASTContext(), Record);
+ W.AddFunctionDefinition(FD);
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
new file mode 100644
index 0000000..ec822f0
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -0,0 +1,2203 @@
+//===--- ASTWriterStmt.cpp - Statement and Expression Serialization -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements serialization for Statements and Expressions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTWriter.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Token.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Statement/expression serialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+
+ class ASTStmtWriter : public StmtVisitor<ASTStmtWriter, void> {
+ friend class OMPClauseWriter;
+ ASTWriter &Writer;
+ ASTWriter::RecordData &Record;
+
+ public:
+ serialization::StmtCode Code;
+ unsigned AbbrevToUse;
+
+ ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
+ : Writer(Writer), Record(Record) { }
+
+ void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args);
+
+ void VisitStmt(Stmt *S);
+#define STMT(Type, Base) \
+ void Visit##Type(Type *);
+#include "clang/AST/StmtNodes.inc"
+ };
+}
+
+void ASTStmtWriter::
+AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args) {
+ Writer.AddSourceLocation(Args.getTemplateKeywordLoc(), Record);
+ Writer.AddSourceLocation(Args.LAngleLoc, Record);
+ Writer.AddSourceLocation(Args.RAngleLoc, Record);
+ for (unsigned i=0; i != Args.NumTemplateArgs; ++i)
+ Writer.AddTemplateArgumentLoc(Args.getTemplateArgs()[i], Record);
+}
+
+void ASTStmtWriter::VisitStmt(Stmt *S) {
+}
+
+void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getSemiLoc(), Record);
+ Record.push_back(S->HasLeadingEmptyMacro);
+ Code = serialization::STMT_NULL;
+}
+
+void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->size());
+ for (auto *CS : S->body())
+ Writer.AddStmt(CS);
+ Writer.AddSourceLocation(S->getLBracLoc(), Record);
+ Writer.AddSourceLocation(S->getRBracLoc(), Record);
+ Code = serialization::STMT_COMPOUND;
+}
+
+void ASTStmtWriter::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Record.push_back(Writer.getSwitchCaseID(S));
+ Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+}
+
+void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ Writer.AddStmt(S->getLHS());
+ Writer.AddStmt(S->getRHS());
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getEllipsisLoc(), Record);
+ Code = serialization::STMT_CASE;
+}
+
+void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ Writer.AddStmt(S->getSubStmt());
+ Code = serialization::STMT_DEFAULT;
+}
+
+void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getDecl(), Record);
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getIdentLoc(), Record);
+ Code = serialization::STMT_LABEL;
+}
+
+void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getAttrs().size());
+ Writer.WriteAttributes(S->getAttrs(), Record);
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getAttrLoc(), Record);
+ Code = serialization::STMT_ATTRIBUTED;
+}
+
+void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getThen());
+ Writer.AddStmt(S->getElse());
+ Writer.AddSourceLocation(S->getIfLoc(), Record);
+ Writer.AddSourceLocation(S->getElseLoc(), Record);
+ Code = serialization::STMT_IF;
+}
+
+void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getSwitchLoc(), Record);
+ Record.push_back(S->isAllEnumCasesCovered());
+ for (SwitchCase *SC = S->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase())
+ Record.push_back(Writer.RecordSwitchCaseID(SC));
+ Code = serialization::STMT_SWITCH;
+}
+
+void ASTStmtWriter::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Code = serialization::STMT_WHILE;
+}
+
+void ASTStmtWriter::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getDoLoc(), Record);
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = serialization::STMT_DO;
+}
+
+void ASTStmtWriter::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getInit());
+ Writer.AddStmt(S->getCond());
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getInc());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getLParenLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = serialization::STMT_FOR;
+}
+
+void ASTStmtWriter::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getLabel(), Record);
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getLabelLoc(), Record);
+ Code = serialization::STMT_GOTO;
+}
+
+void ASTStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getStarLoc(), Record);
+ Writer.AddStmt(S->getTarget());
+ Code = serialization::STMT_INDIRECT_GOTO;
+}
+
+void ASTStmtWriter::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getContinueLoc(), Record);
+ Code = serialization::STMT_CONTINUE;
+}
+
+void ASTStmtWriter::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getBreakLoc(), Record);
+ Code = serialization::STMT_BREAK;
+}
+
+void ASTStmtWriter::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getRetValue());
+ Writer.AddSourceLocation(S->getReturnLoc(), Record);
+ Writer.AddDeclRef(S->getNRVOCandidate(), Record);
+ Code = serialization::STMT_RETURN;
+}
+
+void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getStartLoc(), Record);
+ Writer.AddSourceLocation(S->getEndLoc(), Record);
+ DeclGroupRef DG = S->getDeclGroup();
+ for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D)
+ Writer.AddDeclRef(*D, Record);
+ Code = serialization::STMT_DECL;
+}
+
+void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getNumOutputs());
+ Record.push_back(S->getNumInputs());
+ Record.push_back(S->getNumClobbers());
+ Writer.AddSourceLocation(S->getAsmLoc(), Record);
+ Record.push_back(S->isVolatile());
+ Record.push_back(S->isSimple());
+}
+
+void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
+ VisitAsmStmt(S);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Writer.AddStmt(S->getAsmString());
+
+ // Outputs
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record);
+ Writer.AddStmt(S->getOutputConstraintLiteral(I));
+ Writer.AddStmt(S->getOutputExpr(I));
+ }
+
+ // Inputs
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getInputIdentifier(I), Record);
+ Writer.AddStmt(S->getInputConstraintLiteral(I));
+ Writer.AddStmt(S->getInputExpr(I));
+ }
+
+ // Clobbers
+ for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
+ Writer.AddStmt(S->getClobberStringLiteral(I));
+
+ Code = serialization::STMT_GCCASM;
+}
+
+void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
+ VisitAsmStmt(S);
+ Writer.AddSourceLocation(S->getLBraceLoc(), Record);
+ Writer.AddSourceLocation(S->getEndLoc(), Record);
+ Record.push_back(S->getNumAsmToks());
+ Writer.AddString(S->getAsmString(), Record);
+
+ // Tokens
+ for (unsigned I = 0, N = S->getNumAsmToks(); I != N; ++I) {
+ Writer.AddToken(S->getAsmToks()[I], Record);
+ }
+
+ // Clobbers
+ for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) {
+ Writer.AddString(S->getClobber(I), Record);
+ }
+
+ // Outputs
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddStmt(S->getOutputExpr(I));
+ Writer.AddString(S->getOutputConstraint(I), Record);
+ }
+
+ // Inputs
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ Writer.AddStmt(S->getInputExpr(I));
+ Writer.AddString(S->getInputConstraint(I), Record);
+ }
+
+ Code = serialization::STMT_MSASM;
+}
+
+void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
+ VisitStmt(S);
+ // NumCaptures
+ Record.push_back(std::distance(S->capture_begin(), S->capture_end()));
+
+ // CapturedDecl and captured region kind
+ Writer.AddDeclRef(S->getCapturedDecl(), Record);
+ Record.push_back(S->getCapturedRegionKind());
+
+ Writer.AddDeclRef(S->getCapturedRecordDecl(), Record);
+
+ // Capture inits
+ for (auto *I : S->capture_inits())
+ Writer.AddStmt(I);
+
+ // Body
+ Writer.AddStmt(S->getCapturedStmt());
+
+ // Captures
+ for (const auto &I : S->captures()) {
+ if (I.capturesThis() || I.capturesVariableArrayType())
+ Writer.AddDeclRef(nullptr, Record);
+ else
+ Writer.AddDeclRef(I.getCapturedVar(), Record);
+ Record.push_back(I.getCaptureKind());
+ Writer.AddSourceLocation(I.getLocation(), Record);
+ }
+
+ Code = serialization::STMT_CAPTURED;
+}
+
+void ASTStmtWriter::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ Writer.AddTypeRef(E->getType(), Record);
+ Record.push_back(E->isTypeDependent());
+ Record.push_back(E->isValueDependent());
+ Record.push_back(E->isInstantiationDependent());
+ Record.push_back(E->containsUnexpandedParameterPack());
+ Record.push_back(E->getValueKind());
+ Record.push_back(E->getObjectKind());
+}
+
+void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->getIdentType()); // FIXME: stable encoding
+ Writer.AddStmt(E->getFunctionName());
+ Code = serialization::EXPR_PREDEFINED;
+}
+
+void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+
+ Record.push_back(E->hasQualifier());
+ Record.push_back(E->getDecl() != E->getFoundDecl());
+ Record.push_back(E->hasTemplateKWAndArgsInfo());
+ Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->refersToEnclosingVariableOrCapture());
+
+ if (E->hasTemplateKWAndArgsInfo()) {
+ unsigned NumTemplateArgs = E->getNumTemplateArgs();
+ Record.push_back(NumTemplateArgs);
+ }
+
+ DeclarationName::NameKind nk = (E->getDecl()->getDeclName().getNameKind());
+
+ if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) &&
+ (E->getDecl() == E->getFoundDecl()) &&
+ nk == DeclarationName::Identifier) {
+ AbbrevToUse = Writer.getDeclRefExprAbbrev();
+ }
+
+ if (E->hasQualifier())
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+
+ if (E->getDecl() != E->getFoundDecl())
+ Writer.AddDeclRef(E->getFoundDecl(), Record);
+
+ if (E->hasTemplateKWAndArgsInfo())
+ AddTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo());
+
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record);
+ Code = serialization::EXPR_DECL_REF;
+}
+
+void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddAPInt(E->getValue(), Record);
+
+ if (E->getValue().getBitWidth() == 32) {
+ AbbrevToUse = Writer.getIntegerLiteralAbbrev();
+ }
+
+ Code = serialization::EXPR_INTEGER_LITERAL;
+}
+
+void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getRawSemantics());
+ Record.push_back(E->isExact());
+ Writer.AddAPFloat(E->getValue(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_FLOATING_LITERAL;
+}
+
+void ASTStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_IMAGINARY_LITERAL;
+}
+
+void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getByteLength());
+ Record.push_back(E->getNumConcatenated());
+ Record.push_back(E->getKind());
+ Record.push_back(E->isPascal());
+ // FIXME: String data should be stored as a blob at the end of the
+ // StringLiteral. However, we can't do so now because we have no
+ // provision for coping with abbreviations when we're jumping around
+ // the AST file during deserialization.
+ Record.append(E->getBytes().begin(), E->getBytes().end());
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ Writer.AddSourceLocation(E->getStrTokenLoc(I), Record);
+ Code = serialization::EXPR_STRING_LITERAL;
+}
+
+void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->getKind());
+
+ AbbrevToUse = Writer.getCharacterLiteralAbbrev();
+
+ Code = serialization::EXPR_CHARACTER_LITERAL;
+}
+
+void ASTStmtWriter::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParen(), Record);
+ Writer.AddSourceLocation(E->getRParen(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_PAREN;
+}
+
+void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->NumExprs);
+ for (unsigned i=0; i != E->NumExprs; ++i)
+ Writer.AddStmt(E->Exprs[i]);
+ Writer.AddSourceLocation(E->LParenLoc, Record);
+ Writer.AddSourceLocation(E->RParenLoc, Record);
+ Code = serialization::EXPR_PAREN_LIST;
+}
+
+void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = serialization::EXPR_UNARY_OPERATOR;
+}
+
+void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumComponents());
+ Record.push_back(E->getNumExpressions());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+ Record.push_back(ON.getKind()); // FIXME: Stable encoding
+ Writer.AddSourceLocation(ON.getSourceRange().getBegin(), Record);
+ Writer.AddSourceLocation(ON.getSourceRange().getEnd(), Record);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ Record.push_back(ON.getArrayExprIndex());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ Writer.AddDeclRef(ON.getField(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ Writer.AddIdentifierRef(ON.getFieldName(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ Writer.AddCXXBaseSpecifier(*ON.getBase(), Record);
+ break;
+ }
+ }
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ Writer.AddStmt(E->getIndexExpr(I));
+ Code = serialization::EXPR_OFFSETOF;
+}
+
+void ASTStmtWriter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getKind());
+ if (E->isArgumentType())
+ Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record);
+ else {
+ Record.push_back(0);
+ Writer.AddStmt(E->getArgumentExpr());
+ }
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_SIZEOF_ALIGN_OF;
+}
+
+void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getRBracketLoc(), Record);
+ Code = serialization::EXPR_ARRAY_SUBSCRIPT;
+}
+
+void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddStmt(E->getCallee());
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.AddStmt(*Arg);
+ Code = serialization::EXPR_CALL;
+}
+
+void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
+ // Don't call VisitExpr, we'll write everything here.
+
+ Record.push_back(E->hasQualifier());
+ if (E->hasQualifier())
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ Writer.AddSourceLocation(E->getTemplateKeywordLoc(), Record);
+ unsigned NumTemplateArgs = E->getNumTemplateArgs();
+ Record.push_back(NumTemplateArgs);
+ Writer.AddSourceLocation(E->getLAngleLoc(), Record);
+ Writer.AddSourceLocation(E->getRAngleLoc(), Record);
+ for (unsigned i=0; i != NumTemplateArgs; ++i)
+ Writer.AddTemplateArgumentLoc(E->getTemplateArgs()[i], Record);
+ }
+
+ Record.push_back(E->hadMultipleCandidates());
+
+ DeclAccessPair FoundDecl = E->getFoundDecl();
+ Writer.AddDeclRef(FoundDecl.getDecl(), Record);
+ Record.push_back(FoundDecl.getAccess());
+
+ Writer.AddTypeRef(E->getType(), Record);
+ Record.push_back(E->getValueKind());
+ Record.push_back(E->getObjectKind());
+ Writer.AddStmt(E->getBase());
+ Writer.AddDeclRef(E->getMemberDecl(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddDeclarationNameLoc(E->MemberDNLoc,
+ E->getMemberDecl()->getDeclName(), Record);
+ Code = serialization::EXPR_MEMBER;
+}
+
+void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getBase());
+ Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
+ Record.push_back(E->isArrow());
+ Code = serialization::EXPR_OBJC_ISA;
+}
+
+void ASTStmtWriter::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->shouldCopy());
+ Code = serialization::EXPR_OBJC_INDIRECT_COPY_RESTORE;
+}
+
+void ASTStmtWriter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getBridgeKeywordLoc(), Record);
+ Record.push_back(E->getBridgeKind()); // FIXME: Stable encoding
+ Code = serialization::EXPR_OBJC_BRIDGED_CAST;
+}
+
+void ASTStmtWriter::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->path_size());
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->getCastKind()); // FIXME: stable encoding
+
+ for (CastExpr::path_iterator
+ PI = E->path_begin(), PE = E->path_end(); PI != PE; ++PI)
+ Writer.AddCXXBaseSpecifier(**PI, Record);
+}
+
+void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Record.push_back(E->isFPContractable());
+ Code = serialization::EXPR_BINARY_OPERATOR;
+}
+
+void ASTStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ Writer.AddTypeRef(E->getComputationLHSType(), Record);
+ Writer.AddTypeRef(E->getComputationResultType(), Record);
+ Code = serialization::EXPR_COMPOUND_ASSIGN_OPERATOR;
+}
+
+void ASTStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getCond());
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getQuestionLoc(), Record);
+ Writer.AddSourceLocation(E->getColonLoc(), Record);
+ Code = serialization::EXPR_CONDITIONAL_OPERATOR;
+}
+
+void
+ASTStmtWriter::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getOpaqueValue());
+ Writer.AddStmt(E->getCommon());
+ Writer.AddStmt(E->getCond());
+ Writer.AddStmt(E->getTrueExpr());
+ Writer.AddStmt(E->getFalseExpr());
+ Writer.AddSourceLocation(E->getQuestionLoc(), Record);
+ Writer.AddSourceLocation(E->getColonLoc(), Record);
+ Code = serialization::EXPR_BINARY_CONDITIONAL_OPERATOR;
+}
+
+void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+
+ if (E->path_size() == 0)
+ AbbrevToUse = Writer.getExprImplicitCastAbbrev();
+
+ Code = serialization::EXPR_IMPLICIT_CAST;
+}
+
+void ASTStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record);
+}
+
+void ASTStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_CSTYLE_CAST;
+}
+
+void ASTStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddStmt(E->getInitializer());
+ Record.push_back(E->isFileScope());
+ Code = serialization::EXPR_COMPOUND_LITERAL;
+}
+
+void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getBase());
+ Writer.AddIdentifierRef(&E->getAccessor(), Record);
+ Writer.AddSourceLocation(E->getAccessorLoc(), Record);
+ Code = serialization::EXPR_EXT_VECTOR_ELEMENT;
+}
+
+void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ // NOTE: only add the (possibly null) syntactic form.
+ // No need to serialize the isSemanticForm flag and the semantic form.
+ Writer.AddStmt(E->getSyntacticForm());
+ Writer.AddSourceLocation(E->getLBraceLoc(), Record);
+ Writer.AddSourceLocation(E->getRBraceLoc(), Record);
+ bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>();
+ Record.push_back(isArrayFiller);
+ if (isArrayFiller)
+ Writer.AddStmt(E->getArrayFiller());
+ else
+ Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
+ Record.push_back(E->hadArrayRangeDesignator());
+ Record.push_back(E->getNumInits());
+ if (isArrayFiller) {
+ // ArrayFiller may have filled "holes" due to designated initializer.
+ // Replace them by 0 to indicate that the filler goes in that place.
+ Expr *filler = E->getArrayFiller();
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.AddStmt(E->getInit(I) != filler ? E->getInit(I) : nullptr);
+ } else {
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.AddStmt(E->getInit(I));
+ }
+ Code = serialization::EXPR_INIT_LIST;
+}
+
+void ASTStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getSubExpr(I));
+ Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record);
+ Record.push_back(E->usesGNUSyntax());
+ for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
+ DEnd = E->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (FieldDecl *Field = D->getField()) {
+ Record.push_back(serialization::DESIG_FIELD_DECL);
+ Writer.AddDeclRef(Field, Record);
+ } else {
+ Record.push_back(serialization::DESIG_FIELD_NAME);
+ Writer.AddIdentifierRef(D->getFieldName(), Record);
+ }
+ Writer.AddSourceLocation(D->getDotLoc(), Record);
+ Writer.AddSourceLocation(D->getFieldLoc(), Record);
+ } else if (D->isArrayDesignator()) {
+ Record.push_back(serialization::DESIG_ARRAY);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ } else {
+ assert(D->isArrayRangeDesignator() && "Unknown designator");
+ Record.push_back(serialization::DESIG_ARRAY_RANGE);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getEllipsisLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ }
+ }
+ Code = serialization::EXPR_DESIGNATED_INIT;
+}
+
+void ASTStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+ Code = serialization::EXPR_IMPLICIT_VALUE_INIT;
+}
+
+void ASTStmtWriter::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Writer.AddTypeSourceInfo(E->getWrittenTypeInfo(), Record);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_VA_ARG;
+}
+
+void ASTStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
+ Writer.AddSourceLocation(E->getLabelLoc(), Record);
+ Writer.AddDeclRef(E->getLabel(), Record);
+ Code = serialization::EXPR_ADDR_LABEL;
+}
+
+void ASTStmtWriter::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubStmt());
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_STMT;
+}
+
+void ASTStmtWriter::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getCond());
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Record.push_back(E->isConditionDependent() ? false : E->isConditionTrue());
+ Code = serialization::EXPR_CHOOSE;
+}
+
+void ASTStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getTokenLocation(), Record);
+ Code = serialization::EXPR_GNU_NULL;
+}
+
+void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getExpr(I));
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_SHUFFLE_VECTOR;
+}
+
+void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddStmt(E->getSrcExpr());
+ Code = serialization::EXPR_CONVERT_VECTOR;
+}
+
+void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getBlockDecl(), Record);
+ Code = serialization::EXPR_BLOCK;
+}
+
+void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumAssocs());
+
+ Writer.AddStmt(E->getControllingExpr());
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ Writer.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I), Record);
+ Writer.AddStmt(E->getAssocExpr(I));
+ }
+ Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex());
+
+ Writer.AddSourceLocation(E->getGenericLoc(), Record);
+ Writer.AddSourceLocation(E->getDefaultLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_GENERIC_SELECTION;
+}
+
+void ASTStmtWriter::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSemanticExprs());
+
+ // Push the result index. Currently, this needs to exactly match
+ // the encoding used internally for ResultIndex.
+ unsigned result = E->getResultExprIndex();
+ result = (result == PseudoObjectExpr::NoResult ? 0 : result + 1);
+ Record.push_back(result);
+
+ Writer.AddStmt(E->getSyntacticForm());
+ for (PseudoObjectExpr::semantics_iterator
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+ Writer.AddStmt(*i);
+ }
+ Code = serialization::EXPR_PSEUDO_OBJECT;
+}
+
+void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getOp());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getSubExprs()[I]);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_ATOMIC;
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getString());
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Code = serialization::EXPR_OBJC_STRING_LITERAL;
+}
+
+void ASTStmtWriter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Writer.AddDeclRef(E->getBoxingMethod(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Code = serialization::EXPR_OBJC_BOXED_EXPRESSION;
+}
+
+void ASTStmtWriter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumElements());
+ for (unsigned i = 0; i < E->getNumElements(); i++)
+ Writer.AddStmt(E->getElement(i));
+ Writer.AddDeclRef(E->getArrayWithObjectsMethod(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Code = serialization::EXPR_OBJC_ARRAY_LITERAL;
+}
+
+void ASTStmtWriter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumElements());
+ Record.push_back(E->HasPackExpansions);
+ for (unsigned i = 0; i < E->getNumElements(); i++) {
+ ObjCDictionaryElement Element = E->getKeyValueElement(i);
+ Writer.AddStmt(Element.Key);
+ Writer.AddStmt(Element.Value);
+ if (E->HasPackExpansions) {
+ Writer.AddSourceLocation(Element.EllipsisLoc, Record);
+ unsigned NumExpansions = 0;
+ if (Element.NumExpansions)
+ NumExpansions = *Element.NumExpansions + 1;
+ Record.push_back(NumExpansions);
+ }
+ }
+
+ Writer.AddDeclRef(E->getDictWithObjectsMethod(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Code = serialization::EXPR_OBJC_DICTIONARY_LITERAL;
+}
+
+void ASTStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_OBJC_ENCODE;
+}
+
+void ASTStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_OBJC_SELECTOR_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getProtocol(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->ProtoLoc, Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_OBJC_PROTOCOL_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
+ Writer.AddStmt(E->getBase());
+ Record.push_back(E->isArrow());
+ Record.push_back(E->isFreeIvar());
+ Code = serialization::EXPR_OBJC_IVAR_REF_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->SetterAndMethodRefFlags.getInt());
+ Record.push_back(E->isImplicitProperty());
+ if (E->isImplicitProperty()) {
+ Writer.AddDeclRef(E->getImplicitPropertyGetter(), Record);
+ Writer.AddDeclRef(E->getImplicitPropertySetter(), Record);
+ } else {
+ Writer.AddDeclRef(E->getExplicitProperty(), Record);
+ }
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getReceiverLocation(), Record);
+ if (E->isObjectReceiver()) {
+ Record.push_back(0);
+ Writer.AddStmt(E->getBase());
+ } else if (E->isSuperReceiver()) {
+ Record.push_back(1);
+ Writer.AddTypeRef(E->getSuperReceiverType(), Record);
+ } else {
+ Record.push_back(2);
+ Writer.AddDeclRef(E->getClassReceiver(), Record);
+ }
+
+ Code = serialization::EXPR_OBJC_PROPERTY_REF_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getRBracket(), Record);
+ Writer.AddStmt(E->getBaseExpr());
+ Writer.AddStmt(E->getKeyExpr());
+ Writer.AddDeclRef(E->getAtIndexMethodDecl(), Record);
+ Writer.AddDeclRef(E->setAtIndexMethodDecl(), Record);
+
+ Code = serialization::EXPR_OBJC_SUBSCRIPT_REF_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Record.push_back(E->getNumStoredSelLocs());
+ Record.push_back(E->SelLocsKind);
+ Record.push_back(E->isDelegateInitCall());
+ Record.push_back(E->IsImplicit);
+ Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Writer.AddStmt(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record);
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ Writer.AddTypeRef(E->getSuperType(), Record);
+ Writer.AddSourceLocation(E->getSuperLoc(), Record);
+ break;
+ }
+
+ if (E->getMethodDecl()) {
+ Record.push_back(1);
+ Writer.AddDeclRef(E->getMethodDecl(), Record);
+ } else {
+ Record.push_back(0);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ }
+
+ Writer.AddSourceLocation(E->getLeftLoc(), Record);
+ Writer.AddSourceLocation(E->getRightLoc(), Record);
+
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.AddStmt(*Arg);
+
+ SourceLocation *Locs = E->getStoredSelLocs();
+ for (unsigned i = 0, e = E->getNumStoredSelLocs(); i != e; ++i)
+ Writer.AddSourceLocation(Locs[i], Record);
+
+ Code = serialization::EXPR_OBJC_MESSAGE_EXPR;
+}
+
+void ASTStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getElement());
+ Writer.AddStmt(S->getCollection());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = serialization::STMT_OBJC_FOR_COLLECTION;
+}
+
+void ASTStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ Writer.AddStmt(S->getCatchBody());
+ Writer.AddDeclRef(S->getCatchParamDecl(), Record);
+ Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = serialization::STMT_OBJC_CATCH;
+}
+
+void ASTStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ Writer.AddStmt(S->getFinallyBody());
+ Writer.AddSourceLocation(S->getAtFinallyLoc(), Record);
+ Code = serialization::STMT_OBJC_FINALLY;
+}
+
+void ASTStmtWriter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getAtLoc(), Record);
+ Code = serialization::STMT_OBJC_AUTORELEASE_POOL;
+}
+
+void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ Record.push_back(S->getNumCatchStmts());
+ Record.push_back(S->getFinallyStmt() != nullptr);
+ Writer.AddStmt(S->getTryBody());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ Writer.AddStmt(S->getCatchStmt(I));
+ if (S->getFinallyStmt())
+ Writer.AddStmt(S->getFinallyStmt());
+ Writer.AddSourceLocation(S->getAtTryLoc(), Record);
+ Code = serialization::STMT_OBJC_AT_TRY;
+}
+
+void ASTStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ Writer.AddStmt(S->getSynchExpr());
+ Writer.AddStmt(S->getSynchBody());
+ Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record);
+ Code = serialization::STMT_OBJC_AT_SYNCHRONIZED;
+}
+
+void ASTStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ Writer.AddStmt(S->getThrowExpr());
+ Writer.AddSourceLocation(S->getThrowLoc(), Record);
+ Code = serialization::STMT_OBJC_AT_THROW;
+}
+
+void ASTStmtWriter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_OBJC_BOOL_LITERAL;
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void ASTStmtWriter::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getCatchLoc(), Record);
+ Writer.AddDeclRef(S->getExceptionDecl(), Record);
+ Writer.AddStmt(S->getHandlerBlock());
+ Code = serialization::STMT_CXX_CATCH;
+}
+
+void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getNumHandlers());
+ Writer.AddSourceLocation(S->getTryLoc(), Record);
+ Writer.AddStmt(S->getTryBlock());
+ for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i)
+ Writer.AddStmt(S->getHandler(i));
+ Code = serialization::STMT_CXX_TRY;
+}
+
+void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Writer.AddStmt(S->getRangeStmt());
+ Writer.AddStmt(S->getBeginEndStmt());
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getInc());
+ Writer.AddStmt(S->getLoopVarStmt());
+ Writer.AddStmt(S->getBody());
+ Code = serialization::STMT_CXX_FOR_RANGE;
+}
+
+void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+ Record.push_back(S->isIfExists());
+ Writer.AddNestedNameSpecifierLoc(S->getQualifierLoc(), Record);
+ Writer.AddDeclarationNameInfo(S->getNameInfo(), Record);
+ Writer.AddStmt(S->getSubStmt());
+ Code = serialization::STMT_MS_DEPENDENT_EXISTS;
+}
+
+void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ VisitCallExpr(E);
+ Record.push_back(E->getOperator());
+ Writer.AddSourceRange(E->Range, Record);
+ Record.push_back(E->isFPContractable());
+ Code = serialization::EXPR_CXX_OPERATOR_CALL;
+}
+
+void ASTStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ VisitCallExpr(E);
+ Code = serialization::EXPR_CXX_MEMBER_CALL;
+}
+
+void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.AddStmt(E->getArg(I));
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isElidable());
+ Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->isListInitialization());
+ Record.push_back(E->isStdInitListInitialization());
+ Record.push_back(E->requiresZeroInitialization());
+ Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
+ Writer.AddSourceRange(E->getParenOrBraceRange(), Record);
+ Code = serialization::EXPR_CXX_CONSTRUCT;
+}
+
+void ASTStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+ VisitCXXConstructExpr(E);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Code = serialization::EXPR_CXX_TEMPORARY_OBJECT;
+}
+
+void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->NumCaptures);
+ unsigned NumArrayIndexVars = 0;
+ if (E->HasArrayIndexVars)
+ NumArrayIndexVars = E->getArrayIndexStarts()[E->NumCaptures];
+ Record.push_back(NumArrayIndexVars);
+ Writer.AddSourceRange(E->IntroducerRange, Record);
+ Record.push_back(E->CaptureDefault); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->CaptureDefaultLoc, Record);
+ Record.push_back(E->ExplicitParams);
+ Record.push_back(E->ExplicitResultType);
+ Writer.AddSourceLocation(E->ClosingBrace, Record);
+
+ // Add capture initializers.
+ for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(),
+ CEnd = E->capture_init_end();
+ C != CEnd; ++C) {
+ Writer.AddStmt(*C);
+ }
+
+ // Add array index variables, if any.
+ if (NumArrayIndexVars) {
+ Record.append(E->getArrayIndexStarts(),
+ E->getArrayIndexStarts() + E->NumCaptures + 1);
+ VarDecl **ArrayIndexVars = E->getArrayIndexVars();
+ for (unsigned I = 0; I != NumArrayIndexVars; ++I)
+ Writer.AddDeclRef(ArrayIndexVars[I], Record);
+ }
+
+ Code = serialization::EXPR_LAMBDA;
+}
+
+void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_CXX_STD_INITIALIZER_LIST;
+}
+
+void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
+ Record);
+ Writer.AddSourceRange(E->getAngleBrackets(), Record);
+}
+
+void ASTStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = serialization::EXPR_CXX_STATIC_CAST;
+}
+
+void ASTStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = serialization::EXPR_CXX_DYNAMIC_CAST;
+}
+
+void ASTStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = serialization::EXPR_CXX_REINTERPRET_CAST;
+}
+
+void ASTStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = serialization::EXPR_CXX_CONST_CAST;
+}
+
+void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_CXX_FUNCTIONAL_CAST;
+}
+
+void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ Writer.AddSourceLocation(E->UDSuffixLoc, Record);
+ Code = serialization::EXPR_USER_DEFINED_LITERAL;
+}
+
+void ASTStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_CXX_BOOL_LITERAL;
+}
+
+void ASTStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_CXX_NULL_PTR_LITERAL;
+}
+
+void ASTStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ if (E->isTypeOperand()) {
+ Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
+ Code = serialization::EXPR_CXX_TYPEID_TYPE;
+ } else {
+ Writer.AddStmt(E->getExprOperand());
+ Code = serialization::EXPR_CXX_TYPEID_EXPR;
+ }
+}
+
+void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isImplicit());
+ Code = serialization::EXPR_CXX_THIS;
+}
+
+void ASTStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getThrowLoc(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->isThrownVariableInScope());
+ Code = serialization::EXPR_CXX_THROW;
+}
+
+void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+
+ bool HasOtherExprStored = E->Param.getInt();
+ // Store these first, the reader reads them before creation.
+ Record.push_back(HasOtherExprStored);
+ if (HasOtherExprStored)
+ Writer.AddStmt(E->getExpr());
+ Writer.AddDeclRef(E->getParam(), Record);
+ Writer.AddSourceLocation(E->getUsedLocation(), Record);
+
+ Code = serialization::EXPR_CXX_DEFAULT_ARG;
+}
+
+void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getField(), Record);
+ Writer.AddSourceLocation(E->getExprLoc(), Record);
+ Code = serialization::EXPR_CXX_DEFAULT_INIT;
+}
+
+void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ Writer.AddCXXTemporary(E->getTemporary(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_CXX_BIND_TEMPORARY;
+}
+
+void ASTStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_CXX_SCALAR_VALUE_INIT;
+}
+
+void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isGlobalNew());
+ Record.push_back(E->isArray());
+ Record.push_back(E->doesUsualArrayDeleteWantSize());
+ Record.push_back(E->getNumPlacementArgs());
+ Record.push_back(E->StoredInitializationStyle);
+ Writer.AddDeclRef(E->getOperatorNew(), Record);
+ Writer.AddDeclRef(E->getOperatorDelete(), Record);
+ Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record);
+ Writer.AddSourceRange(E->getTypeIdParens(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddSourceRange(E->getDirectInitRange(), Record);
+ for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
+ I != e; ++I)
+ Writer.AddStmt(*I);
+
+ Code = serialization::EXPR_CXX_NEW;
+}
+
+void ASTStmtWriter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isGlobalDelete());
+ Record.push_back(E->isArrayForm());
+ Record.push_back(E->isArrayFormAsWritten());
+ Record.push_back(E->doesUsualArrayDeleteWantSize());
+ Writer.AddDeclRef(E->getOperatorDelete(), Record);
+ Writer.AddStmt(E->getArgument());
+ Writer.AddSourceLocation(E->getSourceRange().getBegin(), Record);
+
+ Code = serialization::EXPR_CXX_DELETE;
+}
+
+void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ VisitExpr(E);
+
+ Writer.AddStmt(E->getBase());
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getScopeTypeInfo(), Record);
+ Writer.AddSourceLocation(E->getColonColonLoc(), Record);
+ Writer.AddSourceLocation(E->getTildeLoc(), Record);
+
+ // PseudoDestructorTypeStorage.
+ Writer.AddIdentifierRef(E->getDestroyedTypeIdentifier(), Record);
+ if (E->getDestroyedTypeIdentifier())
+ Writer.AddSourceLocation(E->getDestroyedTypeLoc(), Record);
+ else
+ Writer.AddTypeSourceInfo(E->getDestroyedTypeInfo(), Record);
+
+ Code = serialization::EXPR_CXX_PSEUDO_DESTRUCTOR;
+}
+
+void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumObjects());
+ for (unsigned i = 0, e = E->getNumObjects(); i != e; ++i)
+ Writer.AddDeclRef(E->getObject(i), Record);
+
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_EXPR_WITH_CLEANUPS;
+}
+
+void
+ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
+ VisitExpr(E);
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
+ // emitted first.
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
+ Record.push_back(Args.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(Args);
+ }
+
+ if (!E->isImplicitAccess())
+ Writer.AddStmt(E->getBase());
+ else
+ Writer.AddStmt(nullptr);
+ Writer.AddTypeRef(E->getBaseType(), Record);
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+ Writer.AddDeclRef(E->getFirstQualifierFoundInScope(), Record);
+ Writer.AddDeclarationNameInfo(E->MemberNameInfo, Record);
+ Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
+}
+
+void
+ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ VisitExpr(E);
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
+ // emitted first.
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
+ Record.push_back(Args.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(Args);
+ }
+
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+ Writer.AddDeclarationNameInfo(E->NameInfo, Record);
+ Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF;
+}
+
+void
+ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->arg_size());
+ for (CXXUnresolvedConstructExpr::arg_iterator
+ ArgI = E->arg_begin(), ArgE = E->arg_end(); ArgI != ArgE; ++ArgI)
+ Writer.AddStmt(*ArgI);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_CXX_UNRESOLVED_CONSTRUCT;
+}
+
+void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
+ VisitExpr(E);
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
+ // emitted first.
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
+ Record.push_back(Args.NumTemplateArgs);
+ AddTemplateKWAndArgsInfo(Args);
+ }
+
+ Record.push_back(E->getNumDecls());
+ for (OverloadExpr::decls_iterator
+ OvI = E->decls_begin(), OvE = E->decls_end(); OvI != OvE; ++OvI) {
+ Writer.AddDeclRef(OvI.getDecl(), Record);
+ Record.push_back(OvI.getAccess());
+ }
+
+ Writer.AddDeclarationNameInfo(E->NameInfo, Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+}
+
+void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
+ VisitOverloadExpr(E);
+ Record.push_back(E->isArrow());
+ Record.push_back(E->hasUnresolvedUsing());
+ Writer.AddStmt(!E->isImplicitAccess() ? E->getBase() : nullptr);
+ Writer.AddTypeRef(E->getBaseType(), Record);
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = serialization::EXPR_CXX_UNRESOLVED_MEMBER;
+}
+
+void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+ VisitOverloadExpr(E);
+ Record.push_back(E->requiresADL());
+ Record.push_back(E->isOverloaded());
+ Writer.AddDeclRef(E->getNamingClass(), Record);
+ Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
+}
+
+void ASTStmtWriter::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->TypeTraitExprBits.NumArgs);
+ Record.push_back(E->TypeTraitExprBits.Kind); // FIXME: Stable encoding
+ Record.push_back(E->TypeTraitExprBits.Value);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.AddTypeSourceInfo(E->getArg(I), Record);
+ Code = serialization::EXPR_TYPE_TRAIT;
+}
+
+void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getTrait());
+ Record.push_back(E->getValue());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddTypeSourceInfo(E->getQueriedTypeSourceInfo(), Record);
+ Code = serialization::EXPR_ARRAY_TYPE_TRAIT;
+}
+
+void ASTStmtWriter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getTrait());
+ Record.push_back(E->getValue());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddStmt(E->getQueriedExpression());
+ Code = serialization::EXPR_CXX_EXPRESSION_TRAIT;
+}
+
+void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddStmt(E->getOperand());
+ Code = serialization::EXPR_CXX_NOEXCEPT;
+}
+
+void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getEllipsisLoc(), Record);
+ Record.push_back(E->NumExpansions);
+ Writer.AddStmt(E->getPattern());
+ Code = serialization::EXPR_PACK_EXPANSION;
+}
+
+void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->OperatorLoc, Record);
+ Writer.AddSourceLocation(E->PackLoc, Record);
+ Writer.AddSourceLocation(E->RParenLoc, Record);
+ Record.push_back(E->Length);
+ Writer.AddDeclRef(E->Pack, Record);
+ Code = serialization::EXPR_SIZEOF_PACK;
+}
+
+void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getParameter(), Record);
+ Writer.AddSourceLocation(E->getNameLoc(), Record);
+ Writer.AddStmt(E->getReplacement());
+ Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM;
+}
+
+void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
+ SubstNonTypeTemplateParmPackExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getParameterPack(), Record);
+ Writer.AddTemplateArgument(E->getArgumentPack(), Record);
+ Writer.AddSourceLocation(E->getParameterPackLocation(), Record);
+ Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
+}
+
+void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumExpansions());
+ Writer.AddDeclRef(E->getParameterPack(), Record);
+ Writer.AddSourceLocation(E->getParameterPackLocation(), Record);
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = serialization::EXPR_FUNCTION_PARM_PACK;
+}
+
+void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getTemporary());
+ Writer.AddDeclRef(E->getExtendingDecl(), Record);
+ Record.push_back(E->getManglingNumber());
+ Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
+}
+
+void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->LParenLoc, Record);
+ Writer.AddSourceLocation(E->EllipsisLoc, Record);
+ Writer.AddSourceLocation(E->RParenLoc, Record);
+ Writer.AddStmt(E->SubExprs[0]);
+ Writer.AddStmt(E->SubExprs[1]);
+ Record.push_back(E->Opcode);
+ Code = serialization::EXPR_CXX_FOLD;
+}
+
+void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSourceExpr());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_OPAQUE_VALUE;
+}
+
+void ASTStmtWriter::VisitTypoExpr(TypoExpr *E) {
+ VisitExpr(E);
+ // TODO: Figure out sane writer behavior for a TypoExpr, if necessary
+ assert(false && "Cannot write TypoExpr nodes");
+}
+
+//===----------------------------------------------------------------------===//
+// CUDA Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
+ VisitCallExpr(E);
+ Writer.AddStmt(E->getConfig());
+ Code = serialization::EXPR_CUDA_KERNEL_CALL;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenCL Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddStmt(E->getSrcExpr());
+ Code = serialization::EXPR_ASTYPE;
+}
+
+//===----------------------------------------------------------------------===//
+// Microsoft Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isArrow());
+ Writer.AddStmt(E->getBaseExpr());
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Writer.AddDeclRef(E->getPropertyDecl(), Record);
+ Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR;
+}
+
+void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ if (E->isTypeOperand()) {
+ Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
+ Code = serialization::EXPR_CXX_UUIDOF_TYPE;
+ } else {
+ Writer.AddStmt(E->getExprOperand());
+ Code = serialization::EXPR_CXX_UUIDOF_EXPR;
+ }
+}
+
+void ASTStmtWriter::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getExceptLoc(), Record);
+ Writer.AddStmt(S->getFilterExpr());
+ Writer.AddStmt(S->getBlock());
+ Code = serialization::STMT_SEH_EXCEPT;
+}
+
+void ASTStmtWriter::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getFinallyLoc(), Record);
+ Writer.AddStmt(S->getBlock());
+ Code = serialization::STMT_SEH_FINALLY;
+}
+
+void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getIsCXXTry());
+ Writer.AddSourceLocation(S->getTryLoc(), Record);
+ Writer.AddStmt(S->getTryBlock());
+ Writer.AddStmt(S->getHandler());
+ Code = serialization::STMT_SEH_TRY;
+}
+
+void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getLeaveLoc(), Record);
+ Code = serialization::STMT_SEH_LEAVE;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Clauses.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+class OMPClauseWriter : public OMPClauseVisitor<OMPClauseWriter> {
+ ASTStmtWriter *Writer;
+ ASTWriter::RecordData &Record;
+public:
+ OMPClauseWriter(ASTStmtWriter *W, ASTWriter::RecordData &Record)
+ : Writer(W), Record(Record) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+ void writeClause(OMPClause *C);
+};
+}
+
+void OMPClauseWriter::writeClause(OMPClause *C) {
+ Record.push_back(C->getClauseKind());
+ Visit(C);
+ Writer->Writer.AddSourceLocation(C->getLocStart(), Record);
+ Writer->Writer.AddSourceLocation(C->getLocEnd(), Record);
+}
+
+void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) {
+ Writer->Writer.AddStmt(C->getCondition());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
+ Writer->Writer.AddStmt(C->getCondition());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ Writer->Writer.AddStmt(C->getNumThreads());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) {
+ Writer->Writer.AddStmt(C->getSafelen());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ Writer->Writer.AddStmt(C->getNumForLoops());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
+ Record.push_back(C->getDefaultKind());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
+ Record.push_back(C->getProcBindKind());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getProcBindKindKwLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ Record.push_back(C->getScheduleKind());
+ Writer->Writer.AddStmt(C->getChunkSize());
+ Writer->Writer.AddStmt(C->getHelperChunkSize());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getScheduleKindLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *) {}
+
+void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {}
+
+void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {}
+
+void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *) {}
+
+void OMPClauseWriter::VisitOMPReadClause(OMPReadClause *) {}
+
+void OMPClauseWriter::VisitOMPWriteClause(OMPWriteClause *) {}
+
+void OMPClauseWriter::VisitOMPUpdateClause(OMPUpdateClause *) {}
+
+void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {}
+
+void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
+
+void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->private_copies()) {
+ Writer->Writer.AddStmt(VE);
+ }
+}
+
+void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->private_copies()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->inits()) {
+ Writer->Writer.AddStmt(VE);
+ }
+}
+
+void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ for (auto *E : C->private_copies())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
+}
+
+void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(), Record);
+ Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ for (auto *E : C->lhs_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->rhs_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->reduction_ops())
+ Writer->Writer.AddStmt(E);
+}
+
+void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->inits()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->updates()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->finals()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ Writer->Writer.AddStmt(C->getStep());
+ Writer->Writer.AddStmt(C->getCalcStep());
+}
+
+void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ Writer->Writer.AddStmt(C->getAlignment());
+}
+
+void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
+}
+
+void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
+}
+
+void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP Directives.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
+ Writer.AddSourceLocation(E->getLocStart(), Record);
+ Writer.AddSourceLocation(E->getLocEnd(), Record);
+ OMPClauseWriter ClauseWriter(this, Record);
+ for (unsigned i = 0; i < E->getNumClauses(); ++i) {
+ ClauseWriter.writeClause(E->getClause(i));
+ }
+ if (E->hasAssociatedStmt())
+ Writer.AddStmt(E->getAssociatedStmt());
+}
+
+void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ Record.push_back(D->getCollapsedNumber());
+ VisitOMPExecutableDirective(D);
+ Writer.AddStmt(D->getIterationVariable());
+ Writer.AddStmt(D->getLastIteration());
+ Writer.AddStmt(D->getCalcLastIteration());
+ Writer.AddStmt(D->getPreCond());
+ Writer.AddStmt(D->getCond(/* SeparateIter */ false));
+ Writer.AddStmt(D->getCond(/* SeparateIter */ true));
+ Writer.AddStmt(D->getInit());
+ Writer.AddStmt(D->getInc());
+ if (isOpenMPWorksharingDirective(D->getDirectiveKind())) {
+ Writer.AddStmt(D->getIsLastIterVariable());
+ Writer.AddStmt(D->getLowerBoundVariable());
+ Writer.AddStmt(D->getUpperBoundVariable());
+ Writer.AddStmt(D->getStrideVariable());
+ Writer.AddStmt(D->getEnsureUpperBound());
+ Writer.AddStmt(D->getNextLowerBound());
+ Writer.AddStmt(D->getNextUpperBound());
+ }
+ for (auto I : D->counters()) {
+ Writer.AddStmt(I);
+ }
+ for (auto I : D->updates()) {
+ Writer.AddStmt(I);
+ }
+ for (auto I : D->finals()) {
+ Writer.AddStmt(I);
+ }
+}
+
+void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_FOR_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPForSimdDirective(OMPForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_FOR_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SECTIONS_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSectionDirective(OMPSectionDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SECTION_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSingleDirective(OMPSingleDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SINGLE_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPMasterDirective(OMPMasterDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_MASTER_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Writer.AddDeclarationNameInfo(D->getDirectiveName(), Record);
+ Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_FOR_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelForSimdDirective(
+ OMPParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASK_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPAtomicDirective(OMPAtomicDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Writer.AddStmt(D->getX());
+ Writer.AddStmt(D->getV());
+ Writer.AddStmt(D->getExpr());
+ Writer.AddStmt(D->getUpdateExpr());
+ Record.push_back(D->isXLHSInRHSPart() ? 1 : 0);
+ Record.push_back(D->isPostfixUpdate() ? 1 : 0);
+ Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTargetDirective(OMPTargetDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TARGET_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASKYIELD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPBarrierDirective(OMPBarrierDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_BARRIER_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPFlushDirective(OMPFlushDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_FLUSH_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPOrderedDirective(OMPOrderedDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_ORDERED_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTeamsDirective(OMPTeamsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TEAMS_DIRECTIVE;
+}
+
+//===----------------------------------------------------------------------===//
+// ASTWriter Implementation
+//===----------------------------------------------------------------------===//
+
+unsigned ASTWriter::RecordSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
+ "SwitchCase recorded twice");
+ unsigned NextID = SwitchCaseIDs.size();
+ SwitchCaseIDs[S] = NextID;
+ return NextID;
+}
+
+unsigned ASTWriter::getSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
+ "SwitchCase hasn't been seen yet");
+ return SwitchCaseIDs[S];
+}
+
+void ASTWriter::ClearSwitchCaseIDs() {
+ SwitchCaseIDs.clear();
+}
+
+/// \brief Write the given substatement or subexpression to the
+/// bitstream.
+void ASTWriter::WriteSubStmt(Stmt *S,
+ llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
+ llvm::DenseSet<Stmt *> &ParentStmts) {
+ RecordData Record;
+ ASTStmtWriter Writer(*this, Record);
+ ++NumStatements;
+
+ if (!S) {
+ Stream.EmitRecord(serialization::STMT_NULL_PTR, Record);
+ return;
+ }
+
+ llvm::DenseMap<Stmt *, uint64_t>::iterator I = SubStmtEntries.find(S);
+ if (I != SubStmtEntries.end()) {
+ Record.push_back(I->second);
+ Stream.EmitRecord(serialization::STMT_REF_PTR, Record);
+ return;
+ }
+
+#ifndef NDEBUG
+ assert(!ParentStmts.count(S) && "There is a Stmt cycle!");
+
+ struct ParentStmtInserterRAII {
+ Stmt *S;
+ llvm::DenseSet<Stmt *> &ParentStmts;
+
+ ParentStmtInserterRAII(Stmt *S, llvm::DenseSet<Stmt *> &ParentStmts)
+ : S(S), ParentStmts(ParentStmts) {
+ ParentStmts.insert(S);
+ }
+ ~ParentStmtInserterRAII() {
+ ParentStmts.erase(S);
+ }
+ };
+
+ ParentStmtInserterRAII ParentStmtInserter(S, ParentStmts);
+#endif
+
+ // Redirect ASTWriter::AddStmt to collect sub-stmts.
+ SmallVector<Stmt *, 16> SubStmts;
+ CollectedStmts = &SubStmts;
+
+ Writer.Code = serialization::STMT_NULL_PTR;
+ Writer.AbbrevToUse = 0;
+ Writer.Visit(S);
+
+#ifndef NDEBUG
+ if (Writer.Code == serialization::STMT_NULL_PTR) {
+ SourceManager &SrcMgr
+ = DeclIDs.begin()->first->getASTContext().getSourceManager();
+ S->dump(SrcMgr);
+ llvm_unreachable("Unhandled sub-statement writing AST file");
+ }
+#endif
+
+ // Revert ASTWriter::AddStmt.
+ CollectedStmts = &StmtsToEmit;
+
+ // Write the sub-stmts in reverse order, last to first. When reading them back
+ // we will read them in correct order by "pop"ing them from the Stmts stack.
+ // This simplifies reading and allows to store a variable number of sub-stmts
+ // without knowing it in advance.
+ while (!SubStmts.empty())
+ WriteSubStmt(SubStmts.pop_back_val(), SubStmtEntries, ParentStmts);
+
+ Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse);
+
+ SubStmtEntries[S] = Stream.GetCurrentBitNo();
+}
+
+/// \brief Flush all of the statements that have been added to the
+/// queue via AddStmt().
+void ASTWriter::FlushStmts() {
+ RecordData Record;
+
+ // We expect to be the only consumer of the two temporary statement maps,
+ // assert that they are empty.
+ assert(SubStmtEntries.empty() && "unexpected entries in sub-stmt map");
+ assert(ParentStmts.empty() && "unexpected entries in parent stmt map");
+
+ for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
+ WriteSubStmt(StmtsToEmit[I], SubStmtEntries, ParentStmts);
+
+ assert(N == StmtsToEmit.size() &&
+ "Substatement written via AddStmt rather than WriteSubStmt!");
+
+ // Note that we are at the end of a full expression. Any
+ // expression records that follow this one are part of a different
+ // expression.
+ Stream.EmitRecord(serialization::STMT_STOP, Record);
+
+ SubStmtEntries.clear();
+ ParentStmts.clear();
+ }
+
+ StmtsToEmit.clear();
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
new file mode 100644
index 0000000..b5031fd
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
@@ -0,0 +1,73 @@
+//===--- GeneratePCH.cpp - Sema Consumer for PCH Generation -----*- 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 PCHGenerator, which as a SemaConsumer that generates
+// a PCH file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTWriter.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+PCHGenerator::PCHGenerator(const Preprocessor &PP,
+ StringRef OutputFile,
+ clang::Module *Module,
+ StringRef isysroot,
+ raw_ostream *OS, bool AllowASTWithErrors)
+ : PP(PP), OutputFile(OutputFile), Module(Module),
+ isysroot(isysroot.str()), Out(OS),
+ SemaPtr(nullptr), Stream(Buffer), Writer(Stream),
+ AllowASTWithErrors(AllowASTWithErrors),
+ HasEmittedPCH(false) {
+}
+
+PCHGenerator::~PCHGenerator() {
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+ // Don't create a PCH if there were fatal failures during module loading.
+ if (PP.getModuleLoader().HadFatalFailure)
+ return;
+
+ bool hasErrors = PP.getDiagnostics().hasErrorOccurred();
+ if (hasErrors && !AllowASTWithErrors)
+ return;
+
+ // Emit the PCH file
+ assert(SemaPtr && "No Sema?");
+ Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, hasErrors);
+
+ // Write the generated bitstream to "Out".
+ Out->write((char *)&Buffer.front(), Buffer.size());
+
+ // Make sure it hits disk now.
+ Out->flush();
+
+ // Free up some memory, in case the process is kept alive.
+ Buffer.clear();
+
+ HasEmittedPCH = true;
+}
+
+ASTMutationListener *PCHGenerator::GetASTMutationListener() {
+ return &Writer;
+}
+
+ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
+ return &Writer;
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp
new file mode 100644
index 0000000..1b52b44
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -0,0 +1,886 @@
+//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the GlobalModuleIndex class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTReaderInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/Module.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include "llvm/Support/Path.h"
+#include <cstdio>
+using namespace clang;
+using namespace serialization;
+
+//----------------------------------------------------------------------------//
+// Shared constants
+//----------------------------------------------------------------------------//
+namespace {
+ enum {
+ /// \brief The block containing the index.
+ GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
+ };
+
+ /// \brief Describes the record types in the index.
+ enum IndexRecordTypes {
+ /// \brief Contains version information and potentially other metadata,
+ /// used to determine if we can read this global index file.
+ INDEX_METADATA,
+ /// \brief Describes a module, including its file name and dependencies.
+ MODULE,
+ /// \brief The index for identifiers.
+ IDENTIFIER_INDEX
+ };
+}
+
+/// \brief The name of the global index file.
+static const char * const IndexFileName = "modules.idx";
+
+/// \brief The global index file version.
+static const unsigned CurrentVersion = 1;
+
+//----------------------------------------------------------------------------//
+// Global module index reader.
+//----------------------------------------------------------------------------//
+
+namespace {
+
+/// \brief Trait used to read the identifier index from the on-disk hash
+/// table.
+class IdentifierIndexReaderTrait {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_type;
+ typedef SmallVector<unsigned, 2> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
+ return a == b;
+ }
+
+ static hash_value_type ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(a);
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
+ return StringRef((const char *)d, n);
+ }
+
+ static data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace llvm::support;
+
+ data_type Result;
+ while (DataLen > 0) {
+ unsigned ID = endian::readNext<uint32_t, little, unaligned>(d);
+ Result.push_back(ID);
+ DataLen -= 4;
+ }
+
+ return Result;
+ }
+};
+
+typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
+ IdentifierIndexTable;
+
+}
+
+GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ llvm::BitstreamCursor Cursor)
+ : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(),
+ NumIdentifierLookupHits() {
+ // Read the global index.
+ bool InGlobalIndexBlock = false;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ return;
+
+ case llvm::BitstreamEntry::EndBlock:
+ if (InGlobalIndexBlock) {
+ InGlobalIndexBlock = false;
+ Done = true;
+ continue;
+ }
+ return;
+
+
+ case llvm::BitstreamEntry::Record:
+ // Entries in the global index block are handled below.
+ if (InGlobalIndexBlock)
+ break;
+
+ return;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
+ if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
+ return;
+
+ InGlobalIndexBlock = true;
+ } else if (Cursor.SkipBlock()) {
+ return;
+ }
+ continue;
+ }
+
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
+ case INDEX_METADATA:
+ // Make sure that the version matches.
+ if (Record.size() < 1 || Record[0] != CurrentVersion)
+ return;
+ break;
+
+ case MODULE: {
+ unsigned Idx = 0;
+ unsigned ID = Record[Idx++];
+
+ // Make room for this module's information.
+ if (ID == Modules.size())
+ Modules.push_back(ModuleInfo());
+ else
+ Modules.resize(ID + 1);
+
+ // Size/modification time for this module file at the time the
+ // global index was built.
+ Modules[ID].Size = Record[Idx++];
+ Modules[ID].ModTime = Record[Idx++];
+
+ // File name.
+ unsigned NameLen = Record[Idx++];
+ Modules[ID].FileName.assign(Record.begin() + Idx,
+ Record.begin() + Idx + NameLen);
+ Idx += NameLen;
+
+ // Dependencies
+ unsigned NumDeps = Record[Idx++];
+ Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
+ Record.begin() + Idx,
+ Record.begin() + Idx + NumDeps);
+ Idx += NumDeps;
+
+ // Make sure we're at the end of the record.
+ assert(Idx == Record.size() && "More module info?");
+
+ // Record this module as an unresolved module.
+ // FIXME: this doesn't work correctly for module names containing path
+ // separators.
+ StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
+ // Remove the -<hash of ModuleMapPath>
+ ModuleName = ModuleName.rsplit('-').first;
+ UnresolvedModules[ModuleName] = ID;
+ break;
+ }
+
+ case IDENTIFIER_INDEX:
+ // Wire up the identifier index.
+ if (Record[0]) {
+ IdentifierIndex = IdentifierIndexTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
+ }
+ break;
+ }
+ }
+}
+
+GlobalModuleIndex::~GlobalModuleIndex() {
+ delete static_cast<IdentifierIndexTable *>(IdentifierIndex);
+}
+
+std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
+GlobalModuleIndex::readIndex(StringRef Path) {
+ // Load the index file, if it's there.
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =
+ llvm::MemoryBuffer::getFile(IndexPath.c_str());
+ if (!BufferOrErr)
+ return std::make_pair(nullptr, EC_NotFound);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
+
+ /// \brief The bitstream reader from which we'll read the AST file.
+ llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ /// \brief The main bitstream cursor for the main block.
+ llvm::BitstreamCursor Cursor(Reader);
+
+ // Sniff for the signature.
+ if (Cursor.Read(8) != 'B' ||
+ Cursor.Read(8) != 'C' ||
+ Cursor.Read(8) != 'G' ||
+ Cursor.Read(8) != 'I') {
+ return std::make_pair(nullptr, EC_IOError);
+ }
+
+ return std::make_pair(new GlobalModuleIndex(std::move(Buffer), Cursor),
+ EC_None);
+}
+
+void
+GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) {
+ ModuleFiles.clear();
+ for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ ModuleFiles.push_back(MF);
+ }
+}
+
+void GlobalModuleIndex::getModuleDependencies(
+ ModuleFile *File,
+ SmallVectorImpl<ModuleFile *> &Dependencies) {
+ // Look for information about this module file.
+ llvm::DenseMap<ModuleFile *, unsigned>::iterator Known
+ = ModulesByFile.find(File);
+ if (Known == ModulesByFile.end())
+ return;
+
+ // Record dependencies.
+ Dependencies.clear();
+ ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;
+ for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ Dependencies.push_back(MF);
+ }
+}
+
+bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
+ Hits.clear();
+
+ // If there's no identifier index, there is nothing we can do.
+ if (!IdentifierIndex)
+ return false;
+
+ // Look into the identifier index.
+ ++NumIdentifierLookups;
+ IdentifierIndexTable &Table
+ = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
+ IdentifierIndexTable::iterator Known = Table.find(Name);
+ if (Known == Table.end()) {
+ return true;
+ }
+
+ SmallVector<unsigned, 2> ModuleIDs = *Known;
+ for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[ModuleIDs[I]].File)
+ Hits.insert(MF);
+ }
+
+ ++NumIdentifierLookupHits;
+ return true;
+}
+
+bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
+ // Look for the module in the global module index based on the module name.
+ StringRef Name = File->ModuleName;
+ llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
+ if (Known == UnresolvedModules.end()) {
+ return true;
+ }
+
+ // Rectify this module with the global module index.
+ ModuleInfo &Info = Modules[Known->second];
+
+ // If the size and modification time match what we expected, record this
+ // module file.
+ bool Failed = true;
+ if (File->File->getSize() == Info.Size &&
+ File->File->getModificationTime() == Info.ModTime) {
+ Info.File = File;
+ ModulesByFile[File] = Known->second;
+
+ Failed = false;
+ }
+
+ // One way or another, we have resolved this module file.
+ UnresolvedModules.erase(Known);
+ return Failed;
+}
+
+void GlobalModuleIndex::printStats() {
+ std::fprintf(stderr, "*** Global Module Index Statistics:\n");
+ if (NumIdentifierLookups) {
+ fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+ std::fprintf(stderr, "\n");
+}
+
+void GlobalModuleIndex::dump() {
+ llvm::errs() << "*** Global Module Index Dump:\n";
+ llvm::errs() << "Module files:\n";
+ for (auto &MI : Modules) {
+ llvm::errs() << "** " << MI.FileName << "\n";
+ if (MI.File)
+ MI.File->dump();
+ else
+ llvm::errs() << "\n";
+ }
+ llvm::errs() << "\n";
+}
+
+//----------------------------------------------------------------------------//
+// Global module index writer.
+//----------------------------------------------------------------------------//
+
+namespace {
+ /// \brief Provides information about a specific module file.
+ struct ModuleFileInfo {
+ /// \brief The numberic ID for this module file.
+ unsigned ID;
+
+ /// \brief The set of modules on which this module depends. Each entry is
+ /// a module ID.
+ SmallVector<unsigned, 4> Dependencies;
+ };
+
+ /// \brief Builder that generates the global module index file.
+ class GlobalModuleIndexBuilder {
+ FileManager &FileMgr;
+
+ /// \brief Mapping from files to module file information.
+ typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
+
+ /// \brief Information about each of the known module files.
+ ModuleFilesMap ModuleFiles;
+
+ /// \brief Mapping from identifiers to the list of module file IDs that
+ /// consider this identifier to be interesting.
+ typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
+
+ /// \brief A mapping from all interesting identifiers to the set of module
+ /// files in which those identifiers are considered interesting.
+ InterestingIdentifierMap InterestingIdentifiers;
+
+ /// \brief Write the block-info block for the global module index file.
+ void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
+
+ /// \brief Retrieve the module file information for the given file.
+ ModuleFileInfo &getModuleFileInfo(const FileEntry *File) {
+ llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known
+ = ModuleFiles.find(File);
+ if (Known != ModuleFiles.end())
+ return Known->second;
+
+ unsigned NewID = ModuleFiles.size();
+ ModuleFileInfo &Info = ModuleFiles[File];
+ Info.ID = NewID;
+ return Info;
+ }
+
+ public:
+ explicit GlobalModuleIndexBuilder(FileManager &FileMgr) : FileMgr(FileMgr){}
+
+ /// \brief Load the contents of the given module file into the builder.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool loadModuleFile(const FileEntry *File);
+
+ /// \brief Write the index to the given bitstream.
+ void writeIndex(llvm::BitstreamWriter &Stream);
+ };
+}
+
+static void emitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (!Name || Name[0] == 0) return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void emitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+void
+GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
+ SmallVector<uint64_t, 64> Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) emitRecordID(X, #X, Stream, Record)
+ BLOCK(GLOBAL_INDEX_BLOCK);
+ RECORD(INDEX_METADATA);
+ RECORD(MODULE);
+ RECORD(IDENTIFIER_INDEX);
+#undef RECORD
+#undef BLOCK
+
+ Stream.ExitBlock();
+}
+
+namespace {
+ class InterestingASTIdentifierLookupTrait
+ : public serialization::reader::ASTIdentifierLookupTraitBase {
+
+ public:
+ /// \brief The identifier and whether it is "interesting".
+ typedef std::pair<StringRef, bool> data_type;
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ // The first bit indicates whether this identifier is interesting.
+ // That's all we care about.
+ using namespace llvm::support;
+ unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
+ bool IsInteresting = RawID & 0x01;
+ return std::make_pair(k, IsInteresting);
+ }
+ };
+}
+
+bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
+ // Open the module file.
+
+ auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the input stream
+ llvm::BitstreamReader InStreamFile;
+ InStreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
+ (const unsigned char *)(*Buffer)->getBufferEnd());
+ llvm::BitstreamCursor InStream(InStreamFile);
+
+ // Sniff for the signature.
+ if (InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'P' ||
+ InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'H') {
+ return true;
+ }
+
+ // Record this module file and assign it a unique ID (if it doesn't have
+ // one already).
+ unsigned ID = getModuleFileInfo(File).ID;
+
+ // Search for the blocks and records we care about.
+ enum { Other, ControlBlock, ASTBlock } State = Other;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = InStream.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Done = true;
+ continue;
+
+ case llvm::BitstreamEntry::Record:
+ // In the 'other' state, just skip the record. We don't care.
+ if (State == Other) {
+ InStream.skipRecord(Entry.ID);
+ continue;
+ }
+
+ // Handle potentially-interesting records below.
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == CONTROL_BLOCK_ID) {
+ if (InStream.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+
+ // Found the control block.
+ State = ControlBlock;
+ continue;
+ }
+
+ if (Entry.ID == AST_BLOCK_ID) {
+ if (InStream.EnterSubBlock(AST_BLOCK_ID))
+ return true;
+
+ // Found the AST block.
+ State = ASTBlock;
+ continue;
+ }
+
+ if (InStream.SkipBlock())
+ return true;
+
+ continue;
+
+ case llvm::BitstreamEntry::EndBlock:
+ State = Other;
+ continue;
+ }
+
+ // Read the given record.
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob);
+
+ // Handle module dependencies.
+ if (State == ControlBlock && Code == IMPORTS) {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+
+ // Skip the imported kind
+ ++Idx;
+
+ // Skip the import location
+ ++Idx;
+
+ // Load stored size/modification time.
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
+
+ // Skip the stored signature.
+ // FIXME: we could read the signature out of the import and validate it.
+ Idx++;
+
+ // Retrieve the imported file name.
+ unsigned Length = Record[Idx++];
+ SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Find the imported module file.
+ const FileEntry *DependsOnFile
+ = FileMgr.getFile(ImportedFile, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (!DependsOnFile ||
+ (StoredSize != DependsOnFile->getSize()) ||
+ (StoredModTime != DependsOnFile->getModificationTime()))
+ return true;
+
+ // Record the dependency.
+ unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
+ getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
+ }
+
+ continue;
+ }
+
+ // Handle the identifier table
+ if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
+ typedef llvm::OnDiskIterableChainedHashTable<
+ InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
+ std::unique_ptr<InterestingIdentifierTable> Table(
+ InterestingIdentifierTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data()));
+ for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
+ DEnd = Table->data_end();
+ D != DEnd; ++D) {
+ std::pair<StringRef, bool> Ident = *D;
+ if (Ident.second)
+ InterestingIdentifiers[Ident.first].push_back(ID);
+ else
+ (void)InterestingIdentifiers[Ident.first];
+ }
+ }
+
+ // We don't care about this record.
+ }
+
+ return false;
+}
+
+namespace {
+
+/// \brief Trait used to generate the identifier index as an on-disk hash
+/// table.
+class IdentifierIndexWriterTrait {
+public:
+ typedef StringRef key_type;
+ typedef StringRef key_type_ref;
+ typedef SmallVector<unsigned, 2> data_type;
+ typedef const SmallVector<unsigned, 2> &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(key_type_ref Key) {
+ return llvm::HashString(Key);
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ unsigned KeyLen = Key.size();
+ unsigned DataLen = Data.size() * 4;
+ LE.write<uint16_t>(KeyLen);
+ LE.write<uint16_t>(DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ Out.write(Key.data(), KeyLen);
+ }
+
+ void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned DataLen) {
+ using namespace llvm::support;
+ for (unsigned I = 0, N = Data.size(); I != N; ++I)
+ endian::Writer<little>(Out).write<uint32_t>(Data[I]);
+ }
+};
+
+}
+
+void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+
+ // Emit the file header.
+ Stream.Emit((unsigned)'B', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'G', 8);
+ Stream.Emit((unsigned)'I', 8);
+
+ // Write the block-info block, which describes the records in this bitcode
+ // file.
+ emitBlockInfoBlock(Stream);
+
+ Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
+
+ // Write the metadata.
+ SmallVector<uint64_t, 2> Record;
+ Record.push_back(CurrentVersion);
+ Stream.EmitRecord(INDEX_METADATA, Record);
+
+ // Write the set of known module files.
+ for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
+ MEnd = ModuleFiles.end();
+ M != MEnd; ++M) {
+ Record.clear();
+ Record.push_back(M->second.ID);
+ Record.push_back(M->first->getSize());
+ Record.push_back(M->first->getModificationTime());
+
+ // File name
+ StringRef Name(M->first->getName());
+ Record.push_back(Name.size());
+ Record.append(Name.begin(), Name.end());
+
+ // Dependencies
+ Record.push_back(M->second.Dependencies.size());
+ Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
+ Stream.EmitRecord(MODULE, Record);
+ }
+
+ // Write the identifier -> module file mapping.
+ {
+ llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
+ IdentifierIndexWriterTrait Trait;
+
+ // Populate the hash table.
+ for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
+ IEnd = InterestingIdentifiers.end();
+ I != IEnd; ++I) {
+ Generator.insert(I->first(), I->second, Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ using namespace llvm::support;
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ Record.clear();
+ Record.push_back(IDENTIFIER_INDEX);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
+ }
+
+ Stream.ExitBlock();
+}
+
+GlobalModuleIndex::ErrorCode
+GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ // Coordinate building the global index file with other processes that might
+ // try to do the same.
+ llvm::LockFileManager Locked(IndexPath);
+ switch (Locked) {
+ case llvm::LockFileManager::LFS_Error:
+ return EC_IOError;
+
+ case llvm::LockFileManager::LFS_Owned:
+ // We're responsible for building the index ourselves. Do so below.
+ break;
+
+ case llvm::LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the index. We don't care
+ // when they finish, so we're done.
+ return EC_Building;
+ }
+
+ // The module index builder.
+ GlobalModuleIndexBuilder Builder(FileMgr);
+
+ // Load each of the module files.
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
+ D != DEnd && !EC;
+ D.increment(EC)) {
+ // If this isn't a module file, we don't care.
+ if (llvm::sys::path::extension(D->path()) != ".pcm") {
+ // ... unless it's a .pcm.lock file, which indicates that someone is
+ // in the process of rebuilding a module. They'll rebuild the index
+ // at the end of that translation unit, so we don't have to.
+ if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
+ return EC_Building;
+
+ continue;
+ }
+
+ // If we can't find the module file, skip it.
+ const FileEntry *ModuleFile = FileMgr.getFile(D->path());
+ if (!ModuleFile)
+ continue;
+
+ // Load this module file.
+ if (Builder.loadModuleFile(ModuleFile))
+ return EC_IOError;
+ }
+
+ // The output buffer, into which the global index will be written.
+ SmallVector<char, 16> OutputBuffer;
+ {
+ llvm::BitstreamWriter OutputStream(OutputBuffer);
+ Builder.writeIndex(OutputStream);
+ }
+
+ // Write the global index file to a temporary file.
+ llvm::SmallString<128> IndexTmpPath;
+ int TmpFD;
+ if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD,
+ IndexTmpPath))
+ return EC_IOError;
+
+ // Open the temporary global index file for output.
+ llvm::raw_fd_ostream Out(TmpFD, true);
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Write the index.
+ Out.write(OutputBuffer.data(), OutputBuffer.size());
+ Out.close();
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Remove the old index file. It isn't relevant any more.
+ llvm::sys::fs::remove(IndexPath);
+
+ // Rename the newly-written index file to the proper name.
+ if (llvm::sys::fs::rename(IndexTmpPath, IndexPath)) {
+ // Rename failed; just remove the
+ llvm::sys::fs::remove(IndexTmpPath);
+ return EC_IOError;
+ }
+
+ // We're done.
+ return EC_None;
+}
+
+namespace {
+ class GlobalIndexIdentifierIterator : public IdentifierIterator {
+ /// \brief The current position within the identifier lookup table.
+ IdentifierIndexTable::key_iterator Current;
+
+ /// \brief The end position within the identifier lookup table.
+ IdentifierIndexTable::key_iterator End;
+
+ public:
+ explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {
+ Current = Idx.key_begin();
+ End = Idx.key_end();
+ }
+
+ StringRef Next() override {
+ if (Current == End)
+ return StringRef();
+
+ StringRef Result = *Current;
+ ++Current;
+ return Result;
+ }
+ };
+}
+
+IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const {
+ IdentifierIndexTable &Table =
+ *static_cast<IdentifierIndexTable *>(IdentifierIndex);
+ return new GlobalIndexIdentifierIterator(Table);
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
new file mode 100644
index 0000000..3b237d5
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
@@ -0,0 +1,123 @@
+//===--- Module.cpp - Module description ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Module class, which describes a module that has
+// been loaded from an AST file.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Serialization/Module.h"
+#include "ASTReaderInternals.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace serialization;
+using namespace reader;
+
+ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
+ : Kind(Kind), File(nullptr), Signature(0), DirectlyImported(false),
+ Generation(Generation), SizeInBits(0),
+ LocalNumSLocEntries(0), SLocEntryBaseID(0),
+ SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr),
+ LocalNumIdentifiers(0),
+ IdentifierOffsets(nullptr), BaseIdentifierID(0),
+ IdentifierTableData(nullptr), IdentifierLookupTable(nullptr),
+ LocalNumMacros(0), MacroOffsets(nullptr),
+ BasePreprocessedEntityID(0),
+ PreprocessedEntityOffsets(nullptr), NumPreprocessedEntities(0),
+ LocalNumHeaderFileInfos(0),
+ HeaderFileInfoTableData(nullptr), HeaderFileInfoTable(nullptr),
+ LocalNumSubmodules(0), BaseSubmoduleID(0),
+ LocalNumSelectors(0), SelectorOffsets(nullptr), BaseSelectorID(0),
+ SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr),
+ LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0),
+ LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr),
+ LocalNumCXXCtorInitializers(0), CXXCtorInitializersOffsets(nullptr),
+ FileSortedDecls(nullptr), NumFileSortedDecls(0),
+ RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0),
+ ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),
+ LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0)
+{}
+
+ModuleFile::~ModuleFile() {
+ for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(),
+ E = DeclContextInfos.end();
+ I != E; ++I) {
+ if (I->second.NameLookupTableData)
+ delete I->second.NameLookupTableData;
+ }
+
+ delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable);
+ delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
+ delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable);
+}
+
+template<typename Key, typename Offset, unsigned InitialCapacity>
+static void
+dumpLocalRemap(StringRef Name,
+ const ContinuousRangeMap<Key, Offset, InitialCapacity> &Map) {
+ if (Map.begin() == Map.end())
+ return;
+
+ typedef ContinuousRangeMap<Key, Offset, InitialCapacity> MapType;
+ llvm::errs() << " " << Name << ":\n";
+ for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
+ I != IEnd; ++I) {
+ llvm::errs() << " " << I->first << " -> " << I->second << "\n";
+ }
+}
+
+void ModuleFile::dump() {
+ llvm::errs() << "\nModule: " << FileName << "\n";
+ if (!Imports.empty()) {
+ llvm::errs() << " Imports: ";
+ for (unsigned I = 0, N = Imports.size(); I != N; ++I) {
+ if (I)
+ llvm::errs() << ", ";
+ llvm::errs() << Imports[I]->FileName;
+ }
+ llvm::errs() << "\n";
+ }
+
+ // Remapping tables.
+ llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset
+ << '\n';
+ dumpLocalRemap("Source location offset local -> global map", SLocRemap);
+
+ llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n'
+ << " Number of identifiers: " << LocalNumIdentifiers << '\n';
+ dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap);
+
+ llvm::errs() << " Base macro ID: " << BaseMacroID << '\n'
+ << " Number of macros: " << LocalNumMacros << '\n';
+ dumpLocalRemap("Macro ID local -> global map", MacroRemap);
+
+ llvm::errs() << " Base submodule ID: " << BaseSubmoduleID << '\n'
+ << " Number of submodules: " << LocalNumSubmodules << '\n';
+ dumpLocalRemap("Submodule ID local -> global map", SubmoduleRemap);
+
+ llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n'
+ << " Number of selectors: " << LocalNumSelectors << '\n';
+ dumpLocalRemap("Selector ID local -> global map", SelectorRemap);
+
+ llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID
+ << '\n'
+ << " Number of preprocessed entities: "
+ << NumPreprocessedEntities << '\n';
+ dumpLocalRemap("Preprocessed entity ID local -> global map",
+ PreprocessedEntityRemap);
+
+ llvm::errs() << " Base type index: " << BaseTypeIndex << '\n'
+ << " Number of types: " << LocalNumTypes << '\n';
+ dumpLocalRemap("Type index local -> global map", TypeRemap);
+
+ llvm::errs() << " Base decl ID: " << BaseDeclID << '\n'
+ << " Number of decls: " << LocalNumDecls << '\n';
+ dumpLocalRemap("Decl ID local -> global map", DeclRemap);
+}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
new file mode 100644
index 0000000..30d9c89
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
@@ -0,0 +1,540 @@
+//===--- ModuleManager.cpp - Module Manager ---------------------*- 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 ModuleManager class, which manages a set of loaded
+// modules for the ASTReader.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/ModuleMap.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+#ifndef NDEBUG
+#include "llvm/Support/GraphWriter.h"
+#endif
+
+using namespace clang;
+using namespace serialization;
+
+ModuleFile *ModuleManager::lookup(StringRef Name) {
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (Entry)
+ return lookup(Entry);
+
+ return nullptr;
+}
+
+ModuleFile *ModuleManager::lookup(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
+ = Modules.find(File);
+ if (Known == Modules.end())
+ return nullptr;
+
+ return Known->second;
+}
+
+std::unique_ptr<llvm::MemoryBuffer>
+ModuleManager::lookupBuffer(StringRef Name) {
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ return std::move(InMemoryBuffers[Entry]);
+}
+
+ModuleManager::AddModuleResult
+ModuleManager::addModule(StringRef FileName, ModuleKind Type,
+ SourceLocation ImportLoc, ModuleFile *ImportedBy,
+ unsigned Generation,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ASTFileSignature ExpectedSignature,
+ ASTFileSignatureReader ReadSignature,
+ ModuleFile *&Module,
+ std::string &ErrorStr) {
+ Module = nullptr;
+
+ // Look for the file entry. This only fails if the expected size or
+ // modification time differ.
+ const FileEntry *Entry;
+ if (Type == MK_ExplicitModule) {
+ // If we're not expecting to pull this file out of the module cache, it
+ // might have a different mtime due to being moved across filesystems in
+ // a distributed build. The size must still match, though. (As must the
+ // contents, but we can't check that.)
+ ExpectedModTime = 0;
+ }
+ if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
+ ErrorStr = "module file out of date";
+ return OutOfDate;
+ }
+
+ if (!Entry && FileName != "-") {
+ ErrorStr = "module file not found";
+ return Missing;
+ }
+
+ // Check whether we already loaded this module, before
+ ModuleFile *&ModuleEntry = Modules[Entry];
+ bool NewModule = false;
+ if (!ModuleEntry) {
+ // Allocate a new module.
+ ModuleFile *New = new ModuleFile(Type, Generation);
+ New->Index = Chain.size();
+ New->FileName = FileName.str();
+ New->File = Entry;
+ New->ImportLoc = ImportLoc;
+ Chain.push_back(New);
+ if (!ImportedBy)
+ Roots.push_back(New);
+ NewModule = true;
+ ModuleEntry = New;
+
+ New->InputFilesValidationTimestamp = 0;
+ if (New->Kind == MK_ImplicitModule) {
+ std::string TimestampFilename = New->getTimestampFilename();
+ vfs::Status Status;
+ // A cached stat value would be fine as well.
+ if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
+ New->InputFilesValidationTimestamp =
+ Status.getLastModificationTime().toEpochTime();
+ }
+
+ // Load the contents of the module
+ if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
+ // The buffer was already provided for us.
+ New->Buffer = std::move(Buffer);
+ } else {
+ // Open the AST file.
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf(
+ (std::error_code()));
+ if (FileName == "-") {
+ Buf = llvm::MemoryBuffer::getSTDIN();
+ } else {
+ // Leave the FileEntry open so if it gets read again by another
+ // ModuleManager it must be the same underlying file.
+ // FIXME: Because FileManager::getFile() doesn't guarantee that it will
+ // give us an open file, this may not be 100% reliable.
+ Buf = FileMgr.getBufferForFile(New->File,
+ /*IsVolatile=*/false,
+ /*ShouldClose=*/false);
+ }
+
+ if (!Buf) {
+ ErrorStr = Buf.getError().message();
+ return Missing;
+ }
+
+ New->Buffer = std::move(*Buf);
+ }
+
+ // Initialize the stream
+ New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
+ (const unsigned char *)New->Buffer->getBufferEnd());
+ }
+
+ if (ExpectedSignature) {
+ if (NewModule)
+ ModuleEntry->Signature = ReadSignature(ModuleEntry->StreamFile);
+ else
+ assert(ModuleEntry->Signature == ReadSignature(ModuleEntry->StreamFile));
+
+ if (ModuleEntry->Signature != ExpectedSignature) {
+ ErrorStr = ModuleEntry->Signature ? "signature mismatch"
+ : "could not read module signature";
+
+ if (NewModule) {
+ // Remove the module file immediately, since removeModules might try to
+ // invalidate the file cache for Entry, and that is not safe if this
+ // module is *itself* up to date, but has an out-of-date importer.
+ Modules.erase(Entry);
+ assert(Chain.back() == ModuleEntry);
+ Chain.pop_back();
+ if (Roots.back() == ModuleEntry)
+ Roots.pop_back();
+ else
+ assert(ImportedBy);
+ delete ModuleEntry;
+ }
+ return OutOfDate;
+ }
+ }
+
+ if (ImportedBy) {
+ ModuleEntry->ImportedBy.insert(ImportedBy);
+ ImportedBy->Imports.insert(ModuleEntry);
+ } else {
+ if (!ModuleEntry->DirectlyImported)
+ ModuleEntry->ImportLoc = ImportLoc;
+
+ ModuleEntry->DirectlyImported = true;
+ }
+
+ Module = ModuleEntry;
+ return NewModule? NewlyLoaded : AlreadyLoaded;
+}
+
+void ModuleManager::removeModules(
+ ModuleIterator first, ModuleIterator last,
+ llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
+ ModuleMap *modMap) {
+ if (first == last)
+ return;
+
+ // Collect the set of module file pointers that we'll be removing.
+ llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
+
+ auto IsVictim = [&](ModuleFile *MF) {
+ return victimSet.count(MF);
+ };
+ // Remove any references to the now-destroyed modules.
+ for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
+ Chain[i]->ImportedBy.remove_if(IsVictim);
+ }
+ Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
+ Roots.end());
+
+ // Delete the modules and erase them from the various structures.
+ for (ModuleIterator victim = first; victim != last; ++victim) {
+ Modules.erase((*victim)->File);
+
+ if (modMap) {
+ StringRef ModuleName = (*victim)->ModuleName;
+ if (Module *mod = modMap->findModule(ModuleName)) {
+ mod->setASTFile(nullptr);
+ }
+ }
+
+ // Files that didn't make it through ReadASTCore successfully will be
+ // rebuilt (or there was an error). Invalidate them so that we can load the
+ // new files that will be renamed over the old ones.
+ if (LoadedSuccessfully.count(*victim) == 0)
+ FileMgr.invalidateCache((*victim)->File);
+
+ delete *victim;
+ }
+
+ // Remove the modules from the chain.
+ Chain.erase(first, last);
+}
+
+void
+ModuleManager::addInMemoryBuffer(StringRef FileName,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+
+ const FileEntry *Entry =
+ FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
+ InMemoryBuffers[Entry] = std::move(Buffer);
+}
+
+bool ModuleManager::addKnownModuleFile(StringRef FileName) {
+ const FileEntry *File;
+ if (lookupModuleFile(FileName, 0, 0, File))
+ return true;
+ if (!Modules.count(File))
+ AdditionalKnownModuleFiles.insert(File);
+ return false;
+}
+
+ModuleManager::VisitState *ModuleManager::allocateVisitState() {
+ // Fast path: if we have a cached state, use it.
+ if (FirstVisitState) {
+ VisitState *Result = FirstVisitState;
+ FirstVisitState = FirstVisitState->NextState;
+ Result->NextState = nullptr;
+ return Result;
+ }
+
+ // Allocate and return a new state.
+ return new VisitState(size());
+}
+
+void ModuleManager::returnVisitState(VisitState *State) {
+ assert(State->NextState == nullptr && "Visited state is in list?");
+ State->NextState = FirstVisitState;
+ FirstVisitState = State;
+}
+
+void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
+ GlobalIndex = Index;
+ if (!GlobalIndex) {
+ ModulesInCommonWithGlobalIndex.clear();
+ return;
+ }
+
+ // Notify the global module index about all of the modules we've already
+ // loaded.
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (!GlobalIndex->loadedModuleFile(Chain[I])) {
+ ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
+ }
+ }
+}
+
+void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
+ AdditionalKnownModuleFiles.remove(MF->File);
+
+ if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
+ return;
+
+ ModulesInCommonWithGlobalIndex.push_back(MF);
+}
+
+ModuleManager::ModuleManager(FileManager &FileMgr)
+ : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(nullptr) {}
+
+ModuleManager::~ModuleManager() {
+ for (unsigned i = 0, e = Chain.size(); i != e; ++i)
+ delete Chain[e - i - 1];
+ delete FirstVisitState;
+}
+
+void
+ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
+ void *UserData,
+ llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
+ // If the visitation order vector is the wrong size, recompute the order.
+ if (VisitOrder.size() != Chain.size()) {
+ unsigned N = size();
+ VisitOrder.clear();
+ VisitOrder.reserve(N);
+
+ // Record the number of incoming edges for each module. When we
+ // encounter a module with no incoming edges, push it into the queue
+ // to seed the queue.
+ SmallVector<ModuleFile *, 4> Queue;
+ Queue.reserve(N);
+ llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
+ UnusedIncomingEdges.reserve(size());
+ for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
+ if (unsigned Size = (*M)->ImportedBy.size())
+ UnusedIncomingEdges.push_back(Size);
+ else {
+ UnusedIncomingEdges.push_back(0);
+ Queue.push_back(*M);
+ }
+ }
+
+ // Traverse the graph, making sure to visit a module before visiting any
+ // of its dependencies.
+ unsigned QueueStart = 0;
+ while (QueueStart < Queue.size()) {
+ ModuleFile *CurrentModule = Queue[QueueStart++];
+ VisitOrder.push_back(CurrentModule);
+
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
+ M = CurrentModule->Imports.begin(),
+ MEnd = CurrentModule->Imports.end();
+ M != MEnd; ++M) {
+ // Remove our current module as an impediment to visiting the
+ // module we depend on. If we were the last unvisited module
+ // that depends on this particular module, push it into the
+ // queue to be visited.
+ unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
+ if (NumUnusedEdges && (--NumUnusedEdges == 0))
+ Queue.push_back(*M);
+ }
+ }
+
+ assert(VisitOrder.size() == N && "Visitation order is wrong?");
+
+ delete FirstVisitState;
+ FirstVisitState = nullptr;
+ }
+
+ VisitState *State = allocateVisitState();
+ unsigned VisitNumber = State->NextVisitNumber++;
+
+ // If the caller has provided us with a hit-set that came from the global
+ // module index, mark every module file in common with the global module
+ // index that is *not* in that set as 'visited'.
+ if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
+ for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
+ {
+ ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
+ if (!ModuleFilesHit->count(M))
+ State->VisitNumber[M->Index] = VisitNumber;
+ }
+ }
+
+ for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
+ ModuleFile *CurrentModule = VisitOrder[I];
+ // Should we skip this module file?
+ if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
+ continue;
+
+ // Visit the module.
+ assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
+ State->VisitNumber[CurrentModule->Index] = VisitNumber;
+ if (!Visitor(*CurrentModule, UserData))
+ continue;
+
+ // The visitor has requested that cut off visitation of any
+ // module that the current module depends on. To indicate this
+ // behavior, we mark all of the reachable modules as having been visited.
+ ModuleFile *NextModule = CurrentModule;
+ do {
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
+ M = NextModule->Imports.begin(),
+ MEnd = NextModule->Imports.end();
+ M != MEnd; ++M) {
+ if (State->VisitNumber[(*M)->Index] != VisitNumber) {
+ State->Stack.push_back(*M);
+ State->VisitNumber[(*M)->Index] = VisitNumber;
+ }
+ }
+
+ if (State->Stack.empty())
+ break;
+
+ // Pop the next module off the stack.
+ NextModule = State->Stack.pop_back_val();
+ } while (true);
+ }
+
+ returnVisitState(State);
+}
+
+static void markVisitedDepthFirst(ModuleFile &M,
+ SmallVectorImpl<bool> &Visited) {
+ for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
+ IMEnd = M.Imports.end();
+ IM != IMEnd; ++IM) {
+ if (Visited[(*IM)->Index])
+ continue;
+ Visited[(*IM)->Index] = true;
+ if (!M.DirectlyImported)
+ markVisitedDepthFirst(**IM, Visited);
+ }
+}
+
+/// \brief Perform a depth-first visit of the current module.
+static bool visitDepthFirst(
+ ModuleFile &M,
+ ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M,
+ void *UserData),
+ bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData,
+ SmallVectorImpl<bool> &Visited) {
+ if (PreorderVisitor) {
+ switch (PreorderVisitor(M, UserData)) {
+ case ModuleManager::Abort:
+ return true;
+ case ModuleManager::SkipImports:
+ markVisitedDepthFirst(M, Visited);
+ return false;
+ case ModuleManager::Continue:
+ break;
+ }
+ }
+
+ // Visit children
+ for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
+ IMEnd = M.Imports.end();
+ IM != IMEnd; ++IM) {
+ if (Visited[(*IM)->Index])
+ continue;
+ Visited[(*IM)->Index] = true;
+
+ if (visitDepthFirst(**IM, PreorderVisitor, PostorderVisitor, UserData, Visited))
+ return true;
+ }
+
+ if (PostorderVisitor)
+ return PostorderVisitor(M, UserData);
+
+ return false;
+}
+
+void ModuleManager::visitDepthFirst(
+ ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M,
+ void *UserData),
+ bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData) {
+ SmallVector<bool, 16> Visited(size(), false);
+ for (unsigned I = 0, N = Roots.size(); I != N; ++I) {
+ if (Visited[Roots[I]->Index])
+ continue;
+ Visited[Roots[I]->Index] = true;
+
+ if (::visitDepthFirst(*Roots[I], PreorderVisitor, PostorderVisitor, UserData, Visited))
+ return;
+ }
+}
+
+bool ModuleManager::lookupModuleFile(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ const FileEntry *&File) {
+ // Open the file immediately to ensure there is no race between stat'ing and
+ // opening the file.
+ File = FileMgr.getFile(FileName, /*openFile=*/true, /*cacheFailure=*/false);
+
+ if (!File && FileName != "-") {
+ return false;
+ }
+
+ if ((ExpectedSize && ExpectedSize != File->getSize()) ||
+ (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
+ // Do not destroy File, as it may be referenced. If we need to rebuild it,
+ // it will be destroyed by removeModules.
+ return true;
+
+ return false;
+}
+
+#ifndef NDEBUG
+namespace llvm {
+ template<>
+ struct GraphTraits<ModuleManager> {
+ typedef ModuleFile NodeType;
+ typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
+ typedef ModuleManager::ModuleConstIterator nodes_iterator;
+
+ static ChildIteratorType child_begin(NodeType *Node) {
+ return Node->Imports.begin();
+ }
+
+ static ChildIteratorType child_end(NodeType *Node) {
+ return Node->Imports.end();
+ }
+
+ static nodes_iterator nodes_begin(const ModuleManager &Manager) {
+ return Manager.begin();
+ }
+
+ static nodes_iterator nodes_end(const ModuleManager &Manager) {
+ return Manager.end();
+ }
+ };
+
+ template<>
+ struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
+ explicit DOTGraphTraits(bool IsSimple = false)
+ : DefaultDOTGraphTraits(IsSimple) { }
+
+ static bool renderGraphFromBottomUp() {
+ return true;
+ }
+
+ std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
+ return M->ModuleName;
+ }
+ };
+}
+
+void ModuleManager::viewGraph() {
+ llvm::ViewGraph(*this, "Modules");
+}
+#endif
OpenPOWER on IntegriCloud