diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization')
16 files changed, 35045 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 000000000000..ca826d83d471 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp @@ -0,0 +1,445 @@ +//===--- 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/Support/DJB.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::ShortAccum: + ID = PREDEF_TYPE_SHORT_ACCUM_ID; + break; + case BuiltinType::Accum: + ID = PREDEF_TYPE_ACCUM_ID; + break; + case BuiltinType::LongAccum: + ID = PREDEF_TYPE_LONG_ACCUM_ID; + break; + case BuiltinType::UShortAccum: + ID = PREDEF_TYPE_USHORT_ACCUM_ID; + break; + case BuiltinType::UAccum: + ID = PREDEF_TYPE_UACCUM_ID; + break; + case BuiltinType::ULongAccum: + ID = PREDEF_TYPE_ULONG_ACCUM_ID; + break; + case BuiltinType::ShortFract: + ID = PREDEF_TYPE_SHORT_FRACT_ID; + break; + case BuiltinType::Fract: + ID = PREDEF_TYPE_FRACT_ID; + break; + case BuiltinType::LongFract: + ID = PREDEF_TYPE_LONG_FRACT_ID; + break; + case BuiltinType::UShortFract: + ID = PREDEF_TYPE_USHORT_FRACT_ID; + break; + case BuiltinType::UFract: + ID = PREDEF_TYPE_UFRACT_ID; + break; + case BuiltinType::ULongFract: + ID = PREDEF_TYPE_ULONG_FRACT_ID; + break; + case BuiltinType::SatShortAccum: + ID = PREDEF_TYPE_SAT_SHORT_ACCUM_ID; + break; + case BuiltinType::SatAccum: + ID = PREDEF_TYPE_SAT_ACCUM_ID; + break; + case BuiltinType::SatLongAccum: + ID = PREDEF_TYPE_SAT_LONG_ACCUM_ID; + break; + case BuiltinType::SatUShortAccum: + ID = PREDEF_TYPE_SAT_USHORT_ACCUM_ID; + break; + case BuiltinType::SatUAccum: + ID = PREDEF_TYPE_SAT_UACCUM_ID; + break; + case BuiltinType::SatULongAccum: + ID = PREDEF_TYPE_SAT_ULONG_ACCUM_ID; + break; + case BuiltinType::SatShortFract: + ID = PREDEF_TYPE_SAT_SHORT_FRACT_ID; + break; + case BuiltinType::SatFract: + ID = PREDEF_TYPE_SAT_FRACT_ID; + break; + case BuiltinType::SatLongFract: + ID = PREDEF_TYPE_SAT_LONG_FRACT_ID; + break; + case BuiltinType::SatUShortFract: + ID = PREDEF_TYPE_SAT_USHORT_FRACT_ID; + break; + case BuiltinType::SatUFract: + ID = PREDEF_TYPE_SAT_UFRACT_ID; + break; + case BuiltinType::SatULongFract: + ID = PREDEF_TYPE_SAT_ULONG_FRACT_ID; + break; + case BuiltinType::Float16: + ID = PREDEF_TYPE_FLOAT16_ID; + break; + case BuiltinType::Float128: + ID = PREDEF_TYPE_FLOAT128_ID; + break; + case BuiltinType::NullPtr: + ID = PREDEF_TYPE_NULLPTR_ID; + break; + case BuiltinType::Char8: + ID = PREDEF_TYPE_CHAR8_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; +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: \ + ID = PREDEF_TYPE_##Id##_ID; \ + break; +#include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + case BuiltinType::Id: \ + ID = PREDEF_TYPE_##Id##_ID; \ + break; +#include "clang/Basic/OpenCLExtensionTypes.def" + case BuiltinType::OCLSampler: + ID = PREDEF_TYPE_SAMPLER_ID; + break; + case BuiltinType::OCLEvent: + ID = PREDEF_TYPE_EVENT_ID; + break; + case BuiltinType::OCLClkEvent: + ID = PREDEF_TYPE_CLK_EVENT_ID; + break; + case BuiltinType::OCLQueue: + ID = PREDEF_TYPE_QUEUE_ID; + break; + case BuiltinType::OCLReserveID: + ID = PREDEF_TYPE_RESERVE_ID_ID; + break; + case BuiltinType::BuiltinFn: + ID = PREDEF_TYPE_BUILTIN_FN; + break; + case BuiltinType::OMPArraySection: + ID = PREDEF_TYPE_OMP_ARRAY_SECTION; + 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::djbHash(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: + case Decl::Export: + 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::CXXDeductionGuide: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::UsingShadow: + case Decl::ConstructorUsingShadow: + 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::UsingPack: + case Decl::ObjCMethod: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCProperty: + case Decl::ObjCCompatibleAlias: + case Decl::LinkageSpec: + case Decl::Export: + case Decl::ObjCPropertyImpl: + case Decl::PragmaComment: + case Decl::PragmaDetectMismatch: + 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: + case Decl::OMPRequires: + case Decl::OMPCapturedExpr: + case Decl::OMPDeclareReduction: + case Decl::BuiltinTemplate: + case Decl::Decomposition: + case Decl::Binding: + return false; + + // These indirectly derive from Redeclarable<T> but are not actually + // redeclarable. + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::ObjCTypeParam: + 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; + } + + // At block scope, we number everything that we need to deduplicate, since we + // can't just use name matching to keep things lined up. + // FIXME: This is only necessary for an inline function or a template or + // similar. + if (D->getLexicalDeclContext()->isFunctionOrMethod()) { + if (auto *VD = dyn_cast<VarDecl>(D)) + return VD->isStaticLocal(); + // FIXME: What about CapturedDecls (and declarations nested within them)? + return isa<TagDecl>(D) || isa<BlockDecl>(D); + } + + // Otherwise, we only care about anonymous class members / block-scope decls. + // FIXME: We need to handle lambdas and blocks within inline / templated + // variables too. + 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 000000000000..12e26c1fc2b9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h @@ -0,0 +1,116 @@ +//===- 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_ADDED_VAR_DEFINITION, + UPD_CXX_POINT_OF_INSTANTIATION, + UPD_CXX_INSTANTIATED_CLASS_DEFINITION, + UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, + UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, + 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_MARKED_OPENMP_DECLARETARGET, + UPD_DECL_EXPORTED, + UPD_ADDED_ATTR_TO_RECORD +}; + +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); + + return IdxForType(T).asTypeID(FastQuals); +} + +unsigned ComputeHash(Selector Sel); + +/// 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); + +/// Determine whether the given declaration kind is redeclarable. +bool isRedeclarableDeclKind(unsigned Kind); + +/// Determine whether the given declaration needs an anonymous +/// declaration number. +bool needsAnonymousDeclarationNumber(const NamedDecl *D); + +/// 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 000000000000..e0b2b24a0d32 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -0,0 +1,12563 @@ +//===- 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/ASTMutationListener.h" +#include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/ODRHash.h" +#include "clang/AST/RawCommentList.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MemoryBufferCache.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PragmaKinds.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Basic/Version.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Lex/Token.h" +#include "clang/Sema/ObjCMethodList.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/Weak.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFileExtension.h" +#include "clang/Serialization/ModuleManager.h" +#include "clang/Serialization/PCHContainerOperations.h" +#include "clang/Serialization/SerializationDiagnostic.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.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/Timer.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdio> +#include <ctime> +#include <iterator> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <system_error> +#include <tuple> +#include <utility> +#include <vector> + +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, + ModuleKind Kind) { + First->visitModuleFile(Filename, Kind); + Second->visitModuleFile(Filename, Kind); +} + +bool ChainedASTReaderListener::visitInputFile(StringRef Filename, + bool isSystem, + bool isOverridden, + bool isExplicitModule) { + bool Continue = false; + if (First->needsInputFileVisitation() && + (!isSystem || First->needsSystemInputFileVisitation())) + Continue |= First->visitInputFile(Filename, isSystem, isOverridden, + isExplicitModule); + if (Second->needsInputFileVisitation() && + (!isSystem || Second->needsSystemInputFileVisitation())) + Continue |= Second->visitInputFile(Filename, isSystem, isOverridden, + isExplicitModule); + return Continue; +} + +void ChainedASTReaderListener::readModuleFileExtension( + const ModuleFileExtensionMetadata &Metadata) { + First->readModuleFileExtension(Metadata); + Second->readModuleFileExtension(Metadata); +} + +//===----------------------------------------------------------------------===// +// PCH validator implementation +//===----------------------------------------------------------------------===// + +ASTReaderListener::~ASTReaderListener() = default; + +/// 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 COMPATIBLE_VALUE_LANGOPT(Name, Bits, Default, Description) \ + if (!AllowCompatibleDifferences) \ + VALUE_LANGOPT(Name, Bits, Default, Description) + +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#define BENIGN_VALUE_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + + if (ExistingLangOpts.ModuleFeatures != LangOpts.ModuleFeatures) { + if (Diags) + Diags->Report(diag::err_pch_langopt_value_mismatch) << "module features"; + return true; + } + + 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; + } + + // Sanitizer feature mismatches are treated as compatible differences. If + // compatible differences aren't allowed, we still only want to check for + // mismatches of non-modular sanitizers (the only ones which can affect AST + // generation). + if (!AllowCompatibleDifferences) { + SanitizerMask ModularSanitizers = getPPTransparentSanitizers(); + SanitizerSet ExistingSanitizers = ExistingLangOpts.Sanitize; + SanitizerSet ImportedSanitizers = LangOpts.Sanitize; + ExistingSanitizers.clear(ModularSanitizers); + ImportedSanitizers.clear(ModularSanitizers); + if (ExistingSanitizers.Mask != ImportedSanitizers.Mask) { + const std::string Flag = "-fsanitize="; + if (Diags) { +#define SANITIZER(NAME, ID) \ + { \ + bool InExistingModule = ExistingSanitizers.has(SanitizerKind::ID); \ + bool InImportedModule = ImportedSanitizers.has(SanitizerKind::ID); \ + if (InExistingModule != InImportedModule) \ + Diags->Report(diag::err_pch_targetopt_feature_mismatch) \ + << InExistingModule << (Flag + NAME); \ + } +#include "clang/Basic/Sanitizers.def" + } + return true; + } + } + + return false; +} + +/// 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()); + llvm::sort(ExistingFeatures); + llvm::sort(ReadFeatures); + + // 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 { + +using MacroDefinitionsMap = + llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>; +using DeclsMap = llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8>>; + +} // namespace + +static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags, + DiagnosticsEngine &Diags, + bool Complain) { + using Level = DiagnosticsEngine::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); +} + +/// Return the top import module if it is implicit, nullptr otherwise. +static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr, + Preprocessor &PP) { + // 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 nullptr; + + StringRef ModuleName = TopImport->ModuleName; + assert(!ModuleName.empty() && "diagnostic options read before module name"); + + Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName); + assert(M && "missing module"); + return M; +} + +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"); + + Module *TopM = getTopImportImplicitModule(ModuleMgr, PP); + if (!TopM) + return false; + + // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that + // contains the union of their flags. + return checkDiagnosticMappings(*Diags, ExistingDiags, TopM->IsSystem, + Complain); +} + +/// 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); + } +} + +/// 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. +/// \param Validate If true, validate preprocessor options. If false, allow +/// macros defined by \p ExistingPPOpts to override those defined by +/// \p PPOpts in SuggestedPredefines. +static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, + const PreprocessorOptions &ExistingPPOpts, + DiagnosticsEngine *Diags, + FileManager &FileMgr, + std::string &SuggestedPredefines, + const LangOptions &LangOpts, + bool Validate = true) { + // 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 (!Validate || 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 && Validate) { + 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 && Validate) { + 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 (!ExistingPPOpts.ImplicitPCHInclude.empty() && + !ExistingPPOpts.PCHThroughHeader.empty()) { + // In case the through header is an include, we must add all the includes + // to the predefines so the start point can be determined. + SuggestedPredefines += "#include \""; + SuggestedPredefines += File; + SuggestedPredefines += "\"\n"; + continue; + } + + 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()); +} + +bool SimpleASTReaderListener::ReadPreprocessorOptions( + const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + return checkPreprocessorOptions(PPOpts, + PP.getPreprocessorOpts(), + nullptr, + PP.getFileManager(), + SuggestedPredefines, + PP.getLangOpts(), + false); +} + +/// 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::djbHash(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); +} + +/// Whether the given identifier is "interesting". +static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, + bool IsModule) { + return II.hadMacroDefinition() || + II.isPoisoned() || + (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) || + II.hasRevertedTokenIDToIdentifier() || + (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) && + II.getFETokenInfo()); +} + +static bool readBit(unsigned &Bits) { + bool Value = Bits & 0x1; + Bits >>= 1; + return Value; +} + +IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) { + using namespace llvm::support; + + unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); + return Reader.getGlobalIdentifierID(F, RawID >> 1); +} + +static void markIdentifierFromAST(ASTReader &Reader, IdentifierInfo &II) { + if (!II.isFromAST()) { + II.setIsFromAST(); + bool IsModule = Reader.getPreprocessor().getCurrentModule() != nullptr; + if (isInterestingIdentifier(Reader, II, IsModule)) + II.setChangedSinceDeserialization(); + } +} + +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; + + // Build the IdentifierInfo and link the identifier ID with it. + IdentifierInfo *II = KnownII; + if (!II) { + II = &Reader.getIdentifierTable().getOwn(k); + KnownII = II; + } + markIdentifierFromAST(Reader, *II); + Reader.markIdentifierUpToDate(II); + + IdentID ID = Reader.getGlobalIdentifierID(F, RawID); + if (!IsInteresting) { + // For uninteresting identifiers, there's nothing else to do. Just notify + // the reader that we've finished loading this identifier. + Reader.SetIdentifierInfo(ID, II); + return II; + } + + unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d); + unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d); + bool CPlusPlusOperatorKeyword = readBit(Bits); + bool HasRevertedTokenIDToIdentifier = readBit(Bits); + bool HasRevertedBuiltin = readBit(Bits); + bool Poisoned = readBit(Bits); + bool ExtensionToken = readBit(Bits); + bool HadMacroDefinition = readBit(Bits); + + assert(Bits == 0 && "Extra bits in the identifier?"); + DataLen -= 8; + + // Set or check the various bits in the IdentifierInfo structure. + // Token IDs are read-only. + if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier) + II->revertTokenIDToIdentifier(); + if (!F.isModule()) + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + else if (HasRevertedBuiltin && II->getBuiltinID()) { + II->revertBuiltin(); + assert((II->hasRevertedBuiltin() || + II->getObjCOrBuiltinID() == ObjCOrBuiltinID) && + "Incorrect ObjC keyword or builtin ID"); + } + 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; +} + +DeclarationNameKey::DeclarationNameKey(DeclarationName Name) + : Kind(Name.getNameKind()) { + switch (Kind) { + case DeclarationName::Identifier: + Data = (uint64_t)Name.getAsIdentifierInfo(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Data = Name.getCXXOverloadedOperator(); + break; + case DeclarationName::CXXLiteralOperatorName: + Data = (uint64_t)Name.getCXXLiteralIdentifier(); + break; + case DeclarationName::CXXDeductionGuideName: + Data = (uint64_t)Name.getCXXDeductionGuideTemplate() + ->getDeclName().getAsIdentifierInfo(); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Data = 0; + break; + } +} + +unsigned DeclarationNameKey::getHash() const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(Kind); + + switch (Kind) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: + ID.AddString(((IdentifierInfo*)Data)->getName()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + ID.AddInteger(serialization::ComputeHash(Selector(Data))); + break; + case DeclarationName::CXXOperatorName: + ID.AddInteger((OverloadedOperatorKind)Data); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + break; + } + + return ID.ComputeHash(); +} + +ModuleFile * +ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { + using namespace llvm::support; + + uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d); + return Reader.getLocalModuleFile(F, ModuleFileID); +} + +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; + + auto Kind = (DeclarationName::NameKind)*d++; + uint64_t Data; + switch (Kind) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: + Data = (uint64_t)Reader.getLocalIdentifier( + F, endian::readNext<uint32_t, little, unaligned>(d)); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Data = + (uint64_t)Reader.getLocalSelector( + F, endian::readNext<uint32_t, little, unaligned>( + d)).getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Data = *d++; // OverloadedOperatorKind + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Data = 0; + break; + } + + return DeclarationNameKey(Kind, Data); +} + +void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, + const unsigned char *d, + unsigned DataLen, + data_type_builder &Val) { + using namespace llvm::support; + + for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) { + uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d); + Val.insert(Reader.getGlobalDeclID(F, LocalID)); + } +} + +bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclContext *DC) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + 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; + } + + assert(!isa<TranslationUnitDecl>(DC) && + "expected a TU_UPDATE_LEXICAL record for TU"); + // If we are handling a C++ class template instantiation, we can see multiple + // lexical updates for the same record. It's important that we select only one + // of them, so that field numbering works properly. Just pick the first one we + // see. + auto &Lex = LexicalDecls[DC]; + if (!Lex.first) { + Lex = std::make_pair( + &M, llvm::makeArrayRef( + reinterpret_cast<const llvm::support::unaligned_uint32_t *>( + Blob.data()), + Blob.size() / 4)); + } + DC->setHasExternalLexicalStorage(true); + return false; +} + +bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclID ID) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + 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; + } + + // We can't safely determine the primary context yet, so delay attaching the + // lookup table until we're done with recursive deserialization. + auto *Data = (const unsigned char*)Blob.data(); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); + return false; +} + +void ASTReader::Error(StringRef Msg) const { + Error(diag::err_fe_pch_malformed, Msg); + if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && + !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { + Diag(diag::note_module_cache_path) + << PP.getHeaderSearchInfo().getModuleCachePath(); + } +} + +void ASTReader::Error(unsigned DiagID, + StringRef Arg1, StringRef Arg2) const { + if (Diags.isDiagnosticInFlight()) + Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); + else + Diag(DiagID) << Arg1 << Arg2; +} + +//===----------------------------------------------------------------------===// +// Source Manager Deserialization +//===----------------------------------------------------------------------===// + +/// 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; + FileIDs[-1] = -1; // For unspecified filenames. + for (unsigned I = 0; Record[Idx]; ++I) { + // Extract the file name + auto Filename = ReadPath(F, Record, Idx); + FileIDs[I] = LineTable.getLineTableFilenameID(Filename); + } + ++Idx; + + // 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 && "no line entries for file ID"); + 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; +} + +/// 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; + } + } +} + +/// 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; + } + + // Local helper to read the (possibly-compressed) buffer data following the + // entry record. + auto ReadBuffer = [this]( + BitstreamCursor &SLocEntryCursor, + StringRef Name) -> std::unique_ptr<llvm::MemoryBuffer> { + RecordData Record; + StringRef Blob; + unsigned Code = SLocEntryCursor.ReadCode(); + unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); + + if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { + if (!llvm::zlib::isAvailable()) { + Error("zlib is not available"); + return nullptr; + } + SmallString<0> Uncompressed; + if (llvm::Error E = + llvm::zlib::uncompress(Blob, Uncompressed, Record[0])) { + Error("could not decompress embedded file contents: " + + llvm::toString(std::move(E))); + return nullptr; + } + return llvm::MemoryBuffer::getMemBufferCopy(Uncompressed, Name); + } else if (RecCode == SM_SLOC_BUFFER_BLOB) { + return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true); + } else { + Error("AST record has invalid code"); + return nullptr; + } + }; + + 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 && ContextObj) { + assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); + FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, + NumFileDecls)); + } + + const SrcMgr::ContentCache *ContentCache + = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter)); + if (OverriddenBuffer && !ContentCache->BufferOverridden && + ContentCache->ContentsEntry == ContentCache->OrigEntry && + !ContentCache->getRawBuffer()) { + auto Buffer = ReadBuffer(SLocEntryCursor, File->getName()); + if (!Buffer) + return true; + 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->isModule()) { + IncludeLoc = getImportLocation(F); + } + + auto Buffer = ReadBuffer(SLocEntryCursor, Name); + if (!Buffer) + return true; + 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[5], + 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->isModule()) + 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)); +} + +/// 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().isValid() && "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)) + return true; + + 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> MacroParams; + 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. + SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); + MacroInfo *MI = PP.AllocateMacroInfo(Loc); + 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++]; + MacroParams.clear(); + unsigned NumArgs = Record[NextIndex++]; + for (unsigned i = 0; i != NumArgs; ++i) + MacroParams.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->setParameterList(MacroParams, 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 { + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + + 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(), + M.HasTimestamps ? FE->getModificationTime() : 0, + 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 && a.ModTime != b.ModTime)) + return false; + + if (llvm::sys::path::is_absolute(a.Filename) && a.Filename == b.Filename) + 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) { + using namespace llvm::support; + + const unsigned char *End = d + DataLen; + HeaderFileInfo HFI; + unsigned Flags = *d++; + // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. + HFI.isImport |= (Flags >> 5) & 0x01; + HFI.isPragmaOnce |= (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 1) & 0x07; + HFI.IndexHeaderMapHeader = Flags & 0x01; + // FIXME: Find a better way to handle this. Maybe just store a + // "has been included" flag? + HFI.NumIncludes = std::max(endian::readNext<uint16_t, little, unaligned>(d), + HFI.NumIncludes); + 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); + } + + assert((End - d) % 4 == 0 && + "Wrong data length in HeaderFileInfo deserialization"); + while (d != End) { + uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d); + auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 3); + LocalSMID >>= 2; + + // 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); + FileManager &FileMgr = Reader.getFileManager(); + ModuleMap &ModMap = + Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + + std::string Filename = key.Filename; + if (key.Imported) + Reader.ResolveImportedPath(M, Filename); + // FIXME: This is not always the right filename-as-written, but we're not + // going to use this information to rebuild the module, so it doesn't make + // a lot of difference. + Module::Header H = { key.Filename, FileMgr.getFile(Filename) }; + ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true); + HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader); + } + + // This HeaderFileInfo was externally loaded. + HFI.External = true; + HFI.IsValid = 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 (ModuleFile &I : llvm::reverse(ModuleMgr)) { + BitstreamCursor &MacroCursor = I.MacroCursor; + + // If there was no preprocessor block, skip this file. + if (MacroCursor.getBitcodeBytes().empty()) + 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: { + IdentifierInfo *II = getLocalIdentifier(I, Record[0]); + if (II->isOutOfDate()) + updateOutOfDateIdentifier(*II); + break; + } + + case PP_TOKEN: + // Ignore tokens. + break; + } + break; + } + } + NextCursor: ; + } +} + +namespace { + + /// Visitor class used to look up identifirs in an AST file. + class IdentifierLookupVisitor { + StringRef Name; + unsigned NameHash; + unsigned PriorGeneration; + unsigned &NumIdentifierLookups; + unsigned &NumIdentifierLookupHits; + IdentifierInfo *Found = nullptr; + + public: + IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, + unsigned &NumIdentifierLookups, + unsigned &NumIdentifierLookupHits) + : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), + PriorGeneration(PriorGeneration), + NumIdentifierLookups(NumIdentifierLookups), + NumIdentifierLookupHits(NumIdentifierLookupHits) {} + + bool operator()(ModuleFile &M) { + // If we've already searched this module file, skip it now. + if (M.Generation <= PriorGeneration) + return true; + + ASTIdentifierLookupTable *IdTable + = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; + if (!IdTable) + return false; + + ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, + Found); + ++NumIdentifierLookups; + ASTIdentifierLookupTable::iterator Pos = + IdTable->find_hashed(Name, NameHash, &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. + ++NumIdentifierLookupHits; + Found = *Pos; + return true; + } + + // Retrieve the identifier info found within the module + // files. + IdentifierInfo *getIdentifierInfo() const { return Found; } + }; + +} // namespace + +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(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.isModule()) + 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, Earliest, 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; + + assert(Record[0] == ID && "Bogus stored ID or offset"); + InputFileInfo R; + R.StoredSize = static_cast<off_t>(Record[1]); + R.StoredTime = static_cast<time_t>(Record[2]); + R.Overridden = static_cast<bool>(Record[3]); + R.Transient = static_cast<bool>(Record[4]); + R.TopLevelModuleMap = static_cast<bool>(Record[5]); + R.Filename = Blob; + ResolveImportedPath(F, R.Filename); + return R; +} + +static unsigned moduleKindForDiagnostic(ModuleKind Kind); +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; + bool Transient = FI.Transient; + StringRef Filename = FI.Filename; + + const FileEntry *File = 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() && !F.BaseDirectory.empty() && + F.OriginalDir != F.BaseDirectory) { + std::string Resolved = resolveFileRelativeToOriginalDir( + Filename, F.OriginalDir, F.BaseDirectory); + if (!Resolved.empty()) + File = FileMgr.getFile(Resolved); + } + + // For an overridden file, create a virtual file with the stored + // size/timestamp. + if ((Overridden || Transient) && 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 '"; + ErrorStr += F.FileName; + ErrorStr += "'"; + Error(ErrorStr); + } + // 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. Overriding such a file + // can lead to problems when lexing using the source locations from the + // PCH. + SourceManager &SM = getSourceManager(); + // FIXME: Reject if the overrides are different. + if ((!Overridden && !Transient) && 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. + // + // FIXME: This recovery is just as broken as the original state; there may + // be another precompiled module that's using the overridden contents, or + // we might be half way through parsing it. Instead, we should treat the + // overridden contents as belonging to a separate FileEntry. + 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() || + (StoredTime && StoredTime != File->getModificationTime() && + !DisableValidation) + )) { + 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.empty()) + ImportStack.push_back(ImportStack.back()->ImportedBy[0]); + + // The top-level PCH is stale. + StringRef TopLevelPCHName(ImportStack.back()->FileName); + unsigned DiagnosticKind = moduleKindForDiagnostic(ImportStack.back()->Kind); + if (DiagnosticKind == 0) + Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName); + else if (DiagnosticKind == 1) + Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName); + else + Error(diag::err_fe_ast_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; + } + // FIXME: If the file is overridden and we've already opened it, + // issue an error (or split it into a separate FileEntry). + + InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate); + + // Note that we've loaded this input file. + F.InputFilesLoaded[ID-1] = IF; + return IF; +} + +/// 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()); +} + +static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) { + switch (ARR) { + case ASTReader::Failure: return true; + case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing); + case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate); + case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch); + case ASTReader::ConfigurationMismatch: + return !(Caps & ASTReader::ARR_ConfigurationMismatch); + case ASTReader::HadErrors: return true; + case ASTReader::Success: return false; + } + + llvm_unreachable("unknown ASTReadResult"); +} + +ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( + BitstreamCursor &Stream, unsigned ClientLoadCapabilities, + bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, + std::string &SuggestedPredefines) { + if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID)) + return Failure; + + // Read all of the records in the options block. + RecordData Record; + ASTReadResult Result = Success; + while (true) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::SubBlock: + return Failure; + + case llvm::BitstreamEntry::EndBlock: + return Result; + + case llvm::BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read and process a record. + Record.clear(); + switch ((OptionsRecordTypes)Stream.readRecord(Entry.ID, Record)) { + case LANGUAGE_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (ParseLanguageOptions(Record, Complain, Listener, + AllowCompatibleConfigurationMismatch)) + Result = ConfigurationMismatch; + break; + } + + case TARGET_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (ParseTargetOptions(Record, Complain, Listener, + AllowCompatibleConfigurationMismatch)) + Result = ConfigurationMismatch; + break; + } + + case FILE_SYSTEM_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParseFileSystemOptions(Record, Complain, Listener)) + Result = ConfigurationMismatch; + break; + } + + case HEADER_SEARCH_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParseHeaderSearchOptions(Record, Complain, Listener)) + Result = ConfigurationMismatch; + break; + } + + case PREPROCESSOR_OPTIONS: + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParsePreprocessorOptions(Record, Complain, Listener, + SuggestedPredefines)) + Result = ConfigurationMismatch; + break; + } + } +} + +ASTReader::ASTReadResult +ASTReader::ReadControlBlock(ModuleFile &F, + SmallVectorImpl<ImportedModule> &Loaded, + const ModuleFile *ImportedBy, + unsigned ClientLoadCapabilities) { + BitstreamCursor &Stream = F.Stream; + ASTReadResult Result = Success; + + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + Error("malformed block record in AST file"); + return Failure; + } + + // Lambda to read the unhashed control block the first time it's called. + // + // For PCM files, the unhashed control block cannot be read until after the + // MODULE_NAME record. However, PCH files have no MODULE_NAME, and yet still + // need to look ahead before reading the IMPORTS record. For consistency, + // this block is always read somehow (see BitstreamEntry::EndBlock). + bool HasReadUnhashedControlBlock = false; + auto readUnhashedControlBlockOnce = [&]() { + if (!HasReadUnhashedControlBlock) { + HasReadUnhashedControlBlock = true; + if (ASTReadResult Result = + readUnhashedControlBlock(F, ImportedBy, ClientLoadCapabilities)) + return Result; + } + return Success; + }; + + // Read all of the records and blocks in the control block. + RecordData Record; + unsigned NumInputs = 0; + unsigned NumUserInputs = 0; + while (true) { + 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 the module before returning. This call catches an AST with + // no module name and no imports. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + + // 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). For explicitly + // loaded module files, ignore missing inputs. + if (!DisableValidation && F.Kind != MK_ExplicitModule && + F.Kind != MK_PrebuiltModule) { + 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, F.Kind); + + 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, + F.Kind == MK_ExplicitModule || + F.Kind == MK_PrebuiltModule); + } + } + + return Result; + } + + 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; + + case OPTIONS_BLOCK_ID: + // If we're reading the first module for this group, check its options + // are compatible with ours. For modules it imports, no further checking + // is required, because we checked them when we built it. + if (Listener && !ImportedBy) { + // 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. + bool AllowCompatibleConfigurationMismatch = + F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; + + Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, + AllowCompatibleConfigurationMismatch, + *Listener, SuggestedPredefines); + if (Result == Failure) { + Error("malformed block record in AST file"); + return Result; + } + + if (DisableValidation || + (AllowConfigurationMismatch && Result == ConfigurationMismatch)) + Result = Success; + + // If we can't load the module, exit early since we likely + // will rebuild the module anyway. The stream may be in the + // middle of a block. + if (Result != Success) + return Result; + } else if (Stream.SkipBlock()) { + 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[7]; + if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { + Diag(diag::err_pch_with_compiler_errors); + return HadErrors; + } + if (hasErrors) { + Diags.ErrorOccurred = true; + Diags.UncompilableErrorOccurred = true; + Diags.UnrecoverableErrorOccurred = true; + } + + F.RelocatablePCH = Record[4]; + // Relative paths in a relocatable PCH are relative to our sysroot. + if (F.RelocatablePCH) + F.BaseDirectory = isysroot.empty() ? "/" : isysroot; + + F.HasTimestamps = Record[5]; + + F.PCHHasObjectFile = Record[6]; + + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch = Blob; + if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch; + return VersionMismatch; + } + break; + } + + case IMPORTS: { + // Validate the AST before processing any imports (otherwise, untangling + // them can be error-prone and expensive). A module will have a name and + // will already have been validated, but this catches the PCH case. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + + // 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, in ReadAST. + SourceLocation ImportLoc = + ReadUntranslatedSourceLocation(Record[Idx++]); + off_t StoredSize = (off_t)Record[Idx++]; + time_t StoredModTime = (time_t)Record[Idx++]; + ASTFileSignature StoredSignature = { + {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++]}}}; + + std::string ImportedName = ReadString(Record, Idx); + std::string ImportedFile; + + // For prebuilt and explicit modules first consult the file map for + // an override. Note that here we don't search prebuilt module + // directories, only the explicit name to file mappings. Also, we will + // still verify the size/signature making sure it is essentially the + // same file but perhaps in a different location. + if (ImportedKind == MK_PrebuiltModule || ImportedKind == MK_ExplicitModule) + ImportedFile = PP.getHeaderSearchInfo().getPrebuiltModuleFileName( + ImportedName, /*FileMapOnly*/ true); + + if (ImportedFile.empty()) + ImportedFile = ReadPath(F, Record, Idx); + else + SkipPath(Record, Idx); + + // If our client can't cope with us being out of date, we can't cope with + // our dependency being missing. + unsigned Capabilities = ClientLoadCapabilities; + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Capabilities &= ~ARR_Missing; + + // Load the AST file. + auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, + Loaded, StoredSize, StoredModTime, + StoredSignature, Capabilities); + + // If we diagnosed a problem, produce a backtrace. + if (isDiagnosedResult(Result, Capabilities)) + Diag(diag::note_module_file_imported_by) + << F.FileName << !F.ModuleName.empty() << F.ModuleName; + + switch (Result) { + 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 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); + + // Validate the AST as soon as we have a name so we can exit early on + // failure. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + + 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, /*AllowSearch*/ true, + /*AllowExtraModuleMapSearch*/ true); + if (M && M->Directory) { + // If we're implicitly loading a module, the base directory can't + // change between the build and use. + // Don't emit module relocation error if we have -fno-validate-pch + if (!PP.getPreprocessorOpts().DisablePCHValidation && + F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) { + 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 llvm::support::unaligned_uint64_t *)Blob.data(); + F.InputFilesLoaded.resize(NumInputs); + F.NumUserInputFiles = NumUserInputs; + 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 (true) { + 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++. + if (ASTContext *Ctx = ContextObj) { + DeclContext *DC = Ctx->getTranslationUnitDecl(); + if (DC->hasExternalLexicalStorage() && !Ctx->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; + auto RecordType = + (ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob); + + // If we're not loading an AST context, we don't care about most records. + if (!ContextObj) { + switch (RecordType) { + case IDENTIFIER_TABLE: + case IDENTIFIER_OFFSET: + case INTERESTING_IDENTIFIERS: + case STATISTICS: + case PP_CONDITIONAL_STACK: + case PP_COUNTER_VALUE: + case SOURCE_LOCATION_OFFSETS: + case MODULE_OFFSET_MAP: + case SOURCE_MANAGER_LINE_TABLE: + case SOURCE_LOCATION_PRELOADS: + case PPD_ENTITIES_OFFSETS: + case HEADER_SEARCH_TABLE: + case IMPORTED_MODULES: + case MACRO_OFFSET: + break; + default: + continue; + } + } + + switch (RecordType) { + 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 = ContextObj->getTranslationUnitDecl(); + LexicalContents Contents( + reinterpret_cast<const llvm::support::unaligned_uint32_t *>( + Blob.data()), + static_cast<unsigned int>(Blob.size() / 4)); + TULexicalDecls.push_back(std::make_pair(&F, Contents)); + TU->setHasExternalLexicalStorage(true); + break; + } + + case UPDATE_VISIBLE: { + unsigned Idx = 0; + serialization::DeclID ID = ReadDeclID(F, Record, Idx); + auto *Data = (const unsigned char*)Blob.data(); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + 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 INTERESTING_IDENTIFIERS: + F.PreloadIdentifierOffsets.assign(Record.begin(), Record.end()); + 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 MODULAR_CODEGEN_DECLS: + // FIXME: Skip reading this record if our ASTConsumer doesn't care about + // them (ie: if we're not codegenerating this module). + if (F.Kind == MK_MainFile) + 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_CONDITIONAL_STACK: + if (!Record.empty()) { + unsigned Idx = 0, End = Record.size() - 1; + bool ReachedEOFWhileSkipping = Record[Idx++]; + llvm::Optional<Preprocessor::PreambleSkipInfo> SkipInfo; + if (ReachedEOFWhileSkipping) { + SourceLocation HashToken = ReadSourceLocation(F, Record, Idx); + SourceLocation IfTokenLoc = ReadSourceLocation(F, Record, Idx); + bool FoundNonSkipPortion = Record[Idx++]; + bool FoundElse = Record[Idx++]; + SourceLocation ElseLoc = ReadSourceLocation(F, Record, Idx); + SkipInfo.emplace(HashToken, IfTokenLoc, FoundNonSkipPortion, + FoundElse, ElseLoc); + } + SmallVector<PPConditionalInfo, 4> ConditionalStack; + while (Idx < End) { + auto Loc = ReadSourceLocation(F, Record, Idx); + bool WasSkipping = Record[Idx++]; + bool FoundNonSkip = Record[Idx++]; + bool FoundElse = Record[Idx++]; + ConditionalStack.push_back( + {Loc, WasSkipping, FoundNonSkip, FoundElse}); + } + PP.setReplayablePreambleConditionalStack(ConditionalStack, SkipInfo); + } + 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); + if (!F.SLocEntryBaseID) { + Error("ran out of source locations"); + break; + } + // 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: + F.ModuleOffsetMap = Blob; + 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() != 3) { + 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 PPD_SKIPPED_RANGES: { + F.PreprocessedSkippedRangeOffsets = (const PPSkippedRange*)Blob.data(); + assert(Blob.size() % sizeof(PPSkippedRange) == 0); + F.NumPreprocessedSkippedRanges = Blob.size() / sizeof(PPSkippedRange); + + if (!PP.getPreprocessingRecord()) + PP.createPreprocessingRecord(); + if (!PP.getPreprocessingRecord()->getExternalSource()) + PP.getPreprocessingRecord()->SetExternalSource(*this); + F.BasePreprocessedSkippedRangeID = PP.getPreprocessingRecord() + ->allocateSkippedRanges(F.NumPreprocessedSkippedRanges); + + if (F.NumPreprocessedSkippedRanges > 0) + GlobalSkippedRangeMap.insert( + std::make_pair(F.BasePreprocessedSkippedRangeID, &F)); + 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( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + } + 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 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: + for (unsigned I = 0, E = Record.size(); I != E; ) { + auto Name = ReadString(Record, I); + auto &Opt = OpenCLExtensions.OptMap[Name]; + Opt.Supported = Record[I++] != 0; + Opt.Enabled = Record[I++] != 0; + Opt.Avail = Record[I++]; + Opt.Core = Record[I++]; + } + break; + + case OPENCL_EXTENSION_TYPES: + for (unsigned I = 0, E = Record.size(); I != E;) { + auto TypeID = static_cast<::TypeID>(Record[I++]); + auto *Type = GetType(TypeID).getTypePtr(); + auto NumExt = static_cast<unsigned>(Record[I++]); + for (unsigned II = 0; II != NumExt; ++II) { + auto Ext = ReadString(Record, I); + OpenCLTypeExtMap[Type].insert(Ext); + } + } + break; + + case OPENCL_EXTENSION_DECLS: + for (unsigned I = 0, E = Record.size(); I != E;) { + auto DeclID = static_cast<::DeclID>(Record[I++]); + auto *Decl = GetDecl(DeclID); + auto NumExt = static_cast<unsigned>(Record[I++]); + for (unsigned II = 0; II != NumExt; ++II) { + auto Ext = ReadString(Record, I); + OpenCLDeclExtMap[Decl].insert(Ext); + } + } + 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.isModule()) { + // 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)); + if (DeserializationListener) + DeserializationListener->ModuleImportRead(GlobalID, Loc); + } + } + } + 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 MSSTRUCT_PRAGMA_OPTIONS: + if (Record.size() != 1) { + Error("invalid pragma ms_struct record"); + return Failure; + } + PragmaMSStructState = Record[0]; + break; + + case POINTERS_TO_MEMBERS_PRAGMA_OPTIONS: + if (Record.size() != 2) { + Error("invalid pragma ms_struct record"); + return Failure; + } + PragmaMSPointersToMembersState = Record[0]; + PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]); + 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; + + case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH: + if (Record.size() != 1) { + Error("invalid cuda pragma options record"); + return Failure; + } + ForceCUDAHostDeviceDepth = Record[0]; + break; + + case PACK_PRAGMA_OPTIONS: { + if (Record.size() < 3) { + Error("invalid pragma pack record"); + return Failure; + } + PragmaPackCurrentValue = Record[0]; + PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]); + unsigned NumStackEntries = Record[2]; + unsigned Idx = 3; + // Reset the stack when importing a new module. + PragmaPackStack.clear(); + for (unsigned I = 0; I < NumStackEntries; ++I) { + PragmaPackStackEntry Entry; + Entry.Value = Record[Idx++]; + Entry.Location = ReadSourceLocation(F, Record[Idx++]); + Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]); + PragmaPackStrings.push_back(ReadString(Record, Idx)); + Entry.SlotLabel = PragmaPackStrings.back(); + PragmaPackStack.push_back(Entry); + } + break; + } + } + } +} + +void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { + assert(!F.ModuleOffsetMap.empty() && "no module offset map to read"); + + // Additional remapping information. + const unsigned char *Data = (const unsigned char*)F.ModuleOffsetMap.data(); + const unsigned char *DataEnd = Data + F.ModuleOffsetMap.size(); + F.ModuleOffsetMap = StringRef(); + + // 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. + using RemapBuilder = ContinuousRangeMap<uint32_t, int, 2>::Builder; + 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) { + // FIXME: Looking up dependency modules by filename is horrible. Let's + // start fixing this with prebuilt and explicit modules and see how it + // goes... + using namespace llvm::support; + ModuleKind Kind = static_cast<ModuleKind>( + endian::readNext<uint8_t, little, unaligned>(Data)); + uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data); + StringRef Name = StringRef((const char*)Data, Len); + Data += Len; + ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule + ? ModuleMgr.lookupByModuleName(Name) + : ModuleMgr.lookupByFileName(Name)); + if (!OM) { + std::string Msg = + "SourceLocation remap refers to unknown module, cannot find "; + Msg.append(Name); + Error(Msg); + return; + } + + 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; + } +} + +ASTReader::ASTReadResult +ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, + const ModuleFile *ImportedBy, + unsigned ClientLoadCapabilities) { + unsigned Idx = 0; + F.ModuleMapPath = ReadPath(F, Record, Idx); + + // 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; + // Don't emit module relocation error if we have -fno-validate-pch + if (!PP.getPreprocessorOpts().DisablePCHValidation && !ModMap) { + assert(ImportedBy && "top-level import should be verified"); + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) { + if (auto *ASTFE = M ? M->getASTFile() : nullptr) { + // This module was defined by an imported (explicit) module. + Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName + << ASTFE->getName(); + } else { + // This module was built with a different module map. + Diag(diag::err_imported_module_not_found) + << F.ModuleName << F.FileName << ImportedBy->FileName + << F.ModuleMapPath; + // In case it was imported by a PCH, there's a chance the user is + // just missing to include the search path to the directory containing + // the modulemap. + if (ImportedBy->Kind == MK_PCH) + Diag(diag::note_imported_by_pch_module_not_found) + << llvm::sys::path::parent_path(F.ModuleMapPath); + } + } + return OutOfDate; + } + + 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; +} + +/// 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->isHidden(); + D->setVisibleDespiteOwningModule(); + + 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); + } + } +} + +/// We've merged the definition \p MergedDef into the existing definition +/// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made +/// visible. +void ASTReader::mergeDefinitionVisibility(NamedDecl *Def, + NamedDecl *MergedDef) { + if (Def->isHidden()) { + // If MergedDef is visible or becomes visible, make the definition visible. + if (!MergedDef->isHidden()) + Def->setVisibleDespiteOwningModule(); + else { + getContext().mergeDefinitionIntoModule( + Def, MergedDef->getImportedOwningModule(), + /*NotifyListeners*/ false); + PendingMergedDefinitionsToDeduplicate.insert(Def); + } + } +} + +bool ASTReader::loadGlobalIndex() { + if (GlobalIndex) + return false; + + if (TriedLoadingGlobalIndex || !UseGlobalIndex || + !PP.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 PP.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"; + OS.close(); + OS.clear_error(); // Avoid triggering a fatal error. +} + +/// 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 (true) { + 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; + } + } +} + +ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, + ModuleKind Type, + SourceLocation ImportLoc, + unsigned ClientLoadCapabilities, + SmallVectorImpl<ImportedSubmodule> *Imported) { + 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 = 0; + if (ContextObj) + PreviousGeneration = incrementGeneration(*ContextObj); + + unsigned NumModules = ModuleMgr.size(); + SmallVector<ImportedModule, 4> Loaded; + switch (ASTReadResult ReadResult = + ReadASTCore(FileName, Type, ImportLoc, + /*ImportedBy=*/nullptr, Loaded, 0, 0, + ASTFileSignature(), 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, LoadedSet, + PP.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; + + // Read the extension blocks. + while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { + if (ASTReadResult Result = ReadExtensionBlock(F)) + 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); + } + + // Map the original source file ID into the ID space of the current + // compilation. + if (F.OriginalSourceFileID.isValid()) { + F.OriginalSourceFileID = FileID::get( + F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1); + } + + // Preload all the pending interesting identifiers by marking them out of + // date. + for (auto Offset : F.PreloadIdentifierOffsets) { + const unsigned char *Data = reinterpret_cast<const unsigned char *>( + F.IdentifierTableData + Offset); + + ASTIdentifierLookupTrait Trait(*this, F); + auto KeyDataLen = Trait.ReadKeyDataLength(Data); + auto Key = Trait.ReadKey(Data, KeyDataLen.first); + auto &II = PP.getIdentifierTable().getOwn(Key); + II.setOutOfDate(true); + + // Mark this identifier as being from an AST file so that we can track + // whether we need to serialize it. + markIdentifierFromAST(*this, II); + + // Associate the ID with the identifier so that the writer can reuse it. + auto ID = Trait.ReadIdentifierID(Data + KeyDataLen.first); + SetIdentifierInfo(ID, &II); + } + } + + // 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; + // FIXME: We assume that locations from PCH / preamble do not need + // any translation. + if (!M->ImportedBy) + F.ImportLoc = M->ImportLoc; + else + F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc); + } + + if (!PP.getLangOpts().CPlusPlus || + (Type != MK_ImplicitModule && Type != MK_ExplicitModule && + Type != MK_PrebuiltModule)) { + // 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 C++ modules, we don't need information on many identifiers (just + // those that provide macros or are poisoned), so we mark all of + // the interesting ones via PreloadIdentifierOffsets. + for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), + IdEnd = PP.getIdentifierTable().end(); + Id != IdEnd; ++Id) + Id->second->setOutOfDate(true); + } + // Mark selectors as out of date. + for (auto Sel : SelectorGeneration) + SelectorOutOfDate[Sel.first] = 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(); + + if (Imported) + Imported->append(ImportedModules.begin(), + ImportedModules.end()); + + // 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. + + if (ContextObj) + InitializeContext(); + + if (SemaObj) + UpdateSema(); + + if (DeserializationListener) + DeserializationListener->ReaderInitialized(this); + + ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); + if (PrimaryModule.OriginalSourceFileID.isValid()) { + // 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. + if (ContextObj) { + 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(StringRef PCH); + +/// Whether \p Stream starts with the AST/PCH file magic number 'CPCH'. +static bool startsWithASTFileMagic(BitstreamCursor &Stream) { + return Stream.canSkipToPos(4) && + Stream.Read(8) == 'C' && + Stream.Read(8) == 'P' && + Stream.Read(8) == 'C' && + Stream.Read(8) == 'H'; +} + +static unsigned moduleKindForDiagnostic(ModuleKind Kind) { + switch (Kind) { + case MK_PCH: + return 0; // PCH + case MK_ImplicitModule: + case MK_ExplicitModule: + case MK_PrebuiltModule: + return 1; // module + case MK_MainFile: + case MK_Preamble: + return 2; // main source file + } + llvm_unreachable("unknown module kind"); +} + +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. + Diag(diag::err_module_file_not_found) << moduleKindForDiagnostic(Type) + << FileName << !ErrorStr.empty() + << ErrorStr; + 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. + Diag(diag::err_module_file_out_of_date) << moduleKindForDiagnostic(Type) + << FileName << !ErrorStr.empty() + << ErrorStr; + return Failure; + } + + assert(M && "Missing module file"); + + ModuleFile &F = *M; + BitstreamCursor &Stream = F.Stream; + Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer)); + F.SizeInBits = F.Buffer->getBufferSize() * 8; + + // Sniff for the signature. + if (!startsWithASTFileMagic(Stream)) { + Diag(diag::err_module_file_invalid) << moduleKindForDiagnostic(Type) + << FileName; + return Failure; + } + + // This is used for compatibility with older PCH formats. + bool HaveReadControlBlock = false; + while (true) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::Record: + case llvm::BitstreamEntry::EndBlock: + Error("invalid record at top-level of AST file"); + return Failure; + + case llvm::BitstreamEntry::SubBlock: + break; + } + + switch (Entry.ID) { + case CONTROL_BLOCK_ID: + HaveReadControlBlock = true; + switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) { + case Success: + // Check that we didn't try to load a non-module AST file as a module. + // + // FIXME: Should we also perform the converse check? Loading a module as + // a PCH file sort of works, but it's a bit wonky. + if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule || + Type == MK_PrebuiltModule) && + F.ModuleName.empty()) { + auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure; + if (Result != OutOfDate || + (ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_module_file_not_module) << FileName; + return Result; + } + 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; + + case UNHASHED_CONTROL_BLOCK_ID: + // This block is handled using look-ahead during ReadControlBlock. We + // shouldn't get here! + Error("malformed block record in AST file"); + return Failure; + + default: + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return Failure; + } + break; + } + } + + return Success; +} + +ASTReader::ASTReadResult +ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy, + unsigned ClientLoadCapabilities) { + const HeaderSearchOptions &HSOpts = + PP.getHeaderSearchInfo().getHeaderSearchOpts(); + bool AllowCompatibleConfigurationMismatch = + F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; + + ASTReadResult Result = readUnhashedControlBlockImpl( + &F, F.Data, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, + Listener.get(), + WasImportedBy ? false : HSOpts.ModulesValidateDiagnosticOptions); + + // If F was directly imported by another module, it's implicitly validated by + // the importing module. + if (DisableValidation || WasImportedBy || + (AllowConfigurationMismatch && Result == ConfigurationMismatch)) + return Success; + + if (Result == Failure) { + Error("malformed block record in AST file"); + return Failure; + } + + if (Result == OutOfDate && F.Kind == MK_ImplicitModule) { + // If this module has already been finalized in the PCMCache, we're stuck + // with it; we can only load a single version of each module. + // + // This can happen when a module is imported in two contexts: in one, as a + // user module; in another, as a system module (due to an import from + // another module marked with the [system] flag). It usually indicates a + // bug in the module map: this module should also be marked with [system]. + // + // If -Wno-system-headers (the default), and the first import is as a + // system module, then validation will fail during the as-user import, + // since -Werror flags won't have been validated. However, it's reasonable + // to treat this consistently as a system module. + // + // If -Wsystem-headers, the PCM on disk was built with + // -Wno-system-headers, and the first import is as a user module, then + // validation will fail during the as-system import since the PCM on disk + // doesn't guarantee that -Werror was respected. However, the -Werror + // flags were checked during the initial as-user import. + if (PCMCache.isBufferFinal(F.FileName)) { + Diag(diag::warn_module_system_bit_conflict) << F.FileName; + return Success; + } + } + + return Result; +} + +ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( + ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities, + bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener, + bool ValidateDiagnosticOptions) { + // Initialize a stream. + BitstreamCursor Stream(StreamData); + + // Sniff for the signature. + if (!startsWithASTFileMagic(Stream)) + return Failure; + + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) + return Failure; + + // Read all of the records in the options block. + RecordData Record; + ASTReadResult Result = Success; + while (true) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::SubBlock: + return Failure; + + case llvm::BitstreamEntry::EndBlock: + return Result; + + case llvm::BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read and process a record. + Record.clear(); + switch ( + (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) { + case SIGNATURE: + if (F) + std::copy(Record.begin(), Record.end(), F->Signature.data()); + break; + case DIAGNOSTIC_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; + if (Listener && ValidateDiagnosticOptions && + !AllowCompatibleConfigurationMismatch && + ParseDiagnosticOptions(Record, Complain, *Listener)) + Result = OutOfDate; // Don't return early. Read the signature. + break; + } + case DIAG_PRAGMA_MAPPINGS: + if (!F) + break; + if (F->PragmaDiagMappings.empty()) + F->PragmaDiagMappings.swap(Record); + else + F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), + Record.begin(), Record.end()); + break; + } + } +} + +/// Parse a record and blob containing module file extension metadata. +static bool parseModuleFileExtensionMetadata( + const SmallVectorImpl<uint64_t> &Record, + StringRef Blob, + ModuleFileExtensionMetadata &Metadata) { + if (Record.size() < 4) return true; + + Metadata.MajorVersion = Record[0]; + Metadata.MinorVersion = Record[1]; + + unsigned BlockNameLen = Record[2]; + unsigned UserInfoLen = Record[3]; + + if (BlockNameLen + UserInfoLen > Blob.size()) return true; + + Metadata.BlockName = std::string(Blob.data(), Blob.data() + BlockNameLen); + Metadata.UserInfo = std::string(Blob.data() + BlockNameLen, + Blob.data() + BlockNameLen + UserInfoLen); + return false; +} + +ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { + BitstreamCursor &Stream = F.Stream; + + RecordData Record; + while (true) { + llvm::BitstreamEntry Entry = Stream.advance(); + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: + if (Stream.SkipBlock()) + return Failure; + + continue; + + case llvm::BitstreamEntry::EndBlock: + return Success; + + case llvm::BitstreamEntry::Error: + return HadErrors; + + case llvm::BitstreamEntry::Record: + break; + } + + Record.clear(); + StringRef Blob; + unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); + switch (RecCode) { + case EXTENSION_METADATA: { + ModuleFileExtensionMetadata Metadata; + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + return Failure; + + // Find a module file extension with this block name. + auto Known = ModuleFileExtensions.find(Metadata.BlockName); + if (Known == ModuleFileExtensions.end()) break; + + // Form a reader. + if (auto Reader = Known->second->createExtensionReader(Metadata, *this, + F, Stream)) { + F.ExtensionReaders.push_back(std::move(Reader)); + } + + break; + } + } + } + + return Success; +} + +void ASTReader::InitializeContext() { + assert(ContextObj && "no context to initialize"); + ASTContext &Context = *ContextObj; + + // 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); + if (Import.ImportLoc.isValid()) + PP.makeModuleVisible(Imported, Import.ImportLoc); + // FIXME: should we tell Sema to make the module visible too? + } + } + ImportedModules.clear(); +} + +void ASTReader::finalizeForWriting() { + // Nothing to do for now. +} + +/// Reads and return the signature record from \p PCH's control block, or +/// else returns 0. +static ASTFileSignature readASTFileSignature(StringRef PCH) { + BitstreamCursor Stream(PCH); + if (!startsWithASTFileMagic(Stream)) + return ASTFileSignature(); + + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) + return ASTFileSignature(); + + // Scan for SIGNATURE inside the diagnostic options block. + ASTReader::RecordData Record; + while (true) { + llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + if (Entry.Kind != llvm::BitstreamEntry::Record) + return ASTFileSignature(); + + Record.clear(); + StringRef Blob; + if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob)) + return {{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], + (uint32_t)Record[3], (uint32_t)Record[4]}}}; + } +} + +/// 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, + const PCHContainerReader &PCHContainerRdr, 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 + BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer)); + + // 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 (true) { + 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); + } + }; + +} // namespace + +bool ASTReader::readASTFileControlBlock( + StringRef Filename, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + bool FindModuleFileExtensions, + ASTReaderListener &Listener, bool ValidateDiagnosticOptions) { + // 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 + StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer); + BitstreamCursor Stream(Bytes); + + // 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; + + RecordData Record; + std::string ModuleDir; + bool DoneWithControlBlock = false; + while (!DoneWithControlBlock) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: { + switch (Entry.ID) { + case OPTIONS_BLOCK_ID: { + std::string IgnoredSuggestedPredefines; + if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate, + /*AllowCompatibleConfigurationMismatch*/ false, + Listener, IgnoredSuggestedPredefines) != Success) + return true; + break; + } + + case INPUT_FILES_BLOCK_ID: + InputFilesCursor = Stream; + if (Stream.SkipBlock() || + (NeedsInputFiles && + ReadBlockAbbrevs(InputFilesCursor, INPUT_FILES_BLOCK_ID))) + return true; + break; + + default: + if (Stream.SkipBlock()) + return true; + break; + } + + continue; + } + + case llvm::BitstreamEntry::EndBlock: + DoneWithControlBlock = true; + break; + + case llvm::BitstreamEntry::Error: + return true; + + case llvm::BitstreamEntry::Record: + break; + } + + if (DoneWithControlBlock) break; + + 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 INPUT_FILE_OFFSETS: { + if (!NeedsInputFiles) + break; + + unsigned NumInputFiles = Record[0]; + unsigned NumUserFiles = Record[1]; + const llvm::support::unaligned_uint64_t *InputFileOffs = + (const llvm::support::unaligned_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, /*IsExplicitModule*/false); + 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 += 1+1+1+1+5; // Kind, ImportLoc, Size, ModTime, Signature + std::string ModuleName = ReadString(Record, Idx); + std::string Filename = ReadString(Record, Idx); + ResolveImportedPath(Filename, ModuleDir); + Listener.visitImport(ModuleName, Filename); + } + break; + } + + default: + // No other validation to perform. + break; + } + } + + // Look for module file extension blocks, if requested. + if (FindModuleFileExtensions) { + BitstreamCursor SavedStream = Stream; + while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) { + bool DoneWithExtensionBlock = false; + while (!DoneWithExtensionBlock) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: + if (Stream.SkipBlock()) + return true; + + continue; + + case llvm::BitstreamEntry::EndBlock: + DoneWithExtensionBlock = true; + continue; + + case llvm::BitstreamEntry::Error: + return true; + + case llvm::BitstreamEntry::Record: + break; + } + + Record.clear(); + StringRef Blob; + unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); + switch (RecCode) { + case EXTENSION_METADATA: { + ModuleFileExtensionMetadata Metadata; + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + return true; + + Listener.readModuleFileExtension(Metadata); + break; + } + } + } + } + Stream = SavedStream; + } + + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (readUnhashedControlBlockImpl( + nullptr, Bytes, ARR_ConfigurationMismatch | ARR_OutOfDate, + /*AllowCompatibleConfigurationMismatch*/ false, &Listener, + ValidateDiagnosticOptions) != Success) + return true; + + return false; +} + +bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + const PreprocessorOptions &PPOpts, + StringRef ExistingModuleCachePath) { + SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, + ExistingModuleCachePath, FileMgr); + return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr, + /*FindModuleFileExtensions=*/false, + validator, + /*ValidateDiagnosticOptions=*/true); +} + +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() < 12) { + Error("malformed module definition"); + return Failure; + } + + StringRef Name = Blob; + unsigned Idx = 0; + SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]); + SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); + Module::ModuleKind Kind = (Module::ModuleKind)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++]; + bool ModuleMapIsPrivate = 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()) { + // Don't emit module relocation error if we have -fno-validate-pch + if (!PP.getPreprocessorOpts().DisablePCHValidation && + 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->PresumedModuleMapFile = F.ModuleMapPath; + } + + CurrentModule->Kind = Kind; + CurrentModule->Signature = F.Signature; + CurrentModule->IsFromModuleFile = true; + CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; + CurrentModule->IsExternC = IsExternC; + CurrentModule->InferSubmodules = InferSubmodules; + CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; + CurrentModule->InferExportWildcard = InferExportWildcard; + CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; + CurrentModule->ModuleMapIsPrivate = ModuleMapIsPrivate; + if (DeserializationListener) + DeserializationListener->ModuleRead(GlobalID, CurrentModule); + + SubmodulesLoaded[GlobalIndex] = CurrentModule; + + // Clear out data that will be replaced by what is in the module file. + CurrentModule->LinkLibraries.clear(); + CurrentModule->ConfigMacros.clear(); + CurrentModule->UnresolvedConflicts.clear(); + CurrentModule->Conflicts.clear(); + + // The module is available unless it's missing a requirement; relevant + // requirements will be (re-)added by SUBMODULE_REQUIRES records. + // Missing headers that were present when the module was built do not + // make it unavailable -- if we got this far, this must be an explicitly + // imported module file. + CurrentModule->Requirements.clear(); + CurrentModule->MissingHeaders.clear(); + CurrentModule->IsMissingRequirement = + ParentModule && ParentModule->IsMissingRequirement; + CurrentModule->IsAvailable = !CurrentModule->IsMissingRequirement; + 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) { + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Error("mismatched umbrella headers in submodule"); + return OutOfDate; + } + } + 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], PP.getLangOpts(), + PP.getTargetInfo()); + break; + + case SUBMODULE_LINK_LIBRARY: + ModMap.resolveLinkAsDependencies(CurrentModule); + 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; + } + + case SUBMODULE_INITIALIZERS: { + if (!ContextObj) + break; + SmallVector<uint32_t, 16> Inits; + for (auto &ID : Record) + Inits.push_back(getGlobalDeclID(F, ID)); + ContextObj->addLazyModuleInitializers(CurrentModule, Inits); + break; + } + + case SUBMODULE_EXPORT_AS: + CurrentModule->ExportAsModule = Blob.str(); + ModMap.addLinkAsDependency(CurrentModule); + break; + } + } +} + +/// 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" + + for (unsigned N = Record[Idx++]; N; --N) + LangOpts.ModuleFeatures.push_back(ReadString(Record, Idx)); + + ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; + VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); + LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); + + LangOpts.CurrentModule = ReadString(Record, Idx); + + // Comment options. + for (unsigned N = Record[Idx++]; N; --N) { + LangOpts.CommentOpts.BlockCommandNames.push_back( + ReadString(Record, Idx)); + } + LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; + + // OpenMP offloading options. + for (unsigned N = Record[Idx++]; N; --N) { + LangOpts.OMPTargetTriples.push_back(llvm::Triple(ReadString(Record, Idx))); + } + + LangOpts.OMPHostIRFile = ReadString(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.ImplicitModuleMaps = Record[Idx++]; + HSOpts.ModuleMapFileHomeIsCwd = 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.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)); +} + +SourceRange ASTReader::ReadSkippedRange(unsigned GlobalIndex) { + auto I = GlobalSkippedRangeMap.find(GlobalIndex); + assert(I != GlobalSkippedRangeMap.end() && + "Corrupted global skipped range map"); + ModuleFile *M = I->second; + unsigned LocalIndex = GlobalIndex - M->BasePreprocessedSkippedRangeID; + assert(LocalIndex < M->NumPreprocessedSkippedRanges); + PPSkippedRange RawRange = M->PreprocessedSkippedRangeOffsets[LocalIndex]; + SourceRange Range(TranslateSourceLocation(*M, RawRange.getBegin()), + TranslateSourceLocation(*M, RawRange.getEnd())); + assert(Range.isValid()); + return Range; +} + +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(TranslateSourceLocation(M, PPOffs.getBegin()), + TranslateSourceLocation(M, PPOffs.getEnd())); + 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"); +} + +/// Find the next module that contains entities and return the ID +/// of the first entry. +/// +/// \param 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. +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 { + +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.TranslateSourceLocation(M, PPE.getBegin()); + } +}; + +} // namespace + +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; + + using pp_iterator = const PPEntityOffset *; + + 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(*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( + TranslateSourceLocation(M, PPI->getEnd()), Loc)) { + First = PPI; + ++First; + Count = Count - Half - 1; + } else + Count = Half; + } + } + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return M.BasePreprocessedEntityID + (PPI - pp_begin); +} + +/// 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); +} + +/// 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 = TranslateSourceLocation(M, PPOffs.getBegin()); + if (Loc.isInvalid()) + return false; + + if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID)) + return true; + else + return false; +} + +namespace { + + /// 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) {} + + bool operator()(ModuleFile &M) { + 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(FE); + if (Pos == Table->end()) + return false; + + HFI = *Pos; + return true; + } + + Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } + }; + +} // namespace + +HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { + HeaderFileInfoVisitor Visitor(FE); + ModuleMgr.visit(Visitor); + if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) + return *HFI; + + return HeaderFileInfo(); +} + +void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { + using DiagState = DiagnosticsEngine::DiagState; + SmallVector<DiagState *, 32> DiagStates; + + for (ModuleFile &F : ModuleMgr) { + unsigned Idx = 0; + auto &Record = F.PragmaDiagMappings; + if (Record.empty()) + continue; + + DiagStates.clear(); + + auto ReadDiagState = + [&](const DiagState &BasedOn, SourceLocation Loc, + bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * { + unsigned BackrefID = Record[Idx++]; + if (BackrefID != 0) + return DiagStates[BackrefID - 1]; + + // A new DiagState was created here. + Diag.DiagStates.push_back(BasedOn); + DiagState *NewState = &Diag.DiagStates.back(); + DiagStates.push_back(NewState); + unsigned Size = Record[Idx++]; + assert(Idx + Size * 2 <= Record.size() && + "Invalid data, not enough diag/map pairs"); + while (Size--) { + unsigned DiagID = Record[Idx++]; + DiagnosticMapping NewMapping = + DiagnosticMapping::deserialize(Record[Idx++]); + if (!NewMapping.isPragma() && !IncludeNonPragmaStates) + continue; + + DiagnosticMapping &Mapping = NewState->getOrAddMapping(DiagID); + + // If this mapping was specified as a warning but the severity was + // upgraded due to diagnostic settings, simulate the current diagnostic + // settings (and use a warning). + if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) { + NewMapping.setSeverity(diag::Severity::Warning); + NewMapping.setUpgradedFromWarning(false); + } + + Mapping = NewMapping; + } + return NewState; + }; + + // Read the first state. + DiagState *FirstState; + if (F.Kind == MK_ImplicitModule) { + // Implicitly-built modules are reused with different diagnostic + // settings. Use the initial diagnostic state from Diag to simulate this + // compilation's diagnostic settings. + FirstState = Diag.DiagStatesByLoc.FirstDiagState; + DiagStates.push_back(FirstState); + + // Skip the initial diagnostic state from the serialized module. + assert(Record[1] == 0 && + "Invalid data, unexpected backref in initial state"); + Idx = 3 + Record[2] * 2; + assert(Idx < Record.size() && + "Invalid data, not enough state change pairs in initial state"); + } else if (F.isModule()) { + // For an explicit module, preserve the flags from the module build + // command line (-w, -Weverything, -Werror, ...) along with any explicit + // -Wblah flags. + unsigned Flags = Record[Idx++]; + DiagState Initial; + Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1; + Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1; + Initial.WarningsAsErrors = Flags & 1; Flags >>= 1; + Initial.EnableAllWarnings = Flags & 1; Flags >>= 1; + Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1; + Initial.ExtBehavior = (diag::Severity)Flags; + FirstState = ReadDiagState(Initial, SourceLocation(), true); + + assert(F.OriginalSourceFileID.isValid()); + + // Set up the root buffer of the module to start with the initial + // diagnostic state of the module itself, to cover files that contain no + // explicit transitions (for which we did not serialize anything). + Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID] + .StateTransitions.push_back({FirstState, 0}); + } else { + // For prefix ASTs, start with whatever the user configured on the + // command line. + Idx++; // Skip flags. + FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState, + SourceLocation(), false); + } + + // Read the state transitions. + unsigned NumLocations = Record[Idx++]; + while (NumLocations--) { + assert(Idx < Record.size() && + "Invalid data, missing pragma diagnostic states"); + SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]); + auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc); + assert(IDAndOffset.first.isValid() && "invalid FileID for transition"); + assert(IDAndOffset.second == 0 && "not a start location for a FileID"); + unsigned Transitions = Record[Idx++]; + + // Note that we don't need to set up Parent/ParentOffset here, because + // we won't be changing the diagnostic state within imported FileIDs + // (other than perhaps appending to the main source file, which has no + // parent). + auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first]; + F.StateTransitions.reserve(F.StateTransitions.size() + Transitions); + for (unsigned I = 0; I != Transitions; ++I) { + unsigned Offset = Record[Idx++]; + auto *State = + ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false); + F.StateTransitions.push_back({State, Offset}); + } + } + + // Read the final state. + assert(Idx < Record.size() && + "Invalid data, missing final pragma diagnostic state"); + SourceLocation CurStateLoc = + ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); + auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false); + + if (!F.isModule()) { + Diag.DiagStatesByLoc.CurDiagState = CurState; + Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc; + + // Preserve the property that the imaginary root file describes the + // current state. + FileID NullFile; + auto &T = Diag.DiagStatesByLoc.Files[NullFile].StateTransitions; + if (T.empty()) + T.push_back({CurState, 0}); + else + T[0].State = CurState; + } + + // Don't try to read these mappings again. + Record.clear(); + } +} + +/// 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]); +} + +/// 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) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; + 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() != 8) { + 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], Record[6], + Record[7]); + 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], + /*nocallersavedregs*/ Record[6], + /*nocfcheck*/ Record[7]); + + unsigned Idx = 8; + + EPI.Variadic = Record[Idx++]; + EPI.HasTrailingReturn = Record[Idx++]; + EPI.TypeQuals = Qualifiers::fromOpaqueValue(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)); + + SmallVector<FunctionProtoType::ExtParameterInfo, 4> ExtParameterInfos; + if (Idx != Record.size()) { + for (unsigned I = 0; I != NumParams; ++I) + ExtParameterInfos.push_back( + FunctionProtoType::ExtParameterInfo + ::getFromOpaqueValue(Record[Idx++])); + EPI.ExtParameterInfos = ExtParameterInfos.data(); + } + + assert(Idx == Record.size()); + + 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); + AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getAutoType(Deduced, Keyword, IsDependent); + } + + case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { + TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getDeducedTemplateSpecializationType(Name, Deduced, + 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); + TagDecl *OwnedTagDecl = ReadDeclAs<TagDecl>(*Loc.F, Record, Idx); + return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedTagDecl); + } + + case TYPE_OBJC_INTERFACE: { + unsigned Idx = 0; + ObjCInterfaceDecl *ItfD + = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx); + return Context.getObjCInterfaceType(ItfD->getCanonicalDecl()); + } + + case TYPE_OBJC_TYPE_PARAM: { + unsigned Idx = 0; + ObjCTypeParamDecl *Decl + = ReadDeclAs<ObjCTypeParamDecl>(*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.getObjCTypeParamType(Decl, Protos); + } + + case TYPE_OBJC_OBJECT: { + unsigned Idx = 0; + QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumTypeArgs = Record[Idx++]; + SmallVector<QualType, 4> TypeArgs; + for (unsigned I = 0; I != NumTypeArgs; ++I) + TypeArgs.push_back(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)); + bool IsKindOf = Record[Idx++]; + return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf); + } + + 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 = 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 = 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); + } + + 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); + else + T = Context.getTemplateSpecializationType(Name, Args, 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); + } + + case TYPE_PIPE: { + if (Record.size() != 2) { + Error("Incorrect encoding of pipe type"); + return QualType(); + } + + // Reading the pipe element type. + QualType ElementType = readType(*Loc.F, Record, Idx); + unsigned ReadOnly = Record[1]; + return Context.getPipeType(ElementType, ReadOnly); + } + + case TYPE_DEPENDENT_SIZED_VECTOR: { + unsigned Idx = 0; + QualType ElementType = readType(*Loc.F, Record, Idx); + Expr *SizeExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + unsigned VecKind = Record[Idx]; + + return Context.getDependentVectorType(ElementType, SizeExpr, AttrLoc, + (VectorType::VectorKind)VecKind); + } + + case TYPE_DEPENDENT_SIZED_EXT_VECTOR: { + unsigned Idx = 0; + + // DependentSizedExtVectorType + QualType ElementType = readType(*Loc.F, Record, Idx); + Expr *SizeExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + + return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, + AttrLoc); + } + + case TYPE_DEPENDENT_ADDRESS_SPACE: { + unsigned Idx = 0; + + // DependentAddressSpaceType + QualType PointeeType = readType(*Loc.F, Record, Idx); + Expr *AddrSpaceExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + + return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr, + AttrLoc); + } + } + 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 (isComputedNoexcept(EST)) { + 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); + } +} + +namespace clang { + +class TypeLocReader : public TypeLocVisitor<TypeLocReader> { + ModuleFile *F; + ASTReader *Reader; + const ASTReader::RecordData &Record; + unsigned &Idx; + + SourceLocation ReadSourceLocation() { + return Reader->ReadSourceLocation(*F, Record, Idx); + } + + TypeSourceInfo *GetTypeSourceInfo() { + return Reader->GetTypeSourceInfo(*F, Record, Idx); + } + + NestedNameSpecifierLoc ReadNestedNameSpecifierLoc() { + return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx); + } + + Attr *ReadAttr() { + return Reader->ReadAttr(*F, Record, Idx); + } + +public: + TypeLocReader(ModuleFile &F, ASTReader &Reader, + const ASTReader::RecordData &Record, unsigned &Idx) + : F(&F), Reader(&Reader), 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); +}; + +} // namespace clang + +void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} + +void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + TL.setBuiltinLoc(ReadSourceLocation()); + 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()); +} + +void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) { + // nothing to do +} + +void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { + // nothing to do +} + +void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + TL.setCaretLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + TL.setAmpLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + TL.setAmpAmpLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation()); + TL.setClassTInfo(GetTypeSourceInfo()); +} + +void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { + TL.setLBracketLoc(ReadSourceLocation()); + TL.setRBracketLoc(ReadSourceLocation()); + 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::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + + TL.setAttrNameLoc(ReadSourceLocation()); + SourceRange range; + range.setBegin(ReadSourceLocation()); + range.setEnd(ReadSourceLocation()); + TL.setAttrOperandParensRange(range); + TL.setAttrExprOperand(Reader->ReadExpr(*F)); +} + +void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitDependentVectorTypeLoc( + DependentVectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + TL.setLocalRangeBegin(ReadSourceLocation()); + TL.setLParenLoc(ReadSourceLocation()); + TL.setRParenLoc(ReadSourceLocation()); + TL.setExceptionSpecRange(SourceRange(Reader->ReadSourceLocation(*F, Record, Idx), + Reader->ReadSourceLocation(*F, Record, Idx))); + TL.setLocalRangeEnd(ReadSourceLocation()); + for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { + TL.setParam(i, Reader->ReadDeclAs<ParmVarDecl>(*F, Record, Idx)); + } +} + +void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} + +void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} + +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + TL.setTypeofLoc(ReadSourceLocation()); + TL.setLParenLoc(ReadSourceLocation()); + TL.setRParenLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + TL.setTypeofLoc(ReadSourceLocation()); + TL.setLParenLoc(ReadSourceLocation()); + TL.setRParenLoc(ReadSourceLocation()); + TL.setUnderlyingTInfo(GetTypeSourceInfo()); +} + +void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation()); + TL.setLParenLoc(ReadSourceLocation()); + TL.setRParenLoc(ReadSourceLocation()); + TL.setUnderlyingTInfo(GetTypeSourceInfo()); +} + +void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + TL.setTemplateNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { + TL.setAttr(ReadAttr()); +} + +void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + TL.setTemplateKeywordLoc(ReadSourceLocation()); + TL.setTemplateNameLoc(ReadSourceLocation()); + TL.setLAngleLoc(ReadSourceLocation()); + TL.setRAngleLoc(ReadSourceLocation()); + 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()); + TL.setRParenLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); +} + +void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); + TL.setTemplateKeywordLoc(ReadSourceLocation()); + TL.setTemplateNameLoc(ReadSourceLocation()); + TL.setLAngleLoc(ReadSourceLocation()); + TL.setRAngleLoc(ReadSourceLocation()); + 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()); +} + +void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { + if (TL.getNumProtocols()) { + TL.setProtocolLAngleLoc(ReadSourceLocation()); + TL.setProtocolRAngleLoc(ReadSourceLocation()); + } + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, ReadSourceLocation()); +} + +void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + TL.setHasBaseTypeAsWritten(Record[Idx++]); + TL.setTypeArgsLAngleLoc(ReadSourceLocation()); + TL.setTypeArgsRAngleLoc(ReadSourceLocation()); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + TL.setTypeArgTInfo(i, GetTypeSourceInfo()); + TL.setProtocolLAngleLoc(ReadSourceLocation()); + TL.setProtocolRAngleLoc(ReadSourceLocation()); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, ReadSourceLocation()); +} + +void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation()); + TL.setLParenLoc(ReadSourceLocation()); + TL.setRParenLoc(ReadSourceLocation()); +} + +void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation()); +} + +void ASTReader::ReadTypeLoc(ModuleFile &F, const ASTReader::RecordData &Record, + unsigned &Idx, TypeLoc TL) { + TypeLocReader TLR(F, *this, Record, Idx); + for (; !TL.isNull(); TL = TL.getNextTypeLoc()) + TLR.Visit(TL); +} + +TypeSourceInfo * +ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record, + unsigned &Idx) { + QualType InfoTy = readType(F, Record, Idx); + if (InfoTy.isNull()) + return nullptr; + + TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); + ReadTypeLoc(F, Record, Idx, TInfo->getTypeLoc()); + return TInfo; +} + +QualType ASTReader::GetType(TypeID ID) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; + + 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_SHORT_ACCUM_ID: + T = Context.ShortAccumTy; + break; + case PREDEF_TYPE_ACCUM_ID: + T = Context.AccumTy; + break; + case PREDEF_TYPE_LONG_ACCUM_ID: + T = Context.LongAccumTy; + break; + case PREDEF_TYPE_USHORT_ACCUM_ID: + T = Context.UnsignedShortAccumTy; + break; + case PREDEF_TYPE_UACCUM_ID: + T = Context.UnsignedAccumTy; + break; + case PREDEF_TYPE_ULONG_ACCUM_ID: + T = Context.UnsignedLongAccumTy; + break; + case PREDEF_TYPE_SHORT_FRACT_ID: + T = Context.ShortFractTy; + break; + case PREDEF_TYPE_FRACT_ID: + T = Context.FractTy; + break; + case PREDEF_TYPE_LONG_FRACT_ID: + T = Context.LongFractTy; + break; + case PREDEF_TYPE_USHORT_FRACT_ID: + T = Context.UnsignedShortFractTy; + break; + case PREDEF_TYPE_UFRACT_ID: + T = Context.UnsignedFractTy; + break; + case PREDEF_TYPE_ULONG_FRACT_ID: + T = Context.UnsignedLongFractTy; + break; + case PREDEF_TYPE_SAT_SHORT_ACCUM_ID: + T = Context.SatShortAccumTy; + break; + case PREDEF_TYPE_SAT_ACCUM_ID: + T = Context.SatAccumTy; + break; + case PREDEF_TYPE_SAT_LONG_ACCUM_ID: + T = Context.SatLongAccumTy; + break; + case PREDEF_TYPE_SAT_USHORT_ACCUM_ID: + T = Context.SatUnsignedShortAccumTy; + break; + case PREDEF_TYPE_SAT_UACCUM_ID: + T = Context.SatUnsignedAccumTy; + break; + case PREDEF_TYPE_SAT_ULONG_ACCUM_ID: + T = Context.SatUnsignedLongAccumTy; + break; + case PREDEF_TYPE_SAT_SHORT_FRACT_ID: + T = Context.SatShortFractTy; + break; + case PREDEF_TYPE_SAT_FRACT_ID: + T = Context.SatFractTy; + break; + case PREDEF_TYPE_SAT_LONG_FRACT_ID: + T = Context.SatLongFractTy; + break; + case PREDEF_TYPE_SAT_USHORT_FRACT_ID: + T = Context.SatUnsignedShortFractTy; + break; + case PREDEF_TYPE_SAT_UFRACT_ID: + T = Context.SatUnsignedFractTy; + break; + case PREDEF_TYPE_SAT_ULONG_FRACT_ID: + T = Context.SatUnsignedLongFractTy; + break; + case PREDEF_TYPE_FLOAT16_ID: + T = Context.Float16Ty; + break; + case PREDEF_TYPE_FLOAT128_ID: + T = Context.Float128Ty; + 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_CHAR8_ID: + T = Context.Char8Ty; + 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; +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case PREDEF_TYPE_##Id##_ID: \ + T = Context.SingletonId; \ + break; +#include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + case PREDEF_TYPE_##Id##_ID: \ + T = Context.Id##Ty; \ + break; +#include "clang/Basic/OpenCLExtensionTypes.def" + case PREDEF_TYPE_SAMPLER_ID: + T = Context.OCLSamplerTy; + break; + case PREDEF_TYPE_EVENT_ID: + T = Context.OCLEventTy; + break; + case PREDEF_TYPE_CLK_EVENT_ID: + T = Context.OCLClkEventTy; + break; + case PREDEF_TYPE_QUEUE_ID: + T = Context.OCLQueueTy; + break; + case PREDEF_TYPE_RESERVE_ID_ID: + T = Context.OCLReserveIDTy; + 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_BUILTIN_FN: + T = Context.BuiltinFnTy; + break; + case PREDEF_TYPE_OMP_ARRAY_SECTION: + T = Context.OMPArraySectionTy; + 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; + + if (!F.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(F); + + 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); +} + +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()) { + if (!getContext().getLangOpts().CPlusPlus && + isa<TranslationUnitDecl>(DC)) { + // Outside of C++, we don't have a lookup table for the TU, so update + // the identifier instead. (For C++ modules, we don't store decls + // in the serialized identifier table, so we do the lookup in the TU.) + auto *II = Name.getAsIdentifierInfo(); + assert(II && "non-identifier name in C?"); + if (II->isOutOfDate()) + updateOutOfDateIdentifier(*II); + } else + DC->lookup(Name); + } else if (needsAnonymousDeclarationNumber(cast<NamedDecl>(D))) { + // Find all declarations of this kind from the relevant context. + for (auto *DCDecl : cast<Decl>(D->getLexicalDeclContext())->redecls()) { + auto *DC = cast<DeclContext>(DCDecl); + SmallVector<Decl*, 8> Decls; + FindExternalLexicalDecls( + DC, [&](Decl::Kind K) { return K == D->getKind(); }, Decls); + } + } + } + + 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(); + } +} + +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); +} + +CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + assert(ContextObj && "reading base specifiers with no AST context"); + ASTContext &Context = *ContextObj; + + 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; + + if (!F.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(F); + + 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; + + return ID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && + ID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls; +} + +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(); + + SourceLocation Loc; + DeclCursorForID(ID, Loc); + return Loc; +} + +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_VA_LIST_TAG: + return Context.getVaListTagDecl(); + + case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID: + return Context.getBuiltinMSVaListDecl(); + + case PREDEF_DECL_EXTERN_C_CONTEXT_ID: + return Context.getExternCContextDecl(); + + case PREDEF_DECL_MAKE_INTEGER_SEQ_ID: + return Context.getMakeIntegerSeqDecl(); + + case PREDEF_DECL_CF_CONSTANT_STRING_ID: + return Context.getCFConstantStringDecl(); + + case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID: + return Context.getCFConstantStringTagDecl(); + + case PREDEF_DECL_TYPE_PACK_ELEMENT_ID: + return Context.getTypePackElementDecl(); + } + llvm_unreachable("PredefinedDeclIDs unknown enum value"); +} + +Decl *ASTReader::GetExistingDecl(DeclID ID) { + assert(ContextObj && "reading decl with no AST context"); + if (ID < NUM_PREDEF_DECL_IDS) { + Decl *D = getPredefinedDecl(*ContextObj, (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 = KeyDecls[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++]); +} + +/// 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); + assert(NumCurrentElementsDeserializing == 0 && + "should not be called while already deserializing"); + Deserializing D(this); + return ReadStmtFromStream(*Loc.F); +} + +void ASTReader::FindExternalLexicalDecls( + const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Decls) { + bool PredefsVisited[NUM_PREDEF_DECL_IDS] = {}; + + auto Visit = [&] (ModuleFile *M, LexicalContents LexicalDecls) { + assert(LexicalDecls.size() % 2 == 0 && "expected an even number of entries"); + for (int I = 0, N = LexicalDecls.size(); I != N; I += 2) { + auto K = (Decl::Kind)+LexicalDecls[I]; + if (!IsKindWeWant(K)) + continue; + + auto ID = (serialization::DeclID)+LexicalDecls[I + 1]; + + // Don't add predefined declarations to the lexical context more + // than once. + if (ID < NUM_PREDEF_DECL_IDS) { + if (PredefsVisited[ID]) + continue; + + PredefsVisited[ID] = true; + } + + if (Decl *D = GetLocalDecl(*M, ID)) { + assert(D->getKind() == K && "wrong kind for lexical decl"); + if (!DC->isDeclInLexicalTraversal(D)) + Decls.push_back(D); + } + } + }; + + if (isa<TranslationUnitDecl>(DC)) { + for (auto Lexical : TULexicalDecls) + Visit(Lexical.first, Lexical.second); + } else { + auto I = LexicalDecls.find(DC); + if (I != LexicalDecls.end()) + Visit(I->second.first, I->second.second); + } + + ++NumLexicalDeclContextsRead; +} + +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))); + } +}; + +} // namespace + +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))); +} + +bool +ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() && + "DeclContext has no visible decls in storage"); + if (!Name) + return false; + + auto It = Lookups.find(DC); + if (It == Lookups.end()) + return false; + + Deserializing LookupResults(this); + + // Load the list of declarations. + SmallVector<NamedDecl *, 64> Decls; + for (DeclID ID : It->second.Table.find(Name)) { + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); + if (ND->getDeclName() == Name) + Decls.push_back(ND); + } + + ++NumVisibleDeclContextsRead; + SetExternalVisibleDeclsForName(DC, Name, Decls); + return !Decls.empty(); +} + +void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { + if (!DC->hasExternalVisibleStorage()) + return; + + auto It = Lookups.find(DC); + assert(It != Lookups.end() && + "have external visible storage but no lookup tables"); + + DeclsMap Decls; + + for (DeclID ID : It->second.Table.findAll()) { + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); + Decls[ND->getDeclName()].push_back(ND); + } + + ++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); +} + +const serialization::reader::DeclContextLookupTable * +ASTReader::getLoadedLookupTables(DeclContext *Primary) const { + auto I = Lookups.find(Primary); + return I == Lookups.end() ? nullptr : &I->second; +} + +/// 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::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> +LLVM_DUMP_METHOD static void +dumpModuleIDMap(StringRef Name, + const ContinuousRangeMap<Key, ModuleFile *, + InitialCapacity> &Map) { + if (Map.begin() == Map.end()) + return; + + using MapType = ContinuousRangeMap<Key, ModuleFile *, InitialCapacity>; + + 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"; + } +} + +LLVM_DUMP_METHOD 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 (ModuleFile &M : ModuleMgr) + 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 (ModuleFile &I : ModuleMgr) { + if (llvm::MemoryBuffer *buf = I.Buffer) { + 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 = FPOptions(FPPragmaOptions[0]); + } + + SemaObj->OpenCLFeatures.copy(OpenCLExtensions); + SemaObj->OpenCLTypeExtMap = OpenCLTypeExtMap; + SemaObj->OpenCLDeclExtMap = OpenCLDeclExtMap; + + 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() % 3 == 0); + for (unsigned I = 0; I != SemaDeclRefs.size(); I += 3) { + if (!SemaObj->StdNamespace) + SemaObj->StdNamespace = SemaDeclRefs[I]; + if (!SemaObj->StdBadAlloc) + SemaObj->StdBadAlloc = SemaDeclRefs[I+1]; + if (!SemaObj->StdAlignValT) + SemaObj->StdAlignValT = SemaDeclRefs[I+2]; + } + SemaDeclRefs.clear(); + } + + // Update the state of pragmas. Use the same API as if we had encountered the + // pragma in the source. + if(OptimizeOffPragmaLocation.isValid()) + SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation); + if (PragmaMSStructState != -1) + SemaObj->ActOnPragmaMSStruct((PragmaMSStructKind)PragmaMSStructState); + if (PointersToMembersPragmaLocation.isValid()) { + SemaObj->ActOnPragmaMSPointersToMembers( + (LangOptions::PragmaMSPointersToMembersKind) + PragmaMSPointersToMembersState, + PointersToMembersPragmaLocation); + } + SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth; + + if (PragmaPackCurrentValue) { + // The bottom of the stack might have a default value. It must be adjusted + // to the current value to ensure that the packing state is preserved after + // popping entries that were included/imported from a PCH/module. + bool DropFirst = false; + if (!PragmaPackStack.empty() && + PragmaPackStack.front().Location.isInvalid()) { + assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + SemaObj->PackStack.Stack.emplace_back( + PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue, + SemaObj->PackStack.CurrentPragmaLocation, + PragmaPackStack.front().PushLocation); + DropFirst = true; + } + for (const auto &Entry : + llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) + SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value, + Entry.Location, Entry.PushLocation); + if (PragmaPackCurrentLocation.isInvalid()) { + assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + // Keep the current values. + } else { + SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue; + SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation; + } + } +} + +IdentifierInfo *ASTReader::get(StringRef Name) { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + + IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0, + NumIdentifierLookups, + NumIdentifierLookupHits); + + // We don't need to do identifier table lookups in C++ modules (we preload + // all interesting declarations, and don't need to use the scope for name + // lookups). Perform the lookup in PCH files, though, since we don't build + // a complete initial identifier table if we're carrying on from a PCH. + if (PP.getLangOpts().CPlusPlus) { + for (auto F : ModuleMgr.pch_modules()) + if (Visitor(*F)) + break; + } else { + // 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; + } + } + + ModuleMgr.visit(Visitor, HitsPtr); + } + + IdentifierInfo *II = Visitor.getIdentifierInfo(); + markIdentifierUpToDate(II); + return II; +} + +namespace clang { + + /// An identifier-lookup iterator that enumerates all of the + /// identifiers stored within a set of AST files. + class ASTIdentifierIterator : public IdentifierIterator { + /// The AST reader whose identifiers are being enumerated. + const ASTReader &Reader; + + /// The current index into the chain of AST files stored in + /// the AST reader. + unsigned Index; + + /// The current position within the identifier lookup table + /// of the current AST file. + ASTIdentifierLookupTable::key_iterator Current; + + /// The end position within the identifier lookup table of + /// the current AST file. + ASTIdentifierLookupTable::key_iterator End; + + /// Whether to skip any modules in the ASTReader. + bool SkipModules; + + public: + explicit ASTIdentifierIterator(const ASTReader &Reader, + bool SkipModules = false); + + StringRef Next() override; + }; + +} // namespace clang + +ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader, + bool SkipModules) + : Reader(Reader), Index(Reader.ModuleMgr.size()), SkipModules(SkipModules) { +} + +StringRef ASTIdentifierIterator::Next() { + while (Current == End) { + // If we have exhausted all of our AST files, we're done. + if (Index == 0) + return StringRef(); + + --Index; + ModuleFile &F = Reader.ModuleMgr[Index]; + if (SkipModules && F.isModule()) + continue; + + ASTIdentifierLookupTable *IdTable = + (ASTIdentifierLookupTable *)F.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; +} + +namespace { + +/// A utility for appending two IdentifierIterators. +class ChainedIdentifierIterator : public IdentifierIterator { + std::unique_ptr<IdentifierIterator> Current; + std::unique_ptr<IdentifierIterator> Queued; + +public: + ChainedIdentifierIterator(std::unique_ptr<IdentifierIterator> First, + std::unique_ptr<IdentifierIterator> Second) + : Current(std::move(First)), Queued(std::move(Second)) {} + + StringRef Next() override { + if (!Current) + return StringRef(); + + StringRef result = Current->Next(); + if (!result.empty()) + return result; + + // Try the queued iterator, which may itself be empty. + Current.reset(); + std::swap(Current, Queued); + return Next(); + } +}; + +} // namespace + +IdentifierIterator *ASTReader::getIdentifiers() { + if (!loadGlobalIndex()) { + std::unique_ptr<IdentifierIterator> ReaderIter( + new ASTIdentifierIterator(*this, /*SkipModules=*/true)); + std::unique_ptr<IdentifierIterator> ModulesIter( + GlobalIndex->createIdentifierIterator()); + return new ChainedIdentifierIterator(std::move(ReaderIter), + std::move(ModulesIter)); + } + + return new ASTIdentifierIterator(*this); +} + +namespace clang { +namespace serialization { + + class ReadMethodPoolVisitor { + ASTReader &Reader; + Selector Sel; + unsigned PriorGeneration; + unsigned InstanceBits = 0; + unsigned FactoryBits = 0; + bool InstanceHasMoreThanOneDecl = false; + bool FactoryHasMoreThanOneDecl = false; + SmallVector<ObjCMethodDecl *, 4> InstanceMethods; + SmallVector<ObjCMethodDecl *, 4> FactoryMethods; + + public: + ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, + unsigned PriorGeneration) + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) {} + + bool operator()(ModuleFile &M) { + if (!M.SelectorLookupTable) + return false; + + // If we've already searched this module file, skip it now. + if (M.Generation <= PriorGeneration) + return true; + + ++Reader.NumMethodPoolTableLookups; + ASTSelectorLookupTable *PoolTable + = (ASTSelectorLookupTable*)M.SelectorLookupTable; + ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); + if (Pos == PoolTable->end()) + return false; + + ++Reader.NumMethodPoolTableHits; + ++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? + ++Reader.NumMethodPoolEntriesRead; + ASTSelectorLookupTrait::data_type Data = *Pos; + if (Reader.DeserializationListener) + Reader.DeserializationListener->SelectorRead(Data.ID, Sel); + + InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); + FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + InstanceBits = Data.InstanceBits; + FactoryBits = Data.FactoryBits; + InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; + FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; + return true; + } + + /// Retrieve the instance methods found by this visitor. + ArrayRef<ObjCMethodDecl *> getInstanceMethods() const { + return InstanceMethods; + } + + /// 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; } + }; + +} // namespace serialization +} // namespace clang + +/// 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(); + SelectorOutOfDate[Sel] = false; + + // Search for methods defined with this selector. + ++NumMethodPoolLookups; + ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); + ModuleMgr.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::updateOutOfDateSelector(Selector Sel) { + if (SelectorOutOfDate[Sel]) + ReadMethodPool(Sel); +} + +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::MapVector<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 *, std::unique_ptr<LateParsedTemplate>> + &LPTMap) { + for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N; + /* In loop */) { + FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++])); + + auto LT = llvm::make_unique<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, std::move(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); +} + +/// 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; + auto &II = PP.getIdentifierTable().get(StringRef(Str, StrLen)); + IdentifiersLoaded[ID] = &II; + markIdentifierFromAST(*this, II); + if (DeserializationListener) + DeserializationListener->IdentifierRead(ID + 1, &II); + } + + 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; + + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + + 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; + + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + + 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; + + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + + 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); +} + +bool ASTReader::DeclIsFromPCHWithObjectFile(const Decl *D) { + ModuleFile *MF = getOwningModuleFile(D); + return MF && MF->PCHHasObjectFile; +} + +ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) { + if (ID & 1) { + // It's a module, look it up by submodule ID. + auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1)); + return I == GlobalSubmoduleMap.end() ? nullptr : I->second; + } else { + // It's a prefix (preamble, PCH, ...). Look it up by index. + unsigned IndexFromEnd = ID >> 1; + assert(IndexFromEnd && "got reference to unknown module file"); + return getModuleManager().pch_modules().end()[-IndexFromEnd]; + } +} + +unsigned ASTReader::getModuleFileID(ModuleFile *F) { + if (!F) + return 1; + + // For a file representing a module, use the submodule ID of the top-level + // module as the file ID. For any other kind of file, the number of such + // files loaded beforehand will be the same on reload. + // FIXME: Is this true even if we have an explicit module file and a PCH? + if (F->isModule()) + return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1; + + auto PCHModules = getModuleManager().pch_modules(); + auto I = std::find(PCHModules.begin(), PCHModules.end(), F); + assert(I != PCHModules.end() && "emitting reference to unknown file"); + return (I - PCHModules.end()) << 1; +} + +llvm::Optional<ExternalASTSource::ASTSourceDescriptor> +ASTReader::getSourceDescriptor(unsigned ID) { + if (const Module *M = getSubmodule(ID)) + return ExternalASTSource::ASTSourceDescriptor(*M); + + // If there is only a single PCH, return it instead. + // Chained PCH are not supported. + const auto &PCHChain = ModuleMgr.pch_modules(); + if (std::distance(std::begin(PCHChain), std::end(PCHChain))) { + ModuleFile &MF = ModuleMgr.getPrimaryModule(); + StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName); + StringRef FileName = llvm::sys::path::filename(MF.FileName); + return ASTReader::ASTSourceDescriptor(ModuleName, MF.OriginalDir, FileName, + MF.Signature); + } + return None; +} + +ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { + auto I = DefinitionSource.find(FD); + if (I == DefinitionSource.end()) + return EK_ReplyHazy; + return I->second ? EK_Never : EK_Always; +} + +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; + + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + + 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) { + ASTContext &Context = getContext(); + 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::CXXDeductionGuideName: + return Context.DeclarationNames.getCXXDeductionGuideName( + ReadDeclAs<TemplateDecl>(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: + case DeclarationName::CXXDeductionGuideName: + 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 (getContext()) 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) { + ASTContext &Context = getContext(); + 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, + bool Canonicalize) { + ASTContext &Context = getContext(); + if (Canonicalize) { + // The caller wants a canonical template argument. Sometimes the AST only + // wants template arguments in canonical form (particularly as the template + // argument lists of template specializations) so ensure we preserve that + // canonical form across serialization. + TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false); + return Context.getCanonicalTemplateArgument(Arg); + } + + 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(llvm::makeArrayRef(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)); + + // TODO: Concepts + TemplateParameterList *TemplateParams = TemplateParameterList::Create( + getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); + return TemplateParams; +} + +void +ASTReader:: +ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, + ModuleFile &F, const RecordData &Record, + unsigned &Idx, bool Canonicalize) { + unsigned NumTemplateArgs = Record[Idx++]; + TemplArgs.reserve(NumTemplateArgs); + while (NumTemplateArgs--) + TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize)); +} + +/// Read a UnresolvedSet structure. +void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, + const RecordData &Record, unsigned &Idx) { + unsigned NumDecls = Record[Idx++]; + Set.reserve(getContext(), NumDecls); + while (NumDecls--) { + DeclID ID = ReadDeclID(F, Record, Idx); + AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; + Set.addLazyDecl(getContext(), 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) { + ASTContext &Context = getContext(); + 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); + + 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 (Member) + BOMInit = new (Context) + CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc, + Init, RParenLoc); + else + BOMInit = new (Context) + CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, + LParenLoc, Init, RParenLoc); + + if (/*IsWritten*/Record[Idx++]) { + unsigned SourceOrder = Record[Idx++]; + BOMInit->setSourceOrder(SourceOrder); + } + + CtorInitializers[i] = BOMInit; + } + + return CtorInitializers; +} + +NestedNameSpecifier * +ASTReader::ReadNestedNameSpecifier(ModuleFile &F, + const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); + 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) { + ASTContext &Context = getContext(); + 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); +} + +/// 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; +} + +/// 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); +} + +/// 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)); +} + +// 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(getContext(), Decl); +} + +DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const { + return Diag(CurrentImportLoc, DiagID); +} + +DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const { + return Diags.Report(Loc, DiagID); +} + +/// Retrieve the identifier table associated with the +/// preprocessor. +IdentifierTable &ASTReader::getIdentifierTable() { + return PP.getIdentifierTable(); +} + +/// 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; +} + +/// 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() { + ASTContext &Context = getContext(); + 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)); + break; + } + } + } + NextCursor: + // De-serialized SourceLocations get negative FileIDs for other modules, + // potentially invalidating the original order. Sort it again. + llvm::sort(Comments, BeforeThanCompare<RawComment>(SourceMgr)); + Context.Comments.addDeserializedComments(Comments); + } +} + +void ASTReader::visitInputFiles(serialization::ModuleFile &MF, + bool IncludeSystem, bool Complain, + llvm::function_ref<void(const serialization::InputFile &IF, + bool isSystem)> Visitor) { + unsigned NumUserInputs = MF.NumUserInputFiles; + unsigned NumInputs = MF.InputFilesLoaded.size(); + assert(NumUserInputs <= NumInputs); + unsigned N = IncludeSystem ? NumInputs : NumUserInputs; + for (unsigned I = 0; I < N; ++I) { + bool IsSystem = I >= NumUserInputs; + InputFile IF = getInputFile(MF, I+1, Complain); + Visitor(IF, IsSystem); + } +} + +void ASTReader::visitTopLevelModuleMaps( + serialization::ModuleFile &MF, + llvm::function_ref<void(const FileEntry *FE)> Visitor) { + unsigned NumInputs = MF.InputFilesLoaded.size(); + for (unsigned I = 0; I < NumInputs; ++I) { + InputFileInfo IFI = readInputFileInfo(MF, I + 1); + if (IFI.TopLevelModuleMap) + // FIXME: This unnecessarily re-reads the InputFileInfo. + if (auto *FE = getInputFile(MF, I + 1).getFile()) + Visitor(FE); + } +} + +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() || !PendingFunctionTypes.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. + using TopLevelDeclsMap = + llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2>>; + 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]); + } + + // Load each function type that we deferred loading because it was a + // deduced type that might refer to a local type declared within itself. + for (unsigned I = 0; I != PendingFunctionTypes.size(); ++I) { + auto *FD = PendingFunctionTypes[I].first; + FD->setType(GetType(PendingFunctionTypes[I].second)); + + // If we gave a function a deduced return type, remember that we need to + // propagate that along the redeclaration chain. + auto *DT = FD->getReturnType()->getContainedDeducedType(); + if (DT && DT->isDeduced()) + PendingDeducedTypeUpdates.insert( + {FD->getCanonicalDecl(), FD->getReturnType()}); + } + PendingFunctionTypes.clear(); + + // 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) + loadPendingDeclChain(PendingDeclChains[I].first, + PendingDeclChains[I].second); + 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->isModule()) + resolvePendingMacro(II, Info); + } + // Handle module imports. + for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; + ++IDIdx) { + const PendingMacroInfo &Info = GlobalIDs[IDIdx]; + if (Info.M->isModule()) + 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); + } + } + + // 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 (hasBody relies on this). + // FIXME: We shouldn't require complete redeclaration chains here. + for (PendingBodiesMap::iterator PB = PendingBodies.begin(), + PBEnd = PendingBodies.end(); + PB != PBEnd; ++PB) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) { + // For a function defined inline within a class template, force the + // canonical definition to be the one inside the canonical definition of + // the template. This ensures that we instantiate from a correct view + // of the template. + // + // Sadly we can't do this more generally: we can't be sure that all + // copies of an arbitrary class definition will have the same members + // defined (eg, some member functions may not be instantiated, and some + // special members may or may not have been implicitly defined). + if (auto *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalParent())) + if (RD->isDependentContext() && !RD->isThisDeclarationADefinition()) + continue; + + // FIXME: Check for =delete/=default? + // FIXME: Complain about ODR violations here? + const FunctionDecl *Defn = nullptr; + if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { + FD->setLazyBody(PB->second); + } else { + auto *NonConstDefn = const_cast<FunctionDecl*>(Defn); + mergeDefinitionVisibility(NonConstDefn, FD); + + if (!FD->isLateTemplateParsed() && + !NonConstDefn->isLateTemplateParsed() && + FD->getODRHash() != NonConstDefn->getODRHash()) { + if (!isa<CXXMethodDecl>(FD)) { + PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); + } else if (FD->getLexicalParent()->isFileContext() && + NonConstDefn->getLexicalParent()->isFileContext()) { + // Only diagnose out-of-line method definitions. If they are + // in class definitions, then an error will be generated when + // processing the class bodies. + PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); + } + } + } + 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() && + PendingFunctionOdrMergeFailures.empty() && + PendingEnumOdrMergeFailures.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 &RecordPair : Merge.second) { + auto *RD = RecordPair.first; + RD->decls_begin(); + RD->bases_begin(); + RD->vbases_begin(); + } + } + + // Trigger the import of functions. + auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMergeFailures); + PendingFunctionOdrMergeFailures.clear(); + for (auto &Merge : FunctionOdrMergeFailures) { + Merge.first->buildLookup(); + Merge.first->decls_begin(); + Merge.first->getBody(); + for (auto &FD : Merge.second) { + FD->buildLookup(); + FD->decls_begin(); + FD->getBody(); + } + } + + // Trigger the import of enums. + auto EnumOdrMergeFailures = std::move(PendingEnumOdrMergeFailures); + PendingEnumOdrMergeFailures.clear(); + for (auto &Merge : EnumOdrMergeFailures) { + Merge.first->decls_begin(); + for (auto &Enum : Merge.second) { + Enum->decls_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; + + // Quick check failed, time to do the slow thing. Note, we can't just + // look up the name of D in CanonDef here, because the member that is + // in CanonDef might not be found by name lookup (it might have been + // replaced by a more recent declaration in the lookup table), and we + // can't necessarily find it in the redeclaration chain because it might + // be merely mergeable, not redeclarable. + llvm::SmallVector<const NamedDecl*, 4> Candidates; + for (auto *CanonMember : CanonDef->decls()) { + if (CanonMember->getCanonicalDecl() == DCanon) { + // This can happen if the declaration is merely mergeable and not + // actually redeclarable (we looked for redeclarations earlier). + // + // FIXME: We should be able to detect this more efficiently, without + // pulling in all of the members of CanonDef. + Found = true; + break; + } + if (auto *ND = dyn_cast<NamedDecl>(CanonMember)) + if (ND->getDeclName() == D->getDeclName()) + Candidates.push_back(ND); + } + + 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() && FunctionOdrMergeFailures.empty() && + EnumOdrMergeFailures.empty()) + return; + + // Ensure we don't accidentally recursively enter deserialization while + // we're producing our diagnostics. + Deserializing RecursionGuard(this); + + // Common code for hashing helpers. + ODRHash Hash; + auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { + Hash.clear(); + Hash.AddQualType(Ty); + return Hash.CalculateHash(); + }; + + auto ComputeODRHash = [&Hash](const Stmt *S) { + assert(S); + Hash.clear(); + Hash.AddStmt(S); + return Hash.CalculateHash(); + }; + + auto ComputeSubDeclODRHash = [&Hash](const Decl *D) { + assert(D); + Hash.clear(); + Hash.AddSubDecl(D); + return Hash.CalculateHash(); + }; + + auto ComputeTemplateArgumentODRHash = [&Hash](const TemplateArgument &TA) { + Hash.clear(); + Hash.AddTemplateArgument(TA); + return Hash.CalculateHash(); + }; + + auto ComputeTemplateParameterListODRHash = + [&Hash](const TemplateParameterList *TPL) { + assert(TPL); + Hash.clear(); + Hash.AddTemplateParameterList(TPL); + return Hash.CalculateHash(); + }; + + // 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; + CXXRecordDecl *FirstRecord = Merge.first; + std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord); + for (auto &RecordPair : Merge.second) { + CXXRecordDecl *SecondRecord = RecordPair.first; + // Multiple different declarations got merged together; tell the user + // where they came from. + if (FirstRecord == SecondRecord) + continue; + + std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord); + + auto *FirstDD = FirstRecord->DefinitionData; + auto *SecondDD = RecordPair.second; + + assert(FirstDD && SecondDD && "Definitions without DefinitionData"); + + // Diagnostics from DefinitionData are emitted here. + if (FirstDD != SecondDD) { + enum ODRDefinitionDataDifference { + NumBases, + NumVBases, + BaseType, + BaseVirtual, + BaseAccess, + }; + auto ODRDiagError = [FirstRecord, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRDefinitionDataDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_definition_data) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, + this](SourceLocation Loc, SourceRange Range, + ODRDefinitionDataDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_definition_data) + << SecondModule << Range << DiffType; + }; + + unsigned FirstNumBases = FirstDD->NumBases; + unsigned FirstNumVBases = FirstDD->NumVBases; + unsigned SecondNumBases = SecondDD->NumBases; + unsigned SecondNumVBases = SecondDD->NumVBases; + + auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) { + unsigned NumBases = DD->NumBases; + if (NumBases == 0) return SourceRange(); + auto bases = DD->bases(); + return SourceRange(bases[0].getBeginLoc(), + bases[NumBases - 1].getEndLoc()); + }; + + if (FirstNumBases != SecondNumBases) { + ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD), + NumBases) + << FirstNumBases; + ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), + NumBases) + << SecondNumBases; + Diagnosed = true; + break; + } + + if (FirstNumVBases != SecondNumVBases) { + ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD), + NumVBases) + << FirstNumVBases; + ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), + NumVBases) + << SecondNumVBases; + Diagnosed = true; + break; + } + + auto FirstBases = FirstDD->bases(); + auto SecondBases = SecondDD->bases(); + unsigned i = 0; + for (i = 0; i < FirstNumBases; ++i) { + auto FirstBase = FirstBases[i]; + auto SecondBase = SecondBases[i]; + if (ComputeQualTypeODRHash(FirstBase.getType()) != + ComputeQualTypeODRHash(SecondBase.getType())) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseType) + << (i + 1) << FirstBase.getType(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseType) + << (i + 1) << SecondBase.getType(); + break; + } + + if (FirstBase.isVirtual() != SecondBase.isVirtual()) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseVirtual) + << (i + 1) << FirstBase.isVirtual() << FirstBase.getType(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseVirtual) + << (i + 1) << SecondBase.isVirtual() << SecondBase.getType(); + break; + } + + if (FirstBase.getAccessSpecifierAsWritten() != + SecondBase.getAccessSpecifierAsWritten()) { + ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(), + BaseAccess) + << (i + 1) << FirstBase.getType() + << (int)FirstBase.getAccessSpecifierAsWritten(); + ODRDiagNote(SecondRecord->getLocation(), + SecondBase.getSourceRange(), BaseAccess) + << (i + 1) << SecondBase.getType() + << (int)SecondBase.getAccessSpecifierAsWritten(); + break; + } + } + + if (i != FirstNumBases) { + Diagnosed = true; + break; + } + } + + using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>; + + const ClassTemplateDecl *FirstTemplate = + FirstRecord->getDescribedClassTemplate(); + const ClassTemplateDecl *SecondTemplate = + SecondRecord->getDescribedClassTemplate(); + + assert(!FirstTemplate == !SecondTemplate && + "Both pointers should be null or non-null"); + + enum ODRTemplateDifference { + ParamEmptyName, + ParamName, + ParamSingleDefaultArgument, + ParamDifferentDefaultArgument, + }; + + if (FirstTemplate && SecondTemplate) { + DeclHashes FirstTemplateHashes; + DeclHashes SecondTemplateHashes; + + auto PopulateTemplateParameterHashs = + [&ComputeSubDeclODRHash](DeclHashes &Hashes, + const ClassTemplateDecl *TD) { + for (auto *D : TD->getTemplateParameters()->asArray()) { + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); + } + }; + + PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate); + PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate); + + assert(FirstTemplateHashes.size() == SecondTemplateHashes.size() && + "Number of template parameters should be equal."); + + auto FirstIt = FirstTemplateHashes.begin(); + auto FirstEnd = FirstTemplateHashes.end(); + auto SecondIt = SecondTemplateHashes.begin(); + for (; FirstIt != FirstEnd; ++FirstIt, ++SecondIt) { + if (FirstIt->second == SecondIt->second) + continue; + + auto ODRDiagError = [FirstRecord, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRTemplateDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_template_parameter) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, + this](SourceLocation Loc, SourceRange Range, + ODRTemplateDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_template_parameter) + << SecondModule << Range << DiffType; + }; + + const NamedDecl* FirstDecl = cast<NamedDecl>(FirstIt->first); + const NamedDecl* SecondDecl = cast<NamedDecl>(SecondIt->first); + + assert(FirstDecl->getKind() == SecondDecl->getKind() && + "Parameter Decl's should be the same kind."); + + DeclarationName FirstName = FirstDecl->getDeclName(); + DeclarationName SecondName = SecondDecl->getDeclName(); + + if (FirstName != SecondName) { + const bool FirstNameEmpty = + FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo(); + const bool SecondNameEmpty = + SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo(); + assert((!FirstNameEmpty || !SecondNameEmpty) && + "Both template parameters cannot be unnamed."); + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + FirstNameEmpty ? ParamEmptyName : ParamName) + << FirstName; + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + SecondNameEmpty ? ParamEmptyName : ParamName) + << SecondName; + break; + } + + switch (FirstDecl->getKind()) { + default: + llvm_unreachable("Invalid template parameter type."); + case Decl::TemplateTypeParm: { + const auto *FirstParam = cast<TemplateTypeParmDecl>(FirstDecl); + const auto *SecondParam = cast<TemplateTypeParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + case Decl::NonTypeTemplateParm: { + const auto *FirstParam = cast<NonTypeTemplateParmDecl>(FirstDecl); + const auto *SecondParam = cast<NonTypeTemplateParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + case Decl::TemplateTemplateParm: { + const auto *FirstParam = cast<TemplateTemplateParmDecl>(FirstDecl); + const auto *SecondParam = + cast<TemplateTemplateParmDecl>(SecondDecl); + const bool HasFirstDefaultArgument = + FirstParam->hasDefaultArgument() && + !FirstParam->defaultArgumentWasInherited(); + const bool HasSecondDefaultArgument = + SecondParam->hasDefaultArgument() && + !SecondParam->defaultArgumentWasInherited(); + + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstDecl->getLocation(), + FirstDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasFirstDefaultArgument; + ODRDiagNote(SecondDecl->getLocation(), + SecondDecl->getSourceRange(), + ParamSingleDefaultArgument) + << HasSecondDefaultArgument; + break; + } + + assert(HasFirstDefaultArgument && HasSecondDefaultArgument && + "Expecting default arguments."); + + ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(), + ParamDifferentDefaultArgument); + ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(), + ParamDifferentDefaultArgument); + + break; + } + } + + break; + } + + if (FirstIt != FirstEnd) { + Diagnosed = true; + break; + } + } + + DeclHashes FirstHashes; + DeclHashes SecondHashes; + + auto PopulateHashes = [&ComputeSubDeclODRHash, FirstRecord]( + DeclHashes &Hashes, CXXRecordDecl *Record) { + for (auto *D : Record->decls()) { + // Due to decl merging, the first CXXRecordDecl is the parent of + // Decls in both records. + if (!ODRHash::isWhitelistedDecl(D, FirstRecord)) + continue; + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); + } + }; + PopulateHashes(FirstHashes, FirstRecord); + PopulateHashes(SecondHashes, SecondRecord); + + // Used with err_module_odr_violation_mismatch_decl and + // note_module_odr_violation_mismatch_decl + // This list should be the same Decl's as in ODRHash::isWhiteListedDecl + enum { + EndOfClass, + PublicSpecifer, + PrivateSpecifer, + ProtectedSpecifer, + StaticAssert, + Field, + CXXMethod, + TypeAlias, + TypeDef, + Var, + Friend, + FunctionTemplate, + Other + } FirstDiffType = Other, + SecondDiffType = Other; + + auto DifferenceSelector = [](Decl *D) { + assert(D && "valid Decl required"); + switch (D->getKind()) { + default: + return Other; + case Decl::AccessSpec: + switch (D->getAccess()) { + case AS_public: + return PublicSpecifer; + case AS_private: + return PrivateSpecifer; + case AS_protected: + return ProtectedSpecifer; + case AS_none: + break; + } + llvm_unreachable("Invalid access specifier"); + case Decl::StaticAssert: + return StaticAssert; + case Decl::Field: + return Field; + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + return CXXMethod; + case Decl::TypeAlias: + return TypeAlias; + case Decl::Typedef: + return TypeDef; + case Decl::Var: + return Var; + case Decl::Friend: + return Friend; + case Decl::FunctionTemplate: + return FunctionTemplate; + } + }; + + Decl *FirstDecl = nullptr; + Decl *SecondDecl = nullptr; + auto FirstIt = FirstHashes.begin(); + auto SecondIt = SecondHashes.begin(); + + // If there is a diagnoseable difference, FirstDiffType and + // SecondDiffType will not be Other and FirstDecl and SecondDecl will be + // filled in if not EndOfClass. + while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) { + if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() && + FirstIt->second == SecondIt->second) { + ++FirstIt; + ++SecondIt; + continue; + } + + FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; + SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; + + FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass; + SecondDiffType = + SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass; + + break; + } + + if (FirstDiffType == Other || SecondDiffType == Other) { + // Reaching this point means an unexpected Decl was encountered + // or no difference was detected. This causes a generic error + // message to be emitted. + Diag(FirstRecord->getLocation(), + diag::err_module_odr_violation_different_definitions) + << FirstRecord << FirstModule.empty() << FirstModule; + + if (FirstDecl) { + Diag(FirstDecl->getLocation(), diag::note_first_module_difference) + << FirstRecord << FirstDecl->getSourceRange(); + } + + Diag(SecondRecord->getLocation(), + diag::note_module_odr_violation_different_definitions) + << SecondModule; + + if (SecondDecl) { + Diag(SecondDecl->getLocation(), diag::note_second_module_difference) + << SecondDecl->getSourceRange(); + } + + Diagnosed = true; + break; + } + + if (FirstDiffType != SecondDiffType) { + SourceLocation FirstLoc; + SourceRange FirstRange; + if (FirstDiffType == EndOfClass) { + FirstLoc = FirstRecord->getBraceRange().getEnd(); + } else { + FirstLoc = FirstIt->first->getLocation(); + FirstRange = FirstIt->first->getSourceRange(); + } + Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl) + << FirstRecord << FirstModule.empty() << FirstModule << FirstRange + << FirstDiffType; + + SourceLocation SecondLoc; + SourceRange SecondRange; + if (SecondDiffType == EndOfClass) { + SecondLoc = SecondRecord->getBraceRange().getEnd(); + } else { + SecondLoc = SecondDecl->getLocation(); + SecondRange = SecondDecl->getSourceRange(); + } + Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl) + << SecondModule << SecondRange << SecondDiffType; + Diagnosed = true; + break; + } + + assert(FirstDiffType == SecondDiffType); + + // Used with err_module_odr_violation_mismatch_decl_diff and + // note_module_odr_violation_mismatch_decl_diff + enum ODRDeclDifference { + StaticAssertCondition, + StaticAssertMessage, + StaticAssertOnlyMessage, + FieldName, + FieldTypeName, + FieldSingleBitField, + FieldDifferentWidthBitField, + FieldSingleMutable, + FieldSingleInitializer, + FieldDifferentInitializers, + MethodName, + MethodDeleted, + MethodDefaulted, + MethodVirtual, + MethodStatic, + MethodVolatile, + MethodConst, + MethodInline, + MethodNumberParameters, + MethodParameterType, + MethodParameterName, + MethodParameterSingleDefaultArgument, + MethodParameterDifferentDefaultArgument, + MethodNoTemplateArguments, + MethodDifferentNumberTemplateArguments, + MethodDifferentTemplateArgument, + MethodSingleBody, + MethodDifferentBody, + TypedefName, + TypedefType, + VarName, + VarType, + VarSingleInitializer, + VarDifferentInitializer, + VarConstexpr, + FriendTypeFunction, + FriendType, + FriendFunction, + FunctionTemplateDifferentNumberParameters, + FunctionTemplateParameterDifferentKind, + FunctionTemplateParameterName, + FunctionTemplateParameterSingleDefaultArgument, + FunctionTemplateParameterDifferentDefaultArgument, + FunctionTemplateParameterDifferentType, + FunctionTemplatePackParameter, + }; + + // These lambdas have the common portions of the ODR diagnostics. This + // has the same return as Diag(), so addition parameters can be passed + // in with operator<< + auto ODRDiagError = [FirstRecord, &FirstModule, this]( + SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_diff) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, this]( + SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_diff) + << SecondModule << Range << DiffType; + }; + + switch (FirstDiffType) { + case Other: + case EndOfClass: + case PublicSpecifer: + case PrivateSpecifer: + case ProtectedSpecifer: + llvm_unreachable("Invalid diff type"); + + case StaticAssert: { + StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl); + StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl); + + Expr *FirstExpr = FirstSA->getAssertExpr(); + Expr *SecondExpr = SecondSA->getAssertExpr(); + unsigned FirstODRHash = ComputeODRHash(FirstExpr); + unsigned SecondODRHash = ComputeODRHash(SecondExpr); + if (FirstODRHash != SecondODRHash) { + ODRDiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(), + StaticAssertCondition); + ODRDiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(), + StaticAssertCondition); + Diagnosed = true; + break; + } + + StringLiteral *FirstStr = FirstSA->getMessage(); + StringLiteral *SecondStr = SecondSA->getMessage(); + assert((FirstStr || SecondStr) && "Both messages cannot be empty"); + if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) { + SourceLocation FirstLoc, SecondLoc; + SourceRange FirstRange, SecondRange; + if (FirstStr) { + FirstLoc = FirstStr->getBeginLoc(); + FirstRange = FirstStr->getSourceRange(); + } else { + FirstLoc = FirstSA->getBeginLoc(); + FirstRange = FirstSA->getSourceRange(); + } + if (SecondStr) { + SecondLoc = SecondStr->getBeginLoc(); + SecondRange = SecondStr->getSourceRange(); + } else { + SecondLoc = SecondSA->getBeginLoc(); + SecondRange = SecondSA->getSourceRange(); + } + ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage) + << (FirstStr == nullptr); + ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage) + << (SecondStr == nullptr); + Diagnosed = true; + break; + } + + if (FirstStr && SecondStr && + FirstStr->getString() != SecondStr->getString()) { + ODRDiagError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(), + StaticAssertMessage); + ODRDiagNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(), + StaticAssertMessage); + Diagnosed = true; + break; + } + break; + } + case Field: { + FieldDecl *FirstField = cast<FieldDecl>(FirstDecl); + FieldDecl *SecondField = cast<FieldDecl>(SecondDecl); + IdentifierInfo *FirstII = FirstField->getIdentifier(); + IdentifierInfo *SecondII = SecondField->getIdentifier(); + if (FirstII->getName() != SecondII->getName()) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldName) + << FirstII; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldName) + << SecondII; + + Diagnosed = true; + break; + } + + assert(getContext().hasSameType(FirstField->getType(), + SecondField->getType())); + + QualType FirstType = FirstField->getType(); + QualType SecondType = SecondField->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldTypeName) + << FirstII << FirstType; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldTypeName) + << SecondII << SecondType; + + Diagnosed = true; + break; + } + + const bool IsFirstBitField = FirstField->isBitField(); + const bool IsSecondBitField = SecondField->isBitField(); + if (IsFirstBitField != IsSecondBitField) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleBitField) + << FirstII << IsFirstBitField; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleBitField) + << SecondII << IsSecondBitField; + Diagnosed = true; + break; + } + + if (IsFirstBitField && IsSecondBitField) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldDifferentWidthBitField) + << FirstII << FirstField->getBitWidth()->getSourceRange(); + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldDifferentWidthBitField) + << SecondII << SecondField->getBitWidth()->getSourceRange(); + Diagnosed = true; + break; + } + + const bool IsFirstMutable = FirstField->isMutable(); + const bool IsSecondMutable = SecondField->isMutable(); + if (IsFirstMutable != IsSecondMutable) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleMutable) + << FirstII << IsFirstMutable; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleMutable) + << SecondII << IsSecondMutable; + Diagnosed = true; + break; + } + + const Expr *FirstInitializer = FirstField->getInClassInitializer(); + const Expr *SecondInitializer = SecondField->getInClassInitializer(); + if ((!FirstInitializer && SecondInitializer) || + (FirstInitializer && !SecondInitializer)) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleInitializer) + << FirstII << (FirstInitializer != nullptr); + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleInitializer) + << SecondII << (SecondInitializer != nullptr); + Diagnosed = true; + break; + } + + if (FirstInitializer && SecondInitializer) { + unsigned FirstInitHash = ComputeODRHash(FirstInitializer); + unsigned SecondInitHash = ComputeODRHash(SecondInitializer); + if (FirstInitHash != SecondInitHash) { + ODRDiagError(FirstField->getLocation(), + FirstField->getSourceRange(), + FieldDifferentInitializers) + << FirstII << FirstInitializer->getSourceRange(); + ODRDiagNote(SecondField->getLocation(), + SecondField->getSourceRange(), + FieldDifferentInitializers) + << SecondII << SecondInitializer->getSourceRange(); + Diagnosed = true; + break; + } + } + + break; + } + case CXXMethod: { + enum { + DiagMethod, + DiagConstructor, + DiagDestructor, + } FirstMethodType, + SecondMethodType; + auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl* D) { + if (isa<CXXConstructorDecl>(D)) return DiagConstructor; + if (isa<CXXDestructorDecl>(D)) return DiagDestructor; + return DiagMethod; + }; + const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl); + const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl); + FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod); + SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod); + auto FirstName = FirstMethod->getDeclName(); + auto SecondName = SecondMethod->getDeclName(); + if (FirstMethodType != SecondMethodType || FirstName != SecondName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodName) + << FirstMethodType << FirstName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodName) + << SecondMethodType << SecondName; + + Diagnosed = true; + break; + } + + const bool FirstDeleted = FirstMethod->isDeletedAsWritten(); + const bool SecondDeleted = SecondMethod->isDeletedAsWritten(); + if (FirstDeleted != SecondDeleted) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodDeleted) + << FirstMethodType << FirstName << FirstDeleted; + + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodDeleted) + << SecondMethodType << SecondName << SecondDeleted; + Diagnosed = true; + break; + } + + const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted(); + const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted(); + if (FirstDefaulted != SecondDefaulted) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodDefaulted) + << FirstMethodType << FirstName << FirstDefaulted; + + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodDefaulted) + << SecondMethodType << SecondName << SecondDefaulted; + Diagnosed = true; + break; + } + + const bool FirstVirtual = FirstMethod->isVirtualAsWritten(); + const bool SecondVirtual = SecondMethod->isVirtualAsWritten(); + const bool FirstPure = FirstMethod->isPure(); + const bool SecondPure = SecondMethod->isPure(); + if ((FirstVirtual || SecondVirtual) && + (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodVirtual) + << FirstMethodType << FirstName << FirstPure << FirstVirtual; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVirtual) + << SecondMethodType << SecondName << SecondPure << SecondVirtual; + Diagnosed = true; + break; + } + + // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging, + // FirstDecl is the canonical Decl of SecondDecl, so the storage + // class needs to be checked instead. + const auto FirstStorage = FirstMethod->getStorageClass(); + const auto SecondStorage = SecondMethod->getStorageClass(); + const bool FirstStatic = FirstStorage == SC_Static; + const bool SecondStatic = SecondStorage == SC_Static; + if (FirstStatic != SecondStatic) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodStatic) + << FirstMethodType << FirstName << FirstStatic; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodStatic) + << SecondMethodType << SecondName << SecondStatic; + Diagnosed = true; + break; + } + + const bool FirstVolatile = FirstMethod->isVolatile(); + const bool SecondVolatile = SecondMethod->isVolatile(); + if (FirstVolatile != SecondVolatile) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodVolatile) + << FirstMethodType << FirstName << FirstVolatile; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVolatile) + << SecondMethodType << SecondName << SecondVolatile; + Diagnosed = true; + break; + } + + const bool FirstConst = FirstMethod->isConst(); + const bool SecondConst = SecondMethod->isConst(); + if (FirstConst != SecondConst) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodConst) + << FirstMethodType << FirstName << FirstConst; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodConst) + << SecondMethodType << SecondName << SecondConst; + Diagnosed = true; + break; + } + + const bool FirstInline = FirstMethod->isInlineSpecified(); + const bool SecondInline = SecondMethod->isInlineSpecified(); + if (FirstInline != SecondInline) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodInline) + << FirstMethodType << FirstName << FirstInline; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodInline) + << SecondMethodType << SecondName << SecondInline; + Diagnosed = true; + break; + } + + const unsigned FirstNumParameters = FirstMethod->param_size(); + const unsigned SecondNumParameters = SecondMethod->param_size(); + if (FirstNumParameters != SecondNumParameters) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodNumberParameters) + << FirstMethodType << FirstName << FirstNumParameters; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodNumberParameters) + << SecondMethodType << SecondName << SecondNumParameters; + Diagnosed = true; + break; + } + + // Need this status boolean to know when break out of the switch. + bool ParameterMismatch = false; + for (unsigned I = 0; I < FirstNumParameters; ++I) { + const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I); + const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I); + + QualType FirstParamType = FirstParam->getType(); + QualType SecondParamType = SecondParam->getType(); + if (FirstParamType != SecondParamType && + ComputeQualTypeODRHash(FirstParamType) != + ComputeQualTypeODRHash(SecondParamType)) { + if (const DecayedType *ParamDecayedType = + FirstParamType->getAs<DecayedType>()) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstMethodType << FirstName << (I + 1) << FirstParamType + << true << ParamDecayedType->getOriginalType(); + } else { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstMethodType << FirstName << (I + 1) << FirstParamType + << false; + } + + if (const DecayedType *ParamDecayedType = + SecondParamType->getAs<DecayedType>()) { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondMethodType << SecondName << (I + 1) + << SecondParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondMethodType << SecondName << (I + 1) + << SecondParamType << false; + } + ParameterMismatch = true; + break; + } + + DeclarationName FirstParamName = FirstParam->getDeclName(); + DeclarationName SecondParamName = SecondParam->getDeclName(); + if (FirstParamName != SecondParamName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterName) + << FirstMethodType << FirstName << (I + 1) << FirstParamName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterName) + << SecondMethodType << SecondName << (I + 1) << SecondParamName; + ParameterMismatch = true; + break; + } + + const Expr *FirstInit = FirstParam->getInit(); + const Expr *SecondInit = SecondParam->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << FirstMethodType << FirstName << (I + 1) + << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << SecondMethodType << SecondName << (I + 1) + << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + ParameterMismatch = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << FirstMethodType << FirstName << (I + 1) + << FirstInit->getSourceRange(); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << SecondMethodType << SecondName << (I + 1) + << SecondInit->getSourceRange(); + ParameterMismatch = true; + break; + + } + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + + const auto *FirstTemplateArgs = + FirstMethod->getTemplateSpecializationArgs(); + const auto *SecondTemplateArgs = + SecondMethod->getTemplateSpecializationArgs(); + + if ((FirstTemplateArgs && !SecondTemplateArgs) || + (!FirstTemplateArgs && SecondTemplateArgs)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodNoTemplateArguments) + << FirstMethodType << FirstName << (FirstTemplateArgs != nullptr); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodNoTemplateArguments) + << SecondMethodType << SecondName + << (SecondTemplateArgs != nullptr); + + Diagnosed = true; + break; + } + + if (FirstTemplateArgs && SecondTemplateArgs) { + // Remove pack expansions from argument list. + auto ExpandTemplateArgumentList = + [](const TemplateArgumentList *TAL) { + llvm::SmallVector<const TemplateArgument *, 8> ExpandedList; + for (const TemplateArgument &TA : TAL->asArray()) { + if (TA.getKind() != TemplateArgument::Pack) { + ExpandedList.push_back(&TA); + continue; + } + for (const TemplateArgument &PackTA : TA.getPackAsArray()) { + ExpandedList.push_back(&PackTA); + } + } + return ExpandedList; + }; + llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList = + ExpandTemplateArgumentList(FirstTemplateArgs); + llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList = + ExpandTemplateArgumentList(SecondTemplateArgs); + + if (FirstExpandedList.size() != SecondExpandedList.size()) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodDifferentNumberTemplateArguments) + << FirstMethodType << FirstName + << (unsigned)FirstExpandedList.size(); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodDifferentNumberTemplateArguments) + << SecondMethodType << SecondName + << (unsigned)SecondExpandedList.size(); + + Diagnosed = true; + break; + } + + bool TemplateArgumentMismatch = false; + for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) { + const TemplateArgument &FirstTA = *FirstExpandedList[i], + &SecondTA = *SecondExpandedList[i]; + if (ComputeTemplateArgumentODRHash(FirstTA) == + ComputeTemplateArgumentODRHash(SecondTA)) { + continue; + } + + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodDifferentTemplateArgument) + << FirstMethodType << FirstName << FirstTA << i + 1; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodDifferentTemplateArgument) + << SecondMethodType << SecondName << SecondTA << i + 1; + + TemplateArgumentMismatch = true; + break; + } + + if (TemplateArgumentMismatch) { + Diagnosed = true; + break; + } + } + + // Compute the hash of the method as if it has no body. + auto ComputeCXXMethodODRHash = [&Hash](const CXXMethodDecl *D) { + Hash.clear(); + Hash.AddFunctionDecl(D, true /*SkipBody*/); + return Hash.CalculateHash(); + }; + + // Compare the hash generated to the hash stored. A difference means + // that a body was present in the original source. Due to merging, + // the stardard way of detecting a body will not work. + const bool HasFirstBody = + ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash(); + const bool HasSecondBody = + ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash(); + + if (HasFirstBody != HasSecondBody) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodSingleBody) + << FirstMethodType << FirstName << HasFirstBody; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodSingleBody) + << SecondMethodType << SecondName << HasSecondBody; + Diagnosed = true; + break; + } + + if (HasFirstBody && HasSecondBody) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodDifferentBody) + << FirstMethodType << FirstName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodDifferentBody) + << SecondMethodType << SecondName; + Diagnosed = true; + break; + } + + break; + } + case TypeAlias: + case TypeDef: { + TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl); + TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl); + auto FirstName = FirstTD->getDeclName(); + auto SecondName = SecondTD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << FirstName; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstTD->getUnderlyingType(); + QualType SecondType = SecondTD->getUnderlyingType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << FirstName << FirstType; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << SecondName << SecondType; + Diagnosed = true; + break; + } + break; + } + case Var: { + VarDecl *FirstVD = cast<VarDecl>(FirstDecl); + VarDecl *SecondVD = cast<VarDecl>(SecondDecl); + auto FirstName = FirstVD->getDeclName(); + auto SecondName = SecondVD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarName) + << FirstName; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarName) + << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstVD->getType(); + QualType SecondType = SecondVD->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarType) + << FirstName << FirstType; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarType) + << SecondName << SecondType; + Diagnosed = true; + break; + } + + const Expr *FirstInit = FirstVD->getInit(); + const Expr *SecondInit = SecondVD->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarSingleInitializer) + << FirstName << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange(): SourceRange()); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarSingleInitializer) + << SecondName << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + Diagnosed = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarDifferentInitializer) + << FirstName << FirstInit->getSourceRange(); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarDifferentInitializer) + << SecondName << SecondInit->getSourceRange(); + Diagnosed = true; + break; + } + + const bool FirstIsConstexpr = FirstVD->isConstexpr(); + const bool SecondIsConstexpr = SecondVD->isConstexpr(); + if (FirstIsConstexpr != SecondIsConstexpr) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarConstexpr) + << FirstName << FirstIsConstexpr; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarConstexpr) + << SecondName << SecondIsConstexpr; + Diagnosed = true; + break; + } + break; + } + case Friend: { + FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); + FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); + + NamedDecl *FirstND = FirstFriend->getFriendDecl(); + NamedDecl *SecondND = SecondFriend->getFriendDecl(); + + TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); + TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); + + if (FirstND && SecondND) { + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendFunction) + << FirstND; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendFunction) + << SecondND; + + Diagnosed = true; + break; + } + + if (FirstTSI && SecondTSI) { + QualType FirstFriendType = FirstTSI->getType(); + QualType SecondFriendType = SecondTSI->getType(); + assert(ComputeQualTypeODRHash(FirstFriendType) != + ComputeQualTypeODRHash(SecondFriendType)); + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendType) + << FirstFriendType; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendType) + << SecondFriendType; + Diagnosed = true; + break; + } + + ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), + FriendTypeFunction) + << (FirstTSI == nullptr); + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendTypeFunction) + << (SecondTSI == nullptr); + + Diagnosed = true; + break; + } + case FunctionTemplate: { + FunctionTemplateDecl *FirstTemplate = + cast<FunctionTemplateDecl>(FirstDecl); + FunctionTemplateDecl *SecondTemplate = + cast<FunctionTemplateDecl>(SecondDecl); + + TemplateParameterList *FirstTPL = + FirstTemplate->getTemplateParameters(); + TemplateParameterList *SecondTPL = + SecondTemplate->getTemplateParameters(); + + if (FirstTPL->size() != SecondTPL->size()) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateDifferentNumberParameters) + << FirstTemplate << FirstTPL->size(); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateDifferentNumberParameters) + << SecondTemplate << SecondTPL->size(); + + Diagnosed = true; + break; + } + + bool ParameterMismatch = false; + for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) { + NamedDecl *FirstParam = FirstTPL->getParam(i); + NamedDecl *SecondParam = SecondTPL->getParam(i); + + if (FirstParam->getKind() != SecondParam->getKind()) { + enum { + TemplateTypeParameter, + NonTypeTemplateParameter, + TemplateTemplateParameter, + }; + auto GetParamType = [](NamedDecl *D) { + switch (D->getKind()) { + default: + llvm_unreachable("Unexpected template parameter type"); + case Decl::TemplateTypeParm: + return TemplateTypeParameter; + case Decl::NonTypeTemplateParm: + return NonTypeTemplateParameter; + case Decl::TemplateTemplateParm: + return TemplateTemplateParameter; + } + }; + + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentKind) + << FirstTemplate << (i + 1) << GetParamType(FirstParam); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentKind) + << SecondTemplate << (i + 1) << GetParamType(SecondParam); + + ParameterMismatch = true; + break; + } + + if (FirstParam->getName() != SecondParam->getName()) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterName) + << FirstTemplate << (i + 1) << (bool)FirstParam->getIdentifier() + << FirstParam; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterName) + << SecondTemplate << (i + 1) + << (bool)SecondParam->getIdentifier() << SecondParam; + ParameterMismatch = true; + break; + } + + if (isa<TemplateTypeParmDecl>(FirstParam) && + isa<TemplateTypeParmDecl>(SecondParam)) { + TemplateTypeParmDecl *FirstTTPD = + cast<TemplateTypeParmDecl>(FirstParam); + TemplateTypeParmDecl *SecondTTPD = + cast<TemplateTypeParmDecl>(SecondParam); + bool HasFirstDefaultArgument = + FirstTTPD->hasDefaultArgument() && + !FirstTTPD->defaultArgumentWasInherited(); + bool HasSecondDefaultArgument = + SecondTTPD->hasDefaultArgument() && + !SecondTTPD->defaultArgumentWasInherited(); + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << FirstTemplate << (i + 1) << HasFirstDefaultArgument; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << SecondTemplate << (i + 1) << HasSecondDefaultArgument; + ParameterMismatch = true; + break; + } + + if (HasFirstDefaultArgument && HasSecondDefaultArgument) { + QualType FirstType = FirstTTPD->getDefaultArgument(); + QualType SecondType = SecondTTPD->getDefaultArgument(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << FirstTemplate << (i + 1) << FirstType; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << SecondTemplate << (i + 1) << SecondType; + ParameterMismatch = true; + break; + } + } + + if (FirstTTPD->isParameterPack() != + SecondTTPD->isParameterPack()) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << FirstTemplate << (i + 1) << FirstTTPD->isParameterPack(); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << SecondTemplate << (i + 1) << SecondTTPD->isParameterPack(); + ParameterMismatch = true; + break; + } + } + + if (isa<TemplateTemplateParmDecl>(FirstParam) && + isa<TemplateTemplateParmDecl>(SecondParam)) { + TemplateTemplateParmDecl *FirstTTPD = + cast<TemplateTemplateParmDecl>(FirstParam); + TemplateTemplateParmDecl *SecondTTPD = + cast<TemplateTemplateParmDecl>(SecondParam); + + TemplateParameterList *FirstTPL = + FirstTTPD->getTemplateParameters(); + TemplateParameterList *SecondTPL = + SecondTTPD->getTemplateParameters(); + + if (ComputeTemplateParameterListODRHash(FirstTPL) != + ComputeTemplateParameterListODRHash(SecondTPL)) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentType) + << FirstTemplate << (i + 1); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentType) + << SecondTemplate << (i + 1); + ParameterMismatch = true; + break; + } + + bool HasFirstDefaultArgument = + FirstTTPD->hasDefaultArgument() && + !FirstTTPD->defaultArgumentWasInherited(); + bool HasSecondDefaultArgument = + SecondTTPD->hasDefaultArgument() && + !SecondTTPD->defaultArgumentWasInherited(); + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << FirstTemplate << (i + 1) << HasFirstDefaultArgument; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << SecondTemplate << (i + 1) << HasSecondDefaultArgument; + ParameterMismatch = true; + break; + } + + if (HasFirstDefaultArgument && HasSecondDefaultArgument) { + TemplateArgument FirstTA = + FirstTTPD->getDefaultArgument().getArgument(); + TemplateArgument SecondTA = + SecondTTPD->getDefaultArgument().getArgument(); + if (ComputeTemplateArgumentODRHash(FirstTA) != + ComputeTemplateArgumentODRHash(SecondTA)) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << FirstTemplate << (i + 1) << FirstTA; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << SecondTemplate << (i + 1) << SecondTA; + ParameterMismatch = true; + break; + } + } + + if (FirstTTPD->isParameterPack() != + SecondTTPD->isParameterPack()) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << FirstTemplate << (i + 1) << FirstTTPD->isParameterPack(); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << SecondTemplate << (i + 1) << SecondTTPD->isParameterPack(); + ParameterMismatch = true; + break; + } + } + + if (isa<NonTypeTemplateParmDecl>(FirstParam) && + isa<NonTypeTemplateParmDecl>(SecondParam)) { + NonTypeTemplateParmDecl *FirstNTTPD = + cast<NonTypeTemplateParmDecl>(FirstParam); + NonTypeTemplateParmDecl *SecondNTTPD = + cast<NonTypeTemplateParmDecl>(SecondParam); + + QualType FirstType = FirstNTTPD->getType(); + QualType SecondType = SecondNTTPD->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentType) + << FirstTemplate << (i + 1); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentType) + << SecondTemplate << (i + 1); + ParameterMismatch = true; + break; + } + + bool HasFirstDefaultArgument = + FirstNTTPD->hasDefaultArgument() && + !FirstNTTPD->defaultArgumentWasInherited(); + bool HasSecondDefaultArgument = + SecondNTTPD->hasDefaultArgument() && + !SecondNTTPD->defaultArgumentWasInherited(); + if (HasFirstDefaultArgument != HasSecondDefaultArgument) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << FirstTemplate << (i + 1) << HasFirstDefaultArgument; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterSingleDefaultArgument) + << SecondTemplate << (i + 1) << HasSecondDefaultArgument; + ParameterMismatch = true; + break; + } + + if (HasFirstDefaultArgument && HasSecondDefaultArgument) { + Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument(); + Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument(); + if (ComputeODRHash(FirstDefaultArgument) != + ComputeODRHash(SecondDefaultArgument)) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << FirstTemplate << (i + 1) << FirstDefaultArgument; + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplateParameterDifferentDefaultArgument) + << SecondTemplate << (i + 1) << SecondDefaultArgument; + ParameterMismatch = true; + break; + } + } + + if (FirstNTTPD->isParameterPack() != + SecondNTTPD->isParameterPack()) { + ODRDiagError(FirstTemplate->getLocation(), + FirstTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << FirstTemplate << (i + 1) << FirstNTTPD->isParameterPack(); + ODRDiagNote(SecondTemplate->getLocation(), + SecondTemplate->getSourceRange(), + FunctionTemplatePackParameter) + << SecondTemplate << (i + 1) + << SecondNTTPD->isParameterPack(); + ParameterMismatch = true; + break; + } + } + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + + break; + } + } + + if (Diagnosed) + continue; + + Diag(FirstDecl->getLocation(), + diag::err_module_odr_violation_mismatch_decl_unknown) + << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType + << FirstDecl->getSourceRange(); + Diag(SecondDecl->getLocation(), + diag::note_module_odr_violation_mismatch_decl_unknown) + << SecondModule << FirstDiffType << SecondDecl->getSourceRange(); + Diagnosed = true; + } + + 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; + } + } + + // Issue ODR failures diagnostics for functions. + for (auto &Merge : FunctionOdrMergeFailures) { + enum ODRFunctionDifference { + ReturnType, + ParameterName, + ParameterType, + ParameterSingleDefaultArgument, + ParameterDifferentDefaultArgument, + FunctionBody, + }; + + FunctionDecl *FirstFunction = Merge.first; + std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction); + + bool Diagnosed = false; + for (auto &SecondFunction : Merge.second) { + + if (FirstFunction == SecondFunction) + continue; + + std::string SecondModule = + getOwningModuleNameForDiagnostic(SecondFunction); + + auto ODRDiagError = [FirstFunction, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRFunctionDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_function) + << FirstFunction << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc, + SourceRange Range, + ODRFunctionDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_function) + << SecondModule << Range << DiffType; + }; + + if (ComputeQualTypeODRHash(FirstFunction->getReturnType()) != + ComputeQualTypeODRHash(SecondFunction->getReturnType())) { + ODRDiagError(FirstFunction->getReturnTypeSourceRange().getBegin(), + FirstFunction->getReturnTypeSourceRange(), ReturnType) + << FirstFunction->getReturnType(); + ODRDiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(), + SecondFunction->getReturnTypeSourceRange(), ReturnType) + << SecondFunction->getReturnType(); + Diagnosed = true; + break; + } + + assert(FirstFunction->param_size() == SecondFunction->param_size() && + "Merged functions with different number of parameters"); + + auto ParamSize = FirstFunction->param_size(); + bool ParameterMismatch = false; + for (unsigned I = 0; I < ParamSize; ++I) { + auto *FirstParam = FirstFunction->getParamDecl(I); + auto *SecondParam = SecondFunction->getParamDecl(I); + + assert(getContext().hasSameType(FirstParam->getType(), + SecondParam->getType()) && + "Merged function has different parameter types."); + + if (FirstParam->getDeclName() != SecondParam->getDeclName()) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterName) + << I + 1 << FirstParam->getDeclName(); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterName) + << I + 1 << SecondParam->getDeclName(); + ParameterMismatch = true; + break; + }; + + QualType FirstParamType = FirstParam->getType(); + QualType SecondParamType = SecondParam->getType(); + if (FirstParamType != SecondParamType && + ComputeQualTypeODRHash(FirstParamType) != + ComputeQualTypeODRHash(SecondParamType)) { + if (const DecayedType *ParamDecayedType = + FirstParamType->getAs<DecayedType>()) { + ODRDiagError(FirstParam->getLocation(), + FirstParam->getSourceRange(), ParameterType) + << (I + 1) << FirstParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagError(FirstParam->getLocation(), + FirstParam->getSourceRange(), ParameterType) + << (I + 1) << FirstParamType << false; + } + + if (const DecayedType *ParamDecayedType = + SecondParamType->getAs<DecayedType>()) { + ODRDiagNote(SecondParam->getLocation(), + SecondParam->getSourceRange(), ParameterType) + << (I + 1) << SecondParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagNote(SecondParam->getLocation(), + SecondParam->getSourceRange(), ParameterType) + << (I + 1) << SecondParamType << false; + } + ParameterMismatch = true; + break; + } + + const Expr *FirstInit = FirstParam->getInit(); + const Expr *SecondInit = SecondParam->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterSingleDefaultArgument) + << (I + 1) << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterSingleDefaultArgument) + << (I + 1) << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + ParameterMismatch = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterDifferentDefaultArgument) + << (I + 1) << FirstInit->getSourceRange(); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterDifferentDefaultArgument) + << (I + 1) << SecondInit->getSourceRange(); + ParameterMismatch = true; + break; + } + + assert(ComputeSubDeclODRHash(FirstParam) == + ComputeSubDeclODRHash(SecondParam) && + "Undiagnosed parameter difference."); + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + + // If no error has been generated before now, assume the problem is in + // the body and generate a message. + ODRDiagError(FirstFunction->getLocation(), + FirstFunction->getSourceRange(), FunctionBody); + ODRDiagNote(SecondFunction->getLocation(), + SecondFunction->getSourceRange(), FunctionBody); + Diagnosed = true; + break; + } + (void)Diagnosed; + assert(Diagnosed && "Unable to emit ODR diagnostic."); + } + + // Issue ODR failures diagnostics for enums. + for (auto &Merge : EnumOdrMergeFailures) { + enum ODREnumDifference { + SingleScopedEnum, + EnumTagKeywordMismatch, + SingleSpecifiedType, + DifferentSpecifiedTypes, + DifferentNumberEnumConstants, + EnumConstantName, + EnumConstantSingleInitilizer, + EnumConstantDifferentInitilizer, + }; + + // If we've already pointed out a specific problem with this enum, don't + // bother issuing a general "something's different" diagnostic. + if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) + continue; + + EnumDecl *FirstEnum = Merge.first; + std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum); + + using DeclHashes = + llvm::SmallVector<std::pair<EnumConstantDecl *, unsigned>, 4>; + auto PopulateHashes = [&ComputeSubDeclODRHash, FirstEnum]( + DeclHashes &Hashes, EnumDecl *Enum) { + for (auto *D : Enum->decls()) { + // Due to decl merging, the first EnumDecl is the parent of + // Decls in both records. + if (!ODRHash::isWhitelistedDecl(D, FirstEnum)) + continue; + assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind"); + Hashes.emplace_back(cast<EnumConstantDecl>(D), + ComputeSubDeclODRHash(D)); + } + }; + DeclHashes FirstHashes; + PopulateHashes(FirstHashes, FirstEnum); + bool Diagnosed = false; + for (auto &SecondEnum : Merge.second) { + + if (FirstEnum == SecondEnum) + continue; + + std::string SecondModule = + getOwningModuleNameForDiagnostic(SecondEnum); + + auto ODRDiagError = [FirstEnum, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODREnumDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_enum) + << FirstEnum << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc, + SourceRange Range, + ODREnumDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_enum) + << SecondModule << Range << DiffType; + }; + + if (FirstEnum->isScoped() != SecondEnum->isScoped()) { + ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(), + SingleScopedEnum) + << FirstEnum->isScoped(); + ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(), + SingleScopedEnum) + << SecondEnum->isScoped(); + Diagnosed = true; + continue; + } + + if (FirstEnum->isScoped() && SecondEnum->isScoped()) { + if (FirstEnum->isScopedUsingClassTag() != + SecondEnum->isScopedUsingClassTag()) { + ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(), + EnumTagKeywordMismatch) + << FirstEnum->isScopedUsingClassTag(); + ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(), + EnumTagKeywordMismatch) + << SecondEnum->isScopedUsingClassTag(); + Diagnosed = true; + continue; + } + } + + QualType FirstUnderlyingType = + FirstEnum->getIntegerTypeSourceInfo() + ? FirstEnum->getIntegerTypeSourceInfo()->getType() + : QualType(); + QualType SecondUnderlyingType = + SecondEnum->getIntegerTypeSourceInfo() + ? SecondEnum->getIntegerTypeSourceInfo()->getType() + : QualType(); + if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) { + ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(), + SingleSpecifiedType) + << !FirstUnderlyingType.isNull(); + ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(), + SingleSpecifiedType) + << !SecondUnderlyingType.isNull(); + Diagnosed = true; + continue; + } + + if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) { + if (ComputeQualTypeODRHash(FirstUnderlyingType) != + ComputeQualTypeODRHash(SecondUnderlyingType)) { + ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(), + DifferentSpecifiedTypes) + << FirstUnderlyingType; + ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(), + DifferentSpecifiedTypes) + << SecondUnderlyingType; + Diagnosed = true; + continue; + } + } + + DeclHashes SecondHashes; + PopulateHashes(SecondHashes, SecondEnum); + + if (FirstHashes.size() != SecondHashes.size()) { + ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(), + DifferentNumberEnumConstants) + << (int)FirstHashes.size(); + ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(), + DifferentNumberEnumConstants) + << (int)SecondHashes.size(); + Diagnosed = true; + continue; + } + + for (unsigned I = 0; I < FirstHashes.size(); ++I) { + if (FirstHashes[I].second == SecondHashes[I].second) + continue; + const EnumConstantDecl *FirstEnumConstant = FirstHashes[I].first; + const EnumConstantDecl *SecondEnumConstant = SecondHashes[I].first; + + if (FirstEnumConstant->getDeclName() != + SecondEnumConstant->getDeclName()) { + + ODRDiagError(FirstEnumConstant->getLocation(), + FirstEnumConstant->getSourceRange(), EnumConstantName) + << I + 1 << FirstEnumConstant; + ODRDiagNote(SecondEnumConstant->getLocation(), + SecondEnumConstant->getSourceRange(), EnumConstantName) + << I + 1 << SecondEnumConstant; + Diagnosed = true; + break; + } + + const Expr *FirstInit = FirstEnumConstant->getInitExpr(); + const Expr *SecondInit = SecondEnumConstant->getInitExpr(); + if (!FirstInit && !SecondInit) + continue; + + if (!FirstInit || !SecondInit) { + ODRDiagError(FirstEnumConstant->getLocation(), + FirstEnumConstant->getSourceRange(), + EnumConstantSingleInitilizer) + << I + 1 << FirstEnumConstant << (FirstInit != nullptr); + ODRDiagNote(SecondEnumConstant->getLocation(), + SecondEnumConstant->getSourceRange(), + EnumConstantSingleInitilizer) + << I + 1 << SecondEnumConstant << (SecondInit != nullptr); + Diagnosed = true; + break; + } + + if (ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstEnumConstant->getLocation(), + FirstEnumConstant->getSourceRange(), + EnumConstantDifferentInitilizer) + << I + 1 << FirstEnumConstant; + ODRDiagNote(SecondEnumConstant->getLocation(), + SecondEnumConstant->getSourceRange(), + EnumConstantDifferentInitilizer) + << I + 1 << SecondEnumConstant; + Diagnosed = true; + break; + } + } + } + + (void)Diagnosed; + assert(Diagnosed && "Unable to emit ODR diagnostic."); + } +} + +void ASTReader::StartedDeserializing() { + if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get()) + ReadTimer->startTimer(); +} + +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 and deduced type updates along + // redeclaration chains. + // + // We do this now rather than in finishPendingActions because we want to + // be able to walk the complete redeclaration chains of the updated decls. + while (!PendingExceptionSpecUpdates.empty() || + !PendingDeducedTypeUpdates.empty()) { + auto ESUpdates = std::move(PendingExceptionSpecUpdates); + PendingExceptionSpecUpdates.clear(); + for (auto Update : ESUpdates) { + ProcessingUpdatesRAIIObj ProcessingUpdates(*this); + auto *FPT = Update.second->getType()->castAs<FunctionProtoType>(); + auto ESI = FPT->getExtProtoInfo().ExceptionSpec; + if (auto *Listener = getContext().getASTMutationListener()) + Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second)); + for (auto *Redecl : Update.second->redecls()) + getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); + } + + auto DTUpdates = std::move(PendingDeducedTypeUpdates); + PendingDeducedTypeUpdates.clear(); + for (auto Update : DTUpdates) { + ProcessingUpdatesRAIIObj ProcessingUpdates(*this); + // FIXME: If the return type is already deduced, check that it matches. + getContext().adjustDeducedFunctionResultType(Update.first, + Update.second); + } + } + + if (ReadTimer) + ReadTimer->stopTimer(); + + 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 : It->second) + 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, + const PCHContainerReader &PCHContainerRdr, + ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, + StringRef isysroot, bool DisableValidation, + bool AllowASTWithCompilerErrors, + bool AllowConfigurationMismatch, bool ValidateSystemInputs, + bool UseGlobalIndex, + std::unique_ptr<llvm::Timer> ReadTimer) + : Listener(DisableValidation + ? cast<ASTReaderListener>(new SimpleASTReaderListener(PP)) + : cast<ASTReaderListener>(new PCHValidator(PP, *this))), + SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), + PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), + ContextObj(Context), + ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr, + PP.getHeaderSearchInfo()), + PCMCache(PP.getPCMCache()), DummyIdResolver(PP), + ReadTimer(std::move(ReadTimer)), isysroot(isysroot), + DisableValidation(DisableValidation), + AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), + AllowConfigurationMismatch(AllowConfigurationMismatch), + ValidateSystemInputs(ValidateSystemInputs), + UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) { + SourceMgr.setExternalSLocEntrySource(this); + + for (const auto &Ext : Extensions) { + auto BlockName = Ext->getExtensionMetadata().BlockName; + auto Known = ModuleFileExtensions.find(BlockName); + if (Known != ModuleFileExtensions.end()) { + Diags.Report(diag::warn_duplicate_module_file_extension) + << BlockName; + continue; + } + + ModuleFileExtensions.insert({BlockName, Ext}); + } +} + +ASTReader::~ASTReader() { + if (OwnsDeserializationListener) + delete DeserializationListener; +} + +IdentifierResolver &ASTReader::getIdResolver() { + return SemaObj ? SemaObj->IdResolver : DummyIdResolver; +} + +unsigned ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor, + unsigned AbbrevID) { + Idx = 0; + Record.clear(); + return Cursor.readRecord(AbbrevID, Record); +} +//===----------------------------------------------------------------------===// +//// OMPClauseReader implementation +////===----------------------------------------------------------------------===// + +OMPClause *OMPClauseReader::readClause() { + OMPClause *C; + switch (Record.readInt()) { + 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_simdlen: + C = new (Context) OMPSimdlenClause(); + 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 = OMPOrderedClause::CreateEmpty(Context, Record.readInt()); + 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_threads: + C = new (Context) OMPThreadsClause(); + break; + case OMPC_simd: + C = new (Context) OMPSIMDClause(); + break; + case OMPC_nogroup: + C = new (Context) OMPNogroupClause(); + break; + case OMPC_unified_address: + C = new (Context) OMPUnifiedAddressClause(); + break; + case OMPC_unified_shared_memory: + C = new (Context) OMPUnifiedSharedMemoryClause(); + break; + case OMPC_reverse_offload: + C = new (Context) OMPReverseOffloadClause(); + break; + case OMPC_dynamic_allocators: + C = new (Context) OMPDynamicAllocatorsClause(); + break; + case OMPC_atomic_default_mem_order: + C = new (Context) OMPAtomicDefaultMemOrderClause(); + break; + case OMPC_private: + C = OMPPrivateClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_firstprivate: + C = OMPFirstprivateClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_lastprivate: + C = OMPLastprivateClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_shared: + C = OMPSharedClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_reduction: + C = OMPReductionClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_task_reduction: + C = OMPTaskReductionClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_in_reduction: + C = OMPInReductionClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_linear: + C = OMPLinearClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_aligned: + C = OMPAlignedClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_copyin: + C = OMPCopyinClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_copyprivate: + C = OMPCopyprivateClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_flush: + C = OMPFlushClause::CreateEmpty(Context, Record.readInt()); + break; + case OMPC_depend: { + unsigned NumVars = Record.readInt(); + unsigned NumLoops = Record.readInt(); + C = OMPDependClause::CreateEmpty(Context, NumVars, NumLoops); + break; + } + case OMPC_device: + C = new (Context) OMPDeviceClause(); + break; + case OMPC_map: { + unsigned NumVars = Record.readInt(); + unsigned NumDeclarations = Record.readInt(); + unsigned NumLists = Record.readInt(); + unsigned NumComponents = Record.readInt(); + C = OMPMapClause::CreateEmpty(Context, NumVars, NumDeclarations, NumLists, + NumComponents); + break; + } + case OMPC_num_teams: + C = new (Context) OMPNumTeamsClause(); + break; + case OMPC_thread_limit: + C = new (Context) OMPThreadLimitClause(); + break; + case OMPC_priority: + C = new (Context) OMPPriorityClause(); + break; + case OMPC_grainsize: + C = new (Context) OMPGrainsizeClause(); + break; + case OMPC_num_tasks: + C = new (Context) OMPNumTasksClause(); + break; + case OMPC_hint: + C = new (Context) OMPHintClause(); + break; + case OMPC_dist_schedule: + C = new (Context) OMPDistScheduleClause(); + break; + case OMPC_defaultmap: + C = new (Context) OMPDefaultmapClause(); + break; + case OMPC_to: { + unsigned NumVars = Record.readInt(); + unsigned NumDeclarations = Record.readInt(); + unsigned NumLists = Record.readInt(); + unsigned NumComponents = Record.readInt(); + C = OMPToClause::CreateEmpty(Context, NumVars, NumDeclarations, NumLists, + NumComponents); + break; + } + case OMPC_from: { + unsigned NumVars = Record.readInt(); + unsigned NumDeclarations = Record.readInt(); + unsigned NumLists = Record.readInt(); + unsigned NumComponents = Record.readInt(); + C = OMPFromClause::CreateEmpty(Context, NumVars, NumDeclarations, NumLists, + NumComponents); + break; + } + case OMPC_use_device_ptr: { + unsigned NumVars = Record.readInt(); + unsigned NumDeclarations = Record.readInt(); + unsigned NumLists = Record.readInt(); + unsigned NumComponents = Record.readInt(); + C = OMPUseDevicePtrClause::CreateEmpty(Context, NumVars, NumDeclarations, + NumLists, NumComponents); + break; + } + case OMPC_is_device_ptr: { + unsigned NumVars = Record.readInt(); + unsigned NumDeclarations = Record.readInt(); + unsigned NumLists = Record.readInt(); + unsigned NumComponents = Record.readInt(); + C = OMPIsDevicePtrClause::CreateEmpty(Context, NumVars, NumDeclarations, + NumLists, NumComponents); + break; + } + } + Visit(C); + C->setLocStart(Record.readSourceLocation()); + C->setLocEnd(Record.readSourceLocation()); + + return C; +} + +void OMPClauseReader::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { + C->setPreInitStmt(Record.readSubStmt(), + static_cast<OpenMPDirectiveKind>(Record.readInt())); +} + +void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { + VisitOMPClauseWithPreInit(C); + C->setPostUpdateExpr(Record.readSubExpr()); +} + +void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { + VisitOMPClauseWithPreInit(C); + C->setNameModifier(static_cast<OpenMPDirectiveKind>(Record.readInt())); + C->setNameModifierLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + C->setCondition(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) { + C->setCondition(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + VisitOMPClauseWithPreInit(C); + C->setNumThreads(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) { + C->setSafelen(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + C->setSimdlen(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) { + C->setNumForLoops(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { + C->setDefaultKind( + static_cast<OpenMPDefaultClauseKind>(Record.readInt())); + C->setLParenLoc(Record.readSourceLocation()); + C->setDefaultKindKwLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { + C->setProcBindKind( + static_cast<OpenMPProcBindClauseKind>(Record.readInt())); + C->setLParenLoc(Record.readSourceLocation()); + C->setProcBindKindKwLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) { + VisitOMPClauseWithPreInit(C); + C->setScheduleKind( + static_cast<OpenMPScheduleClauseKind>(Record.readInt())); + C->setFirstScheduleModifier( + static_cast<OpenMPScheduleClauseModifier>(Record.readInt())); + C->setSecondScheduleModifier( + static_cast<OpenMPScheduleClauseModifier>(Record.readInt())); + C->setChunkSize(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); + C->setFirstScheduleModifierLoc(Record.readSourceLocation()); + C->setSecondScheduleModifierLoc(Record.readSourceLocation()); + C->setScheduleKindLoc(Record.readSourceLocation()); + C->setCommaLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) { + C->setNumForLoops(Record.readSubExpr()); + for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I) + C->setLoopNumIterations(I, Record.readSubExpr()); + for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I) + C->setLoopCounter(I, Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +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::VisitOMPThreadsClause(OMPThreadsClause *) {} + +void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {} + +void OMPClauseReader::VisitOMPNogroupClause(OMPNogroupClause *) {} + +void OMPClauseReader::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {} + +void OMPClauseReader::VisitOMPUnifiedSharedMemoryClause( + OMPUnifiedSharedMemoryClause *) {} + +void OMPClauseReader::VisitOMPReverseOffloadClause(OMPReverseOffloadClause *) {} + +void +OMPClauseReader::VisitOMPDynamicAllocatorsClause(OMPDynamicAllocatorsClause *) { +} + +void OMPClauseReader::VisitOMPAtomicDefaultMemOrderClause( + OMPAtomicDefaultMemOrderClause *C) { + C->setAtomicDefaultMemOrderKind( + static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Record.readInt())); + C->setLParenLoc(Record.readSourceLocation()); + C->setAtomicDefaultMemOrderKindKwLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivateCopies(Vars); +} + +void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { + VisitOMPClauseWithPreInit(C); + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivateCopies(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setInits(Vars); +} + +void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivateCopies(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setSourceExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setDestinationExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setAssignmentOps(Vars); +} + +void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); +} + +void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DNI; + Record.readDeclarationNameInfo(DNI); + 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(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setLHSExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setRHSExprs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setReductionOps(Vars); +} + +void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DNI; + Record.readDeclarationNameInfo(DNI); + 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(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setLHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setRHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setReductionOps(Vars); +} + +void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DNI; + Record.readDeclarationNameInfo(DNI); + 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(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setLHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setRHSExprs(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setReductionOps(Vars); + Vars.clear(); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setTaskgroupDescriptors(Vars); +} + +void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { + VisitOMPClauseWithPostUpdate(C); + C->setLParenLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + C->setModifier(static_cast<OpenMPLinearClauseKind>(Record.readInt())); + C->setModifierLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setInits(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setUpdates(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setFinals(Vars); + C->setStep(Record.readSubExpr()); + C->setCalcStep(Record.readSubExpr()); +} + +void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + C->setAlignment(Record.readSubExpr()); +} + +void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Exprs; + Exprs.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setVarRefs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setSourceExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setDestinationExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setAssignmentOps(Exprs); +} + +void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Exprs; + Exprs.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setVarRefs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setSourceExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setDestinationExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Record.readSubExpr()); + C->setAssignmentOps(Exprs); +} + +void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); +} + +void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + C->setDependencyKind( + static_cast<OpenMPDependClauseKind>(Record.readInt())); + C->setDependencyLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned I = 0; I != NumVars; ++I) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) + C->setLoopData(I, Record.readSubExpr()); +} + +void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { + VisitOMPClauseWithPreInit(C); + C->setDevice(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + for (unsigned I = 0; I < OMPMapClause::NumberOfModifiers; ++I) { + C->setMapTypeModifier( + I, static_cast<OpenMPMapModifierKind>(Record.readInt())); + C->setMapTypeModifierLoc(I, Record.readSourceLocation()); + } + C->setMapType( + static_cast<OpenMPMapClauseKind>(Record.readInt())); + C->setMapLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + + SmallVector<ValueDecl *, 16> Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs<ValueDecl>()); + C->setUniqueDecls(Decls); + + SmallVector<unsigned, 16> ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector<unsigned, 32> ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs<ValueDecl>(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} + +void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + VisitOMPClauseWithPreInit(C); + C->setNumTeams(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + VisitOMPClauseWithPreInit(C); + C->setThreadLimit(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) { + C->setPriority(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { + C->setGrainsize(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) { + C->setNumTasks(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPHintClause(OMPHintClause *C) { + C->setHint(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + VisitOMPClauseWithPreInit(C); + C->setDistScheduleKind( + static_cast<OpenMPDistScheduleClauseKind>(Record.readInt())); + C->setChunkSize(Record.readSubExpr()); + C->setLParenLoc(Record.readSourceLocation()); + C->setDistScheduleKindLoc(Record.readSourceLocation()); + C->setCommaLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) { + C->setDefaultmapKind( + static_cast<OpenMPDefaultmapClauseKind>(Record.readInt())); + C->setDefaultmapModifier( + static_cast<OpenMPDefaultmapClauseModifier>(Record.readInt())); + C->setLParenLoc(Record.readSourceLocation()); + C->setDefaultmapModifierLoc(Record.readSourceLocation()); + C->setDefaultmapKindLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPToClause(OMPToClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + + SmallVector<ValueDecl *, 16> Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs<ValueDecl>()); + C->setUniqueDecls(Decls); + + SmallVector<unsigned, 16> ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector<unsigned, 32> ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs<ValueDecl>(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} + +void OMPClauseReader::VisitOMPFromClause(OMPFromClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + + SmallVector<ValueDecl *, 16> Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs<ValueDecl>()); + C->setUniqueDecls(Decls); + + SmallVector<unsigned, 16> ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector<unsigned, 32> ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs<ValueDecl>(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} + +void OMPClauseReader::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivateCopies(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setInits(Vars); + + SmallVector<ValueDecl *, 16> Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs<ValueDecl>()); + C->setUniqueDecls(Decls); + + SmallVector<unsigned, 16> ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector<unsigned, 32> ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs<ValueDecl>(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} + +void OMPClauseReader::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + + SmallVector<ValueDecl *, 16> Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs<ValueDecl>()); + C->setUniqueDecls(Decls); + + SmallVector<unsigned, 16> ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector<unsigned, 32> ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector<OMPClauseMappableExprCommon::MappableComponent, 32> Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs<ValueDecl>(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} 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 000000000000..763ab527570d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -0,0 +1,4471 @@ +//===- ASTReaderDecl.cpp - Decl Deserialization ---------------------------===// +// +// 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 "ASTCommon.h" +#include "ASTReaderInternals.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/AttrIterator.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/PragmaKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/Module.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SaveAndRestore.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <string> +#include <utility> + +using namespace clang; +using namespace serialization; + +//===----------------------------------------------------------------------===// +// Declaration deserialization +//===----------------------------------------------------------------------===// + +namespace clang { + + class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { + ASTReader &Reader; + ASTRecordReader &Record; + ASTReader::RecordLocation Loc; + const DeclID ThisDeclID; + const SourceLocation ThisDeclLoc; + + using RecordData = ASTReader::RecordData; + + TypeID DeferredTypeID = 0; + unsigned AnonymousDeclNumber; + GlobalDeclID NamedDeclForTagDecl = 0; + IdentifierInfo *TypedefNameForLinkage = nullptr; + + bool HasPendingBody = false; + + ///A flag to carry the information for a decl from the entity is + /// used. We use it to delay the marking of the canonical decl as used until + /// the entire declaration is deserialized and merged. + bool IsDeclMarkedUsed = false; + + uint64_t GetCurrentCursorOffset(); + + uint64_t ReadLocalOffset() { + uint64_t LocalOffset = Record.readInt(); + assert(LocalOffset < Loc.Offset && "offset point after current record"); + return LocalOffset ? Loc.Offset - LocalOffset : 0; + } + + uint64_t ReadGlobalOffset() { + uint64_t Local = ReadLocalOffset(); + return Local ? Record.getGlobalBitOffset(Local) : 0; + } + + SourceLocation ReadSourceLocation() { + return Record.readSourceLocation(); + } + + SourceRange ReadSourceRange() { + return Record.readSourceRange(); + } + + TypeSourceInfo *GetTypeSourceInfo() { + return Record.getTypeSourceInfo(); + } + + serialization::DeclID ReadDeclID() { + return Record.readDeclID(); + } + + std::string ReadString() { + return Record.readString(); + } + + void ReadDeclIDList(SmallVectorImpl<DeclID> &IDs) { + for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) + IDs.push_back(ReadDeclID()); + } + + Decl *ReadDecl() { + return Record.readDecl(); + } + + template<typename T> + T *ReadDeclAs() { + return Record.readDeclAs<T>(); + } + + void ReadQualifierInfo(QualifierInfo &Info) { + Record.readQualifierInfo(Info); + } + + void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name) { + Record.readDeclarationNameLoc(DNLoc, Name); + } + + serialization::SubmoduleID readSubmoduleID() { + if (Record.getIdx() == Record.size()) + return 0; + + return Record.getGlobalSubmoduleID(Record.readInt()); + } + + Module *readModule() { + return Record.getSubmodule(readSubmoduleID()); + } + + void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update); + void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data, + const CXXRecordDecl *D); + void MergeDefinitionData(CXXRecordDecl *D, + struct CXXRecordDecl::DefinitionData &&NewDD); + void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data); + void MergeDefinitionData(ObjCInterfaceDecl *D, + struct ObjCInterfaceDecl::DefinitionData &&NewDD); + void ReadObjCDefinitionData(struct ObjCProtocolDecl::DefinitionData &Data); + void MergeDefinitionData(ObjCProtocolDecl *D, + struct ObjCProtocolDecl::DefinitionData &&NewDD); + + static DeclContext *getPrimaryDCForAnonymousDecl(DeclContext *LexicalDC); + + static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader, + DeclContext *DC, + unsigned Index); + static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC, + unsigned Index, NamedDecl *D); + + /// Results from loading a RedeclarableDecl. + class RedeclarableResult { + Decl *MergeWith; + GlobalDeclID FirstID; + bool IsKeyDecl; + + public: + RedeclarableResult(Decl *MergeWith, GlobalDeclID FirstID, bool IsKeyDecl) + : MergeWith(MergeWith), FirstID(FirstID), IsKeyDecl(IsKeyDecl) {} + + /// Retrieve the first ID. + GlobalDeclID getFirstID() const { return FirstID; } + + /// Is this declaration a key declaration? + bool isKeyDecl() const { return IsKeyDecl; } + + /// Get a known declaration that this should be merged with, if + /// any. + Decl *getKnownMergeTarget() const { return MergeWith; } + }; + + /// 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 = nullptr; + NamedDecl *Existing = nullptr; + bool AddResult = false; + unsigned AnonymousDeclNumber = 0; + IdentifierInfo *TypedefNameForLinkage = nullptr; + + public: + FindExistingResult(ASTReader &Reader) : Reader(Reader) {} + + FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing, + unsigned AnonymousDeclNumber, + IdentifierInfo *TypedefNameForLinkage) + : Reader(Reader), New(New), Existing(Existing), AddResult(true), + AnonymousDeclNumber(AnonymousDeclNumber), + TypedefNameForLinkage(TypedefNameForLinkage) {} + + FindExistingResult(FindExistingResult &&Other) + : Reader(Other.Reader), New(Other.New), Existing(Other.Existing), + AddResult(Other.AddResult), + AnonymousDeclNumber(Other.AnonymousDeclNumber), + TypedefNameForLinkage(Other.TypedefNameForLinkage) { + Other.AddResult = false; + } + + FindExistingResult &operator=(FindExistingResult &&) = delete; + ~FindExistingResult(); + + /// 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, ASTRecordReader &Record, + ASTReader::RecordLocation Loc, + DeclID thisDeclID, SourceLocation ThisDeclLoc) + : Reader(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID), + ThisDeclLoc(ThisDeclLoc) {} + + template <typename T> static + void AddLazySpecializations(T *D, + SmallVectorImpl<serialization::DeclID>& IDs) { + if (IDs.empty()) + return; + + // FIXME: We should avoid this pattern of getting the ASTContext. + ASTContext &C = D->getASTContext(); + + auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; + + if (auto &Old = LazySpecializations) { + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); + llvm::sort(IDs); + IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); + } + + auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; + *Result = IDs.size(); + std::copy(IDs.begin(), IDs.end(), Result + 1); + + LazySpecializations = Result; + } + + 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(...); + + /// Determine whether this declaration has a pending body. + bool hasPendingBody() const { return HasPendingBody; } + + void ReadFunctionDefinition(FunctionDecl *FD); + void Visit(Decl *D); + + void UpdateDecl(Decl *D, SmallVectorImpl<serialization::DeclID> &); + + static void setNextObjCCategory(ObjCCategoryDecl *Cat, + ObjCCategoryDecl *Next) { + Cat->NextClassCategory = Next; + } + + void VisitDecl(Decl *D); + void VisitPragmaCommentDecl(PragmaCommentDecl *D); + void VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *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 VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *GD); + 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 VisitDecompositionDecl(DecompositionDecl *DD); + void VisitBindingDecl(BindingDecl *BD); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + DeclID VisitTemplateDecl(TemplateDecl *D); + RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); + void VisitVarTemplateDecl(VarTemplateDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); + void VisitUsingDecl(UsingDecl *D); + void VisitUsingPackDecl(UsingPackDecl *D); + void VisitUsingShadowDecl(UsingShadowDecl *D); + void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitExportDecl(ExportDecl *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, bool IsKeyDecl); + + ObjCTypeParamList *ReadObjCTypeParamList(); + + // FIXME: Reorder according to DeclNodes.td? + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *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 VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPRequiresDecl(OMPRequiresDecl *D); + void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); + }; + +} // namespace clang + +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; + DeclT *Canonical = nullptr; + DeclT *Current = nullptr; + +public: + MergedRedeclIterator() = default; + MergedRedeclIterator(DeclT *Start) : Start(Start), 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; + } +}; + +} // namespace + +template <typename DeclT> +static llvm::iterator_range<MergedRedeclIterator<DeclT>> +merged_redecls(DeclT *D) { + return llvm::make_range(MergedRedeclIterator<DeclT>(D), + MergedRedeclIterator<DeclT>()); +} + +uint64_t ASTDeclReader::GetCurrentCursorOffset() { + return Loc.F->DeclsCursor.GetCurrentBitNo() + Loc.F->GlobalBitOffset; +} + +void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { + if (Record.readInt()) + Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; + if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { + CD->setNumCtorInitializers(Record.readInt()); + if (CD->getNumCtorInitializers()) + CD->CtorInitializers = ReadGlobalOffset(); + } + // Store the offset of the body so we can lazily load it later. + Reader.PendingBodies[FD] = GetCurrentCursorOffset(); + HasPendingBody = true; +} + +void ASTDeclReader::Visit(Decl *D) { + DeclVisitor<ASTDeclReader, void>::Visit(D); + + // At this point we have deserialized and merged the decl and it is safe to + // update its canonical decl to signal that the entire entity is used. + D->getCanonicalDecl()->Used |= IsDeclMarkedUsed; + IsDeclMarkedUsed = false; + + if (auto *DD = dyn_cast<DeclaratorDecl>(D)) { + if (auto *TInfo = DD->getTypeSourceInfo()) + Record.readTypeLoc(TInfo->getTypeLoc()); + } + + if (auto *TD = dyn_cast<TypeDecl>(D)) { + // We have a fully initialized TypeDecl. Read its type now. + TD->setTypeForDecl(Reader.GetType(DeferredTypeID).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)->TypedefNameDeclOrQualifier = + cast<TypedefNameDecl>(Reader.GetDecl(NamedDeclForTagDecl)); + } else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + // if we have a fully initialized TypeDecl, we can safely read its type now. + ID->TypeForDecl = Reader.GetType(DeferredTypeID).getTypePtrOrNull(); + } else if (auto *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.readInt()) + ReadFunctionDefinition(FD); + } +} + +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(); + GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(); + if (!LexicalDCIDForTemplateParmDecl) + LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl; + Reader.addPendingDeclContextInfo(D, + SemaDCIDForTemplateParmDecl, + LexicalDCIDForTemplateParmDecl); + D->setDeclContext(Reader.getContext().getTranslationUnitDecl()); + } else { + auto *SemaDC = ReadDeclAs<DeclContext>(); + auto *LexicalDC = ReadDeclAs<DeclContext>(); + if (!LexicalDC) + LexicalDC = SemaDC; + 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(ThisDeclLoc); + D->setInvalidDecl(Record.readInt()); + if (Record.readInt()) { // hasAttrs + AttrVec Attrs; + Record.readAttributes(Attrs); + // Avoid calling setAttrs() directly because it uses Decl::getASTContext() + // internally which is unsafe during derialization. + D->setAttrsImpl(Attrs, Reader.getContext()); + } + D->setImplicit(Record.readInt()); + D->Used = Record.readInt(); + IsDeclMarkedUsed |= D->Used; + D->setReferenced(Record.readInt()); + D->setTopLevelDeclInObjCContainer(Record.readInt()); + D->setAccess((AccessSpecifier)Record.readInt()); + D->FromASTFile = true; + bool ModulePrivate = Record.readInt(); + + // Determine whether this declaration is part of a (sub)module. If so, it + // may not yet be visible. + if (unsigned SubmoduleID = readSubmoduleID()) { + // Store the owning submodule ID in the declaration. + D->setModuleOwnershipKind( + ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate + : Decl::ModuleOwnershipKind::VisibleWhenImported); + D->setOwningModuleID(SubmoduleID); + + if (ModulePrivate) { + // 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. + } else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) { + // Mark the declaration as visible when its owning module becomes visible. + if (Owner->NameVisibility == Module::AllVisible) + D->setVisibleDespiteOwningModule(); + else + Reader.HiddenNamesMap[Owner].push_back(D); + } + } else if (ModulePrivate) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + } +} + +void ASTDeclReader::VisitPragmaCommentDecl(PragmaCommentDecl *D) { + VisitDecl(D); + D->setLocation(ReadSourceLocation()); + D->CommentKind = (PragmaMSCommentKind)Record.readInt(); + std::string Arg = ReadString(); + memcpy(D->getTrailingObjects<char>(), Arg.data(), Arg.size()); + D->getTrailingObjects<char>()[Arg.size()] = '\0'; +} + +void ASTDeclReader::VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *D) { + VisitDecl(D); + D->setLocation(ReadSourceLocation()); + std::string Name = ReadString(); + memcpy(D->getTrailingObjects<char>(), Name.data(), Name.size()); + D->getTrailingObjects<char>()[Name.size()] = '\0'; + + D->ValueStart = Name.size() + 1; + std::string Value = ReadString(); + memcpy(D->getTrailingObjects<char>() + D->ValueStart, Value.data(), + Value.size()); + D->getTrailingObjects<char>()[D->ValueStart + Value.size()] = '\0'; +} + +void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { + llvm_unreachable("Translation units are not serialized"); +} + +void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) { + VisitDecl(ND); + ND->setDeclName(Record.readDeclarationName()); + AnonymousDeclNumber = Record.readInt(); +} + +void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { + VisitNamedDecl(TD); + TD->setLocStart(ReadSourceLocation()); + // Delay type reading until after we have fully initialized the decl. + DeferredTypeID = Record.getGlobalTypeID(Record.readInt()); +} + +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) { + RedeclarableResult Redecl = VisitRedeclarable(TD); + VisitTypeDecl(TD); + TypeSourceInfo *TInfo = GetTypeSourceInfo(); + if (Record.readInt()) { // isModed + QualType modedT = Record.readType(); + TD->setModedTypeSourceInfo(TInfo, modedT); + } else + TD->setTypeSourceInfo(TInfo); + // Read and discard the declaration for which this is a typedef name for + // linkage, if it exists. We cannot rely on our type to pull in this decl, + // because it might have been merged with a type from another module and + // thus might not refer to our version of the declaration. + ReadDecl(); + 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>()) + // 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.readInt(); + TD->setTagKind((TagDecl::TagKind)Record.readInt()); + if (!isa<CXXRecordDecl>(TD)) + TD->setCompleteDefinition(Record.readInt()); + TD->setEmbeddedInDeclarator(Record.readInt()); + TD->setFreeStanding(Record.readInt()); + TD->setCompleteDefinitionRequired(Record.readInt()); + TD->setBraceRange(ReadSourceRange()); + + switch (Record.readInt()) { + case 0: + break; + case 1: { // ExtInfo + auto *Info = new (Reader.getContext()) TagDecl::ExtInfo(); + ReadQualifierInfo(*Info); + TD->TypedefNameDeclOrQualifier = Info; + break; + } + case 2: // TypedefNameForAnonDecl + NamedDeclForTagDecl = ReadDeclID(); + TypedefNameForLinkage = Record.getIdentifierInfo(); + 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 = GetTypeSourceInfo()) + ED->setIntegerTypeSourceInfo(TI); + else + ED->setIntegerType(Record.readType()); + ED->setPromotionType(Record.readType()); + ED->setNumPositiveBits(Record.readInt()); + ED->setNumNegativeBits(Record.readInt()); + ED->setScoped(Record.readInt()); + ED->setScopedUsingClassTag(Record.readInt()); + ED->setFixed(Record.readInt()); + + ED->setHasODRHash(true); + ED->ODRHash = Record.readInt(); + + // 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) { + EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]; + if (!OldDef) { + // This is the first time we've seen an imported definition. Look for a + // local definition before deciding that we are the first definition. + for (auto *D : merged_redecls(ED->getCanonicalDecl())) { + if (!D->isFromASTFile() && D->isCompleteDefinition()) { + OldDef = D; + break; + } + } + } + if (OldDef) { + Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef)); + ED->setCompleteDefinition(false); + Reader.mergeDefinitionVisibility(OldDef, ED); + if (OldDef->getODRHash() != ED->getODRHash()) + Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED); + } else { + OldDef = ED; + } + } + + if (auto *InstED = ReadDeclAs<EnumDecl>()) { + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK); + ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + } +} + +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) { + RedeclarableResult Redecl = VisitTagDecl(RD); + RD->setHasFlexibleArrayMember(Record.readInt()); + RD->setAnonymousStructOrUnion(Record.readInt()); + RD->setHasObjectMember(Record.readInt()); + RD->setHasVolatileMember(Record.readInt()); + RD->setNonTrivialToPrimitiveDefaultInitialize(Record.readInt()); + RD->setNonTrivialToPrimitiveCopy(Record.readInt()); + RD->setNonTrivialToPrimitiveDestroy(Record.readInt()); + RD->setParamDestroyedInCallee(Record.readInt()); + RD->setArgPassingRestrictions((RecordDecl::ArgPassingKind)Record.readInt()); + return Redecl; +} + +void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { + VisitNamedDecl(VD); + // For function declarations, defer reading the type in case the function has + // a deduced return type that references an entity declared within the + // function. + if (isa<FunctionDecl>(VD)) + DeferredTypeID = Record.getGlobalTypeID(Record.readInt()); + else + VD->setType(Record.readType()); +} + +void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { + VisitValueDecl(ECD); + if (Record.readInt()) + ECD->setInitExpr(Record.readExpr()); + ECD->setInitVal(Record.readAPSInt()); + mergeMergeable(ECD); +} + +void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { + VisitValueDecl(DD); + DD->setInnerLocStart(ReadSourceLocation()); + if (Record.readInt()) { // hasExtInfo + auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo(); + ReadQualifierInfo(*Info); + DD->DeclInfo = Info; + } + QualType TSIType = Record.readType(); + DD->setTypeSourceInfo( + TSIType.isNull() ? nullptr + : Reader.getContext().CreateTypeSourceInfo(TSIType)); +} + +void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { + RedeclarableResult Redecl = VisitRedeclarable(FD); + VisitDeclaratorDecl(FD); + + // Attach a type to this function. Use the real type if possible, but fall + // back to the type as written if it involves a deduced return type. + if (FD->getTypeSourceInfo() && + FD->getTypeSourceInfo()->getType()->castAs<FunctionType>() + ->getReturnType()->getContainedAutoType()) { + // We'll set up the real type in Visit, once we've finished loading the + // function. + FD->setType(FD->getTypeSourceInfo()->getType()); + Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID}); + } else { + FD->setType(Reader.GetType(DeferredTypeID)); + } + DeferredTypeID = 0; + + ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName()); + FD->IdentifierNamespace = Record.readInt(); + + // FunctionDecl's body is handled last at ASTDeclReader::Visit, + // after everything else is read. + + FD->setStorageClass(static_cast<StorageClass>(Record.readInt())); + FD->setInlineSpecified(Record.readInt()); + FD->setImplicitlyInline(Record.readInt()); + FD->setExplicitSpecified(Record.readInt()); + FD->setVirtualAsWritten(Record.readInt()); + FD->setPure(Record.readInt()); + FD->setHasInheritedPrototype(Record.readInt()); + FD->setHasWrittenPrototype(Record.readInt()); + FD->setDeletedAsWritten(Record.readInt()); + FD->setTrivial(Record.readInt()); + FD->setTrivialForCall(Record.readInt()); + FD->setDefaulted(Record.readInt()); + FD->setExplicitlyDefaulted(Record.readInt()); + FD->setHasImplicitReturnZero(Record.readInt()); + FD->setConstexpr(Record.readInt()); + FD->setUsesSEHTry(Record.readInt()); + FD->setHasSkippedBody(Record.readInt()); + FD->setIsMultiVersion(Record.readInt()); + FD->setLateTemplateParsed(Record.readInt()); + + FD->setCachedLinkage(static_cast<Linkage>(Record.readInt())); + FD->EndRangeLoc = ReadSourceLocation(); + + FD->ODRHash = Record.readInt(); + FD->setHasODRHash(true); + + switch ((FunctionDecl::TemplatedKind)Record.readInt()) { + case FunctionDecl::TK_NonTemplate: + mergeRedeclarable(FD, Redecl); + break; + case FunctionDecl::TK_FunctionTemplate: + // Merged when we merge the template. + FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>()); + break; + case FunctionDecl::TK_MemberSpecialization: { + auto *InstFD = ReadDeclAs<FunctionDecl>(); + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK); + FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + mergeRedeclarable(FD, Redecl); + break; + } + case FunctionDecl::TK_FunctionTemplateSpecialization: { + auto *Template = ReadDeclAs<FunctionTemplateDecl>(); + auto TSK = (TemplateSpecializationKind)Record.readInt(); + + // Template arguments. + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); + + // Template args as written. + SmallVector<TemplateArgumentLoc, 8> TemplArgLocs; + SourceLocation LAngleLoc, RAngleLoc; + bool HasTemplateArgumentsAsWritten = Record.readInt(); + if (HasTemplateArgumentsAsWritten) { + unsigned NumTemplateArgLocs = Record.readInt(); + TemplArgLocs.reserve(NumTemplateArgLocs); + for (unsigned i = 0; i != NumTemplateArgLocs; ++i) + TemplArgLocs.push_back(Record.readTemplateArgumentLoc()); + + LAngleLoc = ReadSourceLocation(); + RAngleLoc = ReadSourceLocation(); + } + + SourceLocation POI = ReadSourceLocation(); + + ASTContext &C = Reader.getContext(); + TemplateArgumentList *TemplArgList + = TemplateArgumentList::CreateCopy(C, TemplArgs); + 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. + auto *CanonTemplate = ReadDeclAs<FunctionTemplateDecl>(); + // 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(); + FunctionTemplateSpecializationInfo *ExistingInfo = + CommonPtr->Specializations.FindNodeOrInsertPos(ID, InsertPos); + if (InsertPos) + CommonPtr->Specializations.InsertNode(FTInfo, InsertPos); + else { + assert(Reader.getContext().getLangOpts().Modules && + "already deserialized this template specialization"); + mergeRedeclarable(FD, ExistingInfo->Function, Redecl); + } + } + break; + } + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { + // Templates. + UnresolvedSet<8> TemplDecls; + unsigned NumTemplates = Record.readInt(); + while (NumTemplates--) + TemplDecls.addDecl(ReadDeclAs<NamedDecl>()); + + // Templates args. + TemplateArgumentListInfo TemplArgs; + unsigned NumArgs = Record.readInt(); + while (NumArgs--) + TemplArgs.addArgument(Record.readTemplateArgumentLoc()); + TemplArgs.setLAngleLoc(ReadSourceLocation()); + TemplArgs.setRAngleLoc(ReadSourceLocation()); + + FD->setDependentTemplateSpecialization(Reader.getContext(), + TemplDecls, TemplArgs); + // These are not merged; we don't need to merge redeclarations of dependent + // template friends. + break; + } + } + + // Read in the parameters. + unsigned NumParams = Record.readInt(); + SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(ReadDeclAs<ParmVarDecl>()); + FD->setParams(Reader.getContext(), Params); +} + +void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { + VisitNamedDecl(MD); + if (Record.readInt()) { + // 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>()); + MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>()); + } + MD->setInstanceMethod(Record.readInt()); + MD->setVariadic(Record.readInt()); + MD->setPropertyAccessor(Record.readInt()); + MD->setDefined(Record.readInt()); + MD->setOverriding(Record.readInt()); + MD->setHasSkippedBody(Record.readInt()); + + MD->setIsRedeclaration(Record.readInt()); + MD->setHasRedeclaration(Record.readInt()); + if (MD->hasRedeclaration()) + Reader.getContext().setObjCMethodRedeclaration(MD, + ReadDeclAs<ObjCMethodDecl>()); + + MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record.readInt()); + MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record.readInt()); + MD->setRelatedResultType(Record.readInt()); + MD->setReturnType(Record.readType()); + MD->setReturnTypeSourceInfo(GetTypeSourceInfo()); + MD->DeclEndLoc = ReadSourceLocation(); + unsigned NumParams = Record.readInt(); + SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(ReadDeclAs<ParmVarDecl>()); + + MD->setSelLocsKind((SelectorLocationsKind)Record.readInt()); + unsigned NumStoredSelLocs = Record.readInt(); + SmallVector<SourceLocation, 16> SelLocs; + SelLocs.reserve(NumStoredSelLocs); + for (unsigned i = 0; i != NumStoredSelLocs; ++i) + SelLocs.push_back(ReadSourceLocation()); + + MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs); +} + +void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + + D->Variance = Record.readInt(); + D->Index = Record.readInt(); + D->VarianceLoc = ReadSourceLocation(); + D->ColonLoc = ReadSourceLocation(); +} + +void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { + VisitNamedDecl(CD); + CD->setAtStartLoc(ReadSourceLocation()); + CD->setAtEndRange(ReadSourceRange()); +} + +ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { + unsigned numParams = Record.readInt(); + if (numParams == 0) + return nullptr; + + SmallVector<ObjCTypeParamDecl *, 4> typeParams; + typeParams.reserve(numParams); + for (unsigned i = 0; i != numParams; ++i) { + auto *typeParam = ReadDeclAs<ObjCTypeParamDecl>(); + if (!typeParam) + return nullptr; + + typeParams.push_back(typeParam); + } + + SourceLocation lAngleLoc = ReadSourceLocation(); + SourceLocation rAngleLoc = ReadSourceLocation(); + + return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc, + typeParams, rAngleLoc); +} + +void ASTDeclReader::ReadObjCDefinitionData( + struct ObjCInterfaceDecl::DefinitionData &Data) { + // Read the superclass. + Data.SuperClassTInfo = GetTypeSourceInfo(); + + Data.EndLoc = ReadSourceLocation(); + Data.HasDesignatedInitializers = Record.readInt(); + + // Read the directly referenced protocols and their SourceLocations. + unsigned NumProtocols = Record.readInt(); + SmallVector<ObjCProtocolDecl *, 16> Protocols; + Protocols.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>()); + SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + ProtoLocs.push_back(ReadSourceLocation()); + Data.ReferencedProtocols.set(Protocols.data(), NumProtocols, ProtoLocs.data(), + Reader.getContext()); + + // Read the transitive closure of protocols referenced by this class. + NumProtocols = Record.readInt(); + Protocols.clear(); + Protocols.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>()); + Data.AllReferencedProtocols.set(Protocols.data(), NumProtocols, + Reader.getContext()); +} + +void ASTDeclReader::MergeDefinitionData(ObjCInterfaceDecl *D, + struct ObjCInterfaceDecl::DefinitionData &&NewDD) { + // FIXME: odr checking? +} + +void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { + RedeclarableResult Redecl = VisitRedeclarable(ID); + VisitObjCContainerDecl(ID); + DeferredTypeID = Record.getGlobalTypeID(Record.readInt()); + mergeRedeclarable(ID, Redecl); + + ID->TypeParamList = ReadObjCTypeParamList(); + if (Record.readInt()) { + // Read the definition. + ID->allocateDefinitionData(); + + ReadObjCDefinitionData(ID->data()); + ObjCInterfaceDecl *Canon = ID->getCanonicalDecl(); + if (Canon->Data.getPointer()) { + // If we already have a definition, keep the definition invariant and + // merge the data. + MergeDefinitionData(Canon, std::move(ID->data())); + ID->Data = Canon->Data; + } else { + // Set the definition data of the canonical declaration, so other + // redeclarations will see it. + ID->getCanonicalDecl()->Data = ID->Data; + + // 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.readInt()); + // This field will be built lazily. + IVD->setNextIvar(nullptr); + bool synth = Record.readInt(); + IVD->setSynthesize(synth); +} + +void ASTDeclReader::ReadObjCDefinitionData( + struct ObjCProtocolDecl::DefinitionData &Data) { + unsigned NumProtoRefs = Record.readInt(); + SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + ProtoRefs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>()); + SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(ReadSourceLocation()); + Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs, + ProtoLocs.data(), Reader.getContext()); +} + +void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D, + struct ObjCProtocolDecl::DefinitionData &&NewDD) { + // FIXME: odr checking? +} + +void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { + RedeclarableResult Redecl = VisitRedeclarable(PD); + VisitObjCContainerDecl(PD); + mergeRedeclarable(PD, Redecl); + + if (Record.readInt()) { + // Read the definition. + PD->allocateDefinitionData(); + + ReadObjCDefinitionData(PD->data()); + + ObjCProtocolDecl *Canon = PD->getCanonicalDecl(); + if (Canon->Data.getPointer()) { + // If we already have a definition, keep the definition invariant and + // merge the data. + MergeDefinitionData(Canon, std::move(PD->data())); + PD->Data = Canon->Data; + } else { + // Set the definition data of the canonical declaration, so other + // redeclarations will see it. + PD->getCanonicalDecl()->Data = PD->Data; + } + // 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()); + CD->setIvarLBraceLoc(ReadSourceLocation()); + CD->setIvarRBraceLoc(ReadSourceLocation()); + + // 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>(); + CD->TypeParamList = ReadObjCTypeParamList(); + unsigned NumProtoRefs = Record.readInt(); + SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + ProtoRefs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>()); + SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(ReadSourceLocation()); + CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + Reader.getContext()); + + // Protocols in the class extension belong to the class. + if (NumProtoRefs > 0 && CD->ClassInterface && CD->IsClassExtension()) + CD->ClassInterface->mergeClassExtensionProtocolList( + (ObjCProtocolDecl *const *)ProtoRefs.data(), NumProtoRefs, + Reader.getContext()); +} + +void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { + VisitNamedDecl(CAD); + CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>()); +} + +void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + VisitNamedDecl(D); + D->setAtLoc(ReadSourceLocation()); + D->setLParenLoc(ReadSourceLocation()); + QualType T = Record.readType(); + TypeSourceInfo *TSI = GetTypeSourceInfo(); + D->setType(T, TSI); + D->setPropertyAttributes( + (ObjCPropertyDecl::PropertyAttributeKind)Record.readInt()); + D->setPropertyAttributesAsWritten( + (ObjCPropertyDecl::PropertyAttributeKind)Record.readInt()); + D->setPropertyImplementation( + (ObjCPropertyDecl::PropertyControl)Record.readInt()); + DeclarationName GetterName = Record.readDeclarationName(); + SourceLocation GetterLoc = ReadSourceLocation(); + D->setGetterName(GetterName.getObjCSelector(), GetterLoc); + DeclarationName SetterName = Record.readDeclarationName(); + SourceLocation SetterLoc = ReadSourceLocation(); + D->setSetterName(SetterName.getObjCSelector(), SetterLoc); + D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); + D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); + D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>()); +} + +void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { + VisitObjCContainerDecl(D); + D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>()); +} + +void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitObjCImplDecl(D); + D->CategoryNameLoc = ReadSourceLocation(); +} + +void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitObjCImplDecl(D); + D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>()); + D->SuperLoc = ReadSourceLocation(); + D->setIvarLBraceLoc(ReadSourceLocation()); + D->setIvarRBraceLoc(ReadSourceLocation()); + D->setHasNonZeroConstructors(Record.readInt()); + D->setHasDestructors(Record.readInt()); + D->NumIvarInitializers = Record.readInt(); + if (D->NumIvarInitializers) + D->IvarInitializers = ReadGlobalOffset(); +} + +void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + VisitDecl(D); + D->setAtLoc(ReadSourceLocation()); + D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>()); + D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(); + D->IvarLoc = ReadSourceLocation(); + D->setGetterCXXConstructor(Record.readExpr()); + D->setSetterCXXAssignment(Record.readExpr()); +} + +void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { + VisitDeclaratorDecl(FD); + FD->Mutable = Record.readInt(); + + if (auto ISK = static_cast<FieldDecl::InitStorageKind>(Record.readInt())) { + FD->InitStorage.setInt(ISK); + FD->InitStorage.setPointer(ISK == FieldDecl::ISK_CapturedVLAType + ? Record.readType().getAsOpaquePtr() + : Record.readExpr()); + } + + if (auto *BW = Record.readExpr()) + FD->setBitWidth(BW); + + if (!FD->getDeclName()) { + if (auto *Tmpl = ReadDeclAs<FieldDecl>()) + Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); + } + mergeMergeable(FD); +} + +void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) { + VisitDeclaratorDecl(PD); + PD->GetterId = Record.getIdentifierInfo(); + PD->SetterId = Record.getIdentifierInfo(); +} + +void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { + VisitValueDecl(FD); + + FD->ChainingSize = Record.readInt(); + 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>(); + + mergeMergeable(FD); +} + +ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { + RedeclarableResult Redecl = VisitRedeclarable(VD); + VisitDeclaratorDecl(VD); + + VD->VarDeclBits.SClass = (StorageClass)Record.readInt(); + VD->VarDeclBits.TSCSpec = Record.readInt(); + VD->VarDeclBits.InitStyle = Record.readInt(); + VD->VarDeclBits.ARCPseudoStrong = Record.readInt(); + if (!isa<ParmVarDecl>(VD)) { + VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = + Record.readInt(); + VD->NonParmVarDeclBits.ExceptionVar = Record.readInt(); + VD->NonParmVarDeclBits.NRVOVariable = Record.readInt(); + VD->NonParmVarDeclBits.CXXForRangeDecl = Record.readInt(); + VD->NonParmVarDeclBits.ObjCForDecl = Record.readInt(); + VD->NonParmVarDeclBits.IsInline = Record.readInt(); + VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt(); + VD->NonParmVarDeclBits.IsConstexpr = Record.readInt(); + VD->NonParmVarDeclBits.IsInitCapture = Record.readInt(); + VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt(); + VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt(); + VD->NonParmVarDeclBits.EscapingByref = Record.readInt(); + } + auto VarLinkage = Linkage(Record.readInt()); + 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.readInt()) { + VD->setInit(Record.readExpr()); + if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3 + EvaluatedStmt *Eval = VD->ensureEvaluatedStmt(); + Eval->CheckedICE = true; + Eval->IsICE = Val == 3; + } + } + + if (VD->hasAttr<BlocksAttr>() && VD->getType()->getAsCXXRecordDecl()) { + Expr *CopyExpr = Record.readExpr(); + if (CopyExpr) + Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt()); + } + + if (VD->getStorageDuration() == SD_Static && Record.readInt()) + Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile; + + enum VarKind { + VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization + }; + switch ((VarKind)Record.readInt()) { + case VarNotTemplate: + // Only true variables (not parameters or implicit parameters) can be + // merged; the other kinds are not really redeclarable at all. + if (!isa<ParmVarDecl>(VD) && !isa<ImplicitParamDecl>(VD) && + !isa<VarTemplateSpecializationDecl>(VD)) + mergeRedeclarable(VD, Redecl); + break; + case VarTemplate: + // Merged when we merge the template. + VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>()); + break; + case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo. + auto *Tmpl = ReadDeclAs<VarDecl>(); + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + 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.readInt(); + unsigned scopeDepth = Record.readInt(); + unsigned scopeIndex = Record.readInt(); + unsigned declQualifier = Record.readInt(); + if (isObjCMethodParam) { + assert(scopeDepth == 0); + PD->setObjCMethodScopeInfo(scopeIndex); + PD->ParmVarDeclBits.ScopeDepthOrObjCQuals = declQualifier; + } else { + PD->setScopeInfo(scopeDepth, scopeIndex); + } + PD->ParmVarDeclBits.IsKNRPromoted = Record.readInt(); + PD->ParmVarDeclBits.HasInheritedDefaultArg = Record.readInt(); + if (Record.readInt()) // hasUninstantiatedDefaultArg. + PD->setUninstantiatedDefaultArg(Record.readExpr()); + + // FIXME: If this is a redeclaration of a function from another module, handle + // inheritance of default arguments. +} + +void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) { + VisitVarDecl(DD); + auto **BDs = DD->getTrailingObjects<BindingDecl *>(); + for (unsigned I = 0; I != DD->NumBindings; ++I) + BDs[I] = ReadDeclAs<BindingDecl>(); +} + +void ASTDeclReader::VisitBindingDecl(BindingDecl *BD) { + VisitValueDecl(BD); + BD->Binding = Record.readExpr(); +} + +void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { + VisitDecl(AD); + AD->setAsmString(cast<StringLiteral>(Record.readExpr())); + AD->setRParenLoc(ReadSourceLocation()); +} + +void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { + VisitDecl(BD); + BD->setBody(cast_or_null<CompoundStmt>(Record.readStmt())); + BD->setSignatureAsWritten(GetTypeSourceInfo()); + unsigned NumParams = Record.readInt(); + SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(ReadDeclAs<ParmVarDecl>()); + BD->setParams(Params); + + BD->setIsVariadic(Record.readInt()); + BD->setBlockMissingReturnType(Record.readInt()); + BD->setIsConversionFromLambda(Record.readInt()); + BD->setDoesNotEscape(Record.readInt()); + + bool capturesCXXThis = Record.readInt(); + unsigned numCaptures = Record.readInt(); + SmallVector<BlockDecl::Capture, 16> captures; + captures.reserve(numCaptures); + for (unsigned i = 0; i != numCaptures; ++i) { + auto *decl = ReadDeclAs<VarDecl>(); + unsigned flags = Record.readInt(); + bool byRef = (flags & 1); + bool nested = (flags & 2); + Expr *copyExpr = ((flags & 4) ? Record.readExpr() : nullptr); + + captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr)); + } + BD->setCaptures(Reader.getContext(), captures, capturesCXXThis); +} + +void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) { + VisitDecl(CD); + unsigned ContextParamPos = Record.readInt(); + CD->setNothrow(Record.readInt() != 0); + // Body is set by VisitCapturedStmt. + for (unsigned I = 0; I < CD->NumParams; ++I) { + if (I != ContextParamPos) + CD->setParam(I, ReadDeclAs<ImplicitParamDecl>()); + else + CD->setContextParam(I, ReadDeclAs<ImplicitParamDecl>()); + } +} + +void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + D->setLanguage((LinkageSpecDecl::LanguageIDs)Record.readInt()); + D->setExternLoc(ReadSourceLocation()); + D->setRBraceLoc(ReadSourceLocation()); +} + +void ASTDeclReader::VisitExportDecl(ExportDecl *D) { + VisitDecl(D); + D->RBraceLoc = ReadSourceLocation(); +} + +void ASTDeclReader::VisitLabelDecl(LabelDecl *D) { + VisitNamedDecl(D); + D->setLocStart(ReadSourceLocation()); +} + +void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { + RedeclarableResult Redecl = VisitRedeclarable(D); + VisitNamedDecl(D); + D->setInline(Record.readInt()); + D->LocStart = ReadSourceLocation(); + D->RBraceLoc = ReadSourceLocation(); + + // 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(); + } 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. + auto *Anon = cast<NamespaceDecl>(Reader.GetDecl(AnonNamespace)); + if (!Record.isModule()) + D->setAnonymousNamespace(Anon); + } +} + +void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + RedeclarableResult Redecl = VisitRedeclarable(D); + VisitNamedDecl(D); + D->NamespaceLoc = ReadSourceLocation(); + D->IdentLoc = ReadSourceLocation(); + D->QualifierLoc = Record.readNestedNameSpecifierLoc(); + D->Namespace = ReadDeclAs<NamedDecl>(); + mergeRedeclarable(D, Redecl); +} + +void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { + VisitNamedDecl(D); + D->setUsingLoc(ReadSourceLocation()); + D->QualifierLoc = Record.readNestedNameSpecifierLoc(); + ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); + D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>()); + D->setTypename(Record.readInt()); + if (auto *Pattern = ReadDeclAs<NamedDecl>()) + Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern); + mergeMergeable(D); +} + +void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) { + VisitNamedDecl(D); + D->InstantiatedFrom = ReadDeclAs<NamedDecl>(); + auto **Expansions = D->getTrailingObjects<NamedDecl *>(); + for (unsigned I = 0; I != D->NumExpansions; ++I) + Expansions[I] = ReadDeclAs<NamedDecl>(); + mergeMergeable(D); +} + +void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { + RedeclarableResult Redecl = VisitRedeclarable(D); + VisitNamedDecl(D); + D->Underlying = ReadDeclAs<NamedDecl>(); + D->IdentifierNamespace = Record.readInt(); + D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(); + auto *Pattern = ReadDeclAs<UsingShadowDecl>(); + if (Pattern) + Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern); + mergeRedeclarable(D, Redecl); +} + +void ASTDeclReader::VisitConstructorUsingShadowDecl( + ConstructorUsingShadowDecl *D) { + VisitUsingShadowDecl(D); + D->NominatedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>(); + D->ConstructedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>(); + D->IsVirtual = Record.readInt(); +} + +void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + D->UsingLoc = ReadSourceLocation(); + D->NamespaceLoc = ReadSourceLocation(); + D->QualifierLoc = Record.readNestedNameSpecifierLoc(); + D->NominatedNamespace = ReadDeclAs<NamedDecl>(); + D->CommonAncestor = ReadDeclAs<DeclContext>(); +} + +void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + D->setUsingLoc(ReadSourceLocation()); + D->QualifierLoc = Record.readNestedNameSpecifierLoc(); + ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); + D->EllipsisLoc = ReadSourceLocation(); + mergeMergeable(D); +} + +void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + D->TypenameLocation = ReadSourceLocation(); + D->QualifierLoc = Record.readNestedNameSpecifierLoc(); + D->EllipsisLoc = ReadSourceLocation(); + mergeMergeable(D); +} + +void ASTDeclReader::ReadCXXDefinitionData( + struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) { + // Note: the caller has deserialized the IsLambda bit already. + Data.UserDeclaredConstructor = Record.readInt(); + Data.UserDeclaredSpecialMembers = Record.readInt(); + Data.Aggregate = Record.readInt(); + Data.PlainOldData = Record.readInt(); + Data.Empty = Record.readInt(); + Data.Polymorphic = Record.readInt(); + Data.Abstract = Record.readInt(); + Data.IsStandardLayout = Record.readInt(); + Data.IsCXX11StandardLayout = Record.readInt(); + Data.HasBasesWithFields = Record.readInt(); + Data.HasBasesWithNonStaticDataMembers = Record.readInt(); + Data.HasPrivateFields = Record.readInt(); + Data.HasProtectedFields = Record.readInt(); + Data.HasPublicFields = Record.readInt(); + Data.HasMutableFields = Record.readInt(); + Data.HasVariantMembers = Record.readInt(); + Data.HasOnlyCMembers = Record.readInt(); + Data.HasInClassInitializer = Record.readInt(); + Data.HasUninitializedReferenceMember = Record.readInt(); + Data.HasUninitializedFields = Record.readInt(); + Data.HasInheritedConstructor = Record.readInt(); + Data.HasInheritedAssignment = Record.readInt(); + Data.NeedOverloadResolutionForCopyConstructor = Record.readInt(); + Data.NeedOverloadResolutionForMoveConstructor = Record.readInt(); + Data.NeedOverloadResolutionForMoveAssignment = Record.readInt(); + Data.NeedOverloadResolutionForDestructor = Record.readInt(); + Data.DefaultedCopyConstructorIsDeleted = Record.readInt(); + Data.DefaultedMoveConstructorIsDeleted = Record.readInt(); + Data.DefaultedMoveAssignmentIsDeleted = Record.readInt(); + Data.DefaultedDestructorIsDeleted = Record.readInt(); + Data.HasTrivialSpecialMembers = Record.readInt(); + Data.HasTrivialSpecialMembersForCall = Record.readInt(); + Data.DeclaredNonTrivialSpecialMembers = Record.readInt(); + Data.DeclaredNonTrivialSpecialMembersForCall = Record.readInt(); + Data.HasIrrelevantDestructor = Record.readInt(); + Data.HasConstexprNonCopyMoveConstructor = Record.readInt(); + Data.HasDefaultedDefaultConstructor = Record.readInt(); + Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt(); + Data.HasConstexprDefaultConstructor = Record.readInt(); + Data.HasNonLiteralTypeFieldsOrBases = Record.readInt(); + Data.ComputedVisibleConversions = Record.readInt(); + Data.UserProvidedDefaultConstructor = Record.readInt(); + Data.DeclaredSpecialMembers = Record.readInt(); + Data.ImplicitCopyConstructorCanHaveConstParamForVBase = Record.readInt(); + Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase = Record.readInt(); + Data.ImplicitCopyAssignmentHasConstParam = Record.readInt(); + Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt(); + Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt(); + Data.ODRHash = Record.readInt(); + Data.HasODRHash = true; + + if (Record.readInt()) + Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile; + + Data.NumBases = Record.readInt(); + if (Data.NumBases) + Data.Bases = ReadGlobalOffset(); + Data.NumVBases = Record.readInt(); + if (Data.NumVBases) + Data.VBases = ReadGlobalOffset(); + + Record.readUnresolvedSet(Data.Conversions); + Record.readUnresolvedSet(Data.VisibleConversions); + assert(Data.Definition && "Data.Definition should be already set!"); + Data.FirstFriend = ReadDeclID(); + + if (Data.IsLambda) { + using Capture = LambdaCapture; + + auto &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data); + Lambda.Dependent = Record.readInt(); + Lambda.IsGenericLambda = Record.readInt(); + Lambda.CaptureDefault = Record.readInt(); + Lambda.NumCaptures = Record.readInt(); + Lambda.NumExplicitCaptures = Record.readInt(); + Lambda.ManglingNumber = Record.readInt(); + Lambda.ContextDecl = ReadDeclID(); + Lambda.Captures = (Capture *)Reader.getContext().Allocate( + sizeof(Capture) * Lambda.NumCaptures); + Capture *ToCapture = Lambda.Captures; + Lambda.MethodTyInfo = GetTypeSourceInfo(); + for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { + SourceLocation Loc = ReadSourceLocation(); + bool IsImplicit = Record.readInt(); + auto Kind = static_cast<LambdaCaptureKind>(Record.readInt()); + switch (Kind) { + case LCK_StarThis: + case LCK_This: + case LCK_VLAType: + *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation()); + break; + case LCK_ByCopy: + case LCK_ByRef: + auto *Var = ReadDeclAs<VarDecl>(); + SourceLocation EllipsisLoc = ReadSourceLocation(); + *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); + break; + } + } + } +} + +void ASTDeclReader::MergeDefinitionData( + CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &&MergeDD) { + assert(D->DefinitionData && + "merging class definition into non-definition"); + auto &DD = *D->DefinitionData; + + if (DD.Definition != MergeDD.Definition) { + // Track that we merged the definitions. + Reader.MergedDeclContexts.insert(std::make_pair(MergeDD.Definition, + DD.Definition)); + Reader.PendingDefinitions.erase(MergeDD.Definition); + MergeDD.Definition->setCompleteDefinition(false); + Reader.mergeDefinitionVisibility(DD.Definition, MergeDD.Definition); + assert(Reader.Lookups.find(MergeDD.Definition) == Reader.Lookups.end() && + "already loaded pending lookups for merged 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(IsCXX11StandardLayout) + MATCH_FIELD(HasBasesWithFields) + MATCH_FIELD(HasBasesWithNonStaticDataMembers) + 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(HasUninitializedFields) + MATCH_FIELD(HasInheritedConstructor) + MATCH_FIELD(HasInheritedAssignment) + MATCH_FIELD(NeedOverloadResolutionForCopyConstructor) + MATCH_FIELD(NeedOverloadResolutionForMoveConstructor) + MATCH_FIELD(NeedOverloadResolutionForMoveAssignment) + MATCH_FIELD(NeedOverloadResolutionForDestructor) + MATCH_FIELD(DefaultedCopyConstructorIsDeleted) + MATCH_FIELD(DefaultedMoveConstructorIsDeleted) + MATCH_FIELD(DefaultedMoveAssignmentIsDeleted) + MATCH_FIELD(DefaultedDestructorIsDeleted) + OR_FIELD(HasTrivialSpecialMembers) + OR_FIELD(HasTrivialSpecialMembersForCall) + OR_FIELD(DeclaredNonTrivialSpecialMembers) + OR_FIELD(DeclaredNonTrivialSpecialMembersForCall) + MATCH_FIELD(HasIrrelevantDestructor) + OR_FIELD(HasConstexprNonCopyMoveConstructor) + OR_FIELD(HasDefaultedDefaultConstructor) + MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr) + OR_FIELD(HasConstexprDefaultConstructor) + MATCH_FIELD(HasNonLiteralTypeFieldsOrBases) + // ComputedVisibleConversions is handled below. + MATCH_FIELD(UserProvidedDefaultConstructor) + OR_FIELD(DeclaredSpecialMembers) + MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForVBase) + MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForNonVBase) + 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 (D->getODRHash() != MergeDD.ODRHash) { + DetectedOdrViolation = true; + } + + if (DetectedOdrViolation) + Reader.PendingOdrMergeFailures[DD.Definition].push_back( + {MergeDD.Definition, &MergeDD}); +} + +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.readInt(); + if (IsLambda) + DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, nullptr, false, false, + LCD_None); + else + DD = new (C) struct CXXRecordDecl::DefinitionData(D); + + CXXRecordDecl *Canon = D->getCanonicalDecl(); + // Set decl definition data before reading it, so that during deserialization + // when we read CXXRecordDecl, it already has definition data and we don't + // set fake one. + if (!Canon->DefinitionData) + Canon->DefinitionData = DD; + D->DefinitionData = Canon->DefinitionData; + ReadCXXDefinitionData(*DD, D); + + // We might already have a different 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. + if (Canon->DefinitionData != DD) { + MergeDefinitionData(Canon, std::move(*DD)); + return; + } + + // Mark this declaration as being a definition. + D->setCompleteDefinition(true); + + // If this is not the first declaration or is an update record, we can have + // other redeclarations already. Make a note that we need to propagate the + // DefinitionData pointer onto them. + if (Update || Canon != D) + 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.readInt()) { + 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. + auto *Template = ReadDeclAs<ClassTemplateDecl>(); + 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. + DeferredTypeID = 0; + } + break; + } + case CXXRecMemberSpecialization: { + auto *RD = ReadDeclAs<CXXRecordDecl>(); + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK); + MSI->setPointOfInstantiation(POI); + D->TemplateOrInstantiation = MSI; + mergeRedeclarable(D, Redecl); + break; + } + } + + bool WasDefinition = Record.readInt(); + 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(); + 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::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); + D->setIsCopyDeductionCandidate(Record.readInt()); +} + +void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { + VisitFunctionDecl(D); + + unsigned NumOverridenMethods = Record.readInt(); + if (D->isCanonicalDecl()) { + while (NumOverridenMethods--) { + // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod, + // MD may be initializing. + if (auto *MD = ReadDeclAs<CXXMethodDecl>()) + 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. + Record.skipInts(NumOverridenMethods); + } +} + +void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + // We need the inherited constructor information to merge the declaration, + // so we have to read it before we call VisitCXXMethodDecl. + if (D->isInheritingConstructor()) { + auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>(); + auto *Ctor = ReadDeclAs<CXXConstructorDecl>(); + *D->getTrailingObjects<InheritedConstructor>() = + InheritedConstructor(Shadow, Ctor); + } + + VisitCXXMethodDecl(D); +} + +void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + VisitCXXMethodDecl(D); + + if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>()) { + CXXDestructorDecl *Canon = D->getCanonicalDecl(); + auto *ThisArg = Record.readExpr(); + // FIXME: Check consistency if we have an old and new operator delete. + if (!Canon->OperatorDelete) { + Canon->OperatorDelete = OperatorDelete; + Canon->OperatorDeleteThisArg = ThisArg; + } + } +} + +void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { + VisitCXXMethodDecl(D); +} + +void ASTDeclReader::VisitImportDecl(ImportDecl *D) { + VisitDecl(D); + D->ImportedAndComplete.setPointer(readModule()); + D->ImportedAndComplete.setInt(Record.readInt()); + auto *StoredLocs = D->getTrailingObjects<SourceLocation>(); + for (unsigned I = 0, N = Record.back(); I != N; ++I) + StoredLocs[I] = ReadSourceLocation(); + Record.skipInts(1); // The number of stored source locations. +} + +void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { + VisitDecl(D); + D->setColonLoc(ReadSourceLocation()); +} + +void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { + VisitDecl(D); + if (Record.readInt()) // hasFriendDecl + D->Friend = ReadDeclAs<NamedDecl>(); + else + D->Friend = GetTypeSourceInfo(); + for (unsigned i = 0; i != D->NumTPLists; ++i) + D->getTrailingObjects<TemplateParameterList *>()[i] = + Record.readTemplateParameterList(); + D->NextFriend = ReadDeclID(); + D->UnsupportedFriend = (Record.readInt() != 0); + D->FriendLoc = ReadSourceLocation(); +} + +void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { + VisitDecl(D); + unsigned NumParams = Record.readInt(); + D->NumParams = NumParams; + D->Params = new TemplateParameterList*[NumParams]; + for (unsigned i = 0; i != NumParams; ++i) + D->Params[i] = Record.readTemplateParameterList(); + if (Record.readInt()) // HasFriendDecl + D->Friend = ReadDeclAs<NamedDecl>(); + else + D->Friend = GetTypeSourceInfo(); + D->FriendLoc = ReadSourceLocation(); +} + +DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { + VisitNamedDecl(D); + + DeclID PatternID = ReadDeclID(); + auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); + TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); + // FIXME handle associated constraints + D->init(TemplatedDecl, TemplateParams); + + 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 (auto *RTD = ReadDeclAs<RedeclarableTemplateDecl>()) { + assert(RTD->getKind() == D->getKind() && + "InstantiatedFromMemberTemplate kind mismatch"); + D->setInstantiatedFromMemberTemplate(RTD); + if (Record.readInt()) + D->setMemberSpecialization(); + } + } + + DeclID PatternID = VisitTemplateDecl(D); + D->IdentifierNamespace = Record.readInt(); + + 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; +} + +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); + ASTDeclReader::AddLazySpecializations(D, 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.getContext().getInjectedClassNameType( + D->getTemplatedDecl(), D->getInjectedClassNameSpecialization()); + } +} + +void ASTDeclReader::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { + llvm_unreachable("BuiltinTemplates are not serialized"); +} + +/// 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); + ASTDeclReader::AddLazySpecializations(D, SpecIDs); + } +} + +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( + ClassTemplateSpecializationDecl *D) { + RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D); + + ASTContext &C = Reader.getContext(); + if (Decl *InstD = ReadDecl()) { + if (auto *CTD = dyn_cast<ClassTemplateDecl>(InstD)) { + D->SpecializedTemplate = CTD; + } else { + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs); + TemplateArgumentList *ArgList + = TemplateArgumentList::CreateCopy(C, TemplArgs); + auto *PS = + new (C) ClassTemplateSpecializationDecl:: + SpecializedPartialSpecialization(); + PS->PartialSpecialization + = cast<ClassTemplatePartialSpecializationDecl>(InstD); + PS->TemplateArgs = ArgList; + D->SpecializedTemplate = PS; + } + } + + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); + D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); + D->PointOfInstantiation = ReadSourceLocation(); + D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); + + bool writtenAsCanonicalDecl = Record.readInt(); + if (writtenAsCanonicalDecl) { + auto *CanonPattern = ReadDeclAs<ClassTemplateDecl>(); + if (D->isCanonicalDecl()) { // It's kept in the folding set. + // Set this as, or find, the canonical declaration for this specialization + ClassTemplateSpecializationDecl *CanonSpec; + if (auto *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) { + if (CanonSpec->DefinitionData) + MergeDefinitionData(CanonSpec, std::move(*DDD)); + else + CanonSpec->DefinitionData = D->DefinitionData; + } + D->DefinitionData = CanonSpec->DefinitionData; + } + } + } + + // Explicit info. + if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) { + auto *ExplicitInfo = + new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = TyInfo; + ExplicitInfo->ExternLoc = ReadSourceLocation(); + ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(); + D->ExplicitInfo = ExplicitInfo; + } + + return Redecl; +} + +void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); + + D->TemplateParams = Record.readTemplateParameterList(); + D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + + // These are read/set from/to the first declaration. + if (ThisDeclID == Redecl.getFirstID()) { + D->InstantiatedFromMember.setPointer( + ReadDeclAs<ClassTemplatePartialSpecializationDecl>()); + D->InstantiatedFromMember.setInt(Record.readInt()); + } +} + +void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D) { + VisitDecl(D); + D->Specialization = ReadDeclAs<CXXMethodDecl>(); +} + +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); + ASTDeclReader::AddLazySpecializations(D, 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()) { + if (auto *VTD = dyn_cast<VarTemplateDecl>(InstD)) { + D->SpecializedTemplate = VTD; + } else { + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs); + TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy( + C, TemplArgs); + auto *PS = + new (C) + VarTemplateSpecializationDecl::SpecializedPartialSpecialization(); + PS->PartialSpecialization = + cast<VarTemplatePartialSpecializationDecl>(InstD); + PS->TemplateArgs = ArgList; + D->SpecializedTemplate = PS; + } + } + + // Explicit info. + if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) { + auto *ExplicitInfo = + new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = TyInfo; + ExplicitInfo->ExternLoc = ReadSourceLocation(); + ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(); + D->ExplicitInfo = ExplicitInfo; + } + + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); + D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); + D->PointOfInstantiation = ReadSourceLocation(); + D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); + D->IsCompleteDefinition = Record.readInt(); + + bool writtenAsCanonicalDecl = Record.readInt(); + if (writtenAsCanonicalDecl) { + auto *CanonPattern = ReadDeclAs<VarTemplateDecl>(); + if (D->isCanonicalDecl()) { // It's kept in the folding set. + // FIXME: If it's already present, merge it. + if (auto *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 = Record.readTemplateParameterList(); + D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + + // These are read/set from/to the first declaration. + if (ThisDeclID == Redecl.getFirstID()) { + D->InstantiatedFromMember.setPointer( + ReadDeclAs<VarTemplatePartialSpecializationDecl>()); + D->InstantiatedFromMember.setInt(Record.readInt()); + } +} + +void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + VisitTypeDecl(D); + + D->setDeclaredWithTypename(Record.readInt()); + + if (Record.readInt()) + D->setDefaultArgument(GetTypeSourceInfo()); +} + +void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + VisitDeclaratorDecl(D); + // TemplateParmPosition. + D->setDepth(Record.readInt()); + D->setPosition(Record.readInt()); + if (D->isExpandedParameterPack()) { + auto TypesAndInfos = + D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); + for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { + new (&TypesAndInfos[I].first) QualType(Record.readType()); + TypesAndInfos[I].second = GetTypeSourceInfo(); + } + } else { + // Rest of NonTypeTemplateParmDecl. + D->ParameterPack = Record.readInt(); + if (Record.readInt()) + D->setDefaultArgument(Record.readExpr()); + } +} + +void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + VisitTemplateDecl(D); + // TemplateParmPosition. + D->setDepth(Record.readInt()); + D->setPosition(Record.readInt()); + if (D->isExpandedParameterPack()) { + auto **Data = D->getTrailingObjects<TemplateParameterList *>(); + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) + Data[I] = Record.readTemplateParameterList(); + } else { + // Rest of TemplateTemplateParmDecl. + D->ParameterPack = Record.readInt(); + if (Record.readInt()) + D->setDefaultArgument(Reader.getContext(), + Record.readTemplateArgumentLoc()); + } +} + +void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); +} + +void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { + VisitDecl(D); + D->AssertExprAndFailed.setPointer(Record.readExpr()); + D->AssertExprAndFailed.setInt(Record.readInt()); + D->Message = cast_or_null<StringLiteral>(Record.readExpr()); + D->RParenLoc = ReadSourceLocation(); +} + +void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) { + VisitDecl(D); +} + +std::pair<uint64_t, uint64_t> +ASTDeclReader::VisitDeclContext(DeclContext *DC) { + uint64_t LexicalOffset = ReadLocalOffset(); + uint64_t VisibleOffset = ReadLocalOffset(); + return std::make_pair(LexicalOffset, VisibleOffset); +} + +template <typename T> +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { + DeclID FirstDeclID = ReadDeclID(); + Decl *MergeWith = nullptr; + + bool IsKeyDecl = ThisDeclID == FirstDeclID; + bool IsFirstLocalDecl = false; + + uint64_t RedeclOffset = 0; + + // 0 indicates that this declaration was the only declaration of its entity, + // and is used for space optimization. + if (FirstDeclID == 0) { + FirstDeclID = ThisDeclID; + IsKeyDecl = true; + IsFirstLocalDecl = true; + } else if (unsigned N = Record.readInt()) { + // This declaration was the first local declaration, but may have imported + // other declarations. + IsKeyDecl = N == 1; + IsFirstLocalDecl = true; + + // 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 - 1; ++I) + MergeWith = ReadDecl(); + + RedeclOffset = ReadLocalOffset(); + } else { + // This declaration was not the first local declaration. Read the first + // local declaration now, to trigger the import of other redeclarations. + (void)ReadDecl(); + } + + auto *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(); + } + + auto *DAsT = static_cast<T *>(D); + + // Note that we need to load local redeclarations of this decl and build a + // decl chain for them. This must happen *after* we perform the preloading + // above; this ensures that the redeclaration chain is built in the correct + // order. + if (IsFirstLocalDecl) + Reader.PendingDeclChains.push_back(std::make_pair(DAsT, RedeclOffset)); + + return RedeclarableResult(MergeWith, FirstDeclID, IsKeyDecl); +} + +/// 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) { + // 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; + + auto *D = static_cast<T *>(DBase); + + 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); +} + +/// "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"); +} + +/// Merge together the pattern declarations from two template +/// declarations. +void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D, + RedeclarableTemplateDecl *Existing, + DeclID DsID, bool IsKeyDecl) { + auto *DPattern = D->getTemplatedDecl(); + auto *ExistingPattern = Existing->getTemplatedDecl(); + RedeclarableResult Result(/*MergeWith*/ ExistingPattern, + DPattern->getCanonicalDecl()->getGlobalID(), + IsKeyDecl); + + 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) { + if (ExistingClass->DefinitionData) { + MergeDefinitionData(ExistingClass, std::move(*DDD)); + } else { + ExistingClass->DefinitionData = DClass->DefinitionData; + // We may have skipped this before because we thought that DClass + // was the canonical declaration. + 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"); +} + +/// 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) { + auto *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; + ExistingCanon->Used |= D->Used; + D->Used = false; + + // 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, Redecl.isKeyDecl()); + + // If this declaration is a key declaration, make a note of that. + if (Redecl.isKeyDecl()) + Reader.KeyDecls[ExistingCanon].push_back(Redecl.getFirstID()); + } +} + +/// ODR-like semantics for C/ObjC allow us to merge tag types and a structural +/// check in Sema guarantees the types can be merged (see C11 6.2.7/1 or C89 +/// 6.1.2.6/1). Although most merging is done in Sema, we need to guarantee +/// that some types are mergeable during deserialization, otherwise name +/// lookup fails. This is the case for EnumConstantDecl. +static bool allowODRLikeMergeInC(NamedDecl *ND) { + if (!ND) + return false; + // TODO: implement merge for other necessary decls. + if (isa<EnumConstantDecl>(ND)) + return true; + return false; +} + +/// 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 performed in C++ and in some cases (tag types) in C. + // Note that C identically-named things in different translation units are + // not redeclarations, but may still have compatible types, where ODR-like + // semantics may apply. + if (!Reader.getContext().getLangOpts().CPlusPlus && + !allowODRLikeMergeInC(dyn_cast<NamedDecl>(static_cast<T*>(D)))) + return; + + if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) + if (T *Existing = ExistingRes) + Reader.getContext().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(Record.readExpr()); + } + D->setVars(Vars); +} + +void ASTDeclReader::VisitOMPRequiresDecl(OMPRequiresDecl * D) { + VisitDecl(D); + unsigned NumClauses = D->clauselist_size(); + SmallVector<OMPClause *, 8> Clauses; + Clauses.reserve(NumClauses); + OMPClauseReader ClauseReader(Record); + for (unsigned I = 0; I != NumClauses; ++I) + Clauses.push_back(ClauseReader.readClause()); + D->setClauses(Clauses); +} + +void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitValueDecl(D); + D->setLocation(ReadSourceLocation()); + Expr *In = Record.readExpr(); + Expr *Out = Record.readExpr(); + D->setCombinerData(In, Out); + Expr *Combiner = Record.readExpr(); + D->setCombiner(Combiner); + Expr *Orig = Record.readExpr(); + Expr *Priv = Record.readExpr(); + D->setInitializerData(Orig, Priv); + Expr *Init = Record.readExpr(); + auto IK = static_cast<OMPDeclareReductionDecl::InitKind>(Record.readInt()); + D->setInitializer(Init, IK); + D->PrevDeclInScope = ReadDeclID(); +} + +void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { + VisitVarDecl(D); +} + +//===----------------------------------------------------------------------===// +// Attribute Reading +//===----------------------------------------------------------------------===// + +namespace { +class AttrReader { + ModuleFile *F; + ASTReader *Reader; + const ASTReader::RecordData &Record; + unsigned &Idx; + +public: + AttrReader(ModuleFile &F, ASTReader &Reader, + const ASTReader::RecordData &Record, unsigned &Idx) + : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {} + + const uint64_t &readInt() { return Record[Idx++]; } + + SourceRange readSourceRange() { + return Reader->ReadSourceRange(*F, Record, Idx); + } + + Expr *readExpr() { return Reader->ReadExpr(*F); } + + std::string readString() { + return Reader->ReadString(Record, Idx); + } + + TypeSourceInfo *getTypeSourceInfo() { + return Reader->GetTypeSourceInfo(*F, Record, Idx); + } + + IdentifierInfo *getIdentifierInfo() { + return Reader->GetIdentifierInfo(*F, Record, Idx); + } + + VersionTuple readVersionTuple() { + return ASTReader::ReadVersionTuple(Record, Idx); + } + + template <typename T> T *GetLocalDeclAs(uint32_t LocalID) { + return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID)); + } +}; +} + +Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec, + unsigned &Idx) { + AttrReader Record(M, *this, Rec, Idx); + auto V = Record.readInt(); + if (!V) + return nullptr; + + Attr *New = nullptr; + // Kind is stored as a 1-based integer because 0 is used to indicate a null + // Attr pointer. + auto Kind = static_cast<attr::Kind>(V - 1); + SourceRange Range = Record.readSourceRange(); + ASTContext &Context = getContext(); + +#include "clang/Serialization/AttrPCHRead.inc" + + assert(New && "Unable to decode attribute?"); + return New; +} + +/// Reads attributes from the current stream position. +void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) { + for (unsigned I = 0, E = Record.readInt(); I != E; ++I) + Attrs.push_back(Record.readAttr()); +} + +//===----------------------------------------------------------------------===// +// ASTReader Implementation +//===----------------------------------------------------------------------===// + +/// 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; +} + +/// 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(ASTContext &Ctx, Decl *D, bool HasBody) { + // An ObjCMethodDecl is never considered as "interesting" because its + // implementation container always is. + + // An ImportDecl or VarDecl imported from a module map module will get + // emitted when we import the relevant module. + if (isa<ImportDecl>(D) || isa<VarDecl>(D)) { + auto *M = D->getImportedOwningModule(); + if (M && M->Kind == Module::ModuleMapModule && + Ctx.DeclMustBeEmitted(D)) + return false; + } + + if (isa<FileScopeAsmDecl>(D) || + isa<ObjCProtocolDecl>(D) || + isa<ObjCImplDecl>(D) || + isa<ImportDecl>(D) || + isa<PragmaCommentDecl>(D) || + isa<PragmaDetectMismatchDecl>(D)) + return true; + if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D)) + return !D->getDeclContext()->isFunctionOrMethod(); + if (const auto *Var = dyn_cast<VarDecl>(D)) + return Var->isFileVarDecl() && + (Var->isThisDeclarationADefinition() == VarDecl::Definition || + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Var)); + if (const auto *Func = dyn_cast<FunctionDecl>(D)) + return Func->doesThisDeclarationHaveABody() || HasBody; + + if (auto *ES = D->getASTContext().getExternalSource()) + if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never) + return true; + + return false; +} + +/// Get the correct cursor and offset for loading a declaration. +ASTReader::RecordLocation +ASTReader::DeclCursorForID(DeclID ID, SourceLocation &Loc) { + 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]; + Loc = TranslateSourceLocation(*M, DOffs.getLocation()); + return RecordLocation(M, DOffs.BitOffset); +} + +ASTReader::RecordLocation ASTReader::getLocalBitOffset(uint64_t GlobalOffset) { + auto 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); + +/// 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 auto *TX = dyn_cast<TemplateTypeParmDecl>(X)) { + const auto *TY = cast<TemplateTypeParmDecl>(Y); + return TX->isParameterPack() == TY->isParameterPack(); + } + + if (const auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) { + const auto *TY = cast<NonTypeTemplateParmDecl>(Y); + return TX->isParameterPack() == TY->isParameterPack() && + TX->getASTContext().hasSameType(TX->getType(), TY->getType()); + } + + const auto *TX = cast<TemplateTemplateParmDecl>(X); + const auto *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; +} + +/// 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; +} + +/// Determine whether the attributes we can overload on are identical for A and +/// B. Will ignore any overloadable attrs represented in the type of A and B. +static bool hasSameOverloadableAttrs(const FunctionDecl *A, + const FunctionDecl *B) { + // Note that pass_object_size attributes are represented in the function's + // ExtParameterInfo, so we don't need to check them here. + + llvm::FoldingSetNodeID Cand1ID, Cand2ID; + auto AEnableIfAttrs = A->specific_attrs<EnableIfAttr>(); + auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>(); + + for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) { + Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); + Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); + + // Return false if the number of enable_if attributes is different. + if (!Cand1A || !Cand2A) + return false; + + Cand1ID.clear(); + Cand2ID.clear(); + + (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true); + (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true); + + // Return false if any of the enable_if expressions of A and B are + // different. + if (Cand1ID != Cand2ID) + return false; + } + return true; +} + +/// 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. + // + // Note that we can't use DeclContext::Equals here, because the DeclContexts + // could be two different declarations of the same function. (We will fix the + // semantic DC to refer to the primary definition after merging.) + if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()), + cast<Decl>(Y->getDeclContext()->getRedeclContext()))) + return false; + + // Two typedefs refer to the same entity if they have the same underlying + // type. + if (const auto *TypedefX = dyn_cast<TypedefNameDecl>(X)) + if (const auto *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 (const auto *TagX = dyn_cast<TagDecl>(X)) { + const auto *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 (const auto *FuncX = dyn_cast<FunctionDecl>(X)) { + const auto *FuncY = cast<FunctionDecl>(Y); + if (const auto *CtorX = dyn_cast<CXXConstructorDecl>(X)) { + const auto *CtorY = cast<CXXConstructorDecl>(Y); + if (CtorX->getInheritedConstructor() && + !isSameEntity(CtorX->getInheritedConstructor().getConstructor(), + CtorY->getInheritedConstructor().getConstructor())) + return false; + } + + if (FuncX->isMultiVersion() != FuncY->isMultiVersion()) + return false; + + // Multiversioned functions with different feature strings are represented + // as separate declarations. + if (FuncX->isMultiVersion()) { + const auto *TAX = FuncX->getAttr<TargetAttr>(); + const auto *TAY = FuncY->getAttr<TargetAttr>(); + assert(TAX && TAY && "Multiversion Function without target attribute"); + + if (TAX->getFeaturesStr() != TAY->getFeaturesStr()) + return false; + } + + ASTContext &C = FuncX->getASTContext(); + auto GetTypeAsWritten = [](const FunctionDecl *FD) { + // Map to the first declaration that we've already merged into this one. + // The TSI of redeclarations might not match (due to calling conventions + // being inherited onto the type but not the TSI), but the TSI type of + // the first declaration of the function should match across modules. + FD = FD->getCanonicalDecl(); + return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType() + : FD->getType(); + }; + QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY); + if (!C.hasSameType(XT, YT)) { + // We can get functions with different types on the redecl chain in C++17 + // if they have differing exception specifications and at least one of + // the excpetion specs is unresolved. + auto *XFPT = XT->getAs<FunctionProtoType>(); + auto *YFPT = YT->getAs<FunctionProtoType>(); + if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT && + (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) || + isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) && + C.hasSameFunctionTypeIgnoringExceptionSpec(XT, YT)) + return true; + return false; + } + return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && + hasSameOverloadableAttrs(FuncX, FuncY); + } + + // Variables with the same type and linkage match. + if (const auto *VarX = dyn_cast<VarDecl>(X)) { + const auto *VarY = cast<VarDecl>(Y); + if (VarX->getLinkageInternal() == VarY->getLinkageInternal()) { + ASTContext &C = VarX->getASTContext(); + if (C.hasSameType(VarX->getType(), VarY->getType())) + return true; + + // We can get decls with different types on the redecl chain. Eg. + // template <typename T> struct S { static T Var[]; }; // #1 + // template <typename T> T S<T>::Var[sizeof(T)]; // #2 + // Only? happens when completing an incomplete array type. In this case + // when comparing #1 and #2 we should go through their element type. + const ArrayType *VarXTy = C.getAsArrayType(VarX->getType()); + const ArrayType *VarYTy = C.getAsArrayType(VarY->getType()); + if (!VarXTy || !VarYTy) + return false; + if (VarXTy->isIncompleteArrayType() || VarYTy->isIncompleteArrayType()) + return C.hasSameType(VarXTy->getElementType(), VarYTy->getElementType()); + } + return false; + } + + // Namespaces with the same name and inlinedness match. + if (const auto *NamespaceX = dyn_cast<NamespaceDecl>(X)) { + const auto *NamespaceY = cast<NamespaceDecl>(Y); + return NamespaceX->isInline() == NamespaceY->isInline(); + } + + // Identical template names and kinds match if their template parameter lists + // and patterns match. + if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) { + const auto *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 (const auto *FDX = dyn_cast<FieldDecl>(X)) { + const auto *FDY = cast<FieldDecl>(Y); + // FIXME: Also check the bitwidth is odr-equivalent, if any. + return X->getASTContext().hasSameType(FDX->getType(), FDY->getType()); + } + + // Indirect fields with the same target field match. + if (const auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) { + const auto *IFDY = cast<IndirectFieldDecl>(Y); + return IFDX->getAnonField()->getCanonicalDecl() == + IFDY->getAnonField()->getCanonicalDecl(); + } + + // 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 (const auto *USX = dyn_cast<UsingShadowDecl>(X)) { + const auto *USY = cast<UsingShadowDecl>(Y); + return USX->getTargetDecl() == USY->getTargetDecl(); + } + + // Using declarations with the same qualifier match. (We already know that + // the name matches.) + if (const auto *UX = dyn_cast<UsingDecl>(X)) { + const auto *UY = cast<UsingDecl>(Y); + return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && + UX->hasTypename() == UY->hasTypename() && + UX->isAccessDeclaration() == UY->isAccessDeclaration(); + } + if (const auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) { + const auto *UY = cast<UnresolvedUsingValueDecl>(Y); + return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && + UX->isAccessDeclaration() == UY->isAccessDeclaration(); + } + if (const auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X)) + return isSameQualifier( + UX->getQualifier(), + cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier()); + + // Namespace alias definitions with the same target match. + if (const auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) { + const auto *NAY = cast<NamespaceAliasDecl>(Y); + return NAX->getNamespace()->Equals(NAY->getNamespace()); + } + + 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 (auto *ND = dyn_cast<NamespaceDecl>(DC)) + return ND->getOriginalNamespace(); + + if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) { + // Try to dig out the definition. + auto *DD = RD->DefinitionData; + if (!DD) + DD = RD->getCanonicalDecl()->DefinitionData; + + // 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.getContext()) struct CXXRecordDecl::DefinitionData(RD); + RD->setCompleteDefinition(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 (auto *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.getContext().getLangOpts().CPlusPlus) { + if (Reader.getIdResolver().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 nullptr; + + if (auto *TND = dyn_cast<TypedefNameDecl>(Found)) + return TND->getAnonDeclWithTypedefName(/*AnyRedecl*/true); + + return nullptr; +} + +/// Find the declaration to use to populate the anonymous declaration table +/// for the given lexical DeclContext. We only care about finding local +/// definitions of the context; we'll merge imported ones as we go. +DeclContext * +ASTDeclReader::getPrimaryDCForAnonymousDecl(DeclContext *LexicalDC) { + // For classes, we track the definition as we merge. + if (auto *RD = dyn_cast<CXXRecordDecl>(LexicalDC)) { + auto *DD = RD->getCanonicalDecl()->DefinitionData; + return DD ? DD->Definition : nullptr; + } + + // For anything else, walk its merged redeclarations looking for a definition. + // Note that we can't just call getDefinition here because the redeclaration + // chain isn't wired up. + for (auto *D : merged_redecls(cast<Decl>(LexicalDC))) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isThisDeclarationADefinition()) + return FD; + if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) + if (MD->isThisDeclarationADefinition()) + return MD; + } + + // No merged definition yet. + return nullptr; +} + +NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader, + DeclContext *DC, + unsigned Index) { + // If the lexical context has been merged, look into the now-canonical + // definition. + auto *CanonDC = cast<Decl>(DC)->getCanonicalDecl(); + + // If we've seen this before, return the canonical declaration. + auto &Previous = Reader.AnonymousDeclarationsForMerging[CanonDC]; + 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. + auto *PrimaryDC = getPrimaryDCForAnonymousDecl(DC); + if (PrimaryDC && !cast<Decl>(PrimaryDC)->isFromASTFile()) { + numberAnonymousDeclsWithin(PrimaryDC, [&](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) { + auto *CanonDC = cast<Decl>(DC)->getCanonicalDecl(); + + auto &Previous = Reader.AnonymousDeclarationsForMerging[CanonDC]; + 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; + } + + 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.getContext().getLangOpts().CPlusPlus) { + IdentifierResolver &IdResolver = Reader.getIdResolver(); + + // Temporarily consider the identifier to be up-to-date. We don't want to + // cause additional lookups here. + class UpToDateIdentifierRAII { + IdentifierInfo *II; + bool WasOutToDate = false; + + public: + explicit UpToDateIdentifierRAII(IdentifierInfo *II) : II(II) { + 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<VarDecl> *D, + Decl *Previous, Decl *Canon) { + auto *VD = static_cast<VarDecl *>(D); + auto *PrevVD = cast<VarDecl>(Previous); + D->RedeclLink.setPrevious(PrevVD); + D->First = PrevVD->First; + + // We should keep at most one definition on the chain. + // FIXME: Cache the definition once we've found it. Building a chain with + // N definitions currently takes O(N^2) time here. + if (VD->isThisDeclarationADefinition() == VarDecl::Definition) { + for (VarDecl *CurD = PrevVD; CurD; CurD = CurD->getPreviousDecl()) { + if (CurD->isThisDeclarationADefinition() == VarDecl::Definition) { + Reader.mergeDefinitionVisibility(CurD, VD); + VD->demoteThisDefinitionToDeclaration(); + break; + } + } + } +} + +static bool isUndeducedReturnType(QualType T) { + auto *DT = T->getContainedDeducedType(); + return DT && !DT->isDeduced(); +} + +template<> +void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, + Redeclarable<FunctionDecl> *D, + Decl *Previous, Decl *Canon) { + auto *FD = static_cast<FunctionDecl *>(D); + auto *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->isInlined() != FD->isInlined()) { + // 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->setImplicitlyInline(true); + } + + auto *FPT = FD->getType()->getAs<FunctionProtoType>(); + auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>(); + if (FPT && PrevFPT) { + // If we need to propagate an exception specification along the redecl + // chain, make a note of that so that we can do so later. + bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType()); + bool WasUnresolved = + isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType()); + if (IsUnresolved != WasUnresolved) + Reader.PendingExceptionSpecUpdates.insert( + {Canon, IsUnresolved ? PrevFD : FD}); + + // If we need to propagate a deduced return type along the redecl chain, + // make a note of that so that we can do it later. + bool IsUndeduced = isUndeducedReturnType(FPT->getReturnType()); + bool WasUndeduced = isUndeducedReturnType(PrevFPT->getReturnType()); + if (IsUndeduced != WasUndeduced) + Reader.PendingDeducedTypeUpdates.insert( + {cast<FunctionDecl>(Canon), + (IsUndeduced ? PrevFPT : FPT)->getReturnType()}); + } +} + +} // namespace clang + +void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) { + llvm_unreachable("attachPreviousDecl on non-redeclarable declaration"); +} + +/// Inherit the default template argument from \p From to \p To. Returns +/// \c false if there is no default template for \p From. +template <typename ParmDecl> +static bool inheritDefaultTemplateArgument(ASTContext &Context, ParmDecl *From, + Decl *ToD) { + auto *To = cast<ParmDecl>(ToD); + if (!From->hasDefaultArgument()) + return false; + To->setInheritedDefaultArgument(Context, From); + return true; +} + +static void inheritDefaultTemplateArguments(ASTContext &Context, + TemplateDecl *From, + TemplateDecl *To) { + auto *FromTP = From->getTemplateParameters(); + auto *ToTP = To->getTemplateParameters(); + assert(FromTP->size() == ToTP->size() && "merged mismatched templates?"); + + for (unsigned I = 0, N = FromTP->size(); I != N; ++I) { + NamedDecl *FromParam = FromTP->getParam(I); + NamedDecl *ToParam = ToTP->getParam(I); + + if (auto *FTTP = dyn_cast<TemplateTypeParmDecl>(FromParam)) + inheritDefaultTemplateArgument(Context, FTTP, ToParam); + else if (auto *FNTTP = dyn_cast<NonTypeTemplateParmDecl>(FromParam)) + inheritDefaultTemplateArgument(Context, FNTTP, ToParam); + else + inheritDefaultTemplateArgument( + Context, cast<TemplateTemplateParmDecl>(FromParam), ToParam); + } +} + +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 declaration declares a template, it may inherit default arguments + // from the previous declaration. + if (auto *TD = dyn_cast<TemplateDecl>(D)) + inheritDefaultTemplateArguments(Reader.getContext(), + cast<TemplateDecl>(Previous), TD); +} + +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" + } +} + +/// Read the declaration at the given offset from the AST file. +Decl *ASTReader::ReadDeclRecord(DeclID ID) { + unsigned Index = ID - NUM_PREDEF_DECL_IDS; + SourceLocation DeclLoc; + RecordLocation Loc = DeclCursorForID(ID, DeclLoc); + 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); + ASTRecordReader Record(*this, *Loc.F); + ASTDeclReader Reader(*this, Record, Loc, ID, DeclLoc); + unsigned Code = DeclsCursor.ReadCode(); + + ASTContext &Context = getContext(); + Decl *D = nullptr; + switch ((DeclCode)Record.readRecord(DeclsCursor, Code)) { + 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_EXPORT: + D = ExportDecl::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_PACK: + D = UsingPackDecl::CreateDeserialized(Context, ID, Record.readInt()); + break; + case DECL_USING_SHADOW: + D = UsingShadowDecl::CreateDeserialized(Context, ID); + break; + case DECL_CONSTRUCTOR_USING_SHADOW: + D = ConstructorUsingShadowDecl::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_DEDUCTION_GUIDE: + D = CXXDeductionGuideDecl::CreateDeserialized(Context, ID); + break; + case DECL_CXX_METHOD: + D = CXXMethodDecl::CreateDeserialized(Context, ID); + break; + case DECL_CXX_CONSTRUCTOR: + D = CXXConstructorDecl::CreateDeserialized(Context, ID, false); + break; + case DECL_CXX_INHERITED_CONSTRUCTOR: + D = CXXConstructorDecl::CreateDeserialized(Context, ID, true); + 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.readInt()); + 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.readInt()); + 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.readInt()); + 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_DECOMPOSITION: + D = DecompositionDecl::CreateDeserialized(Context, ID, Record.readInt()); + break; + case DECL_BINDING: + D = BindingDecl::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.readInt()); + 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.readInt()); + break; + case DECL_OMP_REQUIRES: + D = OMPRequiresDecl::CreateDeserialized(Context, ID, Record.readInt()); + break; + case DECL_OMP_DECLARE_REDUCTION: + D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID); + break; + case DECL_OMP_CAPTUREDEXPR: + D = OMPCapturedExprDecl::CreateDeserialized(Context, ID); + break; + case DECL_PRAGMA_COMMENT: + D = PragmaCommentDecl::CreateDeserialized(Context, ID, Record.readInt()); + break; + case DECL_PRAGMA_DETECT_MISMATCH: + D = PragmaDetectMismatchDecl::CreateDeserialized(Context, ID, + Record.readInt()); + break; + case DECL_EMPTY: + D = EmptyDecl::CreateDeserialized(Context, ID); + break; + case DECL_OBJC_TYPE_PARAM: + D = ObjCTypeParamDecl::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 (auto *DC = dyn_cast<DeclContext>(D)) { + std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); + if (Offsets.first && + ReadLexicalDeclContextStorage(*Loc.F, DeclsCursor, Offsets.first, DC)) + return nullptr; + if (Offsets.second && + ReadVisibleDeclContextStorage(*Loc.F, DeclsCursor, Offsets.second, ID)) + return nullptr; + } + assert(Record.getIdx() == Record.size()); + + // Load any relevant update records. + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/true)); + + // Load the categories after recursive loading is finished. + if (auto *Class = dyn_cast<ObjCInterfaceDecl>(D)) + // If we already have a definition when deserializing the ObjCInterfaceDecl, + // we put the Decl in PendingDefinitions so we can pull the categories here. + if (Class->isThisDeclarationADefinition() || + PendingDefinitions.count(Class)) + 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. + PotentiallyInterestingDecls.push_back( + InterestingDecl(D, Reader.hasPendingBody())); + + return D; +} + +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 (!PotentiallyInterestingDecls.empty()) { + InterestingDecl D = PotentiallyInterestingDecls.front(); + PotentiallyInterestingDecls.pop_front(); + if (isConsumerInterestedIn(getContext(), D.getDecl(), D.hasPendingBody())) + PassInterestingDeclToConsumer(D.getDecl()); + } +} + +void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { + // 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. + serialization::GlobalDeclID ID = Record.ID; + Decl *D = Record.D; + ProcessingUpdatesRAIIObj ProcessingUpdates(*this); + DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); + + SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs; + + if (UpdI != DeclUpdateOffsets.end()) { + auto UpdateOffsets = std::move(UpdI->second); + DeclUpdateOffsets.erase(UpdI); + + // Check if this decl was interesting to the consumer. If we just loaded + // the declaration, then we know it was interesting and we skip the call + // to isConsumerInterestedIn because it is unsafe to call in the + // current ASTReader state. + bool WasInteresting = + Record.JustLoaded || isConsumerInterestedIn(getContext(), D, false); + for (auto &FileAndOffset : UpdateOffsets) { + ModuleFile *F = FileAndOffset.first; + uint64_t Offset = FileAndOffset.second; + llvm::BitstreamCursor &Cursor = F->DeclsCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + unsigned Code = Cursor.ReadCode(); + ASTRecordReader Record(*this, *F); + unsigned RecCode = Record.readRecord(Cursor, Code); + (void)RecCode; + assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!"); + + ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, + SourceLocation()); + Reader.UpdateDecl(D, PendingLazySpecializationIDs); + + // We might have made this declaration interesting. If so, remember that + // we need to hand it off to the consumer. + if (!WasInteresting && + isConsumerInterestedIn(getContext(), D, Reader.hasPendingBody())) { + PotentiallyInterestingDecls.push_back( + InterestingDecl(D, Reader.hasPendingBody())); + WasInteresting = true; + } + } + } + // Add the lazy specializations to the template. + assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) || + isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) && + "Must not have pending specializations"); + if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); + else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); + else if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) + ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs); + PendingLazySpecializationIDs.clear(); + + // Load the pending visible updates for this decl context, if it has any. + auto I = PendingVisibleUpdates.find(ID); + if (I != PendingVisibleUpdates.end()) { + auto VisibleUpdates = std::move(I->second); + PendingVisibleUpdates.erase(I); + + auto *DC = cast<DeclContext>(D)->getPrimaryContext(); + for (const auto &Update : VisibleUpdates) + Lookups[DC].Table.add( + Update.Mod, Update.Data, + reader::ASTDeclContextNameLookupTrait(*this, *Update.Mod)); + DC->setHasExternalVisibleStorage(true); + } +} + +void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { + // Attach FirstLocal to the end of the decl chain. + Decl *CanonDecl = FirstLocal->getCanonicalDecl(); + if (FirstLocal != CanonDecl) { + Decl *PrevMostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); + ASTDeclReader::attachPreviousDecl( + *this, FirstLocal, PrevMostRecent ? PrevMostRecent : CanonDecl, + CanonDecl); + } + + if (!LocalOffset) { + ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal); + return; + } + + // Load the list of other redeclarations from this module file. + ModuleFile *M = getOwningModuleFile(FirstLocal); + assert(M && "imported decl from no module file"); + + llvm::BitstreamCursor &Cursor = M->DeclsCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(LocalOffset); + + RecordData Record; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record); + (void)RecCode; + assert(RecCode == LOCAL_REDECLARATIONS && "expected LOCAL_REDECLARATIONS record!"); + + // FIXME: We have several different dispatches on decl kind here; maybe + // we should instead generate one loop per kind and dispatch up-front? + Decl *MostRecent = FirstLocal; + for (unsigned I = 0, N = Record.size(); I != N; ++I) { + auto *D = GetLocalDecl(*M, Record[N - I - 1]); + ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl); + MostRecent = D; + } + ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent); +} + +namespace { + + /// Given an ObjC interface, goes through the modules and links to the + /// interface all the categories for it. + class ObjCCategoriesVisitor { + ASTReader &Reader; + ObjCInterfaceDecl *Interface; + llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized; + ObjCCategoryDecl *Tail = nullptr; + llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap; + serialization::GlobalDeclID InterfaceID; + unsigned PreviousGeneration; + + 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, + ObjCInterfaceDecl *Interface, + llvm::SmallPtrSetImpl<ObjCCategoryDecl *> &Deserialized, + serialization::GlobalDeclID InterfaceID, + unsigned PreviousGeneration) + : Reader(Reader), Interface(Interface), Deserialized(Deserialized), + InterfaceID(InterfaceID), PreviousGeneration(PreviousGeneration) { + // 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; + } + } + + bool operator()(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; + } + }; + +} // namespace + +void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID, + ObjCInterfaceDecl *D, + unsigned PreviousGeneration) { + ObjCCategoriesVisitor Visitor(*this, D, CategoriesDeserialized, ID, + PreviousGeneration); + ModuleMgr.visit(Visitor); +} + +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, + llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) { + while (Record.getIdx() < Record.size()) { + switch ((DeclUpdateKind)Record.readInt()) { + 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 = Record.readDecl(); + 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); + break; + } + + case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: + // It will be added to the template's lazy specialization set. + PendingLazySpecializationIDs.push_back(ReadDeclID()); + break; + + case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { + auto *Anon = ReadDeclAs<NamespaceDecl>(); + + // 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 (!Record.isModule()) { + if (auto *TU = dyn_cast<TranslationUnitDecl>(D)) + TU->setAnonymousNamespace(Anon); + else + cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon); + } + break; + } + + case UPD_CXX_ADDED_VAR_DEFINITION: { + auto *VD = cast<VarDecl>(D); + VD->NonParmVarDeclBits.IsInline = Record.readInt(); + VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt(); + uint64_t Val = Record.readInt(); + if (Val && !VD->getInit()) { + VD->setInit(Record.readExpr()); + if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3 + EvaluatedStmt *Eval = VD->ensureEvaluatedStmt(); + Eval->CheckedICE = true; + Eval->IsICE = Val == 3; + } + } + break; + } + + case UPD_CXX_POINT_OF_INSTANTIATION: { + SourceLocation POI = Record.readSourceLocation(); + if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + VTSD->setPointOfInstantiation(POI); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + VD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + } else { + auto *FD = cast<FunctionDecl>(D); + if (auto *FTSInfo = FD->TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + FTSInfo->setPointOfInstantiation(POI); + else + FD->TemplateOrSpecialization.get<MemberSpecializationInfo *>() + ->setPointOfInstantiation(POI); + } + break; + } + + case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: { + auto *Param = cast<ParmVarDecl>(D); + + // We have to read the default argument regardless of whether we use it + // so that hypothetical further update records aren't messed up. + // TODO: Add a function to skip over the next expr record. + auto *DefaultArg = Record.readExpr(); + + // Only apply the update if the parameter still has an uninstantiated + // default argument. + if (Param->hasUninstantiatedDefaultArg()) + Param->setDefaultArg(DefaultArg); + break; + } + + case UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER: { + auto *FD = cast<FieldDecl>(D); + auto *DefaultInit = Record.readExpr(); + + // Only apply the update if the field still has an uninstantiated + // default member initializer. + if (FD->hasInClassInitializer() && !FD->getInClassInitializer()) { + if (DefaultInit) + FD->setInClassInitializer(DefaultInit); + else + // Instantiation failed. We can get here if we serialized an AST for + // an invalid program. + FD->removeInClassInitializer(); + } + break; + } + + case UPD_CXX_ADDED_FUNCTION_DEFINITION: { + auto *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.readInt()) { + // 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(ReadSourceLocation()); + ReadFunctionDefinition(FD); + assert(Record.getIdx() == Record.size() && "lazy body must be last"); + break; + } + + case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { + auto *RD = cast<CXXRecordDecl>(D); + auto *OldDD = RD->getCanonicalDecl()->DefinitionData; + bool HadRealDefinition = + OldDD && (OldDD->Definition != RD || + !Reader.PendingFakeDefinitionData.count(OldDD)); + RD->setParamDestroyedInCallee(Record.readInt()); + RD->setArgPassingRestrictions( + (RecordDecl::ArgPassingKind)Record.readInt()); + ReadCXXRecordDefinition(RD, /*Update*/true); + + // Visible update is handled separately. + uint64_t LexicalOffset = ReadLocalOffset(); + if (!HadRealDefinition && LexicalOffset) { + Record.readLexicalDeclContextStorage(LexicalOffset, RD); + Reader.PendingFakeDefinitionData.erase(OldDD); + } + + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + if (MemberSpecializationInfo *MSInfo = + RD->getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(POI); + } else { + auto *Spec = cast<ClassTemplateSpecializationDecl>(RD); + Spec->setTemplateSpecializationKind(TSK); + Spec->setPointOfInstantiation(POI); + + if (Record.readInt()) { + auto *PartialSpec = + ReadDeclAs<ClassTemplatePartialSpecializationDecl>(); + SmallVector<TemplateArgument, 8> TemplArgs; + Record.readTemplateArgumentList(TemplArgs); + auto *TemplArgList = TemplateArgumentList::CreateCopy( + Reader.getContext(), TemplArgs); + + // 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.readInt()); + RD->setLocation(ReadSourceLocation()); + RD->setLocStart(ReadSourceLocation()); + RD->setBraceRange(ReadSourceRange()); + + if (Record.readInt()) { + AttrVec Attrs; + Record.readAttributes(Attrs); + // If the declaration already has attributes, we assume that some other + // AST file already loaded them. + if (!D->hasAttrs()) + 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 = ReadDeclAs<FunctionDecl>(); + auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl()); + auto *ThisArg = Record.readExpr(); + // FIXME: Check consistency if we have an old and new operator delete. + if (!First->OperatorDelete) { + First->OperatorDelete = Del; + First->OperatorDeleteThisArg = ThisArg; + } + break; + } + + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { + FunctionProtoType::ExceptionSpecInfo ESI; + SmallVector<QualType, 8> ExceptionStorage; + Record.readExceptionSpec(ExceptionStorage, ESI); + + // 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.getContext().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: { + auto *FD = cast<FunctionDecl>(D); + QualType DeducedResultType = Record.readType(); + Reader.PendingDeducedTypeUpdates.insert( + {FD->getCanonicalDecl(), DeducedResultType}); + break; + } + + case UPD_DECL_MARKED_USED: + // Maintain AST consistency: any later redeclarations are used too. + D->markUsed(Reader.getContext()); + break; + + case UPD_MANGLING_NUMBER: + Reader.getContext().setManglingNumber(cast<NamedDecl>(D), + Record.readInt()); + break; + + case UPD_STATIC_LOCAL_NUMBER: + Reader.getContext().setStaticLocalNumber(cast<VarDecl>(D), + Record.readInt()); + break; + + case UPD_DECL_MARKED_OPENMP_THREADPRIVATE: + D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(Reader.getContext(), + ReadSourceRange())); + break; + + case UPD_DECL_EXPORTED: { + unsigned SubmoduleID = readSubmoduleID(); + auto *Exported = cast<NamedDecl>(D); + Module *Owner = SubmoduleID ? Reader.getSubmodule(SubmoduleID) : nullptr; + Reader.getContext().mergeDefinitionIntoModule(Exported, Owner); + Reader.PendingMergedDefinitionsToDeduplicate.insert(Exported); + break; + } + + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( + Reader.getContext(), + static_cast<OMPDeclareTargetDeclAttr::MapTypeTy>(Record.readInt()), + ReadSourceRange())); + break; + + case UPD_ADDED_ATTR_TO_RECORD: + AttrVec Attrs; + Record.readAttributes(Attrs); + assert(Attrs.size() == 1); + D->addAttr(Attrs[0]); + 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 000000000000..37a929907dca --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h @@ -0,0 +1,293 @@ +//===- 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 "MultiOnDiskHashTable.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Basic/LLVM.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/OnDiskHashTable.h" +#include <ctime> +#include <utility> + +namespace clang { + +class ASTReader; +class FileEntry; +struct HeaderFileInfo; +class HeaderSearch; +class IdentifierTable; +class ObjCMethodDecl; + +namespace serialization { + +class ModuleFile; + +namespace reader { + +/// Class that performs name lookup into a DeclContext stored +/// in an AST file. +class ASTDeclContextNameLookupTrait { + ASTReader &Reader; + ModuleFile &F; + +public: + // Maximum number of lookup tables we allow before condensing the tables. + static const int MaxTables = 4; + + /// The lookup result is a list of global declaration IDs. + using data_type = SmallVector<DeclID, 4>; + + struct data_type_builder { + data_type &Data; + llvm::DenseSet<DeclID> Found; + + data_type_builder(data_type &D) : Data(D) {} + + void insert(DeclID ID) { + // Just use a linear scan unless we have more than a few IDs. + if (Found.empty() && !Data.empty()) { + if (Data.size() <= 4) { + for (auto I : Found) + if (I == ID) + return; + Data.push_back(ID); + return; + } + + // Switch to tracking found IDs in the set. + Found.insert(Data.begin(), Data.end()); + } + + if (Found.insert(ID).second) + Data.push_back(ID); + } + }; + using hash_value_type = unsigned; + using offset_type = unsigned; + using file_type = ModuleFile *; + + using external_key_type = DeclarationName; + using internal_key_type = DeclarationNameKey; + + 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 == b; + } + + static hash_value_type ComputeHash(const internal_key_type &Key) { + return Key.getHash(); + } + + static internal_key_type GetInternalKey(const external_key_type &Name) { + return Name; + } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char *&d); + + internal_key_type ReadKey(const unsigned char *d, unsigned); + + void ReadDataInto(internal_key_type, const unsigned char *d, + unsigned DataLen, data_type_builder &Val); + + static void MergeDataInto(const data_type &From, data_type_builder &To) { + To.Data.reserve(To.Data.size() + From.size()); + for (DeclID ID : From) + To.insert(ID); + } + + file_type ReadFileRef(const unsigned char *&d); +}; + +struct DeclContextLookupTable { + MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table; +}; + +/// 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 type and the ReadData operation, only. +class ASTIdentifierLookupTraitBase { +public: + using external_key_type = StringRef; + using internal_key_type = StringRef; + using hash_value_type = unsigned; + using offset_type = unsigned; + + 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); +}; + +/// 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: + using data_type = IdentifierInfo *; + + 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); + + IdentID ReadIdentifierID(const unsigned char *d); + + ASTReader &getReader() const { return Reader; } +}; + +/// The on-disk hash table used to contain information about +/// all of the identifiers in the program. +using ASTIdentifierLookupTable = + llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>; + +/// 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; + }; + + using external_key_type = Selector; + using internal_key_type = external_key_type; + using hash_value_type = unsigned; + using offset_type = unsigned; + + 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); +}; + +/// The on-disk hash table used for the global method pool. +using ASTSelectorLookupTable = + llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>; + +/// 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: + using external_key_type = const FileEntry *; + + struct internal_key_type { + off_t Size; + time_t ModTime; + StringRef Filename; + bool Imported; + }; + + using internal_key_ref = const internal_key_type &; + + using data_type = HeaderFileInfo; + using hash_value_type = unsigned; + using offset_type = unsigned; + + 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); + 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); +}; + +/// The on-disk hash table used for known header files. +using HeaderFileInfoLookupTable = + llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>; + +} // namespace reader + +} // namespace serialization + +} // namespace clang + +#endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H 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 000000000000..60abea95bfaf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -0,0 +1,3418 @@ +//===- ASTReaderStmt.cpp - Stmt/Expr Deserialization ----------------------===// +// +// 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/AttrIterator.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/CapturedStmt.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TypeTraits.h" +#include "clang/Lex/Token.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <string> + +using namespace clang; +using namespace serialization; + +namespace clang { + + class ASTStmtReader : public StmtVisitor<ASTStmtReader> { + friend class OMPClauseReader; + + ASTRecordReader &Record; + llvm::BitstreamCursor &DeclsCursor; + + SourceLocation ReadSourceLocation() { + return Record.readSourceLocation(); + } + + SourceRange ReadSourceRange() { + return Record.readSourceRange(); + } + + std::string ReadString() { + return Record.readString(); + } + + TypeSourceInfo *GetTypeSourceInfo() { + return Record.getTypeSourceInfo(); + } + + Decl *ReadDecl() { + return Record.readDecl(); + } + + template<typename T> + T *ReadDeclAs() { + return Record.readDeclAs<T>(); + } + + void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, + DeclarationName Name) { + Record.readDeclarationNameLoc(DNLoc, Name); + } + + void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo) { + Record.readDeclarationNameInfo(NameInfo); + } + + public: + ASTStmtReader(ASTRecordReader &Record, llvm::BitstreamCursor &Cursor) + : Record(Record), DeclsCursor(Cursor) {} + + /// The number of record fields required for the Stmt class + /// itself. + static const unsigned NumStmtFields = 0; + + /// The number of record fields required for the Expr class + /// itself. + static const unsigned NumExprFields = NumStmtFields + 7; + + /// Read and initialize a ExplicitTemplateArgumentList structure. + void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, + TemplateArgumentLoc *ArgsLocArray, + unsigned NumTemplateArgs); + + /// 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" + }; + +} // namespace clang + +void ASTStmtReader::ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, + TemplateArgumentLoc *ArgsLocArray, + unsigned NumTemplateArgs) { + SourceLocation TemplateKWLoc = ReadSourceLocation(); + TemplateArgumentListInfo ArgInfo; + ArgInfo.setLAngleLoc(ReadSourceLocation()); + ArgInfo.setRAngleLoc(ReadSourceLocation()); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + ArgInfo.addArgument(Record.readTemplateArgumentLoc()); + Args.initializeFrom(TemplateKWLoc, ArgInfo, ArgsLocArray); +} + +void ASTStmtReader::VisitStmt(Stmt *S) { + assert(Record.getIdx() == NumStmtFields && "Incorrect statement field count"); +} + +void ASTStmtReader::VisitNullStmt(NullStmt *S) { + VisitStmt(S); + S->setSemiLoc(ReadSourceLocation()); + S->NullStmtBits.HasLeadingEmptyMacro = Record.readInt(); +} + +void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); + SmallVector<Stmt *, 16> Stmts; + unsigned NumStmts = Record.readInt(); + while (NumStmts--) + Stmts.push_back(Record.readSubStmt()); + S->setStmts(Stmts); + S->CompoundStmtBits.LBraceLoc = ReadSourceLocation(); + S->RBraceLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); + Record.recordSwitchCaseID(S, Record.readInt()); + S->setKeywordLoc(ReadSourceLocation()); + S->setColonLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCaseStmt(CaseStmt *S) { + VisitSwitchCase(S); + bool CaseStmtIsGNURange = Record.readInt(); + S->setLHS(Record.readSubExpr()); + S->setSubStmt(Record.readSubStmt()); + if (CaseStmtIsGNURange) { + S->setRHS(Record.readSubExpr()); + S->setEllipsisLoc(ReadSourceLocation()); + } +} + +void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) { + VisitSwitchCase(S); + S->setSubStmt(Record.readSubStmt()); +} + +void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + auto *LD = ReadDeclAs<LabelDecl>(); + LD->setStmt(S); + S->setDecl(LD); + S->setSubStmt(Record.readSubStmt()); + S->setIdentLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + // NumAttrs in AttributedStmt is set when creating an empty + // AttributedStmt in AttributedStmt::CreateEmpty, since it is needed + // to allocate the right amount of space for the trailing Attr *. + uint64_t NumAttrs = Record.readInt(); + AttrVec Attrs; + Record.readAttributes(Attrs); + (void)NumAttrs; + assert(NumAttrs == S->AttributedStmtBits.NumAttrs); + assert(NumAttrs == Attrs.size()); + std::copy(Attrs.begin(), Attrs.end(), S->getAttrArrayPtr()); + S->SubStmt = Record.readSubStmt(); + S->AttributedStmtBits.AttrLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitIfStmt(IfStmt *S) { + VisitStmt(S); + + S->setConstexpr(Record.readInt()); + bool HasElse = Record.readInt(); + bool HasVar = Record.readInt(); + bool HasInit = Record.readInt(); + + S->setCond(Record.readSubExpr()); + S->setThen(Record.readSubStmt()); + if (HasElse) + S->setElse(Record.readSubStmt()); + if (HasVar) + S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + if (HasInit) + S->setInit(Record.readSubStmt()); + + S->setIfLoc(ReadSourceLocation()); + if (HasElse) + S->setElseLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); + + bool HasInit = Record.readInt(); + bool HasVar = Record.readInt(); + bool AllEnumCasesCovered = Record.readInt(); + if (AllEnumCasesCovered) + S->setAllEnumCasesCovered(); + + S->setCond(Record.readSubExpr()); + S->setBody(Record.readSubStmt()); + if (HasInit) + S->setInit(Record.readSubStmt()); + if (HasVar) + S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + + S->setSwitchLoc(ReadSourceLocation()); + + SwitchCase *PrevSC = nullptr; + for (auto E = Record.size(); Record.getIdx() != E; ) { + SwitchCase *SC = Record.getSwitchCaseWithID(Record.readInt()); + if (PrevSC) + PrevSC->setNextSwitchCase(SC); + else + S->setSwitchCaseList(SC); + + PrevSC = SC; + } +} + +void ASTStmtReader::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); + + bool HasVar = Record.readInt(); + + S->setCond(Record.readSubExpr()); + S->setBody(Record.readSubStmt()); + if (HasVar) + S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + + S->setWhileLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitDoStmt(DoStmt *S) { + VisitStmt(S); + S->setCond(Record.readSubExpr()); + S->setBody(Record.readSubStmt()); + S->setDoLoc(ReadSourceLocation()); + S->setWhileLoc(ReadSourceLocation()); + S->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitForStmt(ForStmt *S) { + VisitStmt(S); + S->setInit(Record.readSubStmt()); + S->setCond(Record.readSubExpr()); + S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + S->setInc(Record.readSubExpr()); + S->setBody(Record.readSubStmt()); + S->setForLoc(ReadSourceLocation()); + S->setLParenLoc(ReadSourceLocation()); + S->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + S->setLabel(ReadDeclAs<LabelDecl>()); + S->setGotoLoc(ReadSourceLocation()); + S->setLabelLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + S->setGotoLoc(ReadSourceLocation()); + S->setStarLoc(ReadSourceLocation()); + S->setTarget(Record.readSubExpr()); +} + +void ASTStmtReader::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); + S->setContinueLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); + S->setBreakLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); + + bool HasNRVOCandidate = Record.readInt(); + + S->setRetValue(Record.readSubExpr()); + if (HasNRVOCandidate) + S->setNRVOCandidate(ReadDeclAs<VarDecl>()); + + S->setReturnLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + S->setStartLoc(ReadSourceLocation()); + S->setEndLoc(ReadSourceLocation()); + + if (Record.size() - Record.getIdx() == 1) { + // Single declaration + S->setDeclGroup(DeclGroupRef(ReadDecl())); + } else { + SmallVector<Decl *, 16> Decls; + int N = Record.size() - Record.getIdx(); + Decls.reserve(N); + for (int I = 0; I < N; ++I) + Decls.push_back(ReadDecl()); + S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Record.getContext(), + Decls.data(), + Decls.size()))); + } +} + +void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + S->NumOutputs = Record.readInt(); + S->NumInputs = Record.readInt(); + S->NumClobbers = Record.readInt(); + S->setAsmLoc(ReadSourceLocation()); + S->setVolatile(Record.readInt()); + S->setSimple(Record.readInt()); +} + +void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + S->setRParenLoc(ReadSourceLocation()); + S->setAsmString(cast_or_null<StringLiteral>(Record.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(Record.getIdentifierInfo()); + Constraints.push_back(cast_or_null<StringLiteral>(Record.readSubStmt())); + Exprs.push_back(Record.readSubStmt()); + } + + // Constraints + SmallVector<StringLiteral*, 16> Clobbers; + for (unsigned I = 0; I != NumClobbers; ++I) + Clobbers.push_back(cast_or_null<StringLiteral>(Record.readSubStmt())); + + S->setOutputsAndInputsAndClobbers(Record.getContext(), + Names.data(), Constraints.data(), + Exprs.data(), NumOutputs, NumInputs, + Clobbers.data(), NumClobbers); +} + +void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { + VisitAsmStmt(S); + S->LBraceLoc = ReadSourceLocation(); + S->EndLoc = ReadSourceLocation(); + S->NumAsmToks = Record.readInt(); + std::string AsmStr = ReadString(); + + // Read the tokens. + SmallVector<Token, 16> AsmToks; + AsmToks.reserve(S->NumAsmToks); + for (unsigned i = 0, e = S->NumAsmToks; i != e; ++i) { + AsmToks.push_back(Record.readToken()); + } + + // 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()); + 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>(Record.readSubStmt())); + ConstraintsData.push_back(ReadString()); + Constraints.push_back(ConstraintsData.back()); + } + + S->initialize(Record.getContext(), AsmStr, AsmToks, + Constraints, Exprs, Clobbers); +} + +void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + VisitStmt(S); + assert(Record.peekInt() == S->NumParams); + Record.skipInts(1); + auto *StoredStmts = S->getStoredStmts(); + for (unsigned i = 0; + i < CoroutineBodyStmt::SubStmt::FirstParamMove + S->NumParams; ++i) + StoredStmts[i] = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) { + VisitStmt(S); + S->CoreturnLoc = Record.readSourceLocation(); + for (auto &SubStmt: S->SubStmts) + SubStmt = Record.readSubStmt(); + S->IsImplicit = Record.readInt() != 0; +} + +void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); + E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt()); + E->setIsImplicit(Record.readInt() != 0); +} + +void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); + E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt()); +} + +void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { + VisitStmt(S); + Record.skipInts(1); + S->setCapturedDecl(ReadDeclAs<CapturedDecl>()); + S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record.readInt())); + S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>()); + + // Capture inits + for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), + E = S->capture_init_end(); + I != E; ++I) + *I = Record.readSubExpr(); + + // Body + S->setCapturedStmt(Record.readSubStmt()); + S->getCapturedDecl()->setBody(S->getCapturedStmt()); + + // Captures + for (auto &I : S->captures()) { + I.VarAndKind.setPointer(ReadDeclAs<VarDecl>()); + I.VarAndKind.setInt( + static_cast<CapturedStmt::VariableCaptureKind>(Record.readInt())); + I.Loc = ReadSourceLocation(); + } +} + +void ASTStmtReader::VisitExpr(Expr *E) { + VisitStmt(E); + E->setType(Record.readType()); + E->setTypeDependent(Record.readInt()); + E->setValueDependent(Record.readInt()); + E->setInstantiationDependent(Record.readInt()); + E->ExprBits.ContainsUnexpandedParameterPack = Record.readInt(); + E->setValueKind(static_cast<ExprValueKind>(Record.readInt())); + E->setObjectKind(static_cast<ExprObjectKind>(Record.readInt())); + assert(Record.getIdx() == NumExprFields && + "Incorrect expression field count"); +} + +void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { + VisitExpr(E); + E->setSubExpr(Record.readSubExpr()); +} + +void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { + VisitExpr(E); + bool HasFunctionName = Record.readInt(); + E->PredefinedExprBits.HasFunctionName = HasFunctionName; + E->PredefinedExprBits.Kind = Record.readInt(); + E->setLocation(ReadSourceLocation()); + if (HasFunctionName) + E->setFunctionName(cast<StringLiteral>(Record.readSubExpr())); +} + +void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { + VisitExpr(E); + + E->DeclRefExprBits.HasQualifier = Record.readInt(); + E->DeclRefExprBits.HasFoundDecl = Record.readInt(); + E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record.readInt(); + E->DeclRefExprBits.HadMultipleCandidates = Record.readInt(); + E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record.readInt(); + unsigned NumTemplateArgs = 0; + if (E->hasTemplateKWAndArgsInfo()) + NumTemplateArgs = Record.readInt(); + + if (E->hasQualifier()) + new (E->getTrailingObjects<NestedNameSpecifierLoc>()) + NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc()); + + if (E->hasFoundDecl()) + *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(); + + if (E->hasTemplateKWAndArgsInfo()) + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); + + E->setDecl(ReadDeclAs<ValueDecl>()); + E->setLocation(ReadSourceLocation()); + ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName()); +} + +void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { + VisitExpr(E); + E->setLocation(ReadSourceLocation()); + E->setValue(Record.getContext(), Record.readAPInt()); +} + +void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) { + VisitExpr(E); + E->setLocation(ReadSourceLocation()); + E->setValue(Record.getContext(), Record.readAPInt()); +} + +void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { + VisitExpr(E); + E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record.readInt())); + E->setExact(Record.readInt()); + E->setValue(Record.getContext(), Record.readAPFloat(E->getSemantics())); + E->setLocation(ReadSourceLocation()); +} + +void ASTStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) { + VisitExpr(E); + E->setSubExpr(Record.readSubExpr()); +} + +void ASTStmtReader::VisitStringLiteral(StringLiteral *E) { + VisitExpr(E); + + // NumConcatenated, Length and CharByteWidth are set by the empty + // ctor since they are needed to allocate storage for the trailing objects. + unsigned NumConcatenated = Record.readInt(); + unsigned Length = Record.readInt(); + unsigned CharByteWidth = Record.readInt(); + assert((NumConcatenated == E->getNumConcatenated()) && + "Wrong number of concatenated tokens!"); + assert((Length == E->getLength()) && "Wrong Length!"); + assert((CharByteWidth == E->getCharByteWidth()) && "Wrong character width!"); + E->StringLiteralBits.Kind = Record.readInt(); + E->StringLiteralBits.IsPascal = Record.readInt(); + + // The character width is originally computed via mapCharByteWidth. + // Check that the deserialized character width is consistant with the result + // of calling mapCharByteWidth. + assert((CharByteWidth == + StringLiteral::mapCharByteWidth(Record.getContext().getTargetInfo(), + E->getKind())) && + "Wrong character width!"); + + // Deserialize the trailing array of SourceLocation. + for (unsigned I = 0; I < NumConcatenated; ++I) + E->setStrTokenLoc(I, ReadSourceLocation()); + + // Deserialize the trailing array of char holding the string data. + char *StrData = E->getStrDataAsChar(); + for (unsigned I = 0; I < Length * CharByteWidth; ++I) + StrData[I] = Record.readInt(); +} + +void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { + VisitExpr(E); + E->setValue(Record.readInt()); + E->setLocation(ReadSourceLocation()); + E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record.readInt())); +} + +void ASTStmtReader::VisitParenExpr(ParenExpr *E) { + VisitExpr(E); + E->setLParen(ReadSourceLocation()); + E->setRParen(ReadSourceLocation()); + E->setSubExpr(Record.readSubExpr()); +} + +void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) { + VisitExpr(E); + unsigned NumExprs = Record.readInt(); + assert((NumExprs == E->getNumExprs()) && "Wrong NumExprs!"); + for (unsigned I = 0; I != NumExprs; ++I) + E->getTrailingObjects<Stmt *>()[I] = Record.readSubStmt(); + E->LParenLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) { + VisitExpr(E); + E->setSubExpr(Record.readSubExpr()); + E->setOpcode((UnaryOperator::Opcode)Record.readInt()); + E->setOperatorLoc(ReadSourceLocation()); + E->setCanOverflow(Record.readInt()); +} + +void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { + VisitExpr(E); + assert(E->getNumComponents() == Record.peekInt()); + Record.skipInts(1); + assert(E->getNumExpressions() == Record.peekInt()); + Record.skipInts(1); + E->setOperatorLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); + E->setTypeSourceInfo(GetTypeSourceInfo()); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + auto Kind = static_cast<OffsetOfNode::Kind>(Record.readInt()); + SourceLocation Start = ReadSourceLocation(); + SourceLocation End = ReadSourceLocation(); + switch (Kind) { + case OffsetOfNode::Array: + E->setComponent(I, OffsetOfNode(Start, Record.readInt(), End)); + break; + + case OffsetOfNode::Field: + E->setComponent( + I, OffsetOfNode(Start, ReadDeclAs<FieldDecl>(), End)); + break; + + case OffsetOfNode::Identifier: + E->setComponent( + I, + OffsetOfNode(Start, Record.getIdentifierInfo(), End)); + break; + + case OffsetOfNode::Base: { + auto *Base = new (Record.getContext()) CXXBaseSpecifier(); + *Base = Record.readCXXBaseSpecifier(); + E->setComponent(I, OffsetOfNode(Base)); + break; + } + } + } + + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + E->setIndexExpr(I, Record.readSubExpr()); +} + +void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { + VisitExpr(E); + E->setKind(static_cast<UnaryExprOrTypeTrait>(Record.readInt())); + if (Record.peekInt() == 0) { + E->setArgument(Record.readSubExpr()); + Record.skipInts(1); + } else { + E->setArgument(GetTypeSourceInfo()); + } + E->setOperatorLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + VisitExpr(E); + E->setLHS(Record.readSubExpr()); + E->setRHS(Record.readSubExpr()); + E->setRBracketLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + E->setBase(Record.readSubExpr()); + E->setLowerBound(Record.readSubExpr()); + E->setLength(Record.readSubExpr()); + E->setColonLoc(ReadSourceLocation()); + E->setRBracketLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCallExpr(CallExpr *E) { + VisitExpr(E); + unsigned NumArgs = Record.readInt(); + assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!"); + E->setRParenLoc(ReadSourceLocation()); + E->setCallee(Record.readSubExpr()); + for (unsigned I = 0; I != NumArgs; ++I) + E->setArg(I, Record.readSubExpr()); + E->setADLCallKind(static_cast<CallExpr::ADLCallKind>(Record.readInt())); +} + +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(Record.readSubExpr()); + E->setIsaMemberLoc(ReadSourceLocation()); + E->setOpLoc(ReadSourceLocation()); + E->setArrow(Record.readInt()); +} + +void ASTStmtReader:: +VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { + VisitExpr(E); + E->Operand = Record.readSubExpr(); + E->setShouldCopy(Record.readInt()); +} + +void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { + VisitExplicitCastExpr(E); + E->LParenLoc = ReadSourceLocation(); + E->BridgeKeywordLoc = ReadSourceLocation(); + E->Kind = Record.readInt(); +} + +void ASTStmtReader::VisitCastExpr(CastExpr *E) { + VisitExpr(E); + unsigned NumBaseSpecs = Record.readInt(); + assert(NumBaseSpecs == E->path_size()); + E->setSubExpr(Record.readSubExpr()); + E->setCastKind((CastKind)Record.readInt()); + CastExpr::path_iterator BaseI = E->path_begin(); + while (NumBaseSpecs--) { + auto *BaseSpec = new (Record.getContext()) CXXBaseSpecifier; + *BaseSpec = Record.readCXXBaseSpecifier(); + *BaseI++ = BaseSpec; + } +} + +void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { + VisitExpr(E); + E->setLHS(Record.readSubExpr()); + E->setRHS(Record.readSubExpr()); + E->setOpcode((BinaryOperator::Opcode)Record.readInt()); + E->setOperatorLoc(ReadSourceLocation()); + E->setFPFeatures(FPOptions(Record.readInt())); +} + +void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { + VisitBinaryOperator(E); + E->setComputationLHSType(Record.readType()); + E->setComputationResultType(Record.readType()); +} + +void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) { + VisitExpr(E); + E->SubExprs[ConditionalOperator::COND] = Record.readSubExpr(); + E->SubExprs[ConditionalOperator::LHS] = Record.readSubExpr(); + E->SubExprs[ConditionalOperator::RHS] = Record.readSubExpr(); + E->QuestionLoc = ReadSourceLocation(); + E->ColonLoc = ReadSourceLocation(); +} + +void +ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { + VisitExpr(E); + E->OpaqueValue = cast<OpaqueValueExpr>(Record.readSubExpr()); + E->SubExprs[BinaryConditionalOperator::COMMON] = Record.readSubExpr(); + E->SubExprs[BinaryConditionalOperator::COND] = Record.readSubExpr(); + E->SubExprs[BinaryConditionalOperator::LHS] = Record.readSubExpr(); + E->SubExprs[BinaryConditionalOperator::RHS] = Record.readSubExpr(); + E->QuestionLoc = ReadSourceLocation(); + E->ColonLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { + VisitCastExpr(E); + E->setIsPartOfExplicitCast(Record.readInt()); +} + +void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { + VisitCastExpr(E); + E->setTypeInfoAsWritten(GetTypeSourceInfo()); +} + +void ASTStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { + VisitExplicitCastExpr(E); + E->setLParenLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + VisitExpr(E); + E->setLParenLoc(ReadSourceLocation()); + E->setTypeSourceInfo(GetTypeSourceInfo()); + E->setInitializer(Record.readSubExpr()); + E->setFileScope(Record.readInt()); +} + +void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { + VisitExpr(E); + E->setBase(Record.readSubExpr()); + E->setAccessor(Record.getIdentifierInfo()); + E->setAccessorLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { + VisitExpr(E); + if (auto *SyntForm = cast_or_null<InitListExpr>(Record.readSubStmt())) + E->setSyntacticForm(SyntForm); + E->setLBraceLoc(ReadSourceLocation()); + E->setRBraceLoc(ReadSourceLocation()); + bool isArrayFiller = Record.readInt(); + Expr *filler = nullptr; + if (isArrayFiller) { + filler = Record.readSubExpr(); + E->ArrayFillerOrUnionFieldInit = filler; + } else + E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(); + E->sawArrayRangeDesignator(Record.readInt()); + unsigned NumInits = Record.readInt(); + E->reserveInits(Record.getContext(), NumInits); + if (isArrayFiller) { + for (unsigned I = 0; I != NumInits; ++I) { + Expr *init = Record.readSubExpr(); + E->updateInit(Record.getContext(), I, init ? init : filler); + } + } else { + for (unsigned I = 0; I != NumInits; ++I) + E->updateInit(Record.getContext(), I, Record.readSubExpr()); + } +} + +void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + using Designator = DesignatedInitExpr::Designator; + + VisitExpr(E); + unsigned NumSubExprs = Record.readInt(); + assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs"); + for (unsigned I = 0; I != NumSubExprs; ++I) + E->setSubExpr(I, Record.readSubExpr()); + E->setEqualOrColonLoc(ReadSourceLocation()); + E->setGNUSyntax(Record.readInt()); + + SmallVector<Designator, 4> Designators; + while (Record.getIdx() < Record.size()) { + switch ((DesignatorTypes)Record.readInt()) { + case DESIG_FIELD_DECL: { + auto *Field = ReadDeclAs<FieldDecl>(); + SourceLocation DotLoc = ReadSourceLocation(); + SourceLocation FieldLoc = ReadSourceLocation(); + Designators.push_back(Designator(Field->getIdentifier(), DotLoc, + FieldLoc)); + Designators.back().setField(Field); + break; + } + + case DESIG_FIELD_NAME: { + const IdentifierInfo *Name = Record.getIdentifierInfo(); + SourceLocation DotLoc = ReadSourceLocation(); + SourceLocation FieldLoc = ReadSourceLocation(); + Designators.push_back(Designator(Name, DotLoc, FieldLoc)); + break; + } + + case DESIG_ARRAY: { + unsigned Index = Record.readInt(); + SourceLocation LBracketLoc = ReadSourceLocation(); + SourceLocation RBracketLoc = ReadSourceLocation(); + Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc)); + break; + } + + case DESIG_ARRAY_RANGE: { + unsigned Index = Record.readInt(); + SourceLocation LBracketLoc = ReadSourceLocation(); + SourceLocation EllipsisLoc = ReadSourceLocation(); + SourceLocation RBracketLoc = ReadSourceLocation(); + Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc, + RBracketLoc)); + break; + } + } + } + E->setDesignators(Record.getContext(), + Designators.data(), Designators.size()); +} + +void ASTStmtReader::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) { + VisitExpr(E); + E->setBase(Record.readSubExpr()); + E->setUpdater(Record.readSubExpr()); +} + +void ASTStmtReader::VisitNoInitExpr(NoInitExpr *E) { + VisitExpr(E); +} + +void ASTStmtReader::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) { + VisitExpr(E); + E->SubExprs[0] = Record.readSubExpr(); + E->SubExprs[1] = Record.readSubExpr(); +} + +void ASTStmtReader::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) { + VisitExpr(E); +} + +void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { + VisitExpr(E); +} + +void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) { + VisitExpr(E); + E->setSubExpr(Record.readSubExpr()); + E->setWrittenTypeInfo(GetTypeSourceInfo()); + E->setBuiltinLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); + E->setIsMicrosoftABI(Record.readInt()); +} + +void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + E->setAmpAmpLoc(ReadSourceLocation()); + E->setLabelLoc(ReadSourceLocation()); + E->setLabel(ReadDeclAs<LabelDecl>()); +} + +void ASTStmtReader::VisitStmtExpr(StmtExpr *E) { + VisitExpr(E); + E->setLParenLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); + E->setSubStmt(cast_or_null<CompoundStmt>(Record.readSubStmt())); +} + +void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) { + VisitExpr(E); + E->setCond(Record.readSubExpr()); + E->setLHS(Record.readSubExpr()); + E->setRHS(Record.readSubExpr()); + E->setBuiltinLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); + E->setIsConditionTrue(Record.readInt()); +} + +void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) { + VisitExpr(E); + E->setTokenLocation(ReadSourceLocation()); +} + +void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + VisitExpr(E); + SmallVector<Expr *, 16> Exprs; + unsigned NumExprs = Record.readInt(); + while (NumExprs--) + Exprs.push_back(Record.readSubExpr()); + E->setExprs(Record.getContext(), Exprs); + E->setBuiltinLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) { + VisitExpr(E); + E->BuiltinLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); + E->TInfo = GetTypeSourceInfo(); + E->SrcExpr = Record.readSubExpr(); +} + +void ASTStmtReader::VisitBlockExpr(BlockExpr *E) { + VisitExpr(E); + E->setBlockDecl(ReadDeclAs<BlockDecl>()); +} + +void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { + VisitExpr(E); + E->NumAssocs = Record.readInt(); + E->AssocTypes = new (Record.getContext()) TypeSourceInfo*[E->NumAssocs]; + E->SubExprs = + new(Record.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs]; + + E->SubExprs[GenericSelectionExpr::CONTROLLING] = Record.readSubExpr(); + for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + E->AssocTypes[I] = GetTypeSourceInfo(); + E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Record.readSubExpr(); + } + E->ResultIndex = Record.readInt(); + + E->GenericLoc = ReadSourceLocation(); + E->DefaultLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) { + VisitExpr(E); + unsigned numSemanticExprs = Record.readInt(); + assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs); + E->PseudoObjectExprBits.ResultIndex = Record.readInt(); + + // Read the syntactic expression. + E->getSubExprsBuffer()[0] = Record.readSubExpr(); + + // Read all the semantic expressions. + for (unsigned i = 0; i != numSemanticExprs; ++i) { + Expr *subExpr = Record.readSubExpr(); + E->getSubExprsBuffer()[i+1] = subExpr; + } +} + +void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) { + VisitExpr(E); + E->Op = AtomicExpr::AtomicOp(Record.readInt()); + E->NumSubExprs = AtomicExpr::getNumSubExprs(E->Op); + for (unsigned I = 0; I != E->NumSubExprs; ++I) + E->SubExprs[I] = Record.readSubExpr(); + E->BuiltinLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); +} + +//===----------------------------------------------------------------------===// +// Objective-C Expressions and Statements + +void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) { + VisitExpr(E); + E->setString(cast<StringLiteral>(Record.readSubStmt())); + E->setAtLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + VisitExpr(E); + // could be one of several IntegerLiteral, FloatLiteral, etc. + E->SubExpr = Record.readSubStmt(); + E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(); + E->Range = ReadSourceRange(); +} + +void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + VisitExpr(E); + unsigned NumElements = Record.readInt(); + assert(NumElements == E->getNumElements() && "Wrong number of elements"); + Expr **Elements = E->getElements(); + for (unsigned I = 0, N = NumElements; I != N; ++I) + Elements[I] = Record.readSubExpr(); + E->ArrayWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(); + E->Range = ReadSourceRange(); +} + +void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + VisitExpr(E); + unsigned NumElements = Record.readInt(); + assert(NumElements == E->getNumElements() && "Wrong number of elements"); + bool HasPackExpansions = Record.readInt(); + assert(HasPackExpansions == E->HasPackExpansions &&"Pack expansion mismatch"); + auto *KeyValues = + E->getTrailingObjects<ObjCDictionaryLiteral::KeyValuePair>(); + auto *Expansions = + E->getTrailingObjects<ObjCDictionaryLiteral::ExpansionData>(); + for (unsigned I = 0; I != NumElements; ++I) { + KeyValues[I].Key = Record.readSubExpr(); + KeyValues[I].Value = Record.readSubExpr(); + if (HasPackExpansions) { + Expansions[I].EllipsisLoc = ReadSourceLocation(); + Expansions[I].NumExpansionsPlusOne = Record.readInt(); + } + } + E->DictWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(); + E->Range = ReadSourceRange(); +} + +void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + VisitExpr(E); + E->setEncodedTypeSourceInfo(GetTypeSourceInfo()); + E->setAtLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + VisitExpr(E); + E->setSelector(Record.readSelector()); + E->setAtLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + VisitExpr(E); + E->setProtocol(ReadDeclAs<ObjCProtocolDecl>()); + E->setAtLoc(ReadSourceLocation()); + E->ProtoLoc = ReadSourceLocation(); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + VisitExpr(E); + E->setDecl(ReadDeclAs<ObjCIvarDecl>()); + E->setLocation(ReadSourceLocation()); + E->setOpLoc(ReadSourceLocation()); + E->setBase(Record.readSubExpr()); + E->setIsArrow(Record.readInt()); + E->setIsFreeIvar(Record.readInt()); +} + +void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + VisitExpr(E); + unsigned MethodRefFlags = Record.readInt(); + bool Implicit = Record.readInt() != 0; + if (Implicit) { + auto *Getter = ReadDeclAs<ObjCMethodDecl>(); + auto *Setter = ReadDeclAs<ObjCMethodDecl>(); + E->setImplicitProperty(Getter, Setter, MethodRefFlags); + } else { + E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(), MethodRefFlags); + } + E->setLocation(ReadSourceLocation()); + E->setReceiverLocation(ReadSourceLocation()); + switch (Record.readInt()) { + case 0: + E->setBase(Record.readSubExpr()); + break; + case 1: + E->setSuperReceiver(Record.readType()); + break; + case 2: + E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>()); + break; + } +} + +void ASTStmtReader::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) { + VisitExpr(E); + E->setRBracket(ReadSourceLocation()); + E->setBaseExpr(Record.readSubExpr()); + E->setKeyExpr(Record.readSubExpr()); + E->GetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(); + E->SetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(); +} + +void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { + VisitExpr(E); + assert(Record.peekInt() == E->getNumArgs()); + Record.skipInts(1); + unsigned NumStoredSelLocs = Record.readInt(); + E->SelLocsKind = Record.readInt(); + E->setDelegateInitCall(Record.readInt()); + E->IsImplicit = Record.readInt(); + auto Kind = static_cast<ObjCMessageExpr::ReceiverKind>(Record.readInt()); + switch (Kind) { + case ObjCMessageExpr::Instance: + E->setInstanceReceiver(Record.readSubExpr()); + break; + + case ObjCMessageExpr::Class: + E->setClassReceiver(GetTypeSourceInfo()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: { + QualType T = Record.readType(); + SourceLocation SuperLoc = ReadSourceLocation(); + E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); + break; + } + } + + assert(Kind == E->getReceiverKind()); + + if (Record.readInt()) + E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>()); + else + E->setSelector(Record.readSelector()); + + E->LBracLoc = ReadSourceLocation(); + E->RBracLoc = ReadSourceLocation(); + + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + E->setArg(I, Record.readSubExpr()); + + SourceLocation *Locs = E->getStoredSelLocs(); + for (unsigned I = 0; I != NumStoredSelLocs; ++I) + Locs[I] = ReadSourceLocation(); +} + +void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); + S->setElement(Record.readSubStmt()); + S->setCollection(Record.readSubExpr()); + S->setBody(Record.readSubStmt()); + S->setForLoc(ReadSourceLocation()); + S->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + VisitStmt(S); + S->setCatchBody(Record.readSubStmt()); + S->setCatchParamDecl(ReadDeclAs<VarDecl>()); + S->setAtCatchLoc(ReadSourceLocation()); + S->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + VisitStmt(S); + S->setFinallyBody(Record.readSubStmt()); + S->setAtFinallyLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + VisitStmt(S); + S->setSubStmt(Record.readSubStmt()); + S->setAtLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + VisitStmt(S); + assert(Record.peekInt() == S->getNumCatchStmts()); + Record.skipInts(1); + bool HasFinally = Record.readInt(); + S->setTryBody(Record.readSubStmt()); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) + S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(Record.readSubStmt())); + + if (HasFinally) + S->setFinallyStmt(Record.readSubStmt()); + S->setAtTryLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + VisitStmt(S); + S->setSynchExpr(Record.readSubStmt()); + S->setSynchBody(Record.readSubStmt()); + S->setAtSynchronizedLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + VisitStmt(S); + S->setThrowExpr(Record.readSubStmt()); + S->setThrowLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) { + VisitExpr(E); + E->setValue(Record.readInt()); + E->setLocation(ReadSourceLocation()); +} + +void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + VisitExpr(E); + SourceRange R = Record.readSourceRange(); + E->AtLoc = R.getBegin(); + E->RParen = R.getEnd(); + E->VersionToCheck = Record.readVersionTuple(); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions and Statements +//===----------------------------------------------------------------------===// + +void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) { + VisitStmt(S); + S->CatchLoc = ReadSourceLocation(); + S->ExceptionDecl = ReadDeclAs<VarDecl>(); + S->HandlerBlock = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { + VisitStmt(S); + assert(Record.peekInt() == S->getNumHandlers() && "NumStmtFields is wrong ?"); + Record.skipInts(1); + S->TryLoc = ReadSourceLocation(); + S->getStmts()[0] = Record.readSubStmt(); + for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i) + S->getStmts()[i + 1] = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); + S->ForLoc = ReadSourceLocation(); + S->CoawaitLoc = ReadSourceLocation(); + S->ColonLoc = ReadSourceLocation(); + S->RParenLoc = ReadSourceLocation(); + S->setInit(Record.readSubStmt()); + S->setRangeStmt(Record.readSubStmt()); + S->setBeginStmt(Record.readSubStmt()); + S->setEndStmt(Record.readSubStmt()); + S->setCond(Record.readSubExpr()); + S->setInc(Record.readSubExpr()); + S->setLoopVarStmt(Record.readSubStmt()); + S->setBody(Record.readSubStmt()); +} + +void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { + VisitStmt(S); + S->KeywordLoc = ReadSourceLocation(); + S->IsIfExists = Record.readInt(); + S->QualifierLoc = Record.readNestedNameSpecifierLoc(); + ReadDeclarationNameInfo(S->NameInfo); + S->SubStmt = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + VisitCallExpr(E); + E->CXXOperatorCallExprBits.OperatorKind = Record.readInt(); + E->CXXOperatorCallExprBits.FPFeatures = Record.readInt(); + E->Range = Record.readSourceRange(); +} + +void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { + VisitExpr(E); + + unsigned NumArgs = Record.readInt(); + assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!"); + + E->CXXConstructExprBits.Elidable = Record.readInt(); + E->CXXConstructExprBits.HadMultipleCandidates = Record.readInt(); + E->CXXConstructExprBits.ListInitialization = Record.readInt(); + E->CXXConstructExprBits.StdInitListInitialization = Record.readInt(); + E->CXXConstructExprBits.ZeroInitialization = Record.readInt(); + E->CXXConstructExprBits.ConstructionKind = Record.readInt(); + E->CXXConstructExprBits.Loc = ReadSourceLocation(); + E->Constructor = ReadDeclAs<CXXConstructorDecl>(); + E->ParenOrBraceRange = ReadSourceRange(); + + for (unsigned I = 0; I != NumArgs; ++I) + E->setArg(I, Record.readSubExpr()); +} + +void ASTStmtReader::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) { + VisitExpr(E); + E->Constructor = ReadDeclAs<CXXConstructorDecl>(); + E->Loc = ReadSourceLocation(); + E->ConstructsVirtualBase = Record.readInt(); + E->InheritedFromVirtualBase = Record.readInt(); +} + +void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { + VisitCXXConstructExpr(E); + E->TSI = GetTypeSourceInfo(); +} + +void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) { + VisitExpr(E); + unsigned NumCaptures = Record.readInt(); + assert(NumCaptures == E->NumCaptures);(void)NumCaptures; + E->IntroducerRange = ReadSourceRange(); + E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record.readInt()); + E->CaptureDefaultLoc = ReadSourceLocation(); + E->ExplicitParams = Record.readInt(); + E->ExplicitResultType = Record.readInt(); + E->ClosingBrace = ReadSourceLocation(); + + // Read capture initializers. + for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(), + CEnd = E->capture_init_end(); + C != CEnd; ++C) + *C = Record.readSubExpr(); +} + +void +ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + VisitExpr(E); + E->SubExpr = Record.readSubExpr(); +} + +void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + VisitExplicitCastExpr(E); + SourceRange R = ReadSourceRange(); + E->Loc = R.getBegin(); + E->RParenLoc = R.getEnd(); + R = ReadSourceRange(); + 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()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) { + VisitCallExpr(E); + E->UDSuffixLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + E->setValue(Record.readInt()); + E->setLocation(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + E->setLocation(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + E->setSourceRange(ReadSourceRange()); + if (E->isTypeOperand()) { // typeid(int) + E->setTypeOperandSourceInfo( + GetTypeSourceInfo()); + return; + } + + // typeid(42+2) + E->setExprOperand(Record.readSubExpr()); +} + +void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + E->setLocation(ReadSourceLocation()); + E->setImplicit(Record.readInt()); +} + +void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + E->CXXThrowExprBits.ThrowLoc = ReadSourceLocation(); + E->Operand = Record.readSubExpr(); + E->CXXThrowExprBits.IsThrownVariableInScope = Record.readInt(); +} + +void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + E->Param = ReadDeclAs<ParmVarDecl>(); + E->CXXDefaultArgExprBits.Loc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + E->Field = ReadDeclAs<FieldDecl>(); + E->CXXDefaultInitExprBits.Loc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + E->setTemporary(Record.readCXXTemporary()); + E->setSubExpr(Record.readSubExpr()); +} + +void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { + VisitExpr(E); + E->TypeInfo = GetTypeSourceInfo(); + E->CXXScalarValueInitExprBits.RParenLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + + bool IsArray = Record.readInt(); + bool HasInit = Record.readInt(); + unsigned NumPlacementArgs = Record.readInt(); + bool IsParenTypeId = Record.readInt(); + + E->CXXNewExprBits.IsGlobalNew = Record.readInt(); + E->CXXNewExprBits.ShouldPassAlignment = Record.readInt(); + E->CXXNewExprBits.UsualArrayDeleteWantsSize = Record.readInt(); + E->CXXNewExprBits.StoredInitializationStyle = Record.readInt(); + + assert((IsArray == E->isArray()) && "Wrong IsArray!"); + assert((HasInit == E->hasInitializer()) && "Wrong HasInit!"); + assert((NumPlacementArgs == E->getNumPlacementArgs()) && + "Wrong NumPlacementArgs!"); + assert((IsParenTypeId == E->isParenTypeId()) && "Wrong IsParenTypeId!"); + (void)IsArray; + (void)HasInit; + (void)NumPlacementArgs; + + E->setOperatorNew(ReadDeclAs<FunctionDecl>()); + E->setOperatorDelete(ReadDeclAs<FunctionDecl>()); + E->AllocatedTypeInfo = GetTypeSourceInfo(); + if (IsParenTypeId) + E->getTrailingObjects<SourceRange>()[0] = ReadSourceRange(); + E->Range = ReadSourceRange(); + E->DirectInitRange = ReadSourceRange(); + + // Install all the subexpressions. + for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(), + N = E->raw_arg_end(); + I != N; ++I) + *I = Record.readSubStmt(); +} + +void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) { + VisitExpr(E); + E->CXXDeleteExprBits.GlobalDelete = Record.readInt(); + E->CXXDeleteExprBits.ArrayForm = Record.readInt(); + E->CXXDeleteExprBits.ArrayFormAsWritten = Record.readInt(); + E->CXXDeleteExprBits.UsualArrayDeleteWantsSize = Record.readInt(); + E->OperatorDelete = ReadDeclAs<FunctionDecl>(); + E->Argument = Record.readSubExpr(); + E->CXXDeleteExprBits.Loc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + VisitExpr(E); + + E->Base = Record.readSubExpr(); + E->IsArrow = Record.readInt(); + E->OperatorLoc = ReadSourceLocation(); + E->QualifierLoc = Record.readNestedNameSpecifierLoc(); + E->ScopeType = GetTypeSourceInfo(); + E->ColonColonLoc = ReadSourceLocation(); + E->TildeLoc = ReadSourceLocation(); + + IdentifierInfo *II = Record.getIdentifierInfo(); + if (II) + E->setDestroyedType(II, ReadSourceLocation()); + else + E->setDestroyedType(GetTypeSourceInfo()); +} + +void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { + VisitExpr(E); + + unsigned NumObjects = Record.readInt(); + assert(NumObjects == E->getNumObjects()); + for (unsigned i = 0; i != NumObjects; ++i) + E->getTrailingObjects<BlockDecl *>()[i] = + ReadDeclAs<BlockDecl>(); + + E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt(); + E->SubExpr = Record.readSubExpr(); +} + +void ASTStmtReader::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + VisitExpr(E); + + bool HasTemplateKWAndArgsInfo = Record.readInt(); + unsigned NumTemplateArgs = Record.readInt(); + bool HasFirstQualifierFoundInScope = Record.readInt(); + + assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) && + "Wrong HasTemplateKWAndArgsInfo!"); + assert( + (HasFirstQualifierFoundInScope == E->hasFirstQualifierFoundInScope()) && + "Wrong HasFirstQualifierFoundInScope!"); + + if (HasTemplateKWAndArgsInfo) + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); + + assert((NumTemplateArgs == E->getNumTemplateArgs()) && + "Wrong NumTemplateArgs!"); + + E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt(); + E->CXXDependentScopeMemberExprBits.OperatorLoc = ReadSourceLocation(); + E->BaseType = Record.readType(); + E->QualifierLoc = Record.readNestedNameSpecifierLoc(); + E->Base = Record.readSubExpr(); + + if (HasFirstQualifierFoundInScope) + *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(); + + ReadDeclarationNameInfo(E->MemberNameInfo); +} + +void +ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + VisitExpr(E); + + if (Record.readInt()) // HasTemplateKWAndArgsInfo + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), + /*NumTemplateArgs=*/Record.readInt()); + + E->QualifierLoc = Record.readNestedNameSpecifierLoc(); + ReadDeclarationNameInfo(E->NameInfo); +} + +void +ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { + VisitExpr(E); + assert(Record.peekInt() == E->arg_size() && + "Read wrong record during creation ?"); + Record.skipInts(1); + for (unsigned I = 0, N = E->arg_size(); I != N; ++I) + E->setArg(I, Record.readSubExpr()); + E->TSI = GetTypeSourceInfo(); + E->setLParenLoc(ReadSourceLocation()); + E->setRParenLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { + VisitExpr(E); + + unsigned NumResults = Record.readInt(); + bool HasTemplateKWAndArgsInfo = Record.readInt(); + assert((E->getNumDecls() == NumResults) && "Wrong NumResults!"); + assert((E->hasTemplateKWAndArgsInfo() == HasTemplateKWAndArgsInfo) && + "Wrong HasTemplateKWAndArgsInfo!"); + + if (HasTemplateKWAndArgsInfo) { + unsigned NumTemplateArgs = Record.readInt(); + ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(), + E->getTrailingTemplateArgumentLoc(), + NumTemplateArgs); + assert((E->getNumTemplateArgs() == NumTemplateArgs) && + "Wrong NumTemplateArgs!"); + } + + UnresolvedSet<8> Decls; + for (unsigned I = 0; I != NumResults; ++I) { + auto *D = ReadDeclAs<NamedDecl>(); + auto AS = (AccessSpecifier)Record.readInt(); + Decls.addDecl(D, AS); + } + + DeclAccessPair *Results = E->getTrailingResults(); + UnresolvedSetIterator Iter = Decls.begin(); + for (unsigned I = 0; I != NumResults; ++I) { + Results[I] = (Iter + I).getPair(); + } + + ReadDeclarationNameInfo(E->NameInfo); + E->QualifierLoc = Record.readNestedNameSpecifierLoc(); +} + +void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { + VisitOverloadExpr(E); + E->UnresolvedMemberExprBits.IsArrow = Record.readInt(); + E->UnresolvedMemberExprBits.HasUnresolvedUsing = Record.readInt(); + E->Base = Record.readSubExpr(); + E->BaseType = Record.readType(); + E->OperatorLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { + VisitOverloadExpr(E); + E->UnresolvedLookupExprBits.RequiresADL = Record.readInt(); + E->UnresolvedLookupExprBits.Overloaded = Record.readInt(); + E->NamingClass = ReadDeclAs<CXXRecordDecl>(); +} + +void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) { + VisitExpr(E); + E->TypeTraitExprBits.NumArgs = Record.readInt(); + E->TypeTraitExprBits.Kind = Record.readInt(); + E->TypeTraitExprBits.Value = Record.readInt(); + SourceRange Range = ReadSourceRange(); + E->Loc = Range.getBegin(); + E->RParenLoc = Range.getEnd(); + + auto **Args = E->getTrailingObjects<TypeSourceInfo *>(); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Args[I] = GetTypeSourceInfo(); +} + +void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + VisitExpr(E); + E->ATT = (ArrayTypeTrait)Record.readInt(); + E->Value = (unsigned int)Record.readInt(); + SourceRange Range = ReadSourceRange(); + E->Loc = Range.getBegin(); + E->RParen = Range.getEnd(); + E->QueriedType = GetTypeSourceInfo(); + E->Dimension = Record.readSubExpr(); +} + +void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + VisitExpr(E); + E->ET = (ExpressionTrait)Record.readInt(); + E->Value = (bool)Record.readInt(); + SourceRange Range = ReadSourceRange(); + E->QueriedExpression = Record.readSubExpr(); + E->Loc = Range.getBegin(); + E->RParen = Range.getEnd(); +} + +void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { + VisitExpr(E); + E->CXXNoexceptExprBits.Value = Record.readInt(); + E->Range = ReadSourceRange(); + E->Operand = Record.readSubExpr(); +} + +void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) { + VisitExpr(E); + E->EllipsisLoc = ReadSourceLocation(); + E->NumExpansions = Record.readInt(); + E->Pattern = Record.readSubExpr(); +} + +void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + VisitExpr(E); + unsigned NumPartialArgs = Record.readInt(); + E->OperatorLoc = ReadSourceLocation(); + E->PackLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); + E->Pack = Record.readDeclAs<NamedDecl>(); + if (E->isPartiallySubstituted()) { + assert(E->Length == NumPartialArgs); + for (auto *I = E->getTrailingObjects<TemplateArgument>(), + *E = I + NumPartialArgs; + I != E; ++I) + new (I) TemplateArgument(Record.readTemplateArgument()); + } else if (!E->isValueDependent()) { + E->Length = Record.readInt(); + } +} + +void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + VisitExpr(E); + E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(); + E->SubstNonTypeTemplateParmExprBits.NameLoc = ReadSourceLocation(); + E->Replacement = Record.readSubExpr(); +} + +void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + VisitExpr(E); + E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(); + TemplateArgument ArgPack = Record.readTemplateArgument(); + if (ArgPack.getKind() != TemplateArgument::Pack) + return; + + E->Arguments = ArgPack.pack_begin(); + E->NumArguments = ArgPack.pack_size(); + E->NameLoc = ReadSourceLocation(); +} + +void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + E->NumParameters = Record.readInt(); + E->ParamPack = ReadDeclAs<ParmVarDecl>(); + E->NameLoc = ReadSourceLocation(); + auto **Parms = E->getTrailingObjects<ParmVarDecl *>(); + for (unsigned i = 0, n = E->NumParameters; i != n; ++i) + Parms[i] = ReadDeclAs<ParmVarDecl>(); +} + +void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + VisitExpr(E); + E->State = Record.readSubExpr(); + auto *VD = ReadDeclAs<ValueDecl>(); + unsigned ManglingNumber = Record.readInt(); + E->setExtendingDecl(VD, ManglingNumber); +} + +void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) { + VisitExpr(E); + E->LParenLoc = ReadSourceLocation(); + E->EllipsisLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); + E->SubExprs[0] = Record.readSubExpr(); + E->SubExprs[1] = Record.readSubExpr(); + E->Opcode = (BinaryOperatorKind)Record.readInt(); +} + +void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { + VisitExpr(E); + E->SourceExpr = Record.readSubExpr(); + E->OpaqueValueExprBits.Loc = ReadSourceLocation(); + E->setIsUnique(Record.readInt()); +} + +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.readInt() != 0); + E->BaseExpr = Record.readSubExpr(); + E->QualifierLoc = Record.readNestedNameSpecifierLoc(); + E->MemberLoc = ReadSourceLocation(); + E->TheDecl = ReadDeclAs<MSPropertyDecl>(); +} + +void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + E->setBase(Record.readSubExpr()); + E->setIdx(Record.readSubExpr()); + E->setRBracketLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { + VisitExpr(E); + E->setSourceRange(ReadSourceRange()); + std::string UuidStr = ReadString(); + E->setUuidStr(StringRef(UuidStr).copy(Record.getContext())); + if (E->isTypeOperand()) { // __uuidof(ComType) + E->setTypeOperandSourceInfo( + GetTypeSourceInfo()); + return; + } + + // __uuidof(expr) + E->setExprOperand(Record.readSubExpr()); +} + +void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) { + VisitStmt(S); + S->setLeaveLoc(ReadSourceLocation()); +} + +void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) { + VisitStmt(S); + S->Loc = ReadSourceLocation(); + S->Children[SEHExceptStmt::FILTER_EXPR] = Record.readSubStmt(); + S->Children[SEHExceptStmt::BLOCK] = Record.readSubStmt(); +} + +void ASTStmtReader::VisitSEHFinallyStmt(SEHFinallyStmt *S) { + VisitStmt(S); + S->Loc = ReadSourceLocation(); + S->Block = Record.readSubStmt(); +} + +void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) { + VisitStmt(S); + S->IsCXXTry = Record.readInt(); + S->TryLoc = ReadSourceLocation(); + S->Children[SEHTryStmt::TRY] = Record.readSubStmt(); + S->Children[SEHTryStmt::HANDLER] = Record.readSubStmt(); +} + +//===----------------------------------------------------------------------===// +// CUDA Expressions and Statements +//===----------------------------------------------------------------------===// + +void ASTStmtReader::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) { + VisitCallExpr(E); + E->setConfig(cast<CallExpr>(Record.readSubExpr())); +} + +//===----------------------------------------------------------------------===// +// OpenCL Expressions and Statements. +//===----------------------------------------------------------------------===// +void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) { + VisitExpr(E); + E->BuiltinLoc = ReadSourceLocation(); + E->RParenLoc = ReadSourceLocation(); + E->SrcExpr = Record.readSubExpr(); +} + +//===----------------------------------------------------------------------===// +// OpenMP Directives. +//===----------------------------------------------------------------------===// + +void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { + E->setLocStart(ReadSourceLocation()); + E->setLocEnd(ReadSourceLocation()); + OMPClauseReader ClauseReader(Record); + 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(Record.readSubStmt()); +} + +void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { + VisitStmt(D); + // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream. + Record.skipInts(2); + VisitOMPExecutableDirective(D); + D->setIterationVariable(Record.readSubExpr()); + D->setLastIteration(Record.readSubExpr()); + D->setCalcLastIteration(Record.readSubExpr()); + D->setPreCond(Record.readSubExpr()); + D->setCond(Record.readSubExpr()); + D->setInit(Record.readSubExpr()); + D->setInc(Record.readSubExpr()); + D->setPreInits(Record.readSubStmt()); + if (isOpenMPWorksharingDirective(D->getDirectiveKind()) || + isOpenMPTaskLoopDirective(D->getDirectiveKind()) || + isOpenMPDistributeDirective(D->getDirectiveKind())) { + D->setIsLastIterVariable(Record.readSubExpr()); + D->setLowerBoundVariable(Record.readSubExpr()); + D->setUpperBoundVariable(Record.readSubExpr()); + D->setStrideVariable(Record.readSubExpr()); + D->setEnsureUpperBound(Record.readSubExpr()); + D->setNextLowerBound(Record.readSubExpr()); + D->setNextUpperBound(Record.readSubExpr()); + D->setNumIterations(Record.readSubExpr()); + } + if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) { + D->setPrevLowerBoundVariable(Record.readSubExpr()); + D->setPrevUpperBoundVariable(Record.readSubExpr()); + D->setDistInc(Record.readSubExpr()); + D->setPrevEnsureUpperBound(Record.readSubExpr()); + D->setCombinedLowerBoundVariable(Record.readSubExpr()); + D->setCombinedUpperBoundVariable(Record.readSubExpr()); + D->setCombinedEnsureUpperBound(Record.readSubExpr()); + D->setCombinedInit(Record.readSubExpr()); + D->setCombinedCond(Record.readSubExpr()); + D->setCombinedNextLowerBound(Record.readSubExpr()); + D->setCombinedNextUpperBound(Record.readSubExpr()); + D->setCombinedDistCond(Record.readSubExpr()); + D->setCombinedParForInDistCond(Record.readSubExpr()); + } + SmallVector<Expr *, 4> Sub; + unsigned CollapsedNum = D->getCollapsedNumber(); + Sub.reserve(CollapsedNum); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setCounters(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setPrivateCounters(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setInits(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setUpdates(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setFinals(Sub); +} + +void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPForSimdDirective(OMPForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPSectionDirective(OMPSectionDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPSingleDirective(OMPSingleDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPMasterDirective(OMPMasterDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + ReadDeclarationNameInfo(D->DirName); +} + +void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPParallelForSimdDirective( + OMPParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPParallelSectionsDirective( + OMPParallelSectionsDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setHasCancel(Record.readInt()); +} + +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::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setReductionRef(Record.readSubExpr()); +} + +void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setX(Record.readSubExpr()); + D->setV(Record.readSubExpr()); + D->setExpr(Record.readSubExpr()); + D->setUpdateExpr(Record.readSubExpr()); + D->IsXLHSInRHSPart = Record.readInt() != 0; + D->IsPostfixUpdate = Record.readInt() != 0; +} + +void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetEnterDataDirective( + OMPTargetEnterDataDirective *D) { + VisitStmt(D); + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetExitDataDirective( + OMPTargetExitDataDirective *D) { + VisitStmt(D); + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetParallelDirective( + OMPTargetParallelDirective *D) { + VisitStmt(D); + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetParallelForDirective( + OMPTargetParallelForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPTeamsDirective(OMPTeamsDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPCancellationPointDirective( + OMPCancellationPointDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + D->setCancelRegion(static_cast<OpenMPDirectiveKind>(Record.readInt())); +} + +void ASTStmtReader::VisitOMPCancelDirective(OMPCancelDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); + D->setCancelRegion(static_cast<OpenMPDirectiveKind>(Record.readInt())); +} + +void ASTStmtReader::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { + VisitStmt(D); + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPDistributeParallelForDirective( + OMPDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPDistributeParallelForSimdDirective( + OMPDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPDistributeSimdDirective( + OMPDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTargetParallelForSimdDirective( + OMPTargetParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTargetSimdDirective(OMPTargetSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTeamsDistributeDirective( + OMPTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTeamsDistributeSimdDirective( + OMPTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTeamsDistributeParallelForSimdDirective( + OMPTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTeamsDistributeParallelForDirective( + OMPTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetTeamsDistributeDirective( + OMPTargetTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTargetTeamsDistributeParallelForDirective( + OMPTargetTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + D->setHasCancel(Record.readInt()); +} + +void ASTStmtReader::VisitOMPTargetTeamsDistributeParallelForSimdDirective( + OMPTargetTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTargetTeamsDistributeSimdDirective( + OMPTargetTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(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 + + ASTRecordReader Record(*this, F); + ASTStmtReader Reader(Record, Cursor); + 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; + } + + ASTContext &Context = getContext(); + Stmt *S = nullptr; + bool Finished = false; + bool IsStmtReference = false; + switch ((StmtCode)Record.readRecord(Cursor, Entry.ID)) { + 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.readInt()]; + break; + + case STMT_NULL_PTR: + S = nullptr; + break; + + case STMT_NULL: + S = new (Context) NullStmt(Empty); + break; + + case STMT_COMPOUND: + S = CompoundStmt::CreateEmpty( + Context, /*NumStmts=*/Record[ASTStmtReader::NumStmtFields]); + break; + + case STMT_CASE: + S = CaseStmt::CreateEmpty( + Context, + /*CaseStmtIsGNURange*/ Record[ASTStmtReader::NumStmtFields + 3]); + 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 = IfStmt::CreateEmpty( + Context, + /* HasElse=*/Record[ASTStmtReader::NumStmtFields + 1], + /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 2], + /* HasInit=*/Record[ASTStmtReader::NumStmtFields + 3]); + break; + + case STMT_SWITCH: + S = SwitchStmt::CreateEmpty( + Context, + /* HasInit=*/Record[ASTStmtReader::NumStmtFields], + /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 1]); + break; + + case STMT_WHILE: + S = WhileStmt::CreateEmpty( + Context, + /* HasVar=*/Record[ASTStmtReader::NumStmtFields]); + 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 = ReturnStmt::CreateEmpty( + Context, /* HasNRVOCandidate=*/Record[ASTStmtReader::NumStmtFields]); + 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_CONSTANT: + S = new (Context) ConstantExpr(Empty); + break; + + case EXPR_PREDEFINED: + S = PredefinedExpr::CreateEmpty( + Context, + /*HasFunctionName*/ Record[ASTStmtReader::NumExprFields]); + 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, + /* NumConcatenated=*/Record[ASTStmtReader::NumExprFields], + /* Length=*/Record[ASTStmtReader::NumExprFields + 1], + /* CharByteWidth=*/Record[ASTStmtReader::NumExprFields + 2]); + 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 = ParenListExpr::CreateEmpty( + Context, + /* NumExprs=*/Record[ASTStmtReader::NumExprFields]); + 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_OMP_ARRAY_SECTION: + S = new (Context) OMPArraySectionExpr(Empty); + break; + + case EXPR_CALL: + S = CallExpr::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], 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(Record.getIdx() == 0); + NestedNameSpecifierLoc QualifierLoc; + if (Record.readInt()) { // HasQualifier. + QualifierLoc = Record.readNestedNameSpecifierLoc(); + } + + SourceLocation TemplateKWLoc; + TemplateArgumentListInfo ArgInfo; + bool HasTemplateKWAndArgsInfo = Record.readInt(); + if (HasTemplateKWAndArgsInfo) { + TemplateKWLoc = Record.readSourceLocation(); + unsigned NumTemplateArgs = Record.readInt(); + ArgInfo.setLAngleLoc(Record.readSourceLocation()); + ArgInfo.setRAngleLoc(Record.readSourceLocation()); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + ArgInfo.addArgument(Record.readTemplateArgumentLoc()); + } + + bool HadMultipleCandidates = Record.readInt(); + + auto *FoundD = Record.readDeclAs<NamedDecl>(); + auto AS = (AccessSpecifier)Record.readInt(); + DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS); + + QualType T = Record.readType(); + auto VK = static_cast<ExprValueKind>(Record.readInt()); + auto OK = static_cast<ExprObjectKind>(Record.readInt()); + Expr *Base = ReadSubExpr(); + auto *MemberD = Record.readDeclAs<ValueDecl>(); + SourceLocation MemberLoc = Record.readSourceLocation(); + DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc); + bool IsArrow = Record.readInt(); + SourceLocation OperatorLoc = Record.readSourceLocation(); + + S = MemberExpr::Create(Context, Base, IsArrow, OperatorLoc, QualifierLoc, + TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo, + HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr, T, + VK, OK); + Record.readDeclarationNameLoc(cast<MemberExpr>(S)->MemberDNLoc, + MemberD->getDeclName()); + 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_DESIGNATED_INIT_UPDATE: + S = new (Context) DesignatedInitUpdateExpr(Empty); + break; + + case EXPR_IMPLICIT_VALUE_INIT: + S = new (Context) ImplicitValueInitExpr(Empty); + break; + + case EXPR_NO_INIT: + S = new (Context) NoInitExpr(Empty); + break; + + case EXPR_ARRAY_INIT_LOOP: + S = new (Context) ArrayInitLoopExpr(Empty); + break; + + case EXPR_ARRAY_INIT_INDEX: + S = new (Context) ArrayInitIndexExpr(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 EXPR_OBJC_AVAILABILITY_CHECK: + S = new (Context) ObjCAvailabilityCheckExpr(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, Record[ASTStmtReader::NumStmtFields], 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_TASKGROUP_DIRECTIVE: + S = OMPTaskgroupDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], 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, Record[ASTStmtReader::NumStmtFields], 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_TARGET_DATA_DIRECTIVE: + S = OMPTargetDataDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TARGET_ENTER_DATA_DIRECTIVE: + S = OMPTargetEnterDataDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TARGET_EXIT_DATA_DIRECTIVE: + S = OMPTargetExitDataDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TARGET_PARALLEL_DIRECTIVE: + S = OMPTargetParallelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TARGET_PARALLEL_FOR_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetParallelForDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_UPDATE_DIRECTIVE: + S = OMPTargetUpdateDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TEAMS_DIRECTIVE: + S = OMPTeamsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_CANCELLATION_POINT_DIRECTIVE: + S = OMPCancellationPointDirective::CreateEmpty(Context, Empty); + break; + + case STMT_OMP_CANCEL_DIRECTIVE: + S = OMPCancelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TASKLOOP_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTaskLoopDirective::CreateEmpty(Context, NumClauses, CollapsedNum, + Empty); + break; + } + + case STMT_OMP_TASKLOOP_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTaskLoopSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_DISTRIBUTE_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPDistributeDirective::CreateEmpty(Context, NumClauses, CollapsedNum, + Empty); + break; + } + + case STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPDistributeParallelForDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPDistributeParallelForSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, + Empty); + break; + } + + case STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPDistributeSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_PARALLEL_FOR_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetParallelForSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_SIMD_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetSimdDirective::CreateEmpty(Context, NumClauses, CollapsedNum, + Empty); + break; + } + + case STMT_OMP_TEAMS_DISTRIBUTE_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTeamsDistributeDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTeamsDistributeSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTeamsDistributeParallelForSimdDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + + case STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTeamsDistributeParallelForDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_TEAMS_DIRECTIVE: + S = OMPTargetTeamsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + + case STMT_OMP_TARGET_TEAMS_DISTRIBUTE_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetTeamsDistributeDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetTeamsDistributeParallelForDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetTeamsDistributeParallelForSimdDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + + case STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE: { + auto NumClauses = Record[ASTStmtReader::NumStmtFields]; + auto CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTargetTeamsDistributeSimdDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + + case EXPR_CXX_OPERATOR_CALL: + S = CXXOperatorCallExpr::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); + break; + + case EXPR_CXX_MEMBER_CALL: + S = CXXMemberCallExpr::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); + break; + + case EXPR_CXX_CONSTRUCT: + S = CXXConstructExpr::CreateEmpty( + Context, + /* NumArgs=*/Record[ASTStmtReader::NumExprFields]); + break; + + case EXPR_CXX_INHERITED_CTOR_INIT: + S = new (Context) CXXInheritedCtorInitExpr(Empty); + break; + + case EXPR_CXX_TEMPORARY_OBJECT: + S = CXXTemporaryObjectExpr::CreateEmpty( + Context, + /* NumArgs=*/Record[ASTStmtReader::NumExprFields]); + 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 = UserDefinedLiteral::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], 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_PROPERTY_SUBSCRIPT_EXPR: + S = new (Context) MSPropertySubscriptExpr(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: + 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 = CXXNewExpr::CreateEmpty( + Context, + /*IsArray=*/Record[ASTStmtReader::NumExprFields], + /*HasInit=*/Record[ASTStmtReader::NumExprFields + 1], + /*NumPlacementArgs=*/Record[ASTStmtReader::NumExprFields + 2], + /*IsParenTypeId=*/Record[ASTStmtReader::NumExprFields + 3]); + 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 + 1], + /*HasFirstQualifierFoundInScope=*/ + Record[ASTStmtReader::NumExprFields + 2]); + 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, + /*NumResults=*/Record[ASTStmtReader::NumExprFields], + /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 1], + /*NumTemplateArgs=*/ + Record[ASTStmtReader::NumExprFields + 1] + ? Record[ASTStmtReader::NumExprFields + 2] + : 0); + break; + + case EXPR_CXX_UNRESOLVED_LOOKUP: + S = UnresolvedLookupExpr::CreateEmpty( + Context, + /*NumResults=*/Record[ASTStmtReader::NumExprFields], + /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 1], + /*NumTemplateArgs=*/ + Record[ASTStmtReader::NumExprFields + 1] + ? Record[ASTStmtReader::NumExprFields + 2] + : 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 = SizeOfPackExpr::CreateDeserialized( + Context, + /*NumPartialArgs=*/Record[ASTStmtReader::NumExprFields]); + 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 = CUDAKernelCallExpr::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], 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]; + S = LambdaExpr::CreateDeserialized(Context, NumCaptures); + break; + } + + case STMT_COROUTINE_BODY: { + unsigned NumParams = Record[ASTStmtReader::NumStmtFields]; + S = CoroutineBodyStmt::Create(Context, Empty, NumParams); + break; + } + + case STMT_CORETURN: + S = new (Context) CoreturnStmt(Empty); + break; + + case EXPR_COAWAIT: + S = new (Context) CoawaitExpr(Empty); + break; + + case EXPR_COYIELD: + S = new (Context) CoyieldExpr(Empty); + break; + + case EXPR_DEPENDENT_COAWAIT: + S = new (Context) DependentCoawaitExpr(Empty); + 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(Record.getIdx() == 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 000000000000..37adcb70640d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -0,0 +1,6955 @@ +//===- 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 "ASTReaderInternals.h" +#include "MultiOnDiskHashTable.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/RawCommentList.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MemoryBufferCache.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/Version.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Lex/Token.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/ObjCMethodList.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/Weak.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFileExtension.h" +#include "clang/Serialization/SerializationDiagnostic.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SHA1.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <deque> +#include <limits> +#include <memory> +#include <queue> +#include <tuple> +#include <utility> +#include <vector> + +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 clang { + + class ASTTypeWriter { + ASTWriter &Writer; + ASTRecordWriter Record; + + /// Type code that corresponds to the record generated. + TypeCode Code = static_cast<TypeCode>(0); + + /// Abbreviation to use for the record, if any. + unsigned AbbrevToUse = 0; + + public: + ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record) + : Writer(Writer), Record(Writer, Record) {} + + uint64_t Emit() { + return Record.Emit(Code, AbbrevToUse); + } + + void Visit(QualType T) { + if (T.hasLocalNonFastQualifiers()) { + Qualifiers Qs = T.getLocalQualifiers(); + Record.AddTypeRef(T.getLocalUnqualifiedType()); + Record.push_back(Qs.getAsOpaqueValue()); + Code = TYPE_EXT_QUAL; + AbbrevToUse = Writer.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: Visit##Class##Type(cast<Class##Type>(T)); break; +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + } + } + } + + 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" + }; + +} // namespace clang + +void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { + llvm_unreachable("Built-in types are never serialized"); +} + +void ASTTypeWriter::VisitComplexType(const ComplexType *T) { + Record.AddTypeRef(T->getElementType()); + Code = TYPE_COMPLEX; +} + +void ASTTypeWriter::VisitPointerType(const PointerType *T) { + Record.AddTypeRef(T->getPointeeType()); + Code = TYPE_POINTER; +} + +void ASTTypeWriter::VisitDecayedType(const DecayedType *T) { + Record.AddTypeRef(T->getOriginalType()); + Code = TYPE_DECAYED; +} + +void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) { + Record.AddTypeRef(T->getOriginalType()); + Record.AddTypeRef(T->getAdjustedType()); + Code = TYPE_ADJUSTED; +} + +void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { + Record.AddTypeRef(T->getPointeeType()); + Code = TYPE_BLOCK_POINTER; +} + +void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { + Record.AddTypeRef(T->getPointeeTypeAsWritten()); + Record.push_back(T->isSpelledAsLValue()); + Code = TYPE_LVALUE_REFERENCE; +} + +void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { + Record.AddTypeRef(T->getPointeeTypeAsWritten()); + Code = TYPE_RVALUE_REFERENCE; +} + +void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { + Record.AddTypeRef(T->getPointeeType()); + Record.AddTypeRef(QualType(T->getClass(), 0)); + Code = TYPE_MEMBER_POINTER; +} + +void ASTTypeWriter::VisitArrayType(const ArrayType *T) { + Record.AddTypeRef(T->getElementType()); + Record.push_back(T->getSizeModifier()); // FIXME: stable values + Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values +} + +void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { + VisitArrayType(T); + Record.AddAPInt(T->getSize()); + Code = TYPE_CONSTANT_ARRAY; +} + +void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + VisitArrayType(T); + Code = TYPE_INCOMPLETE_ARRAY; +} + +void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { + VisitArrayType(T); + Record.AddSourceLocation(T->getLBracketLoc()); + Record.AddSourceLocation(T->getRBracketLoc()); + Record.AddStmt(T->getSizeExpr()); + Code = TYPE_VARIABLE_ARRAY; +} + +void ASTTypeWriter::VisitVectorType(const VectorType *T) { + Record.AddTypeRef(T->getElementType()); + 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) { + Record.AddTypeRef(T->getReturnType()); + 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()); + Record.push_back(C.getNoCallerSavedRegs()); + Record.push_back(C.getNoCfCheck()); + + 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(const FunctionProtoType *T, + ASTRecordWriter &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) + Record.AddTypeRef(T->getExceptionType(I)); + } else if (isComputedNoexcept(T->getExceptionSpecType())) { + Record.AddStmt(T->getNoexceptExpr()); + } else if (T->getExceptionSpecType() == EST_Uninstantiated) { + Record.AddDeclRef(T->getExceptionSpecDecl()); + Record.AddDeclRef(T->getExceptionSpecTemplate()); + } else if (T->getExceptionSpecType() == EST_Unevaluated) { + Record.AddDeclRef(T->getExceptionSpecDecl()); + } +} + +void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { + VisitFunctionType(T); + + Record.push_back(T->isVariadic()); + Record.push_back(T->hasTrailingReturn()); + Record.push_back(T->getTypeQuals().getAsOpaqueValue()); + Record.push_back(static_cast<unsigned>(T->getRefQualifier())); + addExceptionSpec(T, Record); + + Record.push_back(T->getNumParams()); + for (unsigned I = 0, N = T->getNumParams(); I != N; ++I) + Record.AddTypeRef(T->getParamType(I)); + + if (T->hasExtParameterInfos()) { + for (unsigned I = 0, N = T->getNumParams(); I != N; ++I) + Record.push_back(T->getExtParameterInfo(I).getOpaqueValue()); + } + + if (T->isVariadic() || T->hasTrailingReturn() || T->getTypeQuals() || + T->getRefQualifier() || T->getExceptionSpecType() != EST_None || + T->hasExtParameterInfos()) + AbbrevToUse = 0; + + Code = TYPE_FUNCTION_PROTO; +} + +void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Record.AddDeclRef(T->getDecl()); + Code = TYPE_UNRESOLVED_USING; +} + +void ASTTypeWriter::VisitTypedefType(const TypedefType *T) { + Record.AddDeclRef(T->getDecl()); + assert(!T->isCanonicalUnqualified() && "Invalid typedef ?"); + Record.AddTypeRef(T->getCanonicalTypeInternal()); + Code = TYPE_TYPEDEF; +} + +void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { + Record.AddStmt(T->getUnderlyingExpr()); + Code = TYPE_TYPEOF_EXPR; +} + +void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) { + Record.AddTypeRef(T->getUnderlyingType()); + Code = TYPE_TYPEOF; +} + +void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { + Record.AddTypeRef(T->getUnderlyingType()); + Record.AddStmt(T->getUnderlyingExpr()); + Code = TYPE_DECLTYPE; +} + +void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { + Record.AddTypeRef(T->getBaseType()); + Record.AddTypeRef(T->getUnderlyingType()); + Record.push_back(T->getUTTKind()); + Code = TYPE_UNARY_TRANSFORM; +} + +void ASTTypeWriter::VisitAutoType(const AutoType *T) { + Record.AddTypeRef(T->getDeducedType()); + Record.push_back((unsigned)T->getKeyword()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); + Code = TYPE_AUTO; +} + +void ASTTypeWriter::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Record.AddTemplateName(T->getTemplateName()); + Record.AddTypeRef(T->getDeducedType()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); + Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION; +} + +void ASTTypeWriter::VisitTagType(const TagType *T) { + Record.push_back(T->isDependentType()); + Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); + 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) { + Record.AddTypeRef(T->getModifiedType()); + Record.AddTypeRef(T->getEquivalentType()); + Record.push_back(T->getAttrKind()); + Code = TYPE_ATTRIBUTED; +} + +void +ASTTypeWriter::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Record.AddTypeRef(QualType(T->getReplacedParameter(), 0)); + Record.AddTypeRef(T->getReplacementType()); + Code = TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void +ASTTypeWriter::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + Record.AddTypeRef(QualType(T->getReplacedParameter(), 0)); + Record.AddTemplateArgument(T->getArgumentPack()); + Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK; +} + +void +ASTTypeWriter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + Record.push_back(T->isDependentType()); + Record.AddTemplateName(T->getTemplateName()); + Record.push_back(T->getNumArgs()); + for (const auto &ArgI : *T) + Record.AddTemplateArgument(ArgI); + Record.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() + : T->isCanonicalUnqualified() + ? QualType() + : T->getCanonicalTypeInternal()); + Code = TYPE_TEMPLATE_SPECIALIZATION; +} + +void +ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { + VisitArrayType(T); + Record.AddStmt(T->getSizeExpr()); + Record.AddSourceRange(T->getBracketsRange()); + Code = TYPE_DEPENDENT_SIZED_ARRAY; +} + +void +ASTTypeWriter::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + Record.AddTypeRef(T->getElementType()); + Record.AddStmt(T->getSizeExpr()); + Record.AddSourceLocation(T->getAttributeLoc()); + Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR; +} + +void ASTTypeWriter::VisitDependentVectorType(const DependentVectorType *T) { + Record.AddTypeRef(T->getElementType()); + Record.AddStmt(const_cast<Expr*>(T->getSizeExpr())); + Record.AddSourceLocation(T->getAttributeLoc()); + Record.push_back(T->getVectorKind()); + Code = TYPE_DEPENDENT_SIZED_VECTOR; +} + +void +ASTTypeWriter::VisitDependentAddressSpaceType( + const DependentAddressSpaceType *T) { + Record.AddTypeRef(T->getPointeeType()); + Record.AddStmt(T->getAddrSpaceExpr()); + Record.AddSourceLocation(T->getAttributeLoc()); + Code = TYPE_DEPENDENT_ADDRESS_SPACE; +} + +void +ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + Record.push_back(T->getDepth()); + Record.push_back(T->getIndex()); + Record.push_back(T->isParameterPack()); + Record.AddDeclRef(T->getDecl()); + Code = TYPE_TEMPLATE_TYPE_PARM; +} + +void +ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) { + Record.push_back(T->getKeyword()); + Record.AddNestedNameSpecifier(T->getQualifier()); + Record.AddIdentifierRef(T->getIdentifier()); + Record.AddTypeRef( + T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal()); + Code = TYPE_DEPENDENT_NAME; +} + +void +ASTTypeWriter::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T) { + Record.push_back(T->getKeyword()); + Record.AddNestedNameSpecifier(T->getQualifier()); + Record.AddIdentifierRef(T->getIdentifier()); + Record.push_back(T->getNumArgs()); + for (const auto &I : *T) + Record.AddTemplateArgument(I); + Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; +} + +void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) { + Record.AddTypeRef(T->getPattern()); + 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) { + Record.AddTypeRef(T->getInnerType()); + Code = TYPE_PAREN; +} + +void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) { + Record.push_back(T->getKeyword()); + Record.AddNestedNameSpecifier(T->getQualifier()); + Record.AddTypeRef(T->getNamedType()); + Record.AddDeclRef(T->getOwnedTagDecl()); + Code = TYPE_ELABORATED; +} + +void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); + Record.AddTypeRef(T->getInjectedSpecializationType()); + Code = TYPE_INJECTED_CLASS_NAME; +} + +void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); + Code = TYPE_OBJC_INTERFACE; +} + +void ASTTypeWriter::VisitObjCTypeParamType(const ObjCTypeParamType *T) { + Record.AddDeclRef(T->getDecl()); + Record.push_back(T->getNumProtocols()); + for (const auto *I : T->quals()) + Record.AddDeclRef(I); + Code = TYPE_OBJC_TYPE_PARAM; +} + +void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { + Record.AddTypeRef(T->getBaseType()); + Record.push_back(T->getTypeArgsAsWritten().size()); + for (auto TypeArg : T->getTypeArgsAsWritten()) + Record.AddTypeRef(TypeArg); + Record.push_back(T->getNumProtocols()); + for (const auto *I : T->quals()) + Record.AddDeclRef(I); + Record.push_back(T->isKindOfTypeAsWritten()); + Code = TYPE_OBJC_OBJECT; +} + +void +ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + Record.AddTypeRef(T->getPointeeType()); + Code = TYPE_OBJC_OBJECT_POINTER; +} + +void +ASTTypeWriter::VisitAtomicType(const AtomicType *T) { + Record.AddTypeRef(T->getValueType()); + Code = TYPE_ATOMIC; +} + +void +ASTTypeWriter::VisitPipeType(const PipeType *T) { + Record.AddTypeRef(T->getElementType()); + Record.push_back(T->isReadOnly()); + Code = TYPE_PIPE; +} + +namespace { + +class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { + ASTRecordWriter &Record; + +public: + TypeLocWriter(ASTRecordWriter &Record) : 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); +}; + +} // namespace + +void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} + +void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + Record.AddSourceLocation(TL.getBuiltinLoc()); + 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) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { + Record.AddSourceLocation(TL.getStarLoc()); +} + +void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) { + // nothing to do +} + +void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { + // nothing to do +} + +void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + Record.AddSourceLocation(TL.getCaretLoc()); +} + +void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + Record.AddSourceLocation(TL.getAmpLoc()); +} + +void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + Record.AddSourceLocation(TL.getAmpAmpLoc()); +} + +void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Record.AddSourceLocation(TL.getStarLoc()); + Record.AddTypeSourceInfo(TL.getClassTInfo()); +} + +void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { + Record.AddSourceLocation(TL.getLBracketLoc()); + Record.AddSourceLocation(TL.getRBracketLoc()); + Record.push_back(TL.getSizeExpr() ? 1 : 0); + if (TL.getSizeExpr()) + Record.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::VisitDependentAddressSpaceTypeLoc( + DependentAddressSpaceTypeLoc TL) { + Record.AddSourceLocation(TL.getAttrNameLoc()); + SourceRange range = TL.getAttrOperandParensRange(); + Record.AddSourceLocation(range.getBegin()); + Record.AddSourceLocation(range.getEnd()); + Record.AddStmt(TL.getAttrExprOperand()); +} + +void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitDependentVectorTypeLoc( + DependentVectorTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + Record.AddSourceLocation(TL.getLocalRangeBegin()); + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); + Record.AddSourceRange(TL.getExceptionSpecRange()); + Record.AddSourceLocation(TL.getLocalRangeEnd()); + for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) + Record.AddDeclRef(TL.getParam(i)); +} + +void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} + +void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} + +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { + if (TL.getNumProtocols()) { + Record.AddSourceLocation(TL.getProtocolLAngleLoc()); + Record.AddSourceLocation(TL.getProtocolRAngleLoc()); + } + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Record.AddSourceLocation(TL.getProtocolLoc(i)); +} + +void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + Record.AddSourceLocation(TL.getTypeofLoc()); + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); +} + +void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + Record.AddSourceLocation(TL.getTypeofLoc()); + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); + Record.AddTypeSourceInfo(TL.getUnderlyingTInfo()); +} + +void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + Record.AddSourceLocation(TL.getKWLoc()); + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); + Record.AddTypeSourceInfo(TL.getUnderlyingTInfo()); +} + +void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + Record.AddSourceLocation(TL.getTemplateNameLoc()); +} + +void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) { + Record.AddAttr(TL.getAttr()); +} + +void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + Record.AddSourceLocation(TL.getTemplateKeywordLoc()); + Record.AddSourceLocation(TL.getTemplateNameLoc()); + Record.AddSourceLocation(TL.getLAngleLoc()); + Record.AddSourceLocation(TL.getRAngleLoc()); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Record.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(), + TL.getArgLoc(i).getLocInfo()); +} + +void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) { + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); +} + +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Record.AddSourceLocation(TL.getElaboratedKeywordLoc()); + Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); +} + +void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + Record.AddSourceLocation(TL.getElaboratedKeywordLoc()); + Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL) { + Record.AddSourceLocation(TL.getElaboratedKeywordLoc()); + Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); + Record.AddSourceLocation(TL.getTemplateKeywordLoc()); + Record.AddSourceLocation(TL.getTemplateNameLoc()); + Record.AddSourceLocation(TL.getLAngleLoc()); + Record.AddSourceLocation(TL.getRAngleLoc()); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + Record.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), + TL.getArgLoc(I).getLocInfo()); +} + +void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + Record.AddSourceLocation(TL.getEllipsisLoc()); +} + +void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + +void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + Record.push_back(TL.hasBaseTypeAsWritten()); + Record.AddSourceLocation(TL.getTypeArgsLAngleLoc()); + Record.AddSourceLocation(TL.getTypeArgsRAngleLoc()); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + Record.AddTypeSourceInfo(TL.getTypeArgTInfo(i)); + Record.AddSourceLocation(TL.getProtocolLAngleLoc()); + Record.AddSourceLocation(TL.getProtocolRAngleLoc()); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Record.AddSourceLocation(TL.getProtocolLoc(i)); +} + +void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + Record.AddSourceLocation(TL.getStarLoc()); +} + +void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + Record.AddSourceLocation(TL.getKWLoc()); + Record.AddSourceLocation(TL.getLParenLoc()); + Record.AddSourceLocation(TL.getRParenLoc()); +} + +void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) { + Record.AddSourceLocation(TL.getKWLoc()); +} + +void ASTWriter::WriteTypeAbbrevs() { + using namespace llvm; + + std::shared_ptr<BitCodeAbbrev> Abv; + + // Abbreviation for TYPE_EXT_QUAL + Abv = std::make_shared<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(std::move(Abv)); + + // Abbreviation for TYPE_FUNCTION_PROTO + Abv = std::make_shared<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 + Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs + Abv->Add(BitCodeAbbrevOp(0)); // NoCfCheck + // 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(std::move(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_DESIGNATED_INIT_UPDATE); + RECORD(EXPR_IMPLICIT_VALUE_INIT); + RECORD(EXPR_NO_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.EnterBlockInfoBlock(); + +#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(MODULE_NAME); + RECORD(MODULE_DIRECTORY); + RECORD(MODULE_MAP_FILE); + RECORD(IMPORTS); + RECORD(ORIGINAL_FILE); + RECORD(ORIGINAL_PCH_DIR); + RECORD(ORIGINAL_FILE_ID); + RECORD(INPUT_FILE_OFFSETS); + + BLOCK(OPTIONS_BLOCK); + RECORD(LANGUAGE_OPTIONS); + RECORD(TARGET_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(MODULAR_CODEGEN_DECLS); + RECORD(SPECIAL_TYPES); + RECORD(STATISTICS); + RECORD(TENTATIVE_DEFINITIONS); + RECORD(SELECTOR_OFFSETS); + RECORD(METHOD_POOL); + RECORD(PP_COUNTER_VALUE); + RECORD(SOURCE_LOCATION_OFFSETS); + RECORD(SOURCE_LOCATION_PRELOADS); + RECORD(EXT_VECTOR_DECLS); + RECORD(UNUSED_FILESCOPED_DECLS); + RECORD(PPD_ENTITIES_OFFSETS); + RECORD(VTABLE_USES); + RECORD(PPD_SKIPPED_RANGES); + RECORD(REFERENCED_SELECTOR_POOL); + RECORD(TU_UPDATE_LEXICAL); + RECORD(SEMA_DECL_REFS); + RECORD(WEAK_UNDECLARED_IDENTIFIERS); + RECORD(PENDING_IMPLICIT_INSTANTIATIONS); + RECORD(UPDATE_VISIBLE); + RECORD(DECL_UPDATE_OFFSETS); + RECORD(DECL_UPDATES); + RECORD(CUDA_SPECIAL_DECL_REFS); + RECORD(HEADER_SEARCH_TABLE); + RECORD(FP_PRAGMA_OPTIONS); + RECORD(OPENCL_EXTENSIONS); + RECORD(OPENCL_EXTENSION_TYPES); + RECORD(OPENCL_EXTENSION_DECLS); + RECORD(DELEGATING_CTORS); + RECORD(KNOWN_NAMESPACES); + RECORD(MODULE_OFFSET_MAP); + RECORD(SOURCE_MANAGER_LINE_TABLE); + RECORD(OBJC_CATEGORIES_MAP); + RECORD(FILE_SORTED_DECLS); + RECORD(IMPORTED_MODULES); + RECORD(OBJC_CATEGORIES); + RECORD(MACRO_OFFSET); + RECORD(INTERESTING_IDENTIFIERS); + RECORD(UNDEFINED_BUT_USED); + RECORD(LATE_PARSED_TEMPLATE); + RECORD(OPTIMIZE_PRAGMA_OPTIONS); + RECORD(MSSTRUCT_PRAGMA_OPTIONS); + RECORD(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS); + RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES); + RECORD(DELETE_EXPRS_TO_ANALYZE); + RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH); + RECORD(PP_CONDITIONAL_STACK); + + // SourceManager Block. + BLOCK(SOURCE_MANAGER_BLOCK); + RECORD(SM_SLOC_FILE_ENTRY); + RECORD(SM_SLOC_BUFFER_ENTRY); + RECORD(SM_SLOC_BUFFER_BLOB); + RECORD(SM_SLOC_BUFFER_BLOB_COMPRESSED); + 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); + + // Submodule Block. + BLOCK(SUBMODULE_BLOCK); + RECORD(SUBMODULE_METADATA); + RECORD(SUBMODULE_DEFINITION); + RECORD(SUBMODULE_UMBRELLA_HEADER); + RECORD(SUBMODULE_HEADER); + RECORD(SUBMODULE_TOPHEADER); + RECORD(SUBMODULE_UMBRELLA_DIR); + RECORD(SUBMODULE_IMPORTS); + RECORD(SUBMODULE_EXPORTS); + RECORD(SUBMODULE_REQUIRES); + RECORD(SUBMODULE_EXCLUDED_HEADER); + RECORD(SUBMODULE_LINK_LIBRARY); + RECORD(SUBMODULE_CONFIG_MACRO); + RECORD(SUBMODULE_CONFLICT); + RECORD(SUBMODULE_PRIVATE_HEADER); + RECORD(SUBMODULE_TEXTUAL_HEADER); + RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); + RECORD(SUBMODULE_INITIALIZERS); + RECORD(SUBMODULE_EXPORT_AS); + + // Comments Block. + BLOCK(COMMENTS_BLOCK); + RECORD(COMMENTS_RAW_COMMENT); + + // 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(TYPE_OBJC_TYPE_PARAM); + RECORD(LOCAL_REDECLARATIONS); + 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_INHERITED_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_TYPE_ALIAS_TEMPLATE); + RECORD(DECL_STATIC_ASSERT); + RECORD(DECL_CXX_BASE_SPECIFIERS); + RECORD(DECL_CXX_CTOR_INITIALIZERS); + RECORD(DECL_INDIRECTFIELD); + RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); + RECORD(DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK); + RECORD(DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION); + RECORD(DECL_IMPORT); + RECORD(DECL_OMP_THREADPRIVATE); + RECORD(DECL_EMPTY); + RECORD(DECL_OBJC_TYPE_PARAM); + RECORD(DECL_OMP_CAPTUREDEXPR); + RECORD(DECL_PRAGMA_COMMENT); + RECORD(DECL_PRAGMA_DETECT_MISMATCH); + RECORD(DECL_OMP_DECLARE_REDUCTION); + + // 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); + + // Decls and Types block. + BLOCK(EXTENSION_BLOCK); + RECORD(EXTENSION_METADATA); + + BLOCK(UNHASHED_CONTROL_BLOCK); + RECORD(SIGNATURE); + RECORD(DIAGNOSTIC_OPTIONS); + RECORD(DIAG_PRAGMA_MAPPINGS); + +#undef RECORD +#undef BLOCK + Stream.ExitBlock(); +} + +/// 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 = FileMgr.makeAbsolutePath(Path); + return Changed | llvm::sys::path::remove_dots(Path); +} + +/// 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; +} + +ASTFileSignature ASTWriter::createSignature(StringRef Bytes) { + // Calculate the hash till start of UNHASHED_CONTROL_BLOCK. + llvm::SHA1 Hasher; + Hasher.update(ArrayRef<uint8_t>(Bytes.bytes_begin(), Bytes.size())); + auto Hash = Hasher.result(); + + // Convert to an array [5*i32]. + ASTFileSignature Signature; + auto LShift = [&](unsigned char Val, unsigned Shift) { + return (uint32_t)Val << Shift; + }; + for (int I = 0; I != 5; ++I) + Signature[I] = LShift(Hash[I * 4 + 0], 24) | LShift(Hash[I * 4 + 1], 16) | + LShift(Hash[I * 4 + 2], 8) | LShift(Hash[I * 4 + 3], 0); + + return Signature; +} + +ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, + ASTContext &Context) { + // Flush first to prepare the PCM hash (signature). + Stream.FlushToWord(); + auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3; + + // Enter the block and prepare to write records. + RecordData Record; + Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5); + + // For implicit modules, write the hash of the PCM as its signature. + ASTFileSignature Signature; + if (WritingModule && + PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) { + Signature = createSignature(StringRef(Buffer.begin(), StartOfUnhashedControl)); + Record.append(Signature.begin(), Signature.end()); + Stream.EmitRecord(SIGNATURE, Record); + Record.clear(); + } + + // Diagnostic options. + const auto &Diags = Context.getDiagnostics(); + const DiagnosticOptions &DiagOpts = Diags.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); + + // Write out the diagnostic/pragma mappings. + WritePragmaDiagnosticMappings(Diags, /* IsModule = */ WritingModule); + + // Leave the options block. + Stream.ExitBlock(); + return Signature; +} + +/// 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 + auto MetadataAbbrev = std::make_shared<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)); // Timestamps + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // PCHHasObjectFile + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned MetadataAbbrevCode = Stream.EmitAbbrev(std::move(MetadataAbbrev)); + assert((!WritingModule || isysroot.empty()) && + "writing module as a relocatable PCH?"); + { + RecordData::value_type Record[] = { + METADATA, + VERSION_MAJOR, + VERSION_MINOR, + CLANG_VERSION_MAJOR, + CLANG_VERSION_MINOR, + !isysroot.empty(), + IncludeTimestamps, + Context.getLangOpts().BuildingPCHWithObjectFile, + ASTHasCompilerErrors}; + Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, + getClangFullRepositoryVersion()); + } + + if (WritingModule) { + // Module name + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); + RecordData::value_type Record[] = {MODULE_NAME}; + Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); + } + + if (WritingModule && WritingModule->Directory) { + SmallString<128> BaseDir(WritingModule->Directory->getName()); + cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); + + // If the home of the module is the current working directory, then we + // want to pick up the cwd of the build process loading the module, not + // our cwd, when we load this module. + if (!PP.getHeaderSearchInfo() + .getHeaderSearchOpts() + .ModuleMapFileHomeIsCwd || + WritingModule->Directory->getName() != StringRef(".")) { + // Module directory. + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory + unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); + + RecordData::value_type Record[] = {MODULE_DIRECTORY}; + 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 && WritingModule->Kind == Module::ModuleMapModule) { + Record.clear(); + + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + AddPath(WritingModule->PresumedModuleMapFile.empty() + ? Map.getModuleMapFileForUniquing(WritingModule)->getName() + : StringRef(WritingModule->PresumedModuleMapFile), + 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 (ModuleFile &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); + + // If we have calculated signature, there is no need to store + // the size or timestamp. + Record.push_back(M.Signature ? 0 : M.File->getSize()); + Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File)); + + for (auto I : M.Signature) + Record.push_back(I); + + AddString(M.ModuleName, Record); + AddPath(M.FileName, Record); + } + Stream.EmitRecord(IMPORTS, Record); + } + + // Write the options block. + Stream.EnterSubblock(OPTIONS_BLOCK_ID, 4); + + // 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(LangOpts.ModuleFeatures.size()); + for (StringRef Feature : LangOpts.ModuleFeatures) + AddString(Feature, Record); + + Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); + AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); + + AddString(LangOpts.CurrentModule, Record); + + // Comment options. + Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size()); + for (const auto &I : LangOpts.CommentOpts.BlockCommandNames) { + AddString(I, Record); + } + Record.push_back(LangOpts.CommentOpts.ParseAllComments); + + // OpenMP offloading options. + Record.push_back(LangOpts.OMPTargetTriples.size()); + for (auto &T : LangOpts.OMPTargetTriples) + AddString(T.getTriple(), Record); + + AddString(LangOpts.OMPHostIRFile, Record); + + 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); + + // File system options. + Record.clear(); + const FileSystemOptions &FSOpts = + Context.getSourceManager().getFileManager().getFileSystemOpts(); + 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.ImplicitModuleMaps); + Record.push_back(HSOpts.ModuleMapFileHomeIsCwd); + 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); + Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary)); + Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record); + + // Leave the options block. + Stream.ExitBlock(); + + // Original file name and file ID + SourceManager &SM = Context.getSourceManager(); + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { + auto FileAbbrev = std::make_shared<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(std::move(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 != "-") { + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); + + SmallString<128> OutputPath(OutputFile); + + SM.getFileManager().makeAbsolutePath(OutputPath); + StringRef origDir = llvm::sys::path::parent_path(OutputPath); + + RecordData::value_type Record[] = {ORIGINAL_PCH_DIR}; + Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); + } + + WriteInputFiles(Context.SourceMgr, + PP.getHeaderSearchInfo().getHeaderSearchOpts(), + PP.getLangOpts().Modules); + Stream.ExitBlock(); +} + +namespace { + +/// An input file. +struct InputFileEntry { + const FileEntry *File; + bool IsSystemFile; + bool IsTransient; + bool BufferOverridden; + bool IsTopLevelModuleMap; +}; + +} // namespace + +void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, + HeaderSearchOptions &HSOpts, + bool Modules) { + using namespace llvm; + + Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); + + // Create input-file abbreviation. + auto IFAbbrev = std::make_shared<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::Fixed, 1)); // Transient + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(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::FileInfo &File = SLoc->getFile(); + const SrcMgr::ContentCache *Cache = File.getContentCache(); + if (!Cache->OrigEntry) + continue; + + InputFileEntry Entry; + Entry.File = Cache->OrigEntry; + Entry.IsSystemFile = Cache->IsSystemFile; + Entry.IsTransient = Cache->IsTransient; + Entry.BufferOverridden = Cache->BufferOverridden; + Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) && + File.getIncludeLoc().isInvalid(); + 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 (const auto &Entry : SortedFiles) { + 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; + + // Emit size/modification time for this file. + // And whether this file was overridden. + RecordData::value_type Record[] = { + INPUT_FILE, + InputFileOffsets.size(), + (uint64_t)Entry.File->getSize(), + (uint64_t)getTimestampForOutput(Entry.File), + Entry.BufferOverridden, + Entry.IsTransient, + Entry.IsTopLevelModuleMap}; + + EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); + } + + Stream.ExitBlock(); + + // Create input file offsets abbreviation. + auto OffsetsAbbrev = std::make_shared<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(std::move(OffsetsAbbrev)); + + // Write input file offsets. + RecordData::value_type Record[] = {INPUT_FILE_OFFSETS, + InputFileOffsets.size(), UserFilesNum}; + Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets)); +} + +//===----------------------------------------------------------------------===// +// Source Manager Serialization +//===----------------------------------------------------------------------===// + +/// Create an abbreviation for the SLocEntry that refers to a +/// file. +static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + + auto Abbrev = std::make_shared<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, 3)); // 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(std::move(Abbrev)); +} + +/// Create an abbreviation for the SLocEntry that refers to a +/// buffer. +static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + + auto Abbrev = std::make_shared<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, 3)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob + return Stream.EmitAbbrev(std::move(Abbrev)); +} + +/// Create an abbreviation for the SLocEntry that refers to a +/// buffer's blob. +static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream, + bool Compressed) { + using namespace llvm; + + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(Compressed ? SM_SLOC_BUFFER_BLOB_COMPRESSED + : SM_SLOC_BUFFER_BLOB)); + if (Compressed) + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Uncompressed size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob + return Stream.EmitAbbrev(std::move(Abbrev)); +} + +/// Create an abbreviation for the SLocEntry that refers to a macro +/// expansion. +static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + + auto Abbrev = std::make_shared<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::Fixed, 1)); // Is token range + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length + return Stream.EmitAbbrev(std::move(Abbrev)); +} + +namespace { + + // Trait used for the on-disk hash table of header search information. + class HeaderFileInfoTrait { + ASTWriter &Writer; + + // Keep track of the framework names we've used during serialization. + SmallVector<char, 128> FrameworkStringData; + llvm::StringMap<unsigned> FrameworkNameOffset; + + public: + HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {} + + struct key_type { + StringRef Filename; + off_t Size; + time_t ModTime; + }; + using key_type_ref = const key_type &; + + using UnresolvedModule = + llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>; + + struct data_type { + const HeaderFileInfo &HFI; + ArrayRef<ModuleMap::KnownHeader> KnownHeaders; + UnresolvedModule Unresolved; + }; + using data_type_ref = const data_type &; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + 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. + return llvm::hash_combine(key.Size, key.ModTime); + } + + std::pair<unsigned, unsigned> + EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + unsigned KeyLen = key.Filename.size() + 1 + 8 + 8; + LE.write<uint16_t>(KeyLen); + unsigned DataLen = 1 + 2 + 4 + 4; + for (auto ModInfo : Data.KnownHeaders) + if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) + DataLen += 4; + if (Data.Unresolved.getPointer()) + DataLen += 4; + LE.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 LE(Out, little); + LE.write<uint64_t>(key.Size); + KeyLen -= 8; + LE.write<uint64_t>(key.ModTime); + KeyLen -= 8; + Out.write(key.Filename.data(), KeyLen); + } + + void EmitData(raw_ostream &Out, key_type_ref key, + data_type_ref Data, unsigned DataLen) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + uint64_t Start = Out.tell(); (void)Start; + + unsigned char Flags = (Data.HFI.isImport << 5) + | (Data.HFI.isPragmaOnce << 4) + | (Data.HFI.DirInfo << 1) + | Data.HFI.IndexHeaderMapHeader; + LE.write<uint8_t>(Flags); + LE.write<uint16_t>(Data.HFI.NumIncludes); + + if (!Data.HFI.ControllingMacro) + LE.write<uint32_t>(Data.HFI.ControllingMacroID); + else + LE.write<uint32_t>(Writer.getIdentifierRef(Data.HFI.ControllingMacro)); + + unsigned Offset = 0; + if (!Data.HFI.Framework.empty()) { + // If this header refers into a framework, save the framework name. + llvm::StringMap<unsigned>::iterator Pos + = FrameworkNameOffset.find(Data.HFI.Framework); + if (Pos == FrameworkNameOffset.end()) { + Offset = FrameworkStringData.size() + 1; + FrameworkStringData.append(Data.HFI.Framework.begin(), + Data.HFI.Framework.end()); + FrameworkStringData.push_back(0); + + FrameworkNameOffset[Data.HFI.Framework] = Offset; + } else + Offset = Pos->second; + } + LE.write<uint32_t>(Offset); + + auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) { + if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) { + uint32_t Value = (ModID << 2) | (unsigned)Role; + assert((Value >> 2) == ModID && "overflow in header module info"); + LE.write<uint32_t>(Value); + } + }; + + // FIXME: If the header is excluded, we should write out some + // record of that fact. + for (auto ModInfo : Data.KnownHeaders) + EmitModule(ModInfo.getModule(), ModInfo.getRole()); + if (Data.Unresolved.getPointer()) + EmitModule(Data.Unresolved.getPointer(), Data.Unresolved.getInt()); + + assert(Out.tell() - Start == DataLen && "Wrong data length"); + } + + const char *strings_begin() const { return FrameworkStringData.begin(); } + const char *strings_end() const { return FrameworkStringData.end(); } + }; + +} // namespace + +/// 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) { + HeaderFileInfoTrait GeneratorTrait(*this); + llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; + SmallVector<const char *, 4> SavedStrings; + unsigned NumHeaderSearchEntries = 0; + + // Find all unresolved headers for the current module. We generally will + // have resolved them before we get here, but not necessarily: we might be + // compiling a preprocessed module, where there is no requirement for the + // original files to exist any more. + const HeaderFileInfo Empty; // So we can take a reference. + if (WritingModule) { + llvm::SmallVector<Module *, 16> Worklist(1, WritingModule); + while (!Worklist.empty()) { + Module *M = Worklist.pop_back_val(); + if (!M->isAvailable()) + continue; + + // Map to disk files where possible, to pick up any missing stat + // information. This also means we don't need to check the unresolved + // headers list when emitting resolved headers in the first loop below. + // FIXME: It'd be preferable to avoid doing this if we were given + // sufficient stat information in the module map. + HS.getModuleMap().resolveHeaderDirectives(M); + + // If the file didn't exist, we can still create a module if we were given + // enough information in the module map. + for (auto U : M->MissingHeaders) { + // Check that we were given enough information to build a module + // without this file existing on disk. + if (!U.Size || (!U.ModTime && IncludeTimestamps)) { + PP->Diag(U.FileNameLoc, diag::err_module_no_size_mtime_for_header) + << WritingModule->getFullModuleName() << U.Size.hasValue() + << U.FileName; + continue; + } + + // Form the effective relative pathname for the file. + SmallString<128> Filename(M->Directory->getName()); + llvm::sys::path::append(Filename, U.FileName); + PreparePathForOutput(Filename); + + StringRef FilenameDup = strdup(Filename.c_str()); + SavedStrings.push_back(FilenameDup.data()); + + HeaderFileInfoTrait::key_type Key = { + FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0 + }; + HeaderFileInfoTrait::data_type Data = { + Empty, {}, {M, ModuleMap::headerKindToRole(U.Kind)} + }; + // FIXME: Deal with cases where there are multiple unresolved header + // directives in different submodules for the same header. + Generator.insert(Key, Data, GeneratorTrait); + ++NumHeaderSearchEntries; + } + + Worklist.append(M->submodule_begin(), M->submodule_end()); + } + } + + SmallVector<const FileEntry *, 16> FilesByUID; + HS.getFileMgr().GetUniqueIDMapping(FilesByUID); + + if (FilesByUID.size() > HS.header_file_size()) + FilesByUID.resize(HS.header_file_size()); + + for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { + const FileEntry *File = FilesByUID[UID]; + if (!File) + continue; + + // Get the file info. This will load info from the external source if + // necessary. Skip emitting this file if we have no information on it + // as a header file (in which case HFI will be null) or if it hasn't + // changed since it was loaded. Also skip it if it's for a modular header + // from a different module; in that case, we rely on the module(s) + // containing the header to provide this information. + const HeaderFileInfo *HFI = + HS.getExistingFileInfo(File, /*WantExternal*/!Chain); + if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) + continue; + + // Massage the file path into an appropriate form. + StringRef 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 = StringRef(strdup(FilenameTmp.c_str())); + SavedStrings.push_back(Filename.data()); + } + + HeaderFileInfoTrait::key_type Key = { + Filename, File->getSize(), getTimestampForOutput(File) + }; + HeaderFileInfoTrait::data_type Data = { + *HFI, HS.getModuleMap().findAllModulesForHeader(File), {} + }; + Generator.insert(Key, Data, 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::write<uint32_t>(Out, 0, little); + BucketOffset = Generator.Emit(Out, GeneratorTrait); + } + + // Create a blob abbreviation + using namespace llvm; + + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + + // Write the header search table + RecordData::value_type Record[] = {HEADER_SEARCH_TABLE, BucketOffset, + NumHeaderSearchEntries, 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])); +} + +static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, + unsigned SLocBufferBlobCompressedAbbrv, + unsigned SLocBufferBlobAbbrv) { + using RecordDataType = ASTWriter::RecordData::value_type; + + // Compress the buffer if possible. We expect that almost all PCM + // consumers will not want its contents. + SmallString<0> CompressedBuffer; + if (llvm::zlib::isAvailable()) { + llvm::Error E = llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer); + if (!E) { + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, + Blob.size() - 1}; + Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, + CompressedBuffer); + return; + } + llvm::consumeError(std::move(E)); + } + + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB}; + Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob); +} + +/// 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, 4); + + // Abbreviations for the various kinds of source-location entries. + unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); + unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); + unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream, false); + unsigned SLocBufferBlobCompressedAbbrv = + CreateSLocBufferBlobAbbrev(Stream, true); + 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(); + AddSourceLocation(File.getIncludeLoc(), Record); + Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding + Record.push_back(File.hasLineDirectives()); + + const SrcMgr::ContentCache *Content = File.getContentCache(); + bool EmitBlob = false; + 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 || Content->IsTransient) + EmitBlob = true; + } 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()); + StringRef Name = Buffer->getBufferIdentifier(); + Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, + StringRef(Name.data(), Name.size() + 1)); + EmitBlob = true; + + if (Name == "<built-in>") + PreloadSLocs.push_back(SLocEntryOffsets.size()); + } + + if (EmitBlob) { + // Include the implicit terminating null character in the on-disk buffer + // if we're writing it uncompressed. + const llvm::MemoryBuffer *Buffer = + Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); + StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1); + emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv, + SLocBufferBlobAbbrv); + } + } else { + // The source location entry is a macro expansion. + const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion(); + AddSourceLocation(Expansion.getSpellingLoc(), Record); + AddSourceLocation(Expansion.getExpansionLocStart(), Record); + AddSourceLocation(Expansion.isMacroArgExpansion() + ? SourceLocation() + : Expansion.getExpansionLocEnd(), + Record); + Record.push_back(Expansion.isExpansionTokenRange()); + + // 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; + + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + { + RecordData::value_type Record[] = { + SOURCE_LOCATION_OFFSETS, SLocEntryOffsets.size(), + 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 needed file names. + llvm::DenseMap<int, int> FilenameMap; + FilenameMap[-1] = -1; // For unspecified filenames. + for (const auto &L : LineTable) { + if (L.first.ID < 0) + continue; + for (auto &LE : L.second) { + if (FilenameMap.insert(std::make_pair(LE.FilenameID, + FilenameMap.size() - 1)).second) + AddPath(LineTable.getFilename(LE.FilenameID), Record); + } + } + Record.push_back(0); + + // Emit the line entries + for (const auto &L : LineTable) { + // 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 (const auto &LE : L.second) { + Record.push_back(LE.FileOffset); + Record.push_back(LE.LineNo); + Record.push_back(FilenameMap[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; +} + +/// 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) { + RecordData::value_type Record[] = {PP.getCounterValue()}; + Stream.EmitRecord(PP_COUNTER_VALUE, Record); + } + + if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) { + assert(!IsModule); + auto SkipInfo = PP.getPreambleSkipInfo(); + if (SkipInfo.hasValue()) { + Record.push_back(true); + AddSourceLocation(SkipInfo->HashTokenLoc, Record); + AddSourceLocation(SkipInfo->IfTokenLoc, Record); + Record.push_back(SkipInfo->FoundNonSkipPortion); + Record.push_back(SkipInfo->FoundElse); + AddSourceLocation(SkipInfo->ElseLoc, Record); + } else { + Record.push_back(false); + } + for (const auto &Cond : PP.getPreambleConditionalStack()) { + AddSourceLocation(Cond.IfLoc, Record); + Record.push_back(Cond.WasSkipping); + Record.push_back(Cond.FoundNonSkip); + Record.push_back(Cond.FoundElse); + } + Stream.EmitRecord(PP_CONDITIONAL_STACK, 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: Include a location for the use, and say which one was used. + if (PP.SawDateOrTime()) + PP.Diag(SourceLocation(), diag::warn_module_uses_date_time) << IsModule; + + // 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. + llvm::sort(MacroIdentifiers, 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; + // We write out exported module macros for PCH as well. + 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(); + } + + /// 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); + 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->getNumParams()); + for (const IdentifierInfo *Param : MI->params()) + AddIdentifierRef(Param, 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 = std::make_shared<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(std::move(Abbrev)); + { + RecordData::value_type Record[] = {MACRO_OFFSET, MacroOffsets.size(), + 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; + { + auto Abbrev = std::make_shared<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(std::move(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 (auto *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 (auto *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 (auto *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; + + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + + RecordData::value_type Record[] = {PPD_ENTITIES_OFFSETS, + FirstPreprocessorEntityID - + NUM_PREDEF_PP_ENTITY_IDS}; + Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, + bytes(PreprocessedEntityOffsets)); + } + + // Write the skipped region table for the preprocessing record. + ArrayRef<SourceRange> SkippedRanges = PPRec.getSkippedRanges(); + if (SkippedRanges.size() > 0) { + std::vector<PPSkippedRange> SerializedSkippedRanges; + SerializedSkippedRanges.reserve(SkippedRanges.size()); + for (auto const& Range : SkippedRanges) + SerializedSkippedRanges.emplace_back(Range); + + using namespace llvm; + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(PPD_SKIPPED_RANGES)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned PPESkippedRangeAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Record.clear(); + Record.push_back(PPD_SKIPPED_RANGES); + Stream.EmitRecordWithBlob(PPESkippedRangeAbbrev, Record, + bytes(SerializedSkippedRanges)); + } +} + +unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) { + if (!Mod) + return 0; + + llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod); + if (Known != SubmoduleIDs.end()) + return Known->second; + + auto *Top = Mod->getTopLevelModule(); + if (Top != WritingModule && + (getLangOpts().CompilingPCH || + !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule)))) + return 0; + + return SubmoduleIDs[Mod] = NextSubmoduleID++; +} + +unsigned ASTWriter::getSubmoduleID(Module *Mod) { + // 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. + unsigned ID = getLocalOrImportedSubmoduleID(Mod); + assert((ID || !Mod) && + "asked for module ID for non-local, non-imported module"); + return ID; +} + +/// Compute the number of modules within the given tree (including the +/// given module). +static unsigned getNumberOfModules(Module *Mod) { + unsigned ChildModules = 0; + for (auto 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; + + auto Abbrev = std::make_shared<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, 2)); // Kind + 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::Fixed, 1)); // ModuleMapIsPriv... + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned UmbrellaAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned HeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned TopHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // State + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature + unsigned RequiresAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TEXTUAL_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned TextualHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_TEXTUAL_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned PrivateTextualHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message + unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXPORT_AS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + // Write the submodule metadata block. + RecordData::value_type Record[] = { + getNumberOfModules(WritingModule), + 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); + + uint64_t ParentID = 0; + if (Mod->Parent) { + assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?"); + ParentID = SubmoduleIDs[Mod->Parent]; + } + + // Emit the definition of the block. + { + RecordData::value_type Record[] = {SUBMODULE_DEFINITION, + ID, + ParentID, + (RecordData::value_type)Mod->Kind, + Mod->IsFramework, + Mod->IsExplicit, + Mod->IsSystem, + Mod->IsExternC, + Mod->InferSubmodules, + Mod->InferExplicitSubmodules, + Mod->InferExportWildcard, + Mod->ConfigMacrosExhaustive, + Mod->ModuleMapIsPrivate}; + Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); + } + + // Emit the requirements. + for (const auto &R : Mod->Requirements) { + RecordData::value_type Record[] = {SUBMODULE_REQUIRES, R.second}; + Stream.EmitRecordWithBlob(RequiresAbbrev, Record, R.first); + } + + // Emit the umbrella header, if there is one. + if (auto UmbrellaHeader = Mod->getUmbrellaHeader()) { + RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_HEADER}; + Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, + UmbrellaHeader.NameAsWritten); + } else if (auto UmbrellaDir = Mod->getUmbrellaDir()) { + RecordData::value_type Record[] = {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) { + RecordData::value_type Record[] = {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()); + RecordData::value_type Record[] = {SUBMODULE_TOPHEADER}; + for (auto *H : TopHeaders) + Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName()); + } + + // Emit the imports. + if (!Mod->Imports.empty()) { + RecordData Record; + for (auto *I : Mod->Imports) + Record.push_back(getSubmoduleID(I)); + Stream.EmitRecord(SUBMODULE_IMPORTS, Record); + } + + // Emit the exports. + if (!Mod->Exports.empty()) { + RecordData Record; + for (const auto &E : Mod->Exports) { + // FIXME: This may fail; we don't require that all exported modules + // are local or imported. + Record.push_back(getSubmoduleID(E.getPointer())); + Record.push_back(E.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 (const auto &LL : Mod->LinkLibraries) { + RecordData::value_type Record[] = {SUBMODULE_LINK_LIBRARY, + LL.IsFramework}; + Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, LL.Library); + } + + // Emit the conflicts. + for (const auto &C : Mod->Conflicts) { + // FIXME: This may fail; we don't require that all conflicting modules + // are local or imported. + RecordData::value_type Record[] = {SUBMODULE_CONFLICT, + getSubmoduleID(C.Other)}; + Stream.EmitRecordWithBlob(ConflictAbbrev, Record, C.Message); + } + + // Emit the configuration macros. + for (const auto &CM : Mod->ConfigMacros) { + RecordData::value_type Record[] = {SUBMODULE_CONFIG_MACRO}; + Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, CM); + } + + // Emit the initializers, if any. + RecordData Inits; + for (Decl *D : Context->getModuleInitializers(Mod)) + Inits.push_back(GetDeclRef(D)); + if (!Inits.empty()) + Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits); + + // Emit the name of the re-exported module, if any. + if (!Mod->ExportAsModule.empty()) { + RecordData::value_type Record[] = {SUBMODULE_EXPORT_AS}; + Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule); + } + + // Queue up the submodules of this module. + for (auto *M : Mod->submodules()) + Q.push(M); + } + + Stream.ExitBlock(); + + assert((NextSubmoduleID - FirstSubmoduleID == + getNumberOfModules(WritingModule)) && + "Wrong # of submodules; found a reference to a non-local, " + "non-imported submodule?"); +} + +void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, + bool isModule) { + llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64> + DiagStateIDMap; + unsigned CurrID = 0; + RecordData Record; + + auto EncodeDiagStateFlags = + [](const DiagnosticsEngine::DiagState *DS) -> unsigned { + unsigned Result = (unsigned)DS->ExtBehavior; + for (unsigned Val : + {(unsigned)DS->IgnoreAllWarnings, (unsigned)DS->EnableAllWarnings, + (unsigned)DS->WarningsAsErrors, (unsigned)DS->ErrorsAsFatal, + (unsigned)DS->SuppressSystemWarnings}) + Result = (Result << 1) | Val; + return Result; + }; + + unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState); + Record.push_back(Flags); + + auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State, + bool IncludeNonPragmaStates) { + // Ensure that the diagnostic state wasn't modified since it was created. + // We will not correctly round-trip this information otherwise. + assert(Flags == EncodeDiagStateFlags(State) && + "diag state flags vary in single AST file"); + + unsigned &DiagStateID = DiagStateIDMap[State]; + Record.push_back(DiagStateID); + + if (DiagStateID == 0) { + DiagStateID = ++CurrID; + + // Add a placeholder for the number of mappings. + auto SizeIdx = Record.size(); + Record.emplace_back(); + for (const auto &I : *State) { + if (I.second.isPragma() || IncludeNonPragmaStates) { + Record.push_back(I.first); + Record.push_back(I.second.serialize()); + } + } + // Update the placeholder. + Record[SizeIdx] = (Record.size() - SizeIdx) / 2; + } + }; + + AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule); + + // Reserve a spot for the number of locations with state transitions. + auto NumLocationsIdx = Record.size(); + Record.emplace_back(); + + // Emit the state transitions. + unsigned NumLocations = 0; + for (auto &FileIDAndFile : Diag.DiagStatesByLoc.Files) { + if (!FileIDAndFile.first.isValid() || + !FileIDAndFile.second.HasLocalTransitions) + continue; + ++NumLocations; + + SourceLocation Loc = Diag.SourceMgr->getComposedLoc(FileIDAndFile.first, 0); + assert(!Loc.isInvalid() && "start loc for valid FileID is invalid"); + AddSourceLocation(Loc, Record); + + Record.push_back(FileIDAndFile.second.StateTransitions.size()); + for (auto &StatePoint : FileIDAndFile.second.StateTransitions) { + Record.push_back(StatePoint.Offset); + AddDiagState(StatePoint.State, false); + } + } + + // Backpatch the number of locations. + Record[NumLocationsIdx] = NumLocations; + + // Emit CurDiagStateLoc. Do it last in order to match source order. + // + // This also protects against a hypothetical corner case with simulating + // -Werror settings for implicit modules in the ASTReader, where reading + // CurDiagState out of context could change whether warning pragmas are + // treated as errors. + AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record); + AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false); + + Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); +} + +//===----------------------------------------------------------------------===// +// Type Serialization +//===----------------------------------------------------------------------===// + +/// Write the representation of a type to the AST stream. +void ASTWriter::WriteType(QualType T) { + TypeIdx &IdxRef = TypeIdxs[T]; + if (IdxRef.getIndex() == 0) // we haven't seen this type before. + IdxRef = TypeIdx(NextTypeID++); + TypeIdx Idx = IdxRef; + + assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST"); + + RecordData Record; + + // Emit the type's representation. + ASTTypeWriter W(*this, Record); + W.Visit(T); + uint64_t Offset = W.Emit(); + + // Record the offset for this type. + unsigned Index = Idx.getIndex() - FirstTypeID; + if (TypeOffsets.size() == Index) + TypeOffsets.push_back(Offset); + else if (TypeOffsets.size() < Index) { + TypeOffsets.resize(Index + 1); + TypeOffsets[Index] = Offset; + } else { + llvm_unreachable("Types emitted in wrong order"); + } +} + +//===----------------------------------------------------------------------===// +// Declaration Serialization +//===----------------------------------------------------------------------===// + +/// 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 +/// bitstream, 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(); + SmallVector<uint32_t, 128> KindDeclPairs; + for (const auto *D : DC->decls()) { + KindDeclPairs.push_back(D->getKind()); + KindDeclPairs.push_back(GetDeclRef(D)); + } + + ++NumLexicalDeclContexts; + RecordData::value_type Record[] = {DECL_CONTEXT_LEXICAL}; + Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, + bytes(KindDeclPairs)); + return Offset; +} + +void ASTWriter::WriteTypeDeclOffsets() { + using namespace llvm; + + // Write the type offsets array + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + { + RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size(), + FirstTypeID - NUM_PREDEF_TYPE_IDS}; + Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); + } + + // Write the declaration offsets array + Abbrev = std::make_shared<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(std::move(Abbrev)); + { + RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size(), + FirstDeclID - NUM_PREDEF_DECL_IDS}; + Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); + } +} + +void ASTWriter::WriteFileDeclIDsMap() { + using namespace llvm; + + SmallVector<std::pair<FileID, DeclIDInFileInfo *>, 64> SortedFileDeclIDs( + FileDeclIDs.begin(), FileDeclIDs.end()); + llvm::sort(SortedFileDeclIDs, 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); + } + + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); + RecordData::value_type Record[] = {FILE_SORTED_DECLS, + FileGroupedDeclIDs.size()}; + Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileGroupedDeclIDs)); +} + +void ASTWriter::WriteComments() { + Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3); + auto _ = llvm::make_scope_exit([this] { Stream.ExitBlock(); }); + if (!PP->getPreprocessorOpts().WriteCommentListToPCH) + return; + ArrayRef<RawComment *> RawComments = Context->Comments.getComments(); + RecordData Record; + for (const auto *I : RawComments) { + 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); + } +} + +//===----------------------------------------------------------------------===// +// 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: + using key_type = Selector; + using key_type_ref = key_type; + + struct data_type { + SelectorID ID; + ObjCMethodList Instance, Factory; + }; + using data_type_ref = const data_type &; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + 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 LE(Out, little); + 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 LE(Out, little); + 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 LE(Out, little); + 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"); + } +}; + +} // namespace + +/// 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::write<uint32_t>(Out, 0, little); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + + // Write the method pool + { + RecordData::value_type Record[] = {METHOD_POOL, BucketOffset, + NumTableEntries}; + Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); + } + + // Create a blob abbreviation for the selector table offsets. + Abbrev = std::make_shared<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(std::move(Abbrev)); + + // Write the selector offsets table. + { + RecordData::value_type Record[] = { + SELECTOR_OFFSETS, SelectorOffsets.size(), + FirstSelectorID - NUM_PREDEF_SELECTOR_IDS}; + Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, + bytes(SelectorOffsets)); + } + } +} + +/// 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; + ASTRecordWriter Writer(*this, 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; + Writer.AddSelectorRef(Sel); + Writer.AddSourceLocation(Loc); + } + Writer.Emit(REFERENCED_SELECTOR_POOL); +} + +//===----------------------------------------------------------------------===// +// 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 we find a local decl, we're done. + if (!Redecl->isFromASTFile()) { + // Exception: in very rare cases (for injected-class-names), not all + // redeclarations are in the same semantic context. Skip ones in a + // different context. They don't go in this lookup table at all. + if (!Redecl->getDeclContext()->getRedeclContext()->Equals( + D->getDeclContext()->getRedeclContext())) + continue; + return cast<NamedDecl>(Redecl); + } + + // If we find a decl from a (chained-)PCH stop since we won't find a + // local one. + if (Redecl->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; + bool IsModule; + bool NeedDecls; + ASTWriter::RecordData *InterestingIdentifierOffsets; + + /// 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(const IdentifierInfo *II, uint64_t MacroOffset) { + if (MacroOffset || + II->isPoisoned() || + (IsModule ? II->hasRevertedBuiltin() : II->getObjCOrBuiltinID()) || + II->hasRevertedTokenIDToIdentifier() || + (NeedDecls && II->getFETokenInfo())) + return true; + + return false; + } + +public: + using key_type = IdentifierInfo *; + using key_type_ref = key_type; + + using data_type = IdentID; + using data_type_ref = data_type; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, + IdentifierResolver &IdResolver, bool IsModule, + ASTWriter::RecordData *InterestingIdentifierOffsets) + : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule), + NeedDecls(!IsModule || !Writer.getLangOpts().CPlusPlus), + InterestingIdentifierOffsets(InterestingIdentifierOffsets) {} + + bool needDecls() const { return NeedDecls; } + + static hash_value_type ComputeHash(const IdentifierInfo* II) { + return llvm::djbHash(II->getName()); + } + + bool isInterestingIdentifier(const IdentifierInfo *II) { + auto MacroOffset = Writer.getMacroDirectivesOffset(II); + return isInterestingIdentifier(II, MacroOffset); + } + + bool isInterestingNonMacroIdentifier(const IdentifierInfo *II) { + return isInterestingIdentifier(II, 0); + } + + 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. + + if (NeedDecls) { + for (IdentifierResolver::iterator D = IdResolver.begin(II), + DEnd = IdResolver.end(); + D != DEnd; ++D) + DataLen += 4; + } + } + + using namespace llvm::support; + + endian::Writer LE(Out, little); + + 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()); + + // Emit the offset of the key/data length information to the interesting + // identifiers table if necessary. + if (InterestingIdentifierOffsets && isInterestingIdentifier(II)) + InterestingIdentifierOffsets->push_back(Out.tell() - 4); + + Out.write(II->getNameStart(), KeyLen); + } + + void EmitData(raw_ostream& Out, IdentifierInfo* II, + IdentID ID, unsigned) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + + 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->hasRevertedBuiltin()); + Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); + Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); + LE.write<uint16_t>(Bits); + + if (HadMacroDefinition) + LE.write<uint32_t>(MacroOffset); + + if (NeedDecls) { + // 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))); + } + } +}; + +} // namespace + +/// 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; + + RecordData InterestingIdents; + + // Create and write out the blob that contains the identifier + // strings. + { + llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; + ASTIdentifierTableTrait Trait( + *this, PP, IdResolver, IsModule, + (getLangOpts().CPlusPlus && IsModule) ? &InterestingIdents : nullptr); + + // 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 (const auto &ID : PP.getIdentifierTable()) + IIs.push_back(ID.second); + // Sort the identifiers lexicographically before getting them references so + // that their order is stable. + llvm::sort(IIs, llvm::less_ptr<IdentifierInfo>()); + for (const IdentifierInfo *II : IIs) + if (Trait.isInterestingNonMacroIdentifier(II)) + 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) { + auto *II = const_cast<IdentifierInfo *>(IdentIDPair.first); + IdentID ID = IdentIDPair.second; + assert(II && "NULL identifier in identifier table"); + // Write out identifiers if either the ID is local or the identifier has + // changed since it was loaded. + if (ID >= FirstIdentID || !Chain || !II->isFromAST() + || II->hasChangedSinceDeserialization() || + (Trait.needDecls() && + II->hasFETokenInfoChangedSinceDeserialization())) + 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::write<uint32_t>(Out, 0, little); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + // Write the identifier table + RecordData::value_type Record[] = {IDENTIFIER_TABLE, BucketOffset}; + Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); + } + + // Write the offsets table for identifier IDs. + auto Abbrev = std::make_shared<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(std::move(Abbrev)); + +#ifndef NDEBUG + for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I) + assert(IdentifierOffsets[I] && "Missing identifier offset?"); +#endif + + RecordData::value_type Record[] = {IDENTIFIER_OFFSET, + IdentifierOffsets.size(), + FirstIdentID - NUM_PREDEF_IDENT_IDS}; + Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, + bytes(IdentifierOffsets)); + + // In C++, write the list of interesting identifiers (those that are + // defined as macros, poisoned, or similar unusual things). + if (!InterestingIdents.empty()) + Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents); +} + +//===----------------------------------------------------------------------===// +// DeclContext's Name Lookup Table Serialization +//===----------------------------------------------------------------------===// + +namespace { + +// Trait used for the on-disk hash table used in the method pool. +class ASTDeclContextNameLookupTrait { + ASTWriter &Writer; + llvm::SmallVector<DeclID, 64> DeclIDs; + +public: + using key_type = DeclarationNameKey; + using key_type_ref = key_type; + + /// A start and end index into DeclIDs, representing a sequence of decls. + using data_type = std::pair<unsigned, unsigned>; + using data_type_ref = const data_type &; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) {} + + template<typename Coll> + data_type getData(const Coll &Decls) { + unsigned Start = DeclIDs.size(); + for (NamedDecl *D : Decls) { + DeclIDs.push_back( + Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D))); + } + return std::make_pair(Start, DeclIDs.size()); + } + + data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { + unsigned Start = DeclIDs.size(); + for (auto ID : FromReader) + DeclIDs.push_back(ID); + return std::make_pair(Start, DeclIDs.size()); + } + + static bool EqualKey(key_type_ref a, key_type_ref b) { + return a == b; + } + + hash_value_type ComputeHash(DeclarationNameKey Name) { + return Name.getHash(); + } + + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { + assert(Writer.hasChain() && + "have reference to loaded module file but no chain?"); + + using namespace llvm::support; + + endian::write<uint32_t>(Out, Writer.getChain()->getModuleFileID(F), little); + } + + std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out, + DeclarationNameKey Name, + data_type_ref Lookup) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + unsigned KeyLen = 1; + switch (Name.getKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: + 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); + + // 4 bytes for each DeclID. + unsigned DataLen = 4 * (Lookup.second - Lookup.first); + assert(uint16_t(DataLen) == DataLen && + "too many decls for serialized lookup result"); + LE.write<uint16_t>(DataLen); + + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + LE.write<uint8_t>(Name.getKind()); + switch (Name.getKind()) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: + LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier())); + return; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + LE.write<uint32_t>(Writer.getSelectorRef(Name.getSelector())); + return; + case DeclarationName::CXXOperatorName: + assert(Name.getOperatorKind() < NUM_OVERLOADED_OPERATORS && + "Invalid operator?"); + LE.write<uint8_t>(Name.getOperatorKind()); + 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 LE(Out, little); + uint64_t Start = Out.tell(); (void)Start; + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) + LE.write<uint32_t>(DeclIDs[I]); + assert(Out.tell() - Start == DataLen && "Data length is wrong"); + } +}; + +} // namespace + +bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, + DeclContext *DC) { + return Result.hasExternalDecls() && + DC->hasNeedToReconcileExternalVisibleStorage(); +} + +bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result, + DeclContext *DC) { + for (auto *D : Result.getLookupResult()) + if (!getDeclForLocalLookup(getLangOpts(), D)->isFromASTFile()) + return false; + + return true; +} + +void +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. + auto *DC = const_cast<DeclContext*>(ConstDC); + assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table"); + + // Create the on-disk hash table representation. + MultiOnDiskHashTableGenerator<reader::ASTDeclContextNameLookupTrait, + 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. If we can't + // write out a lookup set without performing more deserialization, + // just skip this entry. + if (isLookupResultExternal(Result, 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. + llvm::sort(Names); + + 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, Trait.getData(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(), + Trait.getData(ConstructorDecls), Trait); + if (!ConversionDecls.empty()) + Generator.insert(ConversionDecls.front()->getDeclName(), + Trait.getData(ConversionDecls), Trait); + + // Create the on-disk hash table. Also emit the existing imported and + // merged table if there is one. + auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr; + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); +} + +/// 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 we imported a key declaration of this namespace, write the visible + // lookup results as an update record for it rather than including them + // on this declaration. We will only look at key declarations on reload. + if (isa<NamespaceDecl>(DC) && Chain && + Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) { + // Only do this once, for the first local declaration of the namespace. + for (auto *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) + if (!Prev->isFromASTFile()) + return 0; + + // Note that we need to emit an update record for the primary context. + UpdatedDeclContexts.insert(DC->getPrimaryContext()); + + // 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 = DC->getPrimaryContext()->buildLookup(); + SmallVector<std::pair<DeclarationName, DeclContext::lookup_result>, 16> + LookupResults; + if (Map) { + LookupResults.reserve(Map->size()); + for (auto &Entry : *Map) + LookupResults.push_back( + std::make_pair(Entry.first, Entry.second.getLookupResult())); + } + + llvm::sort(LookupResults, 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 (these + // names should never be looked up in a namespace). + assert(Result.empty() && "Cannot have a constructor or conversion " + "function name in a namespace!"); + continue; + } + + for (NamedDecl *ND : Result) + if (!ND->isFromASTFile()) + GetDeclRef(ND); + } + + return 0; + } + + 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; + GenerateNameLookupTable(DC, LookupTable); + + // Write the lookup table + RecordData::value_type Record[] = {DECL_CONTEXT_VISIBLE}; + Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record, + LookupTable); + ++NumVisibleDeclContexts; + return Offset; +} + +/// 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; + GenerateNameLookupTable(DC, LookupTable); + + // If we're updating a namespace, select a key declaration as the key for the + // update record; those are the only ones that will be checked on reload. + if (isa<NamespaceDecl>(DC)) + DC = cast<DeclContext>(Chain->getKeyDeclaration(cast<Decl>(DC))); + + // Write the lookup table + RecordData::value_type Record[] = {UPDATE_VISIBLE, getDeclID(cast<Decl>(DC))}; + Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable); +} + +/// Write an FP_PRAGMA_OPTIONS block for the given FPOptions. +void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { + RecordData::value_type Record[] = {Opts.getInt()}; + Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); +} + +/// 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; + for (const auto &I:Opts.OptMap) { + AddString(I.getKey(), Record); + auto V = I.getValue(); + Record.push_back(V.Supported ? 1 : 0); + Record.push_back(V.Enabled ? 1 : 0); + Record.push_back(V.Avail); + Record.push_back(V.Core); + } + Stream.EmitRecord(OPENCL_EXTENSIONS, Record); +} + +void ASTWriter::WriteOpenCLExtensionTypes(Sema &SemaRef) { + if (!SemaRef.Context.getLangOpts().OpenCL) + return; + + RecordData Record; + for (const auto &I : SemaRef.OpenCLTypeExtMap) { + Record.push_back( + static_cast<unsigned>(getTypeID(I.first->getCanonicalTypeInternal()))); + Record.push_back(I.second.size()); + for (auto Ext : I.second) + AddString(Ext, Record); + } + Stream.EmitRecord(OPENCL_EXTENSION_TYPES, Record); +} + +void ASTWriter::WriteOpenCLExtensionDecls(Sema &SemaRef) { + if (!SemaRef.Context.getLangOpts().OpenCL) + return; + + RecordData Record; + for (const auto &I : SemaRef.OpenCLDeclExtMap) { + Record.push_back(getDeclID(I.first)); + Record.push_back(static_cast<unsigned>(I.second.size())); + for (auto Ext : I.second) + AddString(Ext, Record); + } + Stream.EmitRecord(OPENCL_EXTENSION_DECLS, Record); +} + +void ASTWriter::WriteCUDAPragmas(Sema &SemaRef) { + if (SemaRef.ForceCUDAHostDeviceDepth > 0) { + RecordData::value_type Record[] = {SemaRef.ForceCUDAHostDeviceDepth}; + Stream.EmitRecord(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH, Record); + } +} + +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; + + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned AbbrevID = Stream.EmitAbbrev(std::move(Abbrev)); + + RecordData::value_type Record[] = {OBJC_CATEGORIES_MAP, 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 (const auto &Tok : LPT.Toks) { + AddToken(Tok, Record); + } + } + Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record); +} + +/// 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); +} + +/// Write the state of 'pragma ms_struct' at the end of the module. +void ASTWriter::WriteMSStructPragmaOptions(Sema &SemaRef) { + RecordData Record; + Record.push_back(SemaRef.MSStructPragmaOn ? PMSST_ON : PMSST_OFF); + Stream.EmitRecord(MSSTRUCT_PRAGMA_OPTIONS, Record); +} + +/// Write the state of 'pragma pointers_to_members' at the end of the +//module. +void ASTWriter::WriteMSPointersToMembersPragmaOptions(Sema &SemaRef) { + RecordData Record; + Record.push_back(SemaRef.MSPointerToMemberRepresentationMethod); + AddSourceLocation(SemaRef.ImplicitMSInheritanceAttrLoc, Record); + Stream.EmitRecord(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS, Record); +} + +/// Write the state of 'pragma pack' at the end of the module. +void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) { + // Don't serialize pragma pack state for modules, since it should only take + // effect on a per-submodule basis. + if (WritingModule) + return; + + RecordData Record; + Record.push_back(SemaRef.PackStack.CurrentValue); + AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record); + Record.push_back(SemaRef.PackStack.Stack.size()); + for (const auto &StackEntry : SemaRef.PackStack.Stack) { + Record.push_back(StackEntry.Value); + AddSourceLocation(StackEntry.PragmaLocation, Record); + AddSourceLocation(StackEntry.PragmaPushLocation, Record); + AddString(StackEntry.StackSlotLabel, Record); + } + Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record); +} + +void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, + ModuleFileExtensionWriter &Writer) { + // Enter the extension block. + Stream.EnterSubblock(EXTENSION_BLOCK_ID, 4); + + // Emit the metadata record abbreviation. + auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); + Abv->Add(llvm::BitCodeAbbrevOp(EXTENSION_METADATA)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + unsigned Abbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Emit the metadata record. + RecordData Record; + auto Metadata = Writer.getExtension()->getExtensionMetadata(); + Record.push_back(EXTENSION_METADATA); + Record.push_back(Metadata.MajorVersion); + Record.push_back(Metadata.MinorVersion); + Record.push_back(Metadata.BlockName.size()); + Record.push_back(Metadata.UserInfo.size()); + SmallString<64> Buffer; + Buffer += Metadata.BlockName; + Buffer += Metadata.UserInfo; + Stream.EmitRecordWithBlob(Abbrev, Record, Buffer); + + // Emit the contents of the extension block. + Writer.writeExtensionContents(SemaRef, Stream); + + // Exit the extension block. + Stream.ExitBlock(); +} + +//===----------------------------------------------------------------------===// +// General Serialization Routines +//===----------------------------------------------------------------------===// + +void ASTRecordWriter::AddAttr(const Attr *A) { + auto &Record = *this; + if (!A) + return Record.push_back(0); + Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs + Record.AddSourceRange(A->getRange()); + +#include "clang/Serialization/AttrPCHWrite.inc" +} + +/// Emit the list of attributes to the specified record. +void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) { + push_back(Attrs.size()); + for (const auto *A : Attrs) + AddAttr(A); +} + +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, RecordDataRef 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); +} + +/// 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; +} + +/// 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, + SmallVectorImpl<char> &Buffer, MemoryBufferCache &PCMCache, + ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, + bool IncludeTimestamps) + : Stream(Stream), Buffer(Buffer), PCMCache(PCMCache), + IncludeTimestamps(IncludeTimestamps) { + for (const auto &Ext : Extensions) { + if (auto Writer = Ext->createExtensionWriter(*this)) + ModuleFileExtensionWriters.push_back(std::move(Writer)); + } +} + +ASTWriter::~ASTWriter() { + llvm::DeleteContainerSeconds(FileDeclIDs); +} + +const LangOptions &ASTWriter::getLangOpts() const { + assert(WritingAST && "can't determine lang opts when not writing AST"); + return Context->getLangOpts(); +} + +time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const { + return IncludeTimestamps ? E->getModificationTime() : 0; +} + +ASTFileSignature 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; + ASTFileSignature Signature = + WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); + Context = nullptr; + PP = nullptr; + this->WritingModule = nullptr; + this->BaseDirectory.clear(); + + WritingAST = false; + if (SemaRef.Context.getLangOpts().ImplicitModules && WritingModule) { + // Construct MemoryBuffer and update buffer manager. + PCMCache.addBuffer(OutputFile, + llvm::MemoryBuffer::getMemBufferCopy( + StringRef(Buffer.begin(), Buffer.size()))); + } + return Signature; +} + +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); + } +} + +ASTFileSignature 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. + auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) { + if (D) { + assert(D->isCanonicalDecl() && "predefined decl is not canonical"); + DeclIDs[D] = ID; + } + }; + RegisterPredefDecl(Context.getTranslationUnitDecl(), + PREDEF_DECL_TRANSLATION_UNIT_ID); + RegisterPredefDecl(Context.ObjCIdDecl, PREDEF_DECL_OBJC_ID_ID); + RegisterPredefDecl(Context.ObjCSelDecl, PREDEF_DECL_OBJC_SEL_ID); + RegisterPredefDecl(Context.ObjCClassDecl, PREDEF_DECL_OBJC_CLASS_ID); + RegisterPredefDecl(Context.ObjCProtocolClassDecl, + PREDEF_DECL_OBJC_PROTOCOL_ID); + RegisterPredefDecl(Context.Int128Decl, PREDEF_DECL_INT_128_ID); + RegisterPredefDecl(Context.UInt128Decl, PREDEF_DECL_UNSIGNED_INT_128_ID); + RegisterPredefDecl(Context.ObjCInstanceTypeDecl, + PREDEF_DECL_OBJC_INSTANCETYPE_ID); + RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); + RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG); + RegisterPredefDecl(Context.BuiltinMSVaListDecl, + PREDEF_DECL_BUILTIN_MS_VA_LIST_ID); + RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); + RegisterPredefDecl(Context.MakeIntegerSeqDecl, + PREDEF_DECL_MAKE_INTEGER_SEQ_ID); + RegisterPredefDecl(Context.CFConstantStringTypeDecl, + PREDEF_DECL_CF_CONSTANT_STRING_ID); + RegisterPredefDecl(Context.CFConstantStringTagDecl, + PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID); + RegisterPredefDecl(Context.TypePackElementDecl, + PREDEF_DECL_TYPE_PACK_ELEMENT_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 (const auto &I : SemaRef.PendingInstantiations) { + 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 || SemaRef.StdAlignValT) { + AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs); + AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); + AddDeclRef(SemaRef.getStdAlignValT(), SemaDeclRefs); + } + + RecordData CUDASpecialDeclRefs; + if (Context.getcudaConfigureCallDecl()) { + AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs); + } + + // Build a record containing all of the known namespaces. + RecordData KnownNamespaces; + for (const auto &I : SemaRef.KnownNamespaces) { + 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 (const auto &I : Undefined) { + 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; + + if (!isModule) { + 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. + 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. + { + RecordData Record = {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<uint32_t, 128> NewGlobalKindDeclPairs; + for (const auto *D : TU->noload_decls()) { + if (!D->isFromASTFile()) { + NewGlobalKindDeclPairs.push_back(D->getKind()); + NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); + } + } + + auto Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); + { + RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; + Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, + bytes(NewGlobalKindDeclPairs)); + } + + // And a visible updates block for the translation unit. + Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(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. Likewise for template + // specializations added to imported templates. + for (const auto *I : DeclsToEmitEvenIfUnreferenced) { + GetDeclRef(I); + } + + // Make sure all decls associated with an identifier are registered for + // serialization, if we're storing decls with identifiers. + if (!WritingModule || !getLangOpts().CPlusPlus) { + llvm::SmallVector<const IdentifierInfo*, 256> IIs; + for (const auto &ID : PP.getIdentifierTable()) { + const IdentifierInfo *II = ID.second; + if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) + IIs.push_back(II); + } + // Sort the identifiers to visit based on their name. + llvm::sort(IIs, 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); + } + } + } + + // For method pool in the module, if it contains an entry for a selector, + // the entry should be complete, containing everything introduced by that + // module and all modules it imports. It's possible that the entry is out of + // date, so we need to pull in the new content here. + + // It's possible that updateOutOfDateSelector can update SelectorIDs. To be + // safe, we copy all selectors out. + llvm::SmallVector<Selector, 256> AllSelectors; + for (auto &SelectorAndID : SelectorIDs) + AllSelectors.push_back(SelectorAndID.first); + for (auto &Selector : AllSelectors) + SemaRef.updateOutOfDateSelector(Selector); + + // 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-kind:i8 + // 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) + // + // module-kind is the ModuleKind enum value. If it is MK_PrebuiltModule or + // MK_ExplicitModule, then the module-name is the module name. Otherwise, + // it is the module file name. + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + SmallString<2048> Buffer; + { + llvm::raw_svector_ostream Out(Buffer); + for (ModuleFile &M : Chain->ModuleMgr) { + using namespace llvm::support; + + endian::Writer LE(Out, little); + LE.write<uint8_t>(static_cast<uint8_t>(M.Kind)); + StringRef Name = + M.Kind == MK_PrebuiltModule || M.Kind == MK_ExplicitModule + ? M.ModuleName + : M.FileName; + LE.write<uint16_t>(Name.size()); + Out.write(Name.data(), Name.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); + } + } + RecordData::value_type Record[] = {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(); + 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); + WriteFileDeclIDsMap(); + WriteSourceManagerBlock(Context.getSourceManager(), PP); + WriteComments(); + WritePreprocessor(PP, isModule); + WriteHeaderSearch(PP.getHeaderSearchInfo()); + WriteSelectors(SemaRef); + WriteReferencedSelectorsPool(SemaRef); + WriteLateParsedTemplates(SemaRef); + WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); + WriteFPPragmaOptions(SemaRef.getFPOptions()); + WriteOpenCLExtensions(SemaRef); + WriteOpenCLExtensionTypes(SemaRef); + WriteCUDAPragmas(SemaRef); + + // If we're emitting a module, write out the submodule information. + if (WritingModule) + WriteSubmodules(WritingModule); + + // We need to have information about submodules to correctly deserialize + // decls from OpenCLExtensionDecls block + WriteOpenCLExtensionDecls(SemaRef); + + Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes); + + // Write the record containing external, unnamed definitions. + if (!EagerlyDeserializedDecls.empty()) + Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls); + + if (!ModularCodegenDecls.empty()) + Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls); + + // 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. + llvm::sort(Imports, 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); + } + } + + WriteObjCCategories(); + if(!WritingModule) { + WriteOptimizePragmaOptions(SemaRef); + WriteMSStructPragmaOptions(SemaRef); + WriteMSPointersToMembersPragmaOptions(SemaRef); + } + WritePackPragmaOptions(SemaRef); + + // Some simple statistics + RecordData::value_type Record[] = { + NumStatements, NumMacros, NumLexicalDeclContexts, NumVisibleDeclContexts}; + Stream.EmitRecord(STATISTICS, Record); + Stream.ExitBlock(); + + // Write the module file extension blocks. + for (const auto &ExtWriter : ModuleFileExtensionWriters) + WriteModuleFileExtension(SemaRef, *ExtWriter); + + return writeUnhashedControlBlock(PP, Context); +} + +void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { + if (DeclUpdates.empty()) + return; + + DeclUpdateMap LocalUpdates; + LocalUpdates.swap(DeclUpdates); + + for (auto &DeclUpdate : LocalUpdates) { + const Decl *D = DeclUpdate.first; + + bool HasUpdatedBody = false; + RecordData RecordData; + ASTRecordWriter Record(*this, RecordData); + for (auto &Update : DeclUpdate.second) { + DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind(); + + // 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. + if (Kind == UPD_CXX_ADDED_FUNCTION_DEFINITION) + HasUpdatedBody = true; + else + 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: + break; + + case UPD_CXX_POINT_OF_INSTANTIATION: + // FIXME: Do we need to also save the template specialization kind here? + Record.AddSourceLocation(Update.getLoc()); + break; + + case UPD_CXX_ADDED_VAR_DEFINITION: { + const VarDecl *VD = cast<VarDecl>(D); + Record.push_back(VD->isInline()); + Record.push_back(VD->isInlineSpecified()); + if (VD->getInit()) { + Record.push_back(!VD->isInitKnownICE() ? 1 + : (VD->isInitICE() ? 3 : 2)); + Record.AddStmt(const_cast<Expr*>(VD->getInit())); + } else { + Record.push_back(0); + } + break; + } + + case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: + Record.AddStmt(const_cast<Expr *>( + cast<ParmVarDecl>(Update.getDecl())->getDefaultArg())); + break; + + case UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER: + Record.AddStmt( + cast<FieldDecl>(Update.getDecl())->getInClassInitializer()); + break; + + case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { + auto *RD = cast<CXXRecordDecl>(D); + UpdatedDeclContexts.insert(RD->getPrimaryContext()); + Record.push_back(RD->isParamDestroyedInCallee()); + Record.push_back(RD->getArgPassingRestrictions()); + Record.AddCXXDefinitionData(RD); + Record.AddOffset(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()); + Record.AddSourceLocation(MSInfo->getPointOfInstantiation()); + } else { + auto *Spec = cast<ClassTemplateSpecializationDecl>(RD); + Record.push_back(Spec->getTemplateSpecializationKind()); + Record.AddSourceLocation(Spec->getPointOfInstantiation()); + + // 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); + Record.AddDeclRef(PartialSpec); + Record.AddTemplateArgumentList( + &Spec->getTemplateInstantiationArgs()); + } else { + Record.push_back(false); + } + } + Record.push_back(RD->getTagKind()); + Record.AddSourceLocation(RD->getLocation()); + Record.AddSourceLocation(RD->getBeginLoc()); + Record.AddSourceRange(RD->getBraceRange()); + + // Instantiation may change attributes; write them all out afresh. + Record.push_back(D->hasAttrs()); + if (D->hasAttrs()) + Record.AddAttributes(D->getAttrs()); + + // FIXME: Ensure we don't get here for explicit instantiations. + break; + } + + case UPD_CXX_RESOLVED_DTOR_DELETE: + Record.AddDeclRef(Update.getDecl()); + Record.AddStmt(cast<CXXDestructorDecl>(D)->getOperatorDeleteThisArg()); + break; + + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: + addExceptionSpec( + 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: + Record.AddSourceRange( + D->getAttr<OMPThreadPrivateDeclAttr>()->getRange()); + break; + + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + Record.push_back(D->getAttr<OMPDeclareTargetDeclAttr>()->getMapType()); + Record.AddSourceRange( + D->getAttr<OMPDeclareTargetDeclAttr>()->getRange()); + break; + + case UPD_DECL_EXPORTED: + Record.push_back(getSubmoduleID(Update.getModule())); + break; + + case UPD_ADDED_ATTR_TO_RECORD: + Record.AddAttributes(llvm::makeArrayRef(Update.getAttr())); + break; + } + } + + if (HasUpdatedBody) { + const auto *Def = cast<FunctionDecl>(D); + Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION); + Record.push_back(Def->isInlined()); + Record.AddSourceLocation(Def->getInnerLocStart()); + Record.AddFunctionDefinition(Def); + } + + OffsetsRecord.push_back(GetDeclRef(D)); + OffsetsRecord.push_back(Record.Emit(DECL_UPDATES)); + } +} + +void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) { + uint32_t Raw = Loc.getRawEncoding(); + Record.push_back((Raw << 1) | (Raw >> 31)); +} + +void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) { + AddSourceLocation(Range.getBegin(), Record); + AddSourceLocation(Range.getEnd(), Record); +} + +void ASTRecordWriter::AddAPInt(const llvm::APInt &Value) { + Record->push_back(Value.getBitWidth()); + const uint64_t *Words = Value.getRawData(); + Record->append(Words, Words + Value.getNumWords()); +} + +void ASTRecordWriter::AddAPSInt(const llvm::APSInt &Value) { + Record->push_back(Value.isUnsigned()); + AddAPInt(Value); +} + +void ASTRecordWriter::AddAPFloat(const llvm::APFloat &Value) { + AddAPInt(Value.bitcastToAPInt()); +} + +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 ASTRecordWriter::AddSelectorRef(const Selector SelRef) { + Record->push_back(Writer->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 ASTRecordWriter::AddCXXTemporary(const CXXTemporary *Temp) { + AddDeclRef(Temp->getDestructor()); +} + +void ASTRecordWriter::AddTemplateArgumentLocInfo( + TemplateArgument::ArgKind Kind, const TemplateArgumentLocInfo &Arg) { + switch (Kind) { + case TemplateArgument::Expression: + AddStmt(Arg.getAsExpr()); + break; + case TemplateArgument::Type: + AddTypeSourceInfo(Arg.getAsTypeSourceInfo()); + break; + case TemplateArgument::Template: + AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc()); + AddSourceLocation(Arg.getTemplateNameLoc()); + break; + case TemplateArgument::TemplateExpansion: + AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc()); + AddSourceLocation(Arg.getTemplateNameLoc()); + AddSourceLocation(Arg.getTemplateEllipsisLoc()); + break; + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::Pack: + // FIXME: Is this right? + break; + } +} + +void ASTRecordWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg) { + AddTemplateArgument(Arg.getArgument()); + + 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()); +} + +void ASTRecordWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo) { + if (!TInfo) { + AddTypeRef(QualType()); + return; + } + + AddTypeRef(TInfo->getType()); + AddTypeLoc(TInfo->getTypeLoc()); +} + +void ASTRecordWriter::AddTypeLoc(TypeLoc TL) { + TypeLocWriter TLW(*this); + 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. + // TemplateTemplateParmDecls that are part of an alias template, should not + // have TU as lexical context. + if (isa<ParmVarDecl>(D) || isa<TemplateTemplateParmDecl>(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 ASTRecordWriter::AddDeclarationName(DeclarationName Name) { + // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. + Record->push_back(Name.getNameKind()); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + AddIdentifierRef(Name.getAsIdentifierInfo()); + break; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + AddSelectorRef(Name.getObjCSelector()); + break; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + AddTypeRef(Name.getCXXNameType()); + break; + + case DeclarationName::CXXDeductionGuideName: + AddDeclRef(Name.getCXXDeductionGuideTemplate()); + break; + + case DeclarationName::CXXOperatorName: + Record->push_back(Name.getCXXOverloadedOperator()); + break; + + case DeclarationName::CXXLiteralOperatorName: + AddIdentifierRef(Name.getCXXLiteralIdentifier()); + 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 ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, + DeclarationName Name) { + switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + AddTypeSourceInfo(DNLoc.NamedType.TInfo); + break; + + case DeclarationName::CXXOperatorName: + AddSourceLocation(SourceLocation::getFromRawEncoding( + DNLoc.CXXOperatorName.BeginOpNameLoc)); + AddSourceLocation( + SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.EndOpNameLoc)); + break; + + case DeclarationName::CXXLiteralOperatorName: + AddSourceLocation(SourceLocation::getFromRawEncoding( + DNLoc.CXXLiteralOperatorName.OpNameLoc)); + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: + break; + } +} + +void ASTRecordWriter::AddDeclarationNameInfo( + const DeclarationNameInfo &NameInfo) { + AddDeclarationName(NameInfo.getName()); + AddSourceLocation(NameInfo.getLoc()); + AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName()); +} + +void ASTRecordWriter::AddQualifierInfo(const QualifierInfo &Info) { + AddNestedNameSpecifierLoc(Info.QualifierLoc); + Record->push_back(Info.NumTemplParamLists); + for (unsigned i = 0, e = Info.NumTemplParamLists; i != e; ++i) + AddTemplateParameterList(Info.TemplParamLists[i]); +} + +void ASTRecordWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS) { + // 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()); + break; + + case NestedNameSpecifier::Namespace: + AddDeclRef(NNS->getAsNamespace()); + break; + + case NestedNameSpecifier::NamespaceAlias: + AddDeclRef(NNS->getAsNamespaceAlias()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + AddTypeRef(QualType(NNS->getAsType(), 0)); + 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()); + break; + } + } +} + +void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + // 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()); + AddSourceRange(NNS.getLocalSourceRange()); + break; + + case NestedNameSpecifier::Namespace: + AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace()); + AddSourceRange(NNS.getLocalSourceRange()); + break; + + case NestedNameSpecifier::NamespaceAlias: + AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias()); + AddSourceRange(NNS.getLocalSourceRange()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + Record->push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); + AddTypeRef(NNS.getTypeLoc().getType()); + AddTypeLoc(NNS.getTypeLoc()); + AddSourceLocation(NNS.getLocalSourceRange().getEnd()); + break; + + case NestedNameSpecifier::Global: + AddSourceLocation(NNS.getLocalSourceRange().getEnd()); + break; + + case NestedNameSpecifier::Super: + AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl()); + AddSourceRange(NNS.getLocalSourceRange()); + break; + } + } +} + +void ASTRecordWriter::AddTemplateName(TemplateName Name) { + TemplateName::NameKind Kind = Name.getKind(); + Record->push_back(Kind); + switch (Kind) { + case TemplateName::Template: + AddDeclRef(Name.getAsTemplateDecl()); + break; + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); + Record->push_back(OvT->size()); + for (const auto &I : *OvT) + AddDeclRef(I); + break; + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName(); + AddNestedNameSpecifier(QualT->getQualifier()); + Record->push_back(QualT->hasTemplateKeyword()); + AddDeclRef(QualT->getTemplateDecl()); + break; + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DepT = Name.getAsDependentTemplateName(); + AddNestedNameSpecifier(DepT->getQualifier()); + Record->push_back(DepT->isIdentifier()); + if (DepT->isIdentifier()) + AddIdentifierRef(DepT->getIdentifier()); + else + Record->push_back(DepT->getOperator()); + break; + } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + AddDeclRef(subst->getParameter()); + AddTemplateName(subst->getReplacement()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack(); + AddDeclRef(SubstPack->getParameterPack()); + AddTemplateArgument(SubstPack->getArgumentPack()); + break; + } + } +} + +void ASTRecordWriter::AddTemplateArgument(const TemplateArgument &Arg) { + Record->push_back(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + case TemplateArgument::Type: + AddTypeRef(Arg.getAsType()); + break; + case TemplateArgument::Declaration: + AddDeclRef(Arg.getAsDecl()); + AddTypeRef(Arg.getParamTypeForDecl()); + break; + case TemplateArgument::NullPtr: + AddTypeRef(Arg.getNullPtrType()); + break; + case TemplateArgument::Integral: + AddAPSInt(Arg.getAsIntegral()); + AddTypeRef(Arg.getIntegralType()); + break; + case TemplateArgument::Template: + AddTemplateName(Arg.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::TemplateExpansion: + AddTemplateName(Arg.getAsTemplateOrTemplatePattern()); + 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); + break; + } +} + +void ASTRecordWriter::AddTemplateParameterList( + const TemplateParameterList *TemplateParams) { + assert(TemplateParams && "No TemplateParams!"); + AddSourceLocation(TemplateParams->getTemplateLoc()); + AddSourceLocation(TemplateParams->getLAngleLoc()); + AddSourceLocation(TemplateParams->getRAngleLoc()); + // TODO: Concepts + Record->push_back(TemplateParams->size()); + for (const auto &P : *TemplateParams) + AddDeclRef(P); +} + +/// Emit a template argument list. +void ASTRecordWriter::AddTemplateArgumentList( + const TemplateArgumentList *TemplateArgs) { + assert(TemplateArgs && "No TemplateArgs!"); + Record->push_back(TemplateArgs->size()); + for (int i = 0, e = TemplateArgs->size(); i != e; ++i) + AddTemplateArgument(TemplateArgs->get(i)); +} + +void ASTRecordWriter::AddASTTemplateArgumentListInfo( + const ASTTemplateArgumentListInfo *ASTTemplArgList) { + assert(ASTTemplArgList && "No ASTTemplArgList!"); + AddSourceLocation(ASTTemplArgList->LAngleLoc); + AddSourceLocation(ASTTemplArgList->RAngleLoc); + Record->push_back(ASTTemplArgList->NumTemplateArgs); + const TemplateArgumentLoc *TemplArgs = ASTTemplArgList->getTemplateArgs(); + for (int i = 0, e = ASTTemplArgList->NumTemplateArgs; i != e; ++i) + AddTemplateArgumentLoc(TemplArgs[i]); +} + +void ASTRecordWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set) { + Record->push_back(Set.size()); + for (ASTUnresolvedSet::const_iterator + I = Set.begin(), E = Set.end(); I != E; ++I) { + AddDeclRef(I.getDecl()); + Record->push_back(I.getAccess()); + } +} + +// FIXME: Move this out of the main ASTRecordWriter interface. +void ASTRecordWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base) { + Record->push_back(Base.isVirtual()); + Record->push_back(Base.isBaseOfClass()); + Record->push_back(Base.getAccessSpecifierAsWritten()); + Record->push_back(Base.getInheritConstructors()); + AddTypeSourceInfo(Base.getTypeSourceInfo()); + AddSourceRange(Base.getSourceRange()); + AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc() + : SourceLocation()); +} + +static uint64_t EmitCXXBaseSpecifiers(ASTWriter &W, + ArrayRef<CXXBaseSpecifier> Bases) { + ASTWriter::RecordData Record; + ASTRecordWriter Writer(W, Record); + Writer.push_back(Bases.size()); + + for (auto &Base : Bases) + Writer.AddCXXBaseSpecifier(Base); + + return Writer.Emit(serialization::DECL_CXX_BASE_SPECIFIERS); +} + +// FIXME: Move this out of the main ASTRecordWriter interface. +void ASTRecordWriter::AddCXXBaseSpecifiers(ArrayRef<CXXBaseSpecifier> Bases) { + AddOffset(EmitCXXBaseSpecifiers(*Writer, Bases)); +} + +static uint64_t +EmitCXXCtorInitializers(ASTWriter &W, + ArrayRef<CXXCtorInitializer *> CtorInits) { + ASTWriter::RecordData Record; + ASTRecordWriter Writer(W, Record); + Writer.push_back(CtorInits.size()); + + for (auto *Init : CtorInits) { + if (Init->isBaseInitializer()) { + Writer.push_back(CTOR_INITIALIZER_BASE); + Writer.AddTypeSourceInfo(Init->getTypeSourceInfo()); + Writer.push_back(Init->isBaseVirtual()); + } else if (Init->isDelegatingInitializer()) { + Writer.push_back(CTOR_INITIALIZER_DELEGATING); + Writer.AddTypeSourceInfo(Init->getTypeSourceInfo()); + } else if (Init->isMemberInitializer()){ + Writer.push_back(CTOR_INITIALIZER_MEMBER); + Writer.AddDeclRef(Init->getMember()); + } else { + Writer.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER); + Writer.AddDeclRef(Init->getIndirectMember()); + } + + Writer.AddSourceLocation(Init->getMemberLocation()); + Writer.AddStmt(Init->getInit()); + Writer.AddSourceLocation(Init->getLParenLoc()); + Writer.AddSourceLocation(Init->getRParenLoc()); + Writer.push_back(Init->isWritten()); + if (Init->isWritten()) + Writer.push_back(Init->getSourceOrder()); + } + + return Writer.Emit(serialization::DECL_CXX_CTOR_INITIALIZERS); +} + +// FIXME: Move this out of the main ASTRecordWriter interface. +void ASTRecordWriter::AddCXXCtorInitializers( + ArrayRef<CXXCtorInitializer *> CtorInits) { + AddOffset(EmitCXXCtorInitializers(*Writer, CtorInits)); +} + +void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { + 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.IsCXX11StandardLayout); + Record->push_back(Data.HasBasesWithFields); + Record->push_back(Data.HasBasesWithNonStaticDataMembers); + 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.HasUninitializedFields); + Record->push_back(Data.HasInheritedConstructor); + Record->push_back(Data.HasInheritedAssignment); + Record->push_back(Data.NeedOverloadResolutionForCopyConstructor); + Record->push_back(Data.NeedOverloadResolutionForMoveConstructor); + Record->push_back(Data.NeedOverloadResolutionForMoveAssignment); + Record->push_back(Data.NeedOverloadResolutionForDestructor); + Record->push_back(Data.DefaultedCopyConstructorIsDeleted); + Record->push_back(Data.DefaultedMoveConstructorIsDeleted); + Record->push_back(Data.DefaultedMoveAssignmentIsDeleted); + Record->push_back(Data.DefaultedDestructorIsDeleted); + Record->push_back(Data.HasTrivialSpecialMembers); + Record->push_back(Data.HasTrivialSpecialMembersForCall); + Record->push_back(Data.DeclaredNonTrivialSpecialMembers); + Record->push_back(Data.DeclaredNonTrivialSpecialMembersForCall); + Record->push_back(Data.HasIrrelevantDestructor); + Record->push_back(Data.HasConstexprNonCopyMoveConstructor); + Record->push_back(Data.HasDefaultedDefaultConstructor); + 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.ImplicitCopyConstructorCanHaveConstParamForVBase); + Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase); + Record->push_back(Data.ImplicitCopyAssignmentHasConstParam); + Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam); + Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam); + + // getODRHash will compute the ODRHash if it has not been previously computed. + Record->push_back(D->getODRHash()); + bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo && + Writer->WritingModule && !D->isDependentType(); + Record->push_back(ModulesDebugInfo); + if (ModulesDebugInfo) + Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D)); + + // IsLambda bit is already saved. + + Record->push_back(Data.NumBases); + if (Data.NumBases > 0) + AddCXXBaseSpecifiers(Data.bases()); + + // FIXME: Make VBases lazily computed when needed to avoid storing them. + Record->push_back(Data.NumVBases); + if (Data.NumVBases > 0) + AddCXXBaseSpecifiers(Data.vbases()); + + AddUnresolvedSet(Data.Conversions.get(*Writer->Context)); + AddUnresolvedSet(Data.VisibleConversions.get(*Writer->Context)); + // Data.Definition is the owning decl, no need to write it. + AddDeclRef(D->getFirstFriend()); + + // 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(D->getLambdaContextDecl()); + AddTypeSourceInfo(Lambda.MethodTyInfo); + for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { + const LambdaCapture &Capture = Lambda.Captures[I]; + AddSourceLocation(Capture.getLocation()); + Record->push_back(Capture.isImplicit()); + Record->push_back(Capture.getCaptureKind()); + switch (Capture.getCaptureKind()) { + case LCK_StarThis: + case LCK_This: + case LCK_VLAType: + break; + case LCK_ByCopy: + case LCK_ByRef: + VarDecl *Var = + Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr; + AddDeclRef(Var); + AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc() + : SourceLocation()); + 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) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(D->isCompleteDefinition()); + assert(!WritingAST && "Already writing the AST!"); + if (auto *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)); + } + } +} + +static bool isImportedDeclContext(ASTReader *Chain, const Decl *D) { + if (D->isFromASTFile()) + return true; + + // The predefined __va_list_tag struct is imported if we imported any decls. + // FIXME: This is a gross hack. + return D == D->getASTContext().getVaListTagDecl(); +} + +void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(DC->isLookupContext() && + "Should not add lookup results to non-lookup contexts!"); + + // TU is handled elsewhere. + if (isa<TranslationUnitDecl>(DC)) + return; + + // Namespaces are handled elsewhere, except for template instantiations of + // FunctionTemplateDecls in namespaces. We are interested in cases where the + // local instantiations are added to an imported context. Only happens when + // adding ADL lookup candidates, for example templated friends. + if (isa<NamespaceDecl>(DC) && D->getFriendObjectKind() == Decl::FOK_None && + !isa<FunctionTemplateDecl>(D)) + return; + + // We're only interested in cases where a local declaration is added to an + // imported context. + if (D->isFromASTFile() || !isImportedDeclContext(Chain, cast<Decl>(DC))) + return; + + assert(DC == DC->getPrimaryContext() && "added to non-primary context"); + assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!"); + assert(!WritingAST && "Already writing the AST!"); + if (UpdatedDeclContexts.insert(DC) && !cast<Decl>(DC)->isFromASTFile()) { + // We're adding a visible declaration to a predefined decl context. Ensure + // that we write out all of its lookup results so we don't get a nasty + // surprise when we try to emit its lookup table. + for (auto *Child : DC->decls()) + DeclsToEmitEvenIfUnreferenced.push_back(Child); + } + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(D->isImplicit()); + + // We're only interested in cases where a local declaration is added to an + // imported context. + if (D->isFromASTFile() || !isImportedDeclContext(Chain, RD)) + return; + + if (!isa<CXXMethodDecl>(D)) + return; + + // 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::ResolvedExceptionSpec(const FunctionDecl *FD) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); + if (!Chain) return; + Chain->forEachImportedKeyDecl(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) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!Chain) return; + Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); + }); +} + +void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, + const FunctionDecl *Delete, + Expr *ThisArg) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + assert(Delete && "Not given an operator delete"); + if (!Chain) return; + Chain->forEachImportedKeyDecl(DD, [&](const Decl *D) { + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); + }); +} + +void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + 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::VariableDefinitionInstantiated(const VarDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_VAR_DEFINITION)); +} + +void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); +} + +void ASTWriter::InstantiationRequested(const ValueDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + 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. + SourceLocation POI; + if (auto *VD = dyn_cast<VarDecl>(D)) + POI = VD->getPointOfInstantiation(); + else + POI = cast<FunctionDecl>(D)->getPointOfInstantiation(); + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_POINT_OF_INSTANTIATION, POI)); +} + +void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, D)); +} + +void ASTWriter::DefaultMemberInitializerInstantiated(const FieldDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, D)); +} + +void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + 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::DeclarationMarkedUsed(const Decl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + + // If there is *any* declaration of the entity that's not from an AST file, + // we can skip writing the update record. We make sure that isUsed() triggers + // completion of the redeclaration chain of the entity. + for (auto Prev = D->getMostRecentDecl(); Prev; Prev = Prev->getPreviousDecl()) + if (IsLocalDecl(Prev)) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED)); +} + +void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE)); +} + +void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D, + const Attr *Attr) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back( + DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARETARGET, Attr)); +} + +void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + assert(D->isHidden() && "expected a hidden declaration"); + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M)); +} + +void ASTWriter::AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) { + if (Chain && Chain->isProcessingUpdateRecords()) return; + assert(!WritingAST && "Already writing the AST!"); + if (!Record->isFromASTFile()) + return; + DeclUpdates[Record].push_back(DeclUpdate(UPD_ADDED_ATTR_TO_RECORD, Attr)); +} + +void ASTWriter::AddedCXXTemplateSpecialization( + const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +void ASTWriter::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +//===----------------------------------------------------------------------===// +//// OMPClause Serialization +////===----------------------------------------------------------------------===// + +void OMPClauseWriter::writeClause(OMPClause *C) { + Record.push_back(C->getClauseKind()); + Visit(C); + Record.AddSourceLocation(C->getBeginLoc()); + Record.AddSourceLocation(C->getEndLoc()); +} + +void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { + Record.push_back(C->getCaptureRegion()); + Record.AddStmt(C->getPreInitStmt()); +} + +void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getPostUpdateExpr()); +} + +void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { + VisitOMPClauseWithPreInit(C); + Record.push_back(C->getNameModifier()); + Record.AddSourceLocation(C->getNameModifierLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.AddStmt(C->getCondition()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) { + Record.AddStmt(C->getCondition()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getNumThreads()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) { + Record.AddStmt(C->getSafelen()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + Record.AddStmt(C->getSimdlen()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) { + Record.AddStmt(C->getNumForLoops()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { + Record.push_back(C->getDefaultKind()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getDefaultKindKwLoc()); +} + +void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { + Record.push_back(C->getProcBindKind()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getProcBindKindKwLoc()); +} + +void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) { + VisitOMPClauseWithPreInit(C); + Record.push_back(C->getScheduleKind()); + Record.push_back(C->getFirstScheduleModifier()); + Record.push_back(C->getSecondScheduleModifier()); + Record.AddStmt(C->getChunkSize()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getFirstScheduleModifierLoc()); + Record.AddSourceLocation(C->getSecondScheduleModifierLoc()); + Record.AddSourceLocation(C->getScheduleKindLoc()); + Record.AddSourceLocation(C->getCommaLoc()); +} + +void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) { + Record.push_back(C->getLoopNumIterations().size()); + Record.AddStmt(C->getNumForLoops()); + for (Expr *NumIter : C->getLoopNumIterations()) + Record.AddStmt(NumIter); + for (unsigned I = 0, E = C->getLoopNumIterations().size(); I <E; ++I) + Record.AddStmt(C->getLoopCounter(I)); + Record.AddSourceLocation(C->getLParenLoc()); +} + +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::VisitOMPThreadsClause(OMPThreadsClause *) {} + +void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {} + +void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {} + +void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) { + Record.AddStmt(VE); + } + for (auto *VE : C->private_copies()) { + Record.AddStmt(VE); + } +} + +void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPreInit(C); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) { + Record.AddStmt(VE); + } + for (auto *VE : C->private_copies()) { + Record.AddStmt(VE); + } + for (auto *VE : C->inits()) { + Record.AddStmt(VE); + } +} + +void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *E : C->private_copies()) + Record.AddStmt(E); + for (auto *E : C->source_exprs()) + Record.AddStmt(E); + for (auto *E : C->destination_exprs()) + Record.AddStmt(E); + for (auto *E : C->assignment_ops()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); +} + +void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); + Record.AddDeclarationNameInfo(C->getNameInfo()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *VE : C->privates()) + Record.AddStmt(VE); + for (auto *E : C->lhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->rhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->reduction_ops()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); + Record.AddDeclarationNameInfo(C->getNameInfo()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *VE : C->privates()) + Record.AddStmt(VE); + for (auto *E : C->lhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->rhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->reduction_ops()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPInReductionClause(OMPInReductionClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); + Record.AddDeclarationNameInfo(C->getNameInfo()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *VE : C->privates()) + Record.AddStmt(VE); + for (auto *E : C->lhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->rhs_exprs()) + Record.AddStmt(E); + for (auto *E : C->reduction_ops()) + Record.AddStmt(E); + for (auto *E : C->taskgroup_descriptors()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { + Record.push_back(C->varlist_size()); + VisitOMPClauseWithPostUpdate(C); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + Record.push_back(C->getModifier()); + Record.AddSourceLocation(C->getModifierLoc()); + for (auto *VE : C->varlists()) { + Record.AddStmt(VE); + } + for (auto *VE : C->privates()) { + Record.AddStmt(VE); + } + for (auto *VE : C->inits()) { + Record.AddStmt(VE); + } + for (auto *VE : C->updates()) { + Record.AddStmt(VE); + } + for (auto *VE : C->finals()) { + Record.AddStmt(VE); + } + Record.AddStmt(C->getStep()); + Record.AddStmt(C->getCalcStep()); +} + +void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getColonLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + Record.AddStmt(C->getAlignment()); +} + +void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *E : C->source_exprs()) + Record.AddStmt(E); + for (auto *E : C->destination_exprs()) + Record.AddStmt(E); + for (auto *E : C->assignment_ops()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *E : C->source_exprs()) + Record.AddStmt(E); + for (auto *E : C->destination_exprs()) + Record.AddStmt(E); + for (auto *E : C->assignment_ops()) + Record.AddStmt(E); +} + +void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); +} + +void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getNumLoops()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.push_back(C->getDependencyKind()); + Record.AddSourceLocation(C->getDependencyLoc()); + Record.AddSourceLocation(C->getColonLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) + Record.AddStmt(C->getLoopData(I)); +} + +void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getDevice()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (unsigned I = 0; I < OMPMapClause::NumberOfModifiers; ++I) { + Record.push_back(C->getMapTypeModifier(I)); + Record.AddSourceLocation(C->getMapTypeModifierLoc(I)); + } + Record.push_back(C->getMapType()); + Record.AddSourceLocation(C->getMapLoc()); + Record.AddSourceLocation(C->getColonLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + +void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getNumTeams()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + VisitOMPClauseWithPreInit(C); + Record.AddStmt(C->getThreadLimit()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) { + Record.AddStmt(C->getPriority()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { + Record.AddStmt(C->getGrainsize()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) { + Record.AddStmt(C->getNumTasks()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPHintClause(OMPHintClause *C) { + Record.AddStmt(C->getHint()); + Record.AddSourceLocation(C->getLParenLoc()); +} + +void OMPClauseWriter::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + VisitOMPClauseWithPreInit(C); + Record.push_back(C->getDistScheduleKind()); + Record.AddStmt(C->getChunkSize()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getDistScheduleKindLoc()); + Record.AddSourceLocation(C->getCommaLoc()); +} + +void OMPClauseWriter::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) { + Record.push_back(C->getDefaultmapKind()); + Record.push_back(C->getDefaultmapModifier()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getDefaultmapModifierLoc()); + Record.AddSourceLocation(C->getDefaultmapKindLoc()); +} + +void OMPClauseWriter::VisitOMPToClause(OMPToClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + +void OMPClauseWriter::VisitOMPFromClause(OMPFromClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + +void OMPClauseWriter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *VE : C->private_copies()) + Record.AddStmt(VE); + for (auto *VE : C->inits()) + Record.AddStmt(VE); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + +void OMPClauseWriter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + +void OMPClauseWriter::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {} + +void OMPClauseWriter::VisitOMPUnifiedSharedMemoryClause( + OMPUnifiedSharedMemoryClause *) {} + +void OMPClauseWriter::VisitOMPReverseOffloadClause(OMPReverseOffloadClause *) {} + +void +OMPClauseWriter::VisitOMPDynamicAllocatorsClause(OMPDynamicAllocatorsClause *) { +} + +void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause( + OMPAtomicDefaultMemOrderClause *C) { + Record.push_back(C->getAtomicDefaultMemOrderKind()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc()); +} 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 000000000000..002b43f81121 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -0,0 +1,2355 @@ +//===--- 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 "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/AST/OpenMPClause.h" +#include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTWriter.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; + ASTRecordWriter Record; + + serialization::DeclCode Code; + unsigned AbbrevToUse; + + public: + ASTDeclWriter(ASTWriter &Writer, ASTContext &Context, + ASTWriter::RecordDataImpl &Record) + : Writer(Writer), Context(Context), Record(Writer, Record), + Code((serialization::DeclCode)0), AbbrevToUse(0) {} + + uint64_t Emit(Decl *D) { + if (!Code) + llvm::report_fatal_error(StringRef("unexpected declaration kind '") + + D->getDeclKindName() + "'"); + return Record.Emit(Code, AbbrevToUse); + } + + void Visit(Decl *D); + + void VisitDecl(Decl *D); + void VisitPragmaCommentDecl(PragmaCommentDecl *D); + void VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *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 VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *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 VisitDecompositionDecl(DecompositionDecl *D); + void VisitBindingDecl(BindingDecl *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 VisitUsingPackDecl(UsingPackDecl *D); + void VisitUsingShadowDecl(UsingShadowDecl *D); + void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitExportDecl(ExportDecl *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); + template <typename T> void VisitRedeclarable(Redeclarable<T> *D); + + + // FIXME: Put in the same order is DeclNodes.td? + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(ObjCTypeParamDecl *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 VisitOMPRequiresDecl(OMPRequiresDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); + + /// Add an Objective-C type parameter list to the given record. + void AddObjCTypeParamList(ObjCTypeParamList *typeParams) { + // Empty type parameter list. + if (!typeParams) { + Record.push_back(0); + return; + } + + Record.push_back(typeParams->size()); + for (auto typeParam : *typeParams) { + Record.AddDeclRef(typeParam); + } + Record.AddSourceLocation(typeParams->getLAngleLoc()); + Record.AddSourceLocation(typeParams->getRAngleLoc()); + } + + /// Add to the record the first declaration from each module file that + /// provides a declaration of D. The intent is to provide a sufficient + /// set such that reloading this set will load all current redeclarations. + void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { + llvm::MapVector<ModuleFile*, const Decl*> Firsts; + // FIXME: We can skip entries that we know are implied by others. + for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) { + if (R->isFromASTFile()) + Firsts[Writer.Chain->getOwningModuleFile(R)] = R; + else if (IncludeLocal) + Firsts[nullptr] = R; + } + for (const auto &F : Firsts) + Record.AddDeclRef(F.second); + } + + /// 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 DeclTy> + void AddTemplateSpecializations(DeclTy *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); + } + + ArrayRef<DeclID> LazySpecializations; + if (auto *LS = Common->LazySpecializations) + LazySpecializations = llvm::makeArrayRef(LS + 1, LS[0]); + + // Add a slot to the record for the number of specializations. + unsigned I = Record.size(); + Record.push_back(0); + + // AddFirstDeclFromEachModule might trigger deserialization, invalidating + // *Specializations iterators. + llvm::SmallVector<const Decl*, 16> Specs; + for (auto &Entry : Common->Specializations) + Specs.push_back(getSpecializationDecl(Entry)); + for (auto &Entry : getPartialSpecializations(Common)) + Specs.push_back(getSpecializationDecl(Entry)); + + for (auto *D : Specs) { + assert(D->isCanonicalDecl() && "non-canonical decl in set"); + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); + } + Record.append(LazySpecializations.begin(), LazySpecializations.end()); + + // Update the size entry we added earlier. + Record[I] = Record.size() - I - 1; + } + + /// Ensure that this template specialization is associated with the specified + /// template on reload. + void RegisterTemplateSpecialization(const Decl *Template, + const Decl *Specialization) { + Template = Template->getCanonicalDecl(); + + // If the canonical template is local, we'll write out this specialization + // when we emit it. + // FIXME: We can do the same thing if there is any local declaration of + // the template, to avoid emitting an update record. + if (!Template->isFromASTFile()) + return; + + // We only need to associate the first local declaration of the + // specialization. The other declarations will get pulled in by it. + if (Writer.getFirstLocalDecl(Specialization) != Specialization) + return; + + Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( + UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); + } + }; +} + +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)) { + if (auto *TInfo = DD->getTypeSourceInfo()) + Record.AddTypeLoc(TInfo->getTypeLoc()); + } + + // 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()) + Record.AddFunctionDefinition(FD); + } + + // 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. + if (DeclContext *DC = dyn_cast<DeclContext>(D)) + VisitDeclContext(DC); +} + +void ASTDeclWriter::VisitDecl(Decl *D) { + Record.AddDeclRef(cast_or_null<Decl>(D->getDeclContext())); + if (D->getDeclContext() != D->getLexicalDeclContext()) + Record.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext())); + else + Record.push_back(0); + Record.push_back(D->isInvalidDecl()); + Record.push_back(D->hasAttrs()); + if (D->hasAttrs()) + Record.AddAttributes(D->getAttrs()); + 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.getSubmoduleID(D->getOwningModule())); + + // 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. + // + // FIXME: Can we handle this in AddedVisibleDecl instead? + 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::VisitPragmaCommentDecl(PragmaCommentDecl *D) { + StringRef Arg = D->getArg(); + Record.push_back(Arg.size()); + VisitDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Record.push_back(D->getCommentKind()); + Record.AddString(Arg); + Code = serialization::DECL_PRAGMA_COMMENT; +} + +void ASTDeclWriter::VisitPragmaDetectMismatchDecl( + PragmaDetectMismatchDecl *D) { + StringRef Name = D->getName(); + StringRef Value = D->getValue(); + Record.push_back(Name.size() + 1 + Value.size()); + VisitDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Record.AddString(Name); + Record.AddString(Value); + Code = serialization::DECL_PRAGMA_DETECT_MISMATCH; +} + +void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + llvm_unreachable("Translation units aren't directly serialized"); +} + +void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) { + VisitDecl(D); + Record.AddDeclarationName(D->getDeclName()); + Record.push_back(needsAnonymousDeclarationNumber(D) + ? Writer.getAnonymousDeclarationNumber(D) + : 0); +} + +void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Record.AddTypeRef(QualType(D->getTypeForDecl(), 0)); +} + +void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) { + VisitRedeclarable(D); + VisitTypeDecl(D); + Record.AddTypeSourceInfo(D->getTypeSourceInfo()); + Record.push_back(D->isModed()); + if (D->isModed()) + Record.AddTypeRef(D->getUnderlyingType()); + Record.AddDeclRef(D->getAnonDeclWithTypedefName(false)); +} + +void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { + VisitTypedefNameDecl(D); + if (D->getDeclContext() == D->getLexicalDeclContext() && + !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); + Record.AddDeclRef(D->getDescribedAliasTemplate()); + 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()); + Record.AddSourceRange(D->getBraceRange()); + + if (D->hasExtInfo()) { + Record.push_back(1); + Record.AddQualifierInfo(*D->getExtInfo()); + } else if (auto *TD = D->getTypedefNameForAnonDecl()) { + Record.push_back(2); + Record.AddDeclRef(TD); + Record.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo()); + } else { + Record.push_back(0); + } +} + +void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { + VisitTagDecl(D); + Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo()); + if (!D->getIntegerTypeSourceInfo()) + Record.AddTypeRef(D->getIntegerType()); + Record.AddTypeRef(D->getPromotionType()); + 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()); + Record.push_back(D->getODRHash()); + + if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) { + Record.AddDeclRef(MemberInfo->getInstantiatedFrom()); + Record.push_back(MemberInfo->getTemplateSpecializationKind()); + Record.AddSourceLocation(MemberInfo->getPointOfInstantiation()); + } else { + Record.AddDeclRef(nullptr); + } + + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->hasExtInfo() && + !D->getTypedefNameForAnonDecl() && + 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()); + Record.push_back(D->isNonTrivialToPrimitiveDefaultInitialize()); + Record.push_back(D->isNonTrivialToPrimitiveCopy()); + Record.push_back(D->isNonTrivialToPrimitiveDestroy()); + Record.push_back(D->isParamDestroyedInCallee()); + Record.push_back(D->getArgPassingRestrictions()); + + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->hasExtInfo() && + !D->getTypedefNameForAnonDecl() && + 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); + Record.AddTypeRef(D->getType()); +} + +void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { + VisitValueDecl(D); + Record.push_back(D->getInitExpr()? 1 : 0); + if (D->getInitExpr()) + Record.AddStmt(D->getInitExpr()); + Record.AddAPSInt(D->getInitVal()); + + Code = serialization::DECL_ENUM_CONSTANT; +} + +void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { + VisitValueDecl(D); + Record.AddSourceLocation(D->getInnerLocStart()); + Record.push_back(D->hasExtInfo()); + if (D->hasExtInfo()) + Record.AddQualifierInfo(*D->getExtInfo()); + // The location information is deferred until the end of the record. + Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() + : QualType()); +} + +void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { + VisitRedeclarable(D); + VisitDeclaratorDecl(D); + Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName()); + Record.push_back(D->getIdentifierNamespace()); + + // FunctionDecl's body is handled last at ASTWriterDecl::Visit, + // after everything else is written. + Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding + Record.push_back(D->isInlineSpecified()); + Record.push_back(D->isInlined()); + Record.push_back(D->isExplicitSpecified()); + Record.push_back(D->isVirtualAsWritten()); + Record.push_back(D->isPure()); + Record.push_back(D->hasInheritedPrototype()); + Record.push_back(D->hasWrittenPrototype()); + Record.push_back(D->isDeletedBit()); + Record.push_back(D->isTrivial()); + Record.push_back(D->isTrivialForCall()); + Record.push_back(D->isDefaulted()); + Record.push_back(D->isExplicitlyDefaulted()); + Record.push_back(D->hasImplicitReturnZero()); + Record.push_back(D->isConstexpr()); + Record.push_back(D->usesSEHTry()); + Record.push_back(D->hasSkippedBody()); + Record.push_back(D->isMultiVersion()); + Record.push_back(D->isLateTemplateParsed()); + Record.push_back(D->getLinkageInternal()); + Record.AddSourceLocation(D->getEndLoc()); + + Record.push_back(D->getODRHash()); + + Record.push_back(D->getTemplatedKind()); + switch (D->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + break; + case FunctionDecl::TK_FunctionTemplate: + Record.AddDeclRef(D->getDescribedFunctionTemplate()); + break; + case FunctionDecl::TK_MemberSpecialization: { + MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo(); + Record.AddDeclRef(MemberInfo->getInstantiatedFrom()); + Record.push_back(MemberInfo->getTemplateSpecializationKind()); + Record.AddSourceLocation(MemberInfo->getPointOfInstantiation()); + break; + } + case FunctionDecl::TK_FunctionTemplateSpecialization: { + FunctionTemplateSpecializationInfo * + FTSInfo = D->getTemplateSpecializationInfo(); + + RegisterTemplateSpecialization(FTSInfo->getTemplate(), D); + + Record.AddDeclRef(FTSInfo->getTemplate()); + Record.push_back(FTSInfo->getTemplateSpecializationKind()); + + // Template arguments. + Record.AddTemplateArgumentList(FTSInfo->TemplateArguments); + + // 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) + Record.AddTemplateArgumentLoc( + (*FTSInfo->TemplateArgumentsAsWritten)[i]); + Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc); + Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc); + } + + Record.AddSourceLocation(FTSInfo->getPointOfInstantiation()); + + if (D->isCanonicalDecl()) { + // Write the template that contains the specializations set. We will + // add a FunctionTemplateSpecializationInfo to it when reading. + Record.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl()); + } + 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) + Record.AddDeclRef(DFTSInfo->getTemplate(i)); + + // Templates args. + Record.push_back(DFTSInfo->getNumTemplateArgs()); + for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) + Record.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i)); + Record.AddSourceLocation(DFTSInfo->getLAngleLoc()); + Record.AddSourceLocation(DFTSInfo->getRAngleLoc()); + break; + } + } + + Record.push_back(D->param_size()); + for (auto P : D->parameters()) + Record.AddDeclRef(P); + Code = serialization::DECL_FUNCTION; +} + +void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); + Record.push_back(D->isCopyDeductionCandidate()); + Code = serialization::DECL_CXX_DEDUCTION_GUIDE; +} + +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) { + Record.AddStmt(D->getBody()); + Record.AddDeclRef(D->getSelfDecl()); + Record.AddDeclRef(D->getCmdDecl()); + } + 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)); + Record.AddDeclRef(Context.getObjCMethodRedeclaration(D)); + } + + // FIXME: stable encoding for @required/@optional + Record.push_back(D->getImplementationControl()); + // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway/nullability + Record.push_back(D->getObjCDeclQualifier()); + Record.push_back(D->hasRelatedResultType()); + Record.AddTypeRef(D->getReturnType()); + Record.AddTypeSourceInfo(D->getReturnTypeSourceInfo()); + Record.AddSourceLocation(D->getEndLoc()); + Record.push_back(D->param_size()); + for (const auto *P : D->parameters()) + Record.AddDeclRef(P); + + Record.push_back(D->getSelLocsKind()); + unsigned NumStoredSelLocs = D->getNumStoredSelLocs(); + SourceLocation *SelLocs = D->getStoredSelLocs(); + Record.push_back(NumStoredSelLocs); + for (unsigned i = 0; i != NumStoredSelLocs; ++i) + Record.AddSourceLocation(SelLocs[i]); + + Code = serialization::DECL_OBJC_METHOD; +} + +void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { + VisitTypedefNameDecl(D); + Record.push_back(D->Variance); + Record.push_back(D->Index); + Record.AddSourceLocation(D->VarianceLoc); + Record.AddSourceLocation(D->ColonLoc); + + Code = serialization::DECL_OBJC_TYPE_PARAM; +} + +void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getAtStartLoc()); + Record.AddSourceRange(D->getAtEndRange()); + // Abstract class (no need to define a stable serialization::DECL code). +} + +void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + VisitRedeclarable(D); + VisitObjCContainerDecl(D); + Record.AddTypeRef(QualType(D->getTypeForDecl(), 0)); + AddObjCTypeParamList(D->TypeParamList); + + Record.push_back(D->isThisDeclarationADefinition()); + if (D->isThisDeclarationADefinition()) { + // Write the DefinitionData + ObjCInterfaceDecl::DefinitionData &Data = D->data(); + + Record.AddTypeSourceInfo(D->getSuperClassTInfo()); + Record.AddSourceLocation(D->getEndOfDefinitionLoc()); + 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()) + Record.AddDeclRef(P); + for (const auto &PL : D->protocol_locs()) + Record.AddSourceLocation(PL); + + // 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) + Record.AddDeclRef(*P); + + + 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->getDeclContext() == D->getLexicalDeclContext() && + !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()) + Record.AddDeclRef(I); + for (const auto &PL : D->protocol_locs()) + Record.AddSourceLocation(PL); + } + + 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); + Record.AddSourceLocation(D->getCategoryNameLoc()); + Record.AddSourceLocation(D->getIvarLBraceLoc()); + Record.AddSourceLocation(D->getIvarRBraceLoc()); + Record.AddDeclRef(D->getClassInterface()); + AddObjCTypeParamList(D->TypeParamList); + Record.push_back(D->protocol_size()); + for (const auto *I : D->protocols()) + Record.AddDeclRef(I); + for (const auto &PL : D->protocol_locs()) + Record.AddSourceLocation(PL); + Code = serialization::DECL_OBJC_CATEGORY; +} + +void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { + VisitNamedDecl(D); + Record.AddDeclRef(D->getClassInterface()); + Code = serialization::DECL_OBJC_COMPATIBLE_ALIAS; +} + +void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getAtLoc()); + Record.AddSourceLocation(D->getLParenLoc()); + Record.AddTypeRef(D->getType()); + Record.AddTypeSourceInfo(D->getTypeSourceInfo()); + // FIXME: stable encoding + Record.push_back((unsigned)D->getPropertyAttributes()); + Record.push_back((unsigned)D->getPropertyAttributesAsWritten()); + // FIXME: stable encoding + Record.push_back((unsigned)D->getPropertyImplementation()); + Record.AddDeclarationName(D->getGetterName()); + Record.AddSourceLocation(D->getGetterNameLoc()); + Record.AddDeclarationName(D->getSetterName()); + Record.AddSourceLocation(D->getSetterNameLoc()); + Record.AddDeclRef(D->getGetterMethodDecl()); + Record.AddDeclRef(D->getSetterMethodDecl()); + Record.AddDeclRef(D->getPropertyIvarDecl()); + Code = serialization::DECL_OBJC_PROPERTY; +} + +void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { + VisitObjCContainerDecl(D); + Record.AddDeclRef(D->getClassInterface()); + // Abstract class (no need to define a stable serialization::DECL code). +} + +void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitObjCImplDecl(D); + Record.AddSourceLocation(D->getCategoryNameLoc()); + Code = serialization::DECL_OBJC_CATEGORY_IMPL; +} + +void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitObjCImplDecl(D); + Record.AddDeclRef(D->getSuperClass()); + Record.AddSourceLocation(D->getSuperClassLoc()); + Record.AddSourceLocation(D->getIvarLBraceLoc()); + Record.AddSourceLocation(D->getIvarRBraceLoc()); + Record.push_back(D->hasNonZeroConstructors()); + Record.push_back(D->hasDestructors()); + Record.push_back(D->NumIvarInitializers); + if (D->NumIvarInitializers) + Record.AddCXXCtorInitializers( + llvm::makeArrayRef(D->init_begin(), D->init_end())); + Code = serialization::DECL_OBJC_IMPLEMENTATION; +} + +void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + VisitDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Record.AddDeclRef(D->getPropertyDecl()); + Record.AddDeclRef(D->getPropertyIvarDecl()); + Record.AddSourceLocation(D->getPropertyIvarDeclLoc()); + Record.AddStmt(D->getGetterCXXConstructor()); + Record.AddStmt(D->getSetterCXXAssignment()); + Code = serialization::DECL_OBJC_PROPERTY_IMPL; +} + +void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { + VisitDeclaratorDecl(D); + Record.push_back(D->isMutable()); + + FieldDecl::InitStorageKind ISK = D->InitStorage.getInt(); + Record.push_back(ISK); + if (ISK == FieldDecl::ISK_CapturedVLAType) + Record.AddTypeRef(QualType(D->getCapturedVLAType(), 0)); + else if (ISK) + Record.AddStmt(D->getInClassInitializer()); + + Record.AddStmt(D->getBitWidth()); + + if (!D->getDeclName()) + Record.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D)); + + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->isInvalidDecl() && + !D->isReferenced() && + !D->isTopLevelDeclInObjCContainer() && + !D->isModulePrivate() && + !D->getBitWidth() && + !D->hasInClassInitializer() && + !D->hasCapturedVLAType() && + !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); + Record.AddIdentifierRef(D->getGetterId()); + Record.AddIdentifierRef(D->getSetterId()); + Code = serialization::DECL_MS_PROPERTY; +} + +void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + VisitValueDecl(D); + Record.push_back(D->getChainingSize()); + + for (const auto *P : D->chain()) + Record.AddDeclRef(P); + 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()); + Record.push_back(D->isARCPseudoStrong()); + if (!isa<ParmVarDecl>(D)) { + Record.push_back(D->isThisDeclarationADemotedDefinition()); + Record.push_back(D->isExceptionVariable()); + Record.push_back(D->isNRVOVariable()); + Record.push_back(D->isCXXForRangeDecl()); + Record.push_back(D->isObjCForDecl()); + Record.push_back(D->isInline()); + Record.push_back(D->isInlineSpecified()); + Record.push_back(D->isConstexpr()); + Record.push_back(D->isInitCapture()); + Record.push_back(D->isPreviousDeclInSameBlockScope()); + if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D)) + Record.push_back(static_cast<unsigned>(IPD->getParameterKind())); + else + Record.push_back(0); + Record.push_back(D->isEscapingByref()); + } + Record.push_back(D->getLinkageInternal()); + + if (D->getInit()) { + Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); + Record.AddStmt(D->getInit()); + } else { + Record.push_back(0); + } + + if (D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) { + ASTContext::BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D); + Record.AddStmt(Init.getCopyExpr()); + if (Init.getCopyExpr()) + Record.push_back(Init.canThrow()); + } + + if (D->getStorageDuration() == SD_Static) { + bool ModulesCodegen = false; + if (Writer.WritingModule && + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + !isa<VarTemplateSpecializationDecl>(D)) { + // When building a C++ Modules TS module interface unit, a strong + // definition in the module interface is provided by the compilation of + // that module interface unit, not by its users. (Inline variables are + // still emitted in module users.) + ModulesCodegen = + (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit && + Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); + } + Record.push_back(ModulesCodegen); + if (ModulesCodegen) + Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D)); + } + + enum { + VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization + }; + if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) { + Record.push_back(VarTemplate); + Record.AddDeclRef(TemplD); + } else if (MemberSpecializationInfo *SpecInfo + = D->getMemberSpecializationInfo()) { + Record.push_back(StaticDataMemberSpecialization); + Record.AddDeclRef(SpecInfo->getInstantiatedFrom()); + Record.push_back(SpecInfo->getTemplateSpecializationKind()); + Record.AddSourceLocation(SpecInfo->getPointOfInstantiation()); + } else { + Record.push_back(VarNotTemplate); + } + + if (D->getDeclContext() == D->getLexicalDeclContext() && + !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->getKind() == Decl::Var && + !D->isInline() && + !D->isConstexpr() && + !D->isInitCapture() && + !D->isPreviousDeclInSameBlockScope() && + !(D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) && + !D->isEscapingByref() && + D->getStorageDuration() != SD_Static && + !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()) + Record.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->getDeclContext() == D->getLexicalDeclContext() && + !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->isThisDeclarationADemotedDefinition() + && "PARM_VAR_DECL can't be demoted definition."); + 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::VisitDecompositionDecl(DecompositionDecl *D) { + // Record the number of bindings first to simplify deserialization. + Record.push_back(D->bindings().size()); + + VisitVarDecl(D); + for (auto *B : D->bindings()) + Record.AddDeclRef(B); + Code = serialization::DECL_DECOMPOSITION; +} + +void ASTDeclWriter::VisitBindingDecl(BindingDecl *D) { + VisitValueDecl(D); + Record.AddStmt(D->getBinding()); + Code = serialization::DECL_BINDING; +} + +void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { + VisitDecl(D); + Record.AddStmt(D->getAsmString()); + Record.AddSourceLocation(D->getRParenLoc()); + Code = serialization::DECL_FILE_SCOPE_ASM; +} + +void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { + VisitDecl(D); + Code = serialization::DECL_EMPTY; +} + +void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { + VisitDecl(D); + Record.AddStmt(D->getBody()); + Record.AddTypeSourceInfo(D->getSignatureAsWritten()); + Record.push_back(D->param_size()); + for (ParmVarDecl *P : D->parameters()) + Record.AddDeclRef(P); + Record.push_back(D->isVariadic()); + Record.push_back(D->blockMissingReturnType()); + Record.push_back(D->isConversionFromLambda()); + Record.push_back(D->doesNotEscape()); + Record.push_back(D->capturesCXXThis()); + Record.push_back(D->getNumCaptures()); + for (const auto &capture : D->captures()) { + Record.AddDeclRef(capture.getVariable()); + + 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()) Record.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) + Record.AddDeclRef(CD->getParam(I)); + Code = serialization::DECL_CAPTURED; +} + +void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + Record.push_back(D->getLanguage()); + Record.AddSourceLocation(D->getExternLoc()); + Record.AddSourceLocation(D->getRBraceLoc()); + Code = serialization::DECL_LINKAGE_SPEC; +} + +void ASTDeclWriter::VisitExportDecl(ExportDecl *D) { + VisitDecl(D); + Record.AddSourceLocation(D->getRBraceLoc()); + Code = serialization::DECL_EXPORT; +} + +void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Code = serialization::DECL_LABEL; +} + + +void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { + VisitRedeclarable(D); + VisitNamedDecl(D); + Record.push_back(D->isInline()); + Record.AddSourceLocation(D->getBeginLoc()); + Record.AddSourceLocation(D->getRBraceLoc()); + + if (D->isOriginalNamespace()) + Record.AddDeclRef(D->getAnonymousNamespace()); + Code = serialization::DECL_NAMESPACE; + + 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); + Record.AddSourceLocation(D->getNamespaceLoc()); + Record.AddSourceLocation(D->getTargetNameLoc()); + Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddDeclRef(D->getNamespace()); + Code = serialization::DECL_NAMESPACE_ALIAS; +} + +void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getUsingLoc()); + Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName()); + Record.AddDeclRef(D->FirstUsingShadow.getPointer()); + Record.push_back(D->hasTypename()); + Record.AddDeclRef(Context.getInstantiatedFromUsingDecl(D)); + Code = serialization::DECL_USING; +} + +void ASTDeclWriter::VisitUsingPackDecl(UsingPackDecl *D) { + Record.push_back(D->NumExpansions); + VisitNamedDecl(D); + Record.AddDeclRef(D->getInstantiatedFromUsingDecl()); + for (auto *E : D->expansions()) + Record.AddDeclRef(E); + Code = serialization::DECL_USING_PACK; +} + +void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { + VisitRedeclarable(D); + VisitNamedDecl(D); + Record.AddDeclRef(D->getTargetDecl()); + Record.push_back(D->getIdentifierNamespace()); + Record.AddDeclRef(D->UsingOrNextShadow); + Record.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D)); + Code = serialization::DECL_USING_SHADOW; +} + +void ASTDeclWriter::VisitConstructorUsingShadowDecl( + ConstructorUsingShadowDecl *D) { + VisitUsingShadowDecl(D); + Record.AddDeclRef(D->NominatedBaseClassShadowDecl); + Record.AddDeclRef(D->ConstructedBaseClassShadowDecl); + Record.push_back(D->IsVirtual); + Code = serialization::DECL_CONSTRUCTOR_USING_SHADOW; +} + +void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getUsingLoc()); + Record.AddSourceLocation(D->getNamespaceKeyLocation()); + Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddDeclRef(D->getNominatedNamespace()); + Record.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor())); + Code = serialization::DECL_USING_DIRECTIVE; +} + +void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + Record.AddSourceLocation(D->getUsingLoc()); + Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName()); + Record.AddSourceLocation(D->getEllipsisLoc()); + Code = serialization::DECL_UNRESOLVED_USING_VALUE; +} + +void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + Record.AddSourceLocation(D->getTypenameLoc()); + Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddSourceLocation(D->getEllipsisLoc()); + 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); + Record.AddDeclRef(TemplD); + } else if (MemberSpecializationInfo *MSInfo + = D->getMemberSpecializationInfo()) { + Record.push_back(CXXRecMemberSpecialization); + Record.AddDeclRef(MSInfo->getInstantiatedFrom()); + Record.push_back(MSInfo->getTemplateSpecializationKind()); + Record.AddSourceLocation(MSInfo->getPointOfInstantiation()); + } else { + Record.push_back(CXXRecNotTemplate); + } + + Record.push_back(D->isThisDeclarationADefinition()); + if (D->isThisDeclarationADefinition()) + Record.AddCXXDefinitionData(D); + + // Store (what we currently believe to be) the key function to avoid + // deserializing every method so we can compute it. + if (D->isCompleteDefinition()) + Record.AddDeclRef(Context.getCurrentKeyFunction(D)); + + Code = serialization::DECL_CXX_RECORD; +} + +void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { + VisitFunctionDecl(D); + if (D->isCanonicalDecl()) { + Record.push_back(D->size_overridden_methods()); + for (const CXXMethodDecl *MD : D->overridden_methods()) + Record.AddDeclRef(MD); + } else { + // We only need to record overridden methods once for the canonical decl. + Record.push_back(0); + } + + if (D->getDeclContext() == D->getLexicalDeclContext() && + 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) { + if (auto Inherited = D->getInheritedConstructor()) { + Record.AddDeclRef(Inherited.getShadowDecl()); + Record.AddDeclRef(Inherited.getConstructor()); + Code = serialization::DECL_CXX_INHERITED_CONSTRUCTOR; + } else { + Code = serialization::DECL_CXX_CONSTRUCTOR; + } + + VisitCXXMethodDecl(D); + + Code = D->isInheritingConstructor() + ? serialization::DECL_CXX_INHERITED_CONSTRUCTOR + : serialization::DECL_CXX_CONSTRUCTOR; +} + +void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + VisitCXXMethodDecl(D); + + Record.AddDeclRef(D->getOperatorDelete()); + if (D->getOperatorDelete()) + Record.AddStmt(D->getOperatorDeleteThisArg()); + + Code = serialization::DECL_CXX_DESTRUCTOR; +} + +void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { + VisitCXXMethodDecl(D); + 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()) { + Record.AddSourceLocation(D->getEndLoc()); + Record.push_back(1); + } else { + for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I) + Record.AddSourceLocation(IdentifierLocs[I]); + 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); + Record.AddSourceLocation(D->getColonLoc()); + 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) + Record.AddDeclRef(D->getFriendDecl()); + else + Record.AddTypeSourceInfo(D->getFriendType()); + for (unsigned i = 0; i < D->NumTPLists; ++i) + Record.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i)); + Record.AddDeclRef(D->getNextFriend()); + Record.push_back(D->UnsupportedFriend); + Record.AddSourceLocation(D->FriendLoc); + 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) + Record.AddTemplateParameterList(D->getTemplateParameterList(i)); + Record.push_back(D->getFriendDecl() != nullptr); + if (D->getFriendDecl()) + Record.AddDeclRef(D->getFriendDecl()); + else + Record.AddTypeSourceInfo(D->getFriendType()); + Record.AddSourceLocation(D->getFriendLoc()); + Code = serialization::DECL_FRIEND_TEMPLATE; +} + +void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) { + VisitNamedDecl(D); + + Record.AddDeclRef(D->getTemplatedDecl()); + Record.AddTemplateParameterList(D->getTemplateParameters()); +} + +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. + Record.AddDeclRef(D->getInstantiatedFromMemberTemplate()); + 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) { + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); + + VisitCXXRecordDecl(D); + + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> InstFrom + = D->getSpecializedTemplateOrPartial(); + if (Decl *InstFromD = InstFrom.dyn_cast<ClassTemplateDecl *>()) { + Record.AddDeclRef(InstFromD); + } else { + Record.AddDeclRef(InstFrom.get<ClassTemplatePartialSpecializationDecl *>()); + Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs()); + } + + Record.AddTemplateArgumentList(&D->getTemplateArgs()); + Record.AddSourceLocation(D->getPointOfInstantiation()); + 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. + Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl()); + } + + // Explicit info. + Record.AddTypeSourceInfo(D->getTypeAsWritten()); + if (D->getTypeAsWritten()) { + Record.AddSourceLocation(D->getExternLoc()); + Record.AddSourceLocation(D->getTemplateKeywordLoc()); + } + + Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION; +} + +void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + VisitClassTemplateSpecializationDecl(D); + + Record.AddTemplateParameterList(D->getTemplateParameters()); + Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); + + // These are read/set from/to the first declaration. + if (D->getPreviousDecl() == nullptr) { + Record.AddDeclRef(D->getInstantiatedFromMember()); + 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) { + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); + + VisitVarDecl(D); + + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + InstFrom = D->getSpecializedTemplateOrPartial(); + if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) { + Record.AddDeclRef(InstFromD); + } else { + Record.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>()); + Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs()); + } + + // Explicit info. + Record.AddTypeSourceInfo(D->getTypeAsWritten()); + if (D->getTypeAsWritten()) { + Record.AddSourceLocation(D->getExternLoc()); + Record.AddSourceLocation(D->getTemplateKeywordLoc()); + } + + Record.AddTemplateArgumentList(&D->getTemplateArgs()); + Record.AddSourceLocation(D->getPointOfInstantiation()); + Record.push_back(D->getSpecializationKind()); + Record.push_back(D->IsCompleteDefinition); + Record.push_back(D->isCanonicalDecl()); + + if (D->isCanonicalDecl()) { + // When reading, we'll add it to the folding set of the following template. + Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl()); + } + + Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION; +} + +void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + VisitVarTemplateSpecializationDecl(D); + + Record.AddTemplateParameterList(D->getTemplateParameters()); + Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); + + // These are read/set from/to the first declaration. + if (D->getPreviousDecl() == nullptr) { + Record.AddDeclRef(D->getInstantiatedFromMember()); + Record.push_back(D->isMemberSpecialization()); + } + + Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; +} + +void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D) { + VisitDecl(D); + Record.AddDeclRef(D->getSpecialization()); + 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()); + + bool OwnsDefaultArg = D->hasDefaultArgument() && + !D->defaultArgumentWasInherited(); + Record.push_back(OwnsDefaultArg); + if (OwnsDefaultArg) + Record.AddTypeSourceInfo(D->getDefaultArgumentInfo()); + + 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) { + Record.AddTypeRef(D->getExpansionType(I)); + Record.AddTypeSourceInfo(D->getExpansionTypeSourceInfo(I)); + } + + Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; + } else { + // Rest of NonTypeTemplateParmDecl. + Record.push_back(D->isParameterPack()); + bool OwnsDefaultArg = D->hasDefaultArgument() && + !D->defaultArgumentWasInherited(); + Record.push_back(OwnsDefaultArg); + if (OwnsDefaultArg) + Record.AddStmt(D->getDefaultArgument()); + 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) + Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I)); + Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; + } else { + // Rest of TemplateTemplateParmDecl. + Record.push_back(D->isParameterPack()); + bool OwnsDefaultArg = D->hasDefaultArgument() && + !D->defaultArgumentWasInherited(); + Record.push_back(OwnsDefaultArg); + if (OwnsDefaultArg) + Record.AddTemplateArgumentLoc(D->getDefaultArgument()); + 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); + Record.AddStmt(D->getAssertExpr()); + Record.push_back(D->isFailed()); + Record.AddStmt(D->getMessage()); + Record.AddSourceLocation(D->getRParenLoc()); + Code = serialization::DECL_STATIC_ASSERT; +} + +/// Emit the DeclContext part of a declaration context decl. +void ASTDeclWriter::VisitDeclContext(DeclContext *DC) { + Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC)); + Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC)); +} + +const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) { + assert(IsLocalDecl(D) && "expected a local declaration"); + + const Decl *Canon = D->getCanonicalDecl(); + if (IsLocalDecl(Canon)) + return Canon; + + const Decl *&CacheEntry = FirstLocalDeclCache[Canon]; + if (CacheEntry) + return CacheEntry; + + for (const Decl *Redecl = D; Redecl; Redecl = Redecl->getPreviousDecl()) + if (IsLocalDecl(Redecl)) + D = Redecl; + return CacheEntry = D; +} + +template <typename T> +void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { + T *First = D->getFirstDecl(); + T *MostRecent = First->getMostRecentDecl(); + T *DAsT = static_cast<T *>(D); + if (MostRecent != First) { + assert(isRedeclarableDeclKind(DAsT->getKind()) && + "Not considered redeclarable?"); + + Record.AddDeclRef(First); + + // Write out a list of local redeclarations of this declaration if it's the + // first local declaration in the chain. + const Decl *FirstLocal = Writer.getFirstLocalDecl(DAsT); + if (DAsT == FirstLocal) { + // Emit a list of all imported first declarations so that we can be sure + // that all redeclarations visible to this module are before D in the + // redecl chain. + unsigned I = Record.size(); + Record.push_back(0); + if (Writer.Chain) + AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false); + // This is the number of imported first declarations + 1. + Record[I] = Record.size() - I; + + // Collect the set of local redeclarations of this declaration, from + // newest to oldest. + ASTWriter::RecordData LocalRedecls; + ASTRecordWriter LocalRedeclWriter(Record, LocalRedecls); + for (const Decl *Prev = FirstLocal->getMostRecentDecl(); + Prev != FirstLocal; Prev = Prev->getPreviousDecl()) + if (!Prev->isFromASTFile()) + LocalRedeclWriter.AddDeclRef(Prev); + + // If we have any redecls, write them now as a separate record preceding + // the declaration itself. + if (LocalRedecls.empty()) + Record.push_back(0); + else + Record.AddOffset(LocalRedeclWriter.Emit(LOCAL_REDECLARATIONS)); + } else { + Record.push_back(0); + Record.AddDeclRef(FirstLocal); + } + + // 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(D->getPreviousDecl()); + (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()) + Record.AddStmt(I); + Code = serialization::DECL_OMP_THREADPRIVATE; +} + +void ASTDeclWriter::VisitOMPRequiresDecl(OMPRequiresDecl *D) { + Record.push_back(D->clauselist_size()); + VisitDecl(D); + OMPClauseWriter ClauseWriter(Record); + for (OMPClause *C : D->clauselists()) + ClauseWriter.writeClause(C); + Code = serialization::DECL_OMP_REQUIRES; +} + +void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitValueDecl(D); + Record.AddSourceLocation(D->getBeginLoc()); + Record.AddStmt(D->getCombinerIn()); + Record.AddStmt(D->getCombinerOut()); + Record.AddStmt(D->getCombiner()); + Record.AddStmt(D->getInitOrig()); + Record.AddStmt(D->getInitPriv()); + Record.AddStmt(D->getInitializer()); + Record.push_back(D->getInitializerKind()); + Record.AddDeclRef(D->getPrevDeclInScope()); + Code = serialization::DECL_OMP_DECLARE_REDUCTION; +} + +void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { + VisitVarDecl(D); + Code = serialization::DECL_OMP_CAPTUREDEXPR; +} + +//===----------------------------------------------------------------------===// +// ASTWriter Implementation +//===----------------------------------------------------------------------===// + +void ASTWriter::WriteDeclAbbrevs() { + using namespace llvm; + + std::shared_ptr<BitCodeAbbrev> Abv; + + // Abbreviation for DECL_FIELD + Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(0)); // 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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType + // FieldDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(0)); // InitStyle + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclFieldAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for DECL_OBJC_IVAR + Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(0)); // 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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType + // FieldDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(0)); // InitStyle + // ObjC Ivar + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclObjCIvarAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for DECL_ENUM + Abv = std::make_shared<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(0)); // 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(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::Fixed, 32));// ODRHash + 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(std::move(Abv)); + + // Abbreviation for DECL_RECORD + Abv = std::make_shared<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(0)); // 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(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 + + // isNonTrivialToPrimitiveDefaultInitialize + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + // isNonTrivialToPrimitiveCopy + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + // isNonTrivialToPrimitiveDestroy + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + // isParamDestroyedInCallee + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + // getArgPassingRestrictions + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); + + // DC + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset + DeclRecordAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for DECL_PARM_VAR + Abv = std::make_shared<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(0)); // 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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType + // VarDecl + Abv->Add(BitCodeAbbrevOp(0)); // SClass + Abv->Add(BitCodeAbbrevOp(0)); // TSCSpec + Abv->Add(BitCodeAbbrevOp(0)); // InitStyle + Abv->Add(BitCodeAbbrevOp(0)); // ARCPseudoStrong + 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::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclParmVarAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for DECL_TYPEDEF + Abv = std::make_shared<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(0)); // 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(std::move(Abv)); + + // Abbreviation for DECL_VAR + Abv = std::make_shared<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(0)); // 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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType + // VarDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // SClass + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // TSCSpec + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // InitStyle + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsThisDeclarationADemotedDefinition + 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)); // isObjCForDecl + Abv->Add(BitCodeAbbrevOp(0)); // isInline + Abv->Add(BitCodeAbbrevOp(0)); // isInlineSpecified + Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr + Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture + Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope + Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind + Abv->Add(BitCodeAbbrevOp(0)); // EscapingByref + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local) + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum) + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclVarAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for DECL_CXX_METHOD + Abv = std::make_shared<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(0)); // 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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType + // 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)); // ExplicitSpecified + 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)); // TrivialForCall + 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)); // UsesSEHTry + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion + 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, 32)); // ODRHash + 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(std::move(Abv)); + + // Abbreviation for EXPR_DECL_REF + Abv = std::make_shared<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(std::move(Abv)); + + // Abbreviation for EXPR_INTEGER_LITERAL + Abv = std::make_shared<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(std::move(Abv)); + + // Abbreviation for EXPR_CHARACTER_LITERAL + Abv = std::make_shared<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, 3)); // getKind + CharacterLiteralAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + // Abbreviation for EXPR_IMPLICIT_CAST + Abv = std::make_shared<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 + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // PartOfExplicitCast + // ImplicitCastExpr + ExprImplicitCastAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclContextLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared<BitCodeAbbrev>(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(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, + bool WritingModule) { + // An ObjCMethodDecl is never considered as "required" because its + // implementation container always is. + + // File scoped assembly or obj-c or OMP declare target implementation must be + // seen. + if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D)) + return true; + + if (WritingModule && (isa<VarDecl>(D) || isa<ImportDecl>(D))) { + // These declarations are part of the module initializer, and are emitted + // if and when the module is imported, rather than being emitted eagerly. + return false; + } + + return Context.DeclMustBeEmitted(D); +} + +void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { + PrettyDeclStackTraceEntry CrashInfo(Context, D, SourceLocation(), + "serializing"); + + // Determine the ID for this declaration. + serialization::DeclID ID; + assert(!D->isFromASTFile() && "should not be emitting imported decl"); + serialization::DeclID &IDR = DeclIDs[D]; + if (IDR == 0) + IDR = NextDeclID++; + + ID = IDR; + + assert(ID >= FirstDeclID && "invalid decl ID"); + + RecordData Record; + ASTDeclWriter W(*this, Context, Record); + + // Build a record for this declaration + W.Visit(D); + + // Emit this declaration to the bitstream. + uint64_t Offset = W.Emit(D); + + // Record the offset for this declaration + SourceLocation Loc = D->getLocation(); + unsigned Index = ID - FirstDeclID; + if (DeclOffsets.size() == Index) + DeclOffsets.push_back(DeclOffset(Loc, Offset)); + else if (DeclOffsets.size() < Index) { + // FIXME: Can/should this happen? + DeclOffsets.resize(Index+1); + DeclOffsets[Index].setLocation(Loc); + DeclOffsets[Index].BitOffset = Offset; + } else { + llvm_unreachable("declarations should be emitted in ID order"); + } + + SourceManager &SM = Context.getSourceManager(); + if (Loc.isValid() && SM.isLocalSourceLocation(Loc)) + associateDeclWithFile(D, ID); + + // 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, WritingModule)) + EagerlyDeserializedDecls.push_back(ID); +} + +void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { + // Switch case IDs are per function body. + Writer->ClearSwitchCaseIDs(); + + assert(FD->doesThisDeclarationHaveABody()); + bool ModulesCodegen = false; + if (Writer->WritingModule && !FD->isDependentContext()) { + Optional<GVALinkage> Linkage; + if (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) { + // When building a C++ Modules TS module interface unit, a strong + // definition in the module interface is provided by the compilation of + // that module interface unit, not by its users. (Inline functions are + // still emitted in module users.) + Linkage = Writer->Context->GetGVALinkageForFunction(FD); + ModulesCodegen = *Linkage == GVA_StrongExternal; + } + if (Writer->Context->getLangOpts().ModulesCodegen) { + // Under -fmodules-codegen, codegen is performed for all non-internal, + // non-always_inline functions. + if (!FD->hasAttr<AlwaysInlineAttr>()) { + if (!Linkage) + Linkage = Writer->Context->GetGVALinkageForFunction(FD); + ModulesCodegen = *Linkage != GVA_Internal; + } + } + } + Record->push_back(ModulesCodegen); + if (ModulesCodegen) + Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); + if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { + Record->push_back(CD->getNumCtorInitializers()); + if (CD->getNumCtorInitializers()) + AddCXXCtorInitializers( + llvm::makeArrayRef(CD->init_begin(), CD->init_end())); + } + AddStmt(FD->getBody()); +} 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 000000000000..6f8b86edcdfc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -0,0 +1,2368 @@ +//===--- 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 +/// 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> { + ASTWriter &Writer; + ASTRecordWriter Record; + + serialization::StmtCode Code; + unsigned AbbrevToUse; + + public: + ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record) + : Writer(Writer), Record(Writer, Record), + Code(serialization::STMT_NULL_PTR), AbbrevToUse(0) {} + + ASTStmtWriter(const ASTStmtWriter&) = delete; + + uint64_t Emit() { + assert(Code != serialization::STMT_NULL_PTR && + "unhandled sub-statement writing AST file"); + return Record.EmitStmt(Code, AbbrevToUse); + } + + void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &ArgInfo, + const TemplateArgumentLoc *Args); + + void VisitStmt(Stmt *S); +#define STMT(Type, Base) \ + void Visit##Type(Type *); +#include "clang/AST/StmtNodes.inc" + }; +} + +void ASTStmtWriter::AddTemplateKWAndArgsInfo( + const ASTTemplateKWAndArgsInfo &ArgInfo, const TemplateArgumentLoc *Args) { + Record.AddSourceLocation(ArgInfo.TemplateKWLoc); + Record.AddSourceLocation(ArgInfo.LAngleLoc); + Record.AddSourceLocation(ArgInfo.RAngleLoc); + for (unsigned i = 0; i != ArgInfo.NumTemplateArgs; ++i) + Record.AddTemplateArgumentLoc(Args[i]); +} + +void ASTStmtWriter::VisitStmt(Stmt *S) { +} + +void ASTStmtWriter::VisitNullStmt(NullStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getSemiLoc()); + Record.push_back(S->NullStmtBits.HasLeadingEmptyMacro); + Code = serialization::STMT_NULL; +} + +void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); + Record.push_back(S->size()); + for (auto *CS : S->body()) + Record.AddStmt(CS); + Record.AddSourceLocation(S->getLBracLoc()); + Record.AddSourceLocation(S->getRBracLoc()); + Code = serialization::STMT_COMPOUND; +} + +void ASTStmtWriter::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); + Record.push_back(Writer.getSwitchCaseID(S)); + Record.AddSourceLocation(S->getKeywordLoc()); + Record.AddSourceLocation(S->getColonLoc()); +} + +void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) { + VisitSwitchCase(S); + Record.push_back(S->caseStmtIsGNURange()); + Record.AddStmt(S->getLHS()); + Record.AddStmt(S->getSubStmt()); + if (S->caseStmtIsGNURange()) { + Record.AddStmt(S->getRHS()); + Record.AddSourceLocation(S->getEllipsisLoc()); + } + Code = serialization::STMT_CASE; +} + +void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) { + VisitSwitchCase(S); + Record.AddStmt(S->getSubStmt()); + Code = serialization::STMT_DEFAULT; +} + +void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + Record.AddDeclRef(S->getDecl()); + Record.AddStmt(S->getSubStmt()); + Record.AddSourceLocation(S->getIdentLoc()); + Code = serialization::STMT_LABEL; +} + +void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + Record.push_back(S->getAttrs().size()); + Record.AddAttributes(S->getAttrs()); + Record.AddStmt(S->getSubStmt()); + Record.AddSourceLocation(S->getAttrLoc()); + Code = serialization::STMT_ATTRIBUTED; +} + +void ASTStmtWriter::VisitIfStmt(IfStmt *S) { + VisitStmt(S); + + bool HasElse = S->getElse() != nullptr; + bool HasVar = S->getConditionVariableDeclStmt() != nullptr; + bool HasInit = S->getInit() != nullptr; + + Record.push_back(S->isConstexpr()); + Record.push_back(HasElse); + Record.push_back(HasVar); + Record.push_back(HasInit); + + Record.AddStmt(S->getCond()); + Record.AddStmt(S->getThen()); + if (HasElse) + Record.AddStmt(S->getElse()); + if (HasVar) + Record.AddDeclRef(S->getConditionVariable()); + if (HasInit) + Record.AddStmt(S->getInit()); + + Record.AddSourceLocation(S->getIfLoc()); + if (HasElse) + Record.AddSourceLocation(S->getElseLoc()); + + Code = serialization::STMT_IF; +} + +void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); + + bool HasInit = S->getInit() != nullptr; + bool HasVar = S->getConditionVariableDeclStmt() != nullptr; + Record.push_back(HasInit); + Record.push_back(HasVar); + Record.push_back(S->isAllEnumCasesCovered()); + + Record.AddStmt(S->getCond()); + Record.AddStmt(S->getBody()); + if (HasInit) + Record.AddStmt(S->getInit()); + if (HasVar) + Record.AddDeclRef(S->getConditionVariable()); + + Record.AddSourceLocation(S->getSwitchLoc()); + + 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); + + bool HasVar = S->getConditionVariableDeclStmt() != nullptr; + Record.push_back(HasVar); + + Record.AddStmt(S->getCond()); + Record.AddStmt(S->getBody()); + if (HasVar) + Record.AddDeclRef(S->getConditionVariable()); + + Record.AddSourceLocation(S->getWhileLoc()); + Code = serialization::STMT_WHILE; +} + +void ASTStmtWriter::VisitDoStmt(DoStmt *S) { + VisitStmt(S); + Record.AddStmt(S->getCond()); + Record.AddStmt(S->getBody()); + Record.AddSourceLocation(S->getDoLoc()); + Record.AddSourceLocation(S->getWhileLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Code = serialization::STMT_DO; +} + +void ASTStmtWriter::VisitForStmt(ForStmt *S) { + VisitStmt(S); + Record.AddStmt(S->getInit()); + Record.AddStmt(S->getCond()); + Record.AddDeclRef(S->getConditionVariable()); + Record.AddStmt(S->getInc()); + Record.AddStmt(S->getBody()); + Record.AddSourceLocation(S->getForLoc()); + Record.AddSourceLocation(S->getLParenLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Code = serialization::STMT_FOR; +} + +void ASTStmtWriter::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + Record.AddDeclRef(S->getLabel()); + Record.AddSourceLocation(S->getGotoLoc()); + Record.AddSourceLocation(S->getLabelLoc()); + Code = serialization::STMT_GOTO; +} + +void ASTStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getGotoLoc()); + Record.AddSourceLocation(S->getStarLoc()); + Record.AddStmt(S->getTarget()); + Code = serialization::STMT_INDIRECT_GOTO; +} + +void ASTStmtWriter::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getContinueLoc()); + Code = serialization::STMT_CONTINUE; +} + +void ASTStmtWriter::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getBreakLoc()); + Code = serialization::STMT_BREAK; +} + +void ASTStmtWriter::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); + + bool HasNRVOCandidate = S->getNRVOCandidate() != nullptr; + Record.push_back(HasNRVOCandidate); + + Record.AddStmt(S->getRetValue()); + if (HasNRVOCandidate) + Record.AddDeclRef(S->getNRVOCandidate()); + + Record.AddSourceLocation(S->getReturnLoc()); + Code = serialization::STMT_RETURN; +} + +void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getBeginLoc()); + Record.AddSourceLocation(S->getEndLoc()); + DeclGroupRef DG = S->getDeclGroup(); + for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D) + Record.AddDeclRef(*D); + 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()); + Record.AddSourceLocation(S->getAsmLoc()); + Record.push_back(S->isVolatile()); + Record.push_back(S->isSimple()); +} + +void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + Record.AddSourceLocation(S->getRParenLoc()); + Record.AddStmt(S->getAsmString()); + + // Outputs + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Record.AddIdentifierRef(S->getOutputIdentifier(I)); + Record.AddStmt(S->getOutputConstraintLiteral(I)); + Record.AddStmt(S->getOutputExpr(I)); + } + + // Inputs + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + Record.AddIdentifierRef(S->getInputIdentifier(I)); + Record.AddStmt(S->getInputConstraintLiteral(I)); + Record.AddStmt(S->getInputExpr(I)); + } + + // Clobbers + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) + Record.AddStmt(S->getClobberStringLiteral(I)); + + Code = serialization::STMT_GCCASM; +} + +void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { + VisitAsmStmt(S); + Record.AddSourceLocation(S->getLBraceLoc()); + Record.AddSourceLocation(S->getEndLoc()); + Record.push_back(S->getNumAsmToks()); + Record.AddString(S->getAsmString()); + + // Tokens + for (unsigned I = 0, N = S->getNumAsmToks(); I != N; ++I) { + // FIXME: Move this to ASTRecordWriter? + Writer.AddToken(S->getAsmToks()[I], Record.getRecordData()); + } + + // Clobbers + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) { + Record.AddString(S->getClobber(I)); + } + + // Outputs + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Record.AddStmt(S->getOutputExpr(I)); + Record.AddString(S->getOutputConstraint(I)); + } + + // Inputs + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + Record.AddStmt(S->getInputExpr(I)); + Record.AddString(S->getInputConstraint(I)); + } + + Code = serialization::STMT_MSASM; +} + +void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *CoroStmt) { + VisitStmt(CoroStmt); + Record.push_back(CoroStmt->getParamMoves().size()); + for (Stmt *S : CoroStmt->children()) + Record.AddStmt(S); + Code = serialization::STMT_COROUTINE_BODY; +} + +void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getKeywordLoc()); + Record.AddStmt(S->getOperand()); + Record.AddStmt(S->getPromiseCall()); + Record.push_back(S->isImplicit()); + Code = serialization::STMT_CORETURN; +} + +void ASTStmtWriter::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getKeywordLoc()); + for (Stmt *S : E->children()) + Record.AddStmt(S); + Record.AddStmt(E->getOpaqueValue()); +} + +void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *E) { + VisitCoroutineSuspendExpr(E); + Record.push_back(E->isImplicit()); + Code = serialization::EXPR_COAWAIT; +} + +void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) { + VisitCoroutineSuspendExpr(E); + Code = serialization::EXPR_COYIELD; +} + +void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getKeywordLoc()); + for (Stmt *S : E->children()) + Record.AddStmt(S); + Code = serialization::EXPR_DEPENDENT_COAWAIT; +} + +void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { + VisitStmt(S); + // NumCaptures + Record.push_back(std::distance(S->capture_begin(), S->capture_end())); + + // CapturedDecl and captured region kind + Record.AddDeclRef(S->getCapturedDecl()); + Record.push_back(S->getCapturedRegionKind()); + + Record.AddDeclRef(S->getCapturedRecordDecl()); + + // Capture inits + for (auto *I : S->capture_inits()) + Record.AddStmt(I); + + // Body + Record.AddStmt(S->getCapturedStmt()); + + // Captures + for (const auto &I : S->captures()) { + if (I.capturesThis() || I.capturesVariableArrayType()) + Record.AddDeclRef(nullptr); + else + Record.AddDeclRef(I.getCapturedVar()); + Record.push_back(I.getCaptureKind()); + Record.AddSourceLocation(I.getLocation()); + } + + Code = serialization::STMT_CAPTURED; +} + +void ASTStmtWriter::VisitExpr(Expr *E) { + VisitStmt(E); + Record.AddTypeRef(E->getType()); + 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::VisitConstantExpr(ConstantExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_CONSTANT; +} + +void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { + VisitExpr(E); + + bool HasFunctionName = E->getFunctionName() != nullptr; + Record.push_back(HasFunctionName); + Record.push_back(E->getIdentKind()); // FIXME: stable encoding + Record.AddSourceLocation(E->getLocation()); + if (HasFunctionName) + Record.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()) + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + + if (E->getDecl() != E->getFoundDecl()) + Record.AddDeclRef(E->getFoundDecl()); + + if (E->hasTemplateKWAndArgsInfo()) + AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>()); + + Record.AddDeclRef(E->getDecl()); + Record.AddSourceLocation(E->getLocation()); + Record.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName()); + Code = serialization::EXPR_DECL_REF; +} + +void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLocation()); + Record.AddAPInt(E->getValue()); + + if (E->getValue().getBitWidth() == 32) { + AbbrevToUse = Writer.getIntegerLiteralAbbrev(); + } + + Code = serialization::EXPR_INTEGER_LITERAL; +} + +void ASTStmtWriter::VisitFixedPointLiteral(FixedPointLiteral *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLocation()); + Record.AddAPInt(E->getValue()); + Code = serialization::EXPR_INTEGER_LITERAL; +} + +void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) { + VisitExpr(E); + Record.push_back(E->getRawSemantics()); + Record.push_back(E->isExact()); + Record.AddAPFloat(E->getValue()); + Record.AddSourceLocation(E->getLocation()); + Code = serialization::EXPR_FLOATING_LITERAL; +} + +void ASTStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_IMAGINARY_LITERAL; +} + +void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) { + VisitExpr(E); + + // Store the various bits of data of StringLiteral. + Record.push_back(E->getNumConcatenated()); + Record.push_back(E->getLength()); + Record.push_back(E->getCharByteWidth()); + Record.push_back(E->getKind()); + Record.push_back(E->isPascal()); + + // Store the trailing array of SourceLocation. + for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I) + Record.AddSourceLocation(E->getStrTokenLoc(I)); + + // Store the trailing array of char holding the string data. + StringRef StrData = E->getBytes(); + for (unsigned I = 0, N = E->getByteLength(); I != N; ++I) + Record.push_back(StrData[I]); + + Code = serialization::EXPR_STRING_LITERAL; +} + +void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Record.AddSourceLocation(E->getLocation()); + Record.push_back(E->getKind()); + + AbbrevToUse = Writer.getCharacterLiteralAbbrev(); + + Code = serialization::EXPR_CHARACTER_LITERAL; +} + +void ASTStmtWriter::VisitParenExpr(ParenExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLParen()); + Record.AddSourceLocation(E->getRParen()); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_PAREN; +} + +void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumExprs()); + for (auto *SubStmt : E->exprs()) + Record.AddStmt(SubStmt); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_PAREN_LIST; +} + +void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Record.push_back(E->getOpcode()); // FIXME: stable encoding + Record.AddSourceLocation(E->getOperatorLoc()); + Record.push_back(E->canOverflow()); + Code = serialization::EXPR_UNARY_OPERATOR; +} + +void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumComponents()); + Record.push_back(E->getNumExpressions()); + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + const OffsetOfNode &ON = E->getComponent(I); + Record.push_back(ON.getKind()); // FIXME: Stable encoding + Record.AddSourceLocation(ON.getSourceRange().getBegin()); + Record.AddSourceLocation(ON.getSourceRange().getEnd()); + switch (ON.getKind()) { + case OffsetOfNode::Array: + Record.push_back(ON.getArrayExprIndex()); + break; + + case OffsetOfNode::Field: + Record.AddDeclRef(ON.getField()); + break; + + case OffsetOfNode::Identifier: + Record.AddIdentifierRef(ON.getFieldName()); + break; + + case OffsetOfNode::Base: + Record.AddCXXBaseSpecifier(*ON.getBase()); + break; + } + } + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + Record.AddStmt(E->getIndexExpr(I)); + Code = serialization::EXPR_OFFSETOF; +} + +void ASTStmtWriter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->getKind()); + if (E->isArgumentType()) + Record.AddTypeSourceInfo(E->getArgumentTypeInfo()); + else { + Record.push_back(0); + Record.AddStmt(E->getArgumentExpr()); + } + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_SIZEOF_ALIGN_OF; +} + +void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getLHS()); + Record.AddStmt(E->getRHS()); + Record.AddSourceLocation(E->getRBracketLoc()); + Code = serialization::EXPR_ARRAY_SUBSCRIPT; +} + +void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddStmt(E->getLowerBound()); + Record.AddStmt(E->getLength()); + Record.AddSourceLocation(E->getColonLoc()); + Record.AddSourceLocation(E->getRBracketLoc()); + Code = serialization::EXPR_OMP_ARRAY_SECTION; +} + +void ASTStmtWriter::VisitCallExpr(CallExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumArgs()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.AddStmt(E->getCallee()); + for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) + Record.AddStmt(*Arg); + Record.push_back(static_cast<unsigned>(E->getADLCallKind())); + 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()) + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + + Record.push_back(E->hasTemplateKWAndArgsInfo()); + if (E->hasTemplateKWAndArgsInfo()) { + Record.AddSourceLocation(E->getTemplateKeywordLoc()); + unsigned NumTemplateArgs = E->getNumTemplateArgs(); + Record.push_back(NumTemplateArgs); + Record.AddSourceLocation(E->getLAngleLoc()); + Record.AddSourceLocation(E->getRAngleLoc()); + for (unsigned i=0; i != NumTemplateArgs; ++i) + Record.AddTemplateArgumentLoc(E->getTemplateArgs()[i]); + } + + Record.push_back(E->hadMultipleCandidates()); + + DeclAccessPair FoundDecl = E->getFoundDecl(); + Record.AddDeclRef(FoundDecl.getDecl()); + Record.push_back(FoundDecl.getAccess()); + + Record.AddTypeRef(E->getType()); + Record.push_back(E->getValueKind()); + Record.push_back(E->getObjectKind()); + Record.AddStmt(E->getBase()); + Record.AddDeclRef(E->getMemberDecl()); + Record.AddSourceLocation(E->getMemberLoc()); + Record.push_back(E->isArrow()); + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddDeclarationNameLoc(E->MemberDNLoc, + E->getMemberDecl()->getDeclName()); + Code = serialization::EXPR_MEMBER; +} + +void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddSourceLocation(E->getIsaMemberLoc()); + Record.AddSourceLocation(E->getOpLoc()); + Record.push_back(E->isArrow()); + Code = serialization::EXPR_OBJC_ISA; +} + +void ASTStmtWriter:: +VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Record.push_back(E->shouldCopy()); + Code = serialization::EXPR_OBJC_INDIRECT_COPY_RESTORE; +} + +void ASTStmtWriter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { + VisitExplicitCastExpr(E); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getBridgeKeywordLoc()); + 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()); + Record.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) + Record.AddCXXBaseSpecifier(**PI); +} + +void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) { + VisitExpr(E); + Record.AddStmt(E->getLHS()); + Record.AddStmt(E->getRHS()); + Record.push_back(E->getOpcode()); // FIXME: stable encoding + Record.AddSourceLocation(E->getOperatorLoc()); + Record.push_back(E->getFPFeatures().getInt()); + Code = serialization::EXPR_BINARY_OPERATOR; +} + +void ASTStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { + VisitBinaryOperator(E); + Record.AddTypeRef(E->getComputationLHSType()); + Record.AddTypeRef(E->getComputationResultType()); + Code = serialization::EXPR_COMPOUND_ASSIGN_OPERATOR; +} + +void ASTStmtWriter::VisitConditionalOperator(ConditionalOperator *E) { + VisitExpr(E); + Record.AddStmt(E->getCond()); + Record.AddStmt(E->getLHS()); + Record.AddStmt(E->getRHS()); + Record.AddSourceLocation(E->getQuestionLoc()); + Record.AddSourceLocation(E->getColonLoc()); + Code = serialization::EXPR_CONDITIONAL_OPERATOR; +} + +void +ASTStmtWriter::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { + VisitExpr(E); + Record.AddStmt(E->getOpaqueValue()); + Record.AddStmt(E->getCommon()); + Record.AddStmt(E->getCond()); + Record.AddStmt(E->getTrueExpr()); + Record.AddStmt(E->getFalseExpr()); + Record.AddSourceLocation(E->getQuestionLoc()); + Record.AddSourceLocation(E->getColonLoc()); + Code = serialization::EXPR_BINARY_CONDITIONAL_OPERATOR; +} + +void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) { + VisitCastExpr(E); + Record.push_back(E->isPartOfExplicitCast()); + + if (E->path_size() == 0) + AbbrevToUse = Writer.getExprImplicitCastAbbrev(); + + Code = serialization::EXPR_IMPLICIT_CAST; +} + +void ASTStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) { + VisitCastExpr(E); + Record.AddTypeSourceInfo(E->getTypeInfoAsWritten()); +} + +void ASTStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { + VisitExplicitCastExpr(E); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_CSTYLE_CAST; +} + +void ASTStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + Record.AddStmt(E->getInitializer()); + Record.push_back(E->isFileScope()); + Code = serialization::EXPR_COMPOUND_LITERAL; +} + +void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddIdentifierRef(&E->getAccessor()); + Record.AddSourceLocation(E->getAccessorLoc()); + 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. + Record.AddStmt(E->getSyntacticForm()); + Record.AddSourceLocation(E->getLBraceLoc()); + Record.AddSourceLocation(E->getRBraceLoc()); + bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>(); + Record.push_back(isArrayFiller); + if (isArrayFiller) + Record.AddStmt(E->getArrayFiller()); + else + Record.AddDeclRef(E->getInitializedFieldInUnion()); + 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) + Record.AddStmt(E->getInit(I) != filler ? E->getInit(I) : nullptr); + } else { + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) + Record.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) + Record.AddStmt(E->getSubExpr(I)); + Record.AddSourceLocation(E->getEqualOrColonLoc()); + Record.push_back(E->usesGNUSyntax()); + for (const DesignatedInitExpr::Designator &D : E->designators()) { + if (D.isFieldDesignator()) { + if (FieldDecl *Field = D.getField()) { + Record.push_back(serialization::DESIG_FIELD_DECL); + Record.AddDeclRef(Field); + } else { + Record.push_back(serialization::DESIG_FIELD_NAME); + Record.AddIdentifierRef(D.getFieldName()); + } + Record.AddSourceLocation(D.getDotLoc()); + Record.AddSourceLocation(D.getFieldLoc()); + } else if (D.isArrayDesignator()) { + Record.push_back(serialization::DESIG_ARRAY); + Record.push_back(D.getFirstExprIndex()); + Record.AddSourceLocation(D.getLBracketLoc()); + Record.AddSourceLocation(D.getRBracketLoc()); + } else { + assert(D.isArrayRangeDesignator() && "Unknown designator"); + Record.push_back(serialization::DESIG_ARRAY_RANGE); + Record.push_back(D.getFirstExprIndex()); + Record.AddSourceLocation(D.getLBracketLoc()); + Record.AddSourceLocation(D.getEllipsisLoc()); + Record.AddSourceLocation(D.getRBracketLoc()); + } + } + Code = serialization::EXPR_DESIGNATED_INIT; +} + +void ASTStmtWriter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddStmt(E->getUpdater()); + Code = serialization::EXPR_DESIGNATED_INIT_UPDATE; +} + +void ASTStmtWriter::VisitNoInitExpr(NoInitExpr *E) { + VisitExpr(E); + Code = serialization::EXPR_NO_INIT; +} + +void ASTStmtWriter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) { + VisitExpr(E); + Record.AddStmt(E->SubExprs[0]); + Record.AddStmt(E->SubExprs[1]); + Code = serialization::EXPR_ARRAY_INIT_LOOP; +} + +void ASTStmtWriter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) { + VisitExpr(E); + Code = serialization::EXPR_ARRAY_INIT_INDEX; +} + +void ASTStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { + VisitExpr(E); + Code = serialization::EXPR_IMPLICIT_VALUE_INIT; +} + +void ASTStmtWriter::VisitVAArgExpr(VAArgExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Record.AddTypeSourceInfo(E->getWrittenTypeInfo()); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.push_back(E->isMicrosoftABI()); + Code = serialization::EXPR_VA_ARG; +} + +void ASTStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getAmpAmpLoc()); + Record.AddSourceLocation(E->getLabelLoc()); + Record.AddDeclRef(E->getLabel()); + Code = serialization::EXPR_ADDR_LABEL; +} + +void ASTStmtWriter::VisitStmtExpr(StmtExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubStmt()); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_STMT; +} + +void ASTStmtWriter::VisitChooseExpr(ChooseExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getCond()); + Record.AddStmt(E->getLHS()); + Record.AddStmt(E->getRHS()); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.push_back(E->isConditionDependent() ? false : E->isConditionTrue()); + Code = serialization::EXPR_CHOOSE; +} + +void ASTStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getTokenLocation()); + 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) + Record.AddStmt(E->getExpr(I)); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_SHUFFLE_VECTOR; +} + +void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + Record.AddStmt(E->getSrcExpr()); + Code = serialization::EXPR_CONVERT_VECTOR; +} + +void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getBlockDecl()); + Code = serialization::EXPR_BLOCK; +} + +void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumAssocs()); + + Record.AddStmt(E->getControllingExpr()); + for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + Record.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I)); + Record.AddStmt(E->getAssocExpr(I)); + } + Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex()); + + Record.AddSourceLocation(E->getGenericLoc()); + Record.AddSourceLocation(E->getDefaultLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + 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); + + Record.AddStmt(E->getSyntacticForm()); + for (PseudoObjectExpr::semantics_iterator + i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) { + Record.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) + Record.AddStmt(E->getSubExprs()[I]); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_ATOMIC; +} + +//===----------------------------------------------------------------------===// +// Objective-C Expressions and Statements. +//===----------------------------------------------------------------------===// + +void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) { + VisitExpr(E); + Record.AddStmt(E->getString()); + Record.AddSourceLocation(E->getAtLoc()); + Code = serialization::EXPR_OBJC_STRING_LITERAL; +} + +void ASTStmtWriter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Record.AddDeclRef(E->getBoxingMethod()); + Record.AddSourceRange(E->getSourceRange()); + 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++) + Record.AddStmt(E->getElement(i)); + Record.AddDeclRef(E->getArrayWithObjectsMethod()); + Record.AddSourceRange(E->getSourceRange()); + 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); + Record.AddStmt(Element.Key); + Record.AddStmt(Element.Value); + if (E->HasPackExpansions) { + Record.AddSourceLocation(Element.EllipsisLoc); + unsigned NumExpansions = 0; + if (Element.NumExpansions) + NumExpansions = *Element.NumExpansions + 1; + Record.push_back(NumExpansions); + } + } + + Record.AddDeclRef(E->getDictWithObjectsMethod()); + Record.AddSourceRange(E->getSourceRange()); + Code = serialization::EXPR_OBJC_DICTIONARY_LITERAL; +} + +void ASTStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + VisitExpr(E); + Record.AddTypeSourceInfo(E->getEncodedTypeSourceInfo()); + Record.AddSourceLocation(E->getAtLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_OBJC_ENCODE; +} + +void ASTStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + VisitExpr(E); + Record.AddSelectorRef(E->getSelector()); + Record.AddSourceLocation(E->getAtLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_OBJC_SELECTOR_EXPR; +} + +void ASTStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getProtocol()); + Record.AddSourceLocation(E->getAtLoc()); + Record.AddSourceLocation(E->ProtoLoc); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_OBJC_PROTOCOL_EXPR; +} + +void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getDecl()); + Record.AddSourceLocation(E->getLocation()); + Record.AddSourceLocation(E->getOpLoc()); + Record.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()) { + Record.AddDeclRef(E->getImplicitPropertyGetter()); + Record.AddDeclRef(E->getImplicitPropertySetter()); + } else { + Record.AddDeclRef(E->getExplicitProperty()); + } + Record.AddSourceLocation(E->getLocation()); + Record.AddSourceLocation(E->getReceiverLocation()); + if (E->isObjectReceiver()) { + Record.push_back(0); + Record.AddStmt(E->getBase()); + } else if (E->isSuperReceiver()) { + Record.push_back(1); + Record.AddTypeRef(E->getSuperReceiverType()); + } else { + Record.push_back(2); + Record.AddDeclRef(E->getClassReceiver()); + } + + Code = serialization::EXPR_OBJC_PROPERTY_REF_EXPR; +} + +void ASTStmtWriter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getRBracket()); + Record.AddStmt(E->getBaseExpr()); + Record.AddStmt(E->getKeyExpr()); + Record.AddDeclRef(E->getAtIndexMethodDecl()); + Record.AddDeclRef(E->setAtIndexMethodDecl()); + + 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: + Record.AddStmt(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + Record.AddTypeSourceInfo(E->getClassReceiverTypeInfo()); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + Record.AddTypeRef(E->getSuperType()); + Record.AddSourceLocation(E->getSuperLoc()); + break; + } + + if (E->getMethodDecl()) { + Record.push_back(1); + Record.AddDeclRef(E->getMethodDecl()); + } else { + Record.push_back(0); + Record.AddSelectorRef(E->getSelector()); + } + + Record.AddSourceLocation(E->getLeftLoc()); + Record.AddSourceLocation(E->getRightLoc()); + + for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) + Record.AddStmt(*Arg); + + SourceLocation *Locs = E->getStoredSelLocs(); + for (unsigned i = 0, e = E->getNumStoredSelLocs(); i != e; ++i) + Record.AddSourceLocation(Locs[i]); + + Code = serialization::EXPR_OBJC_MESSAGE_EXPR; +} + +void ASTStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); + Record.AddStmt(S->getElement()); + Record.AddStmt(S->getCollection()); + Record.AddStmt(S->getBody()); + Record.AddSourceLocation(S->getForLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Code = serialization::STMT_OBJC_FOR_COLLECTION; +} + +void ASTStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + Record.AddStmt(S->getCatchBody()); + Record.AddDeclRef(S->getCatchParamDecl()); + Record.AddSourceLocation(S->getAtCatchLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Code = serialization::STMT_OBJC_CATCH; +} + +void ASTStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + Record.AddStmt(S->getFinallyBody()); + Record.AddSourceLocation(S->getAtFinallyLoc()); + Code = serialization::STMT_OBJC_FINALLY; +} + +void ASTStmtWriter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + Record.AddStmt(S->getSubStmt()); + Record.AddSourceLocation(S->getAtLoc()); + Code = serialization::STMT_OBJC_AUTORELEASE_POOL; +} + +void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + Record.push_back(S->getNumCatchStmts()); + Record.push_back(S->getFinallyStmt() != nullptr); + Record.AddStmt(S->getTryBody()); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) + Record.AddStmt(S->getCatchStmt(I)); + if (S->getFinallyStmt()) + Record.AddStmt(S->getFinallyStmt()); + Record.AddSourceLocation(S->getAtTryLoc()); + Code = serialization::STMT_OBJC_AT_TRY; +} + +void ASTStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + Record.AddStmt(S->getSynchExpr()); + Record.AddStmt(S->getSynchBody()); + Record.AddSourceLocation(S->getAtSynchronizedLoc()); + Code = serialization::STMT_OBJC_AT_SYNCHRONIZED; +} + +void ASTStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + Record.AddStmt(S->getThrowExpr()); + Record.AddSourceLocation(S->getThrowLoc()); + Code = serialization::STMT_OBJC_AT_THROW; +} + +void ASTStmtWriter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Record.AddSourceLocation(E->getLocation()); + Code = serialization::EXPR_OBJC_BOOL_LITERAL; +} + +void ASTStmtWriter::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + VisitExpr(E); + Record.AddSourceRange(E->getSourceRange()); + Record.AddVersionTuple(E->getVersion()); + Code = serialization::EXPR_OBJC_AVAILABILITY_CHECK; +} + +//===----------------------------------------------------------------------===// +// C++ Expressions and Statements. +//===----------------------------------------------------------------------===// + +void ASTStmtWriter::VisitCXXCatchStmt(CXXCatchStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getCatchLoc()); + Record.AddDeclRef(S->getExceptionDecl()); + Record.AddStmt(S->getHandlerBlock()); + Code = serialization::STMT_CXX_CATCH; +} + +void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) { + VisitStmt(S); + Record.push_back(S->getNumHandlers()); + Record.AddSourceLocation(S->getTryLoc()); + Record.AddStmt(S->getTryBlock()); + for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i) + Record.AddStmt(S->getHandler(i)); + Code = serialization::STMT_CXX_TRY; +} + +void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getForLoc()); + Record.AddSourceLocation(S->getCoawaitLoc()); + Record.AddSourceLocation(S->getColonLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Record.AddStmt(S->getInit()); + Record.AddStmt(S->getRangeStmt()); + Record.AddStmt(S->getBeginStmt()); + Record.AddStmt(S->getEndStmt()); + Record.AddStmt(S->getCond()); + Record.AddStmt(S->getInc()); + Record.AddStmt(S->getLoopVarStmt()); + Record.AddStmt(S->getBody()); + Code = serialization::STMT_CXX_FOR_RANGE; +} + +void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getKeywordLoc()); + Record.push_back(S->isIfExists()); + Record.AddNestedNameSpecifierLoc(S->getQualifierLoc()); + Record.AddDeclarationNameInfo(S->getNameInfo()); + Record.AddStmt(S->getSubStmt()); + Code = serialization::STMT_MS_DEPENDENT_EXISTS; +} + +void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + VisitCallExpr(E); + Record.push_back(E->getOperator()); + Record.push_back(E->getFPFeatures().getInt()); + Record.AddSourceRange(E->Range); + 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()); + 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 + Record.AddSourceLocation(E->getLocation()); + Record.AddDeclRef(E->getConstructor()); + Record.AddSourceRange(E->getParenOrBraceRange()); + + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Record.AddStmt(E->getArg(I)); + + Code = serialization::EXPR_CXX_CONSTRUCT; +} + +void ASTStmtWriter::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getConstructor()); + Record.AddSourceLocation(E->getLocation()); + Record.push_back(E->constructsVBase()); + Record.push_back(E->inheritedFromVBase()); + Code = serialization::EXPR_CXX_INHERITED_CTOR_INIT; +} + +void ASTStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { + VisitCXXConstructExpr(E); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + Code = serialization::EXPR_CXX_TEMPORARY_OBJECT; +} + +void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) { + VisitExpr(E); + Record.push_back(E->NumCaptures); + Record.AddSourceRange(E->IntroducerRange); + Record.push_back(E->CaptureDefault); // FIXME: stable encoding + Record.AddSourceLocation(E->CaptureDefaultLoc); + Record.push_back(E->ExplicitParams); + Record.push_back(E->ExplicitResultType); + Record.AddSourceLocation(E->ClosingBrace); + + // Add capture initializers. + for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(), + CEnd = E->capture_init_end(); + C != CEnd; ++C) { + Record.AddStmt(*C); + } + + Code = serialization::EXPR_LAMBDA; +} + +void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_CXX_STD_INITIALIZER_LIST; +} + +void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + VisitExplicitCastExpr(E); + Record.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc())); + Record.AddSourceRange(E->getAngleBrackets()); +} + +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); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_CXX_FUNCTIONAL_CAST; +} + +void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) { + VisitCallExpr(E); + Record.AddSourceLocation(E->UDSuffixLoc); + Code = serialization::EXPR_USER_DEFINED_LITERAL; +} + +void ASTStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Record.AddSourceLocation(E->getLocation()); + Code = serialization::EXPR_CXX_BOOL_LITERAL; +} + +void ASTStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLocation()); + Code = serialization::EXPR_CXX_NULL_PTR_LITERAL; +} + +void ASTStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + Record.AddSourceRange(E->getSourceRange()); + if (E->isTypeOperand()) { + Record.AddTypeSourceInfo(E->getTypeOperandSourceInfo()); + Code = serialization::EXPR_CXX_TYPEID_TYPE; + } else { + Record.AddStmt(E->getExprOperand()); + Code = serialization::EXPR_CXX_TYPEID_EXPR; + } +} + +void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLocation()); + Record.push_back(E->isImplicit()); + Code = serialization::EXPR_CXX_THIS; +} + +void ASTStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getThrowLoc()); + Record.AddStmt(E->getSubExpr()); + Record.push_back(E->isThrownVariableInScope()); + Code = serialization::EXPR_CXX_THROW; +} + +void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getParam()); + Record.AddSourceLocation(E->getUsedLocation()); + Code = serialization::EXPR_CXX_DEFAULT_ARG; +} + +void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getField()); + Record.AddSourceLocation(E->getExprLoc()); + Code = serialization::EXPR_CXX_DEFAULT_INIT; +} + +void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + Record.AddCXXTemporary(E->getTemporary()); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_CXX_BIND_TEMPORARY; +} + +void ASTStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { + VisitExpr(E); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_CXX_SCALAR_VALUE_INIT; +} + +void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + + Record.push_back(E->isArray()); + Record.push_back(E->hasInitializer()); + Record.push_back(E->getNumPlacementArgs()); + Record.push_back(E->isParenTypeId()); + + Record.push_back(E->isGlobalNew()); + Record.push_back(E->passAlignment()); + Record.push_back(E->doesUsualArrayDeleteWantSize()); + Record.push_back(E->CXXNewExprBits.StoredInitializationStyle); + + Record.AddDeclRef(E->getOperatorNew()); + Record.AddDeclRef(E->getOperatorDelete()); + Record.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo()); + if (E->isParenTypeId()) + Record.AddSourceRange(E->getTypeIdParens()); + Record.AddSourceRange(E->getSourceRange()); + Record.AddSourceRange(E->getDirectInitRange()); + + for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), N = E->raw_arg_end(); + I != N; ++I) + Record.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()); + Record.AddDeclRef(E->getOperatorDelete()); + Record.AddStmt(E->getArgument()); + Record.AddSourceLocation(E->getBeginLoc()); + + Code = serialization::EXPR_CXX_DELETE; +} + +void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + VisitExpr(E); + + Record.AddStmt(E->getBase()); + Record.push_back(E->isArrow()); + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + Record.AddTypeSourceInfo(E->getScopeTypeInfo()); + Record.AddSourceLocation(E->getColonColonLoc()); + Record.AddSourceLocation(E->getTildeLoc()); + + // PseudoDestructorTypeStorage. + Record.AddIdentifierRef(E->getDestroyedTypeIdentifier()); + if (E->getDestroyedTypeIdentifier()) + Record.AddSourceLocation(E->getDestroyedTypeLoc()); + else + Record.AddTypeSourceInfo(E->getDestroyedTypeInfo()); + + 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) + Record.AddDeclRef(E->getObject(i)); + + Record.push_back(E->cleanupsHaveSideEffects()); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_EXPR_WITH_CLEANUPS; +} + +void ASTStmtWriter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + VisitExpr(E); + + // Don't emit anything here (or if you do you will have to update + // the corresponding deserialization function). + + Record.push_back(E->hasTemplateKWAndArgsInfo()); + Record.push_back(E->getNumTemplateArgs()); + Record.push_back(E->hasFirstQualifierFoundInScope()); + + if (E->hasTemplateKWAndArgsInfo()) { + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + AddTemplateKWAndArgsInfo(ArgInfo, + E->getTrailingObjects<TemplateArgumentLoc>()); + } + + Record.push_back(E->isArrow()); + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddTypeRef(E->getBaseType()); + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + if (!E->isImplicitAccess()) + Record.AddStmt(E->getBase()); + else + Record.AddStmt(nullptr); + + if (E->hasFirstQualifierFoundInScope()) + Record.AddDeclRef(E->getFirstQualifierFoundInScope()); + + Record.AddDeclarationNameInfo(E->MemberNameInfo); + 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->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo); + if (E->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo) { + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + Record.push_back(ArgInfo.NumTemplateArgs); + AddTemplateKWAndArgsInfo(ArgInfo, + E->getTrailingObjects<TemplateArgumentLoc>()); + } + + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + Record.AddDeclarationNameInfo(E->NameInfo); + 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) + Record.AddStmt(*ArgI); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_CXX_UNRESOLVED_CONSTRUCT; +} + +void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) { + VisitExpr(E); + + Record.push_back(E->getNumDecls()); + Record.push_back(E->hasTemplateKWAndArgsInfo()); + if (E->hasTemplateKWAndArgsInfo()) { + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingASTTemplateKWAndArgsInfo(); + Record.push_back(ArgInfo.NumTemplateArgs); + AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingTemplateArgumentLoc()); + } + + for (OverloadExpr::decls_iterator OvI = E->decls_begin(), + OvE = E->decls_end(); + OvI != OvE; ++OvI) { + Record.AddDeclRef(OvI.getDecl()); + Record.push_back(OvI.getAccess()); + } + + Record.AddDeclarationNameInfo(E->getNameInfo()); + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); +} + +void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { + VisitOverloadExpr(E); + Record.push_back(E->isArrow()); + Record.push_back(E->hasUnresolvedUsing()); + Record.AddStmt(!E->isImplicitAccess() ? E->getBase() : nullptr); + Record.AddTypeRef(E->getBaseType()); + Record.AddSourceLocation(E->getOperatorLoc()); + Code = serialization::EXPR_CXX_UNRESOLVED_MEMBER; +} + +void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { + VisitOverloadExpr(E); + Record.push_back(E->requiresADL()); + Record.push_back(E->isOverloaded()); + Record.AddDeclRef(E->getNamingClass()); + 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); + Record.AddSourceRange(E->getSourceRange()); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Record.AddTypeSourceInfo(E->getArg(I)); + Code = serialization::EXPR_TYPE_TRAIT; +} + +void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->getTrait()); + Record.push_back(E->getValue()); + Record.AddSourceRange(E->getSourceRange()); + Record.AddTypeSourceInfo(E->getQueriedTypeSourceInfo()); + Record.AddStmt(E->getDimensionExpression()); + Code = serialization::EXPR_ARRAY_TYPE_TRAIT; +} + +void ASTStmtWriter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->getTrait()); + Record.push_back(E->getValue()); + Record.AddSourceRange(E->getSourceRange()); + Record.AddStmt(E->getQueriedExpression()); + Code = serialization::EXPR_CXX_EXPRESSION_TRAIT; +} + +void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Record.AddSourceRange(E->getSourceRange()); + Record.AddStmt(E->getOperand()); + Code = serialization::EXPR_CXX_NOEXCEPT; +} + +void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getEllipsisLoc()); + Record.push_back(E->NumExpansions); + Record.AddStmt(E->getPattern()); + Code = serialization::EXPR_PACK_EXPANSION; +} + +void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + VisitExpr(E); + Record.push_back(E->isPartiallySubstituted() ? E->getPartialArguments().size() + : 0); + Record.AddSourceLocation(E->OperatorLoc); + Record.AddSourceLocation(E->PackLoc); + Record.AddSourceLocation(E->RParenLoc); + Record.AddDeclRef(E->Pack); + if (E->isPartiallySubstituted()) { + for (const auto &TA : E->getPartialArguments()) + Record.AddTemplateArgument(TA); + } else if (!E->isValueDependent()) { + Record.push_back(E->getPackLength()); + } + Code = serialization::EXPR_SIZEOF_PACK; +} + +void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getParameter()); + Record.AddSourceLocation(E->getNameLoc()); + Record.AddStmt(E->getReplacement()); + Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM; +} + +void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getParameterPack()); + Record.AddTemplateArgument(E->getArgumentPack()); + Record.AddSourceLocation(E->getParameterPackLocation()); + Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK; +} + +void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumExpansions()); + Record.AddDeclRef(E->getParameterPack()); + Record.AddSourceLocation(E->getParameterPackLocation()); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) + Record.AddDeclRef(*I); + Code = serialization::EXPR_FUNCTION_PARM_PACK; +} + +void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getTemporary()); + Record.AddDeclRef(E->getExtendingDecl()); + Record.push_back(E->getManglingNumber()); + Code = serialization::EXPR_MATERIALIZE_TEMPORARY; +} + +void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->LParenLoc); + Record.AddSourceLocation(E->EllipsisLoc); + Record.AddSourceLocation(E->RParenLoc); + Record.AddStmt(E->SubExprs[0]); + Record.AddStmt(E->SubExprs[1]); + Record.push_back(E->Opcode); + Code = serialization::EXPR_CXX_FOLD; +} + +void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getSourceExpr()); + Record.AddSourceLocation(E->getLocation()); + Record.push_back(E->isUnique()); + Code = serialization::EXPR_OPAQUE_VALUE; +} + +void ASTStmtWriter::VisitTypoExpr(TypoExpr *E) { + VisitExpr(E); + // TODO: Figure out sane writer behavior for a TypoExpr, if necessary + llvm_unreachable("Cannot write TypoExpr nodes"); +} + +//===----------------------------------------------------------------------===// +// CUDA Expressions and Statements. +//===----------------------------------------------------------------------===// + +void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) { + VisitCallExpr(E); + Record.AddStmt(E->getConfig()); + Code = serialization::EXPR_CUDA_KERNEL_CALL; +} + +//===----------------------------------------------------------------------===// +// OpenCL Expressions and Statements. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getBuiltinLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Record.AddStmt(E->getSrcExpr()); + Code = serialization::EXPR_ASTYPE; +} + +//===----------------------------------------------------------------------===// +// Microsoft Expressions and Statements. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + Record.push_back(E->isArrow()); + Record.AddStmt(E->getBaseExpr()); + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + Record.AddSourceLocation(E->getMemberLoc()); + Record.AddDeclRef(E->getPropertyDecl()); + Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; +} + +void ASTStmtWriter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getBase()); + Record.AddStmt(E->getIdx()); + Record.AddSourceLocation(E->getRBracketLoc()); + Code = serialization::EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR; +} + +void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { + VisitExpr(E); + Record.AddSourceRange(E->getSourceRange()); + Record.AddString(E->getUuidStr()); + if (E->isTypeOperand()) { + Record.AddTypeSourceInfo(E->getTypeOperandSourceInfo()); + Code = serialization::EXPR_CXX_UUIDOF_TYPE; + } else { + Record.AddStmt(E->getExprOperand()); + Code = serialization::EXPR_CXX_UUIDOF_EXPR; + } +} + +void ASTStmtWriter::VisitSEHExceptStmt(SEHExceptStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getExceptLoc()); + Record.AddStmt(S->getFilterExpr()); + Record.AddStmt(S->getBlock()); + Code = serialization::STMT_SEH_EXCEPT; +} + +void ASTStmtWriter::VisitSEHFinallyStmt(SEHFinallyStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getFinallyLoc()); + Record.AddStmt(S->getBlock()); + Code = serialization::STMT_SEH_FINALLY; +} + +void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) { + VisitStmt(S); + Record.push_back(S->getIsCXXTry()); + Record.AddSourceLocation(S->getTryLoc()); + Record.AddStmt(S->getTryBlock()); + Record.AddStmt(S->getHandler()); + Code = serialization::STMT_SEH_TRY; +} + +void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getLeaveLoc()); + Code = serialization::STMT_SEH_LEAVE; +} + +//===----------------------------------------------------------------------===// +// OpenMP Directives. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { + Record.AddSourceLocation(E->getBeginLoc()); + Record.AddSourceLocation(E->getEndLoc()); + OMPClauseWriter ClauseWriter(Record); + for (unsigned i = 0; i < E->getNumClauses(); ++i) { + ClauseWriter.writeClause(E->getClause(i)); + } + if (E->hasAssociatedStmt()) + Record.AddStmt(E->getAssociatedStmt()); +} + +void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Record.AddStmt(D->getIterationVariable()); + Record.AddStmt(D->getLastIteration()); + Record.AddStmt(D->getCalcLastIteration()); + Record.AddStmt(D->getPreCond()); + Record.AddStmt(D->getCond()); + Record.AddStmt(D->getInit()); + Record.AddStmt(D->getInc()); + Record.AddStmt(D->getPreInits()); + if (isOpenMPWorksharingDirective(D->getDirectiveKind()) || + isOpenMPTaskLoopDirective(D->getDirectiveKind()) || + isOpenMPDistributeDirective(D->getDirectiveKind())) { + Record.AddStmt(D->getIsLastIterVariable()); + Record.AddStmt(D->getLowerBoundVariable()); + Record.AddStmt(D->getUpperBoundVariable()); + Record.AddStmt(D->getStrideVariable()); + Record.AddStmt(D->getEnsureUpperBound()); + Record.AddStmt(D->getNextLowerBound()); + Record.AddStmt(D->getNextUpperBound()); + Record.AddStmt(D->getNumIterations()); + } + if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) { + Record.AddStmt(D->getPrevLowerBoundVariable()); + Record.AddStmt(D->getPrevUpperBoundVariable()); + Record.AddStmt(D->getDistInc()); + Record.AddStmt(D->getPrevEnsureUpperBound()); + Record.AddStmt(D->getCombinedLowerBoundVariable()); + Record.AddStmt(D->getCombinedUpperBoundVariable()); + Record.AddStmt(D->getCombinedEnsureUpperBound()); + Record.AddStmt(D->getCombinedInit()); + Record.AddStmt(D->getCombinedCond()); + Record.AddStmt(D->getCombinedNextLowerBound()); + Record.AddStmt(D->getCombinedNextUpperBound()); + Record.AddStmt(D->getCombinedDistCond()); + Record.AddStmt(D->getCombinedParForInDistCond()); + } + for (auto I : D->counters()) { + Record.AddStmt(I); + } + for (auto I : D->private_counters()) { + Record.AddStmt(I); + } + for (auto I : D->inits()) { + Record.AddStmt(I); + } + for (auto I : D->updates()) { + Record.AddStmt(I); + } + for (auto I : D->finals()) { + Record.AddStmt(I); + } +} + +void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + 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); + Record.push_back(D->hasCancel() ? 1 : 0); + 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); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_SECTIONS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPSectionDirective(OMPSectionDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + 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); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.AddDeclarationNameInfo(D->getDirectiveName()); + Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) { + VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + 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); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_TASK_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.AddStmt(D->getX()); + Record.AddStmt(D->getV()); + Record.AddStmt(D->getExpr()); + Record.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::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_DATA_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetEnterDataDirective( + OMPTargetEnterDataDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_ENTER_DATA_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetExitDataDirective( + OMPTargetExitDataDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_EXIT_DATA_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetParallelDirective( + OMPTargetParallelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_PARALLEL_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetParallelForDirective( + OMPTargetParallelForDirective *D) { + VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_TARGET_PARALLEL_FOR_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::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.AddStmt(D->getReductionRef()); + Code = serialization::STMT_OMP_TASKGROUP_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); + Record.push_back(D->getNumClauses()); + 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; +} + +void ASTStmtWriter::VisitOMPCancellationPointDirective( + OMPCancellationPointDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + Record.push_back(D->getCancelRegion()); + Code = serialization::STMT_OMP_CANCELLATION_POINT_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Record.push_back(D->getCancelRegion()); + Code = serialization::STMT_OMP_CANCEL_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TASKLOOP_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TASKLOOP_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_UPDATE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeParallelForDirective( + OMPDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeParallelForSimdDirective( + OMPDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeSimdDirective( + OMPDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetParallelForSimdDirective( + OMPTargetParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TARGET_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetSimdDirective(OMPTargetSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TARGET_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTeamsDistributeDirective( + OMPTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TEAMS_DISTRIBUTE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTeamsDistributeSimdDirective( + OMPTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTeamsDistributeParallelForSimdDirective( + OMPTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTeamsDistributeParallelForDirective( + OMPTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_TEAMS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDistributeDirective( + OMPTargetTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TARGET_TEAMS_DISTRIBUTE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDistributeParallelForDirective( + OMPTargetTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); + Code = serialization::STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDistributeParallelForSimdDirective( + OMPTargetTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization:: + STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDistributeSimdDirective( + OMPTargetTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_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(); +} + +/// Write the given substatement or subexpression to the +/// bitstream. +void ASTWriter::WriteSubStmt(Stmt *S) { + 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 + + Writer.Visit(S); + + uint64_t Offset = Writer.Emit(); + SubStmtEntries[S] = Offset; +} + +/// Flush all of the statements that have been added to the +/// queue via AddStmt(). +void ASTRecordWriter::FlushStmts() { + // We expect to be the only consumer of the two temporary statement maps, + // assert that they are empty. + assert(Writer->SubStmtEntries.empty() && "unexpected entries in sub-stmt map"); + assert(Writer->ParentStmts.empty() && "unexpected entries in parent stmt map"); + + for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) { + Writer->WriteSubStmt(StmtsToEmit[I]); + + assert(N == StmtsToEmit.size() && "record modified while being written!"); + + // Note that we are at the end of a full expression. Any + // expression records that follow this one are part of a different + // expression. + Writer->Stream.EmitRecord(serialization::STMT_STOP, ArrayRef<uint32_t>()); + + Writer->SubStmtEntries.clear(); + Writer->ParentStmts.clear(); + } + + StmtsToEmit.clear(); +} + +void ASTRecordWriter::FlushSubStmts() { + // For a nested statement, write out the substatements in reverse order (so + // that a simple stack machine can be used when loading), and don't emit a + // STMT_STOP after each one. + for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) { + Writer->WriteSubStmt(StmtsToEmit[N - I - 1]); + assert(N == StmtsToEmit.size() && "record modified while being written!"); + } + + 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 000000000000..2e0076521f9c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp @@ -0,0 +1,76 @@ +//===--- 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/AST/ASTContext.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Serialization/ASTWriter.h" +#include "llvm/Bitcode/BitstreamWriter.h" + +using namespace clang; + +PCHGenerator::PCHGenerator( + const Preprocessor &PP, StringRef OutputFile, StringRef isysroot, + std::shared_ptr<PCHBuffer> Buffer, + ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, + bool AllowASTWithErrors, bool IncludeTimestamps) + : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()), + SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data), + Writer(Stream, this->Buffer->Data, PP.getPCMCache(), Extensions, + IncludeTimestamps), + AllowASTWithErrors(AllowASTWithErrors) { + this->Buffer->IsComplete = 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; + + Module *Module = nullptr; + if (PP.getLangOpts().isCompilingModule()) { + Module = PP.getHeaderSearchInfo().lookupModule( + PP.getLangOpts().CurrentModule, /*AllowSearch*/ false); + if (!Module) { + assert(hasErrors && "emitting module but current module doesn't exist"); + return; + } + } + + // Emit the PCH file to the Buffer. + assert(SemaPtr && "No Sema?"); + Buffer->Signature = + Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, + // For serialization we are lenient if the errors were + // only warn-as-error kind. + PP.getDiagnostics().hasUncompilableErrorOccurred()); + + Buffer->IsComplete = 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 000000000000..e7642a38924d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp @@ -0,0 +1,943 @@ +//===--- 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 "clang/Serialization/PCHContainerOperations.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/DJB.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 { + /// The block containing the index. + GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + }; + + /// Describes the record types in the index. + enum IndexRecordTypes { + /// Contains version information and potentially other metadata, + /// used to determine if we can read this global index file. + INDEX_METADATA, + /// Describes a module, including its file name and dependencies. + MODULE, + /// The index for identifiers. + IDENTIFIER_INDEX + }; +} + +/// The name of the global index file. +static const char * const IndexFileName = "modules.idx"; + +/// The global index file version. +static const unsigned CurrentVersion = 1; + +//----------------------------------------------------------------------------// +// Global module index reader. +//----------------------------------------------------------------------------// + +namespace { + +/// 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::djbHash(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()); + + /// The main bitstream cursor for the main block. + llvm::BitstreamCursor Cursor(*Buffer); + + // 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"); +} + +LLVM_DUMP_METHOD 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 { + /// Provides information about a specific module file. + struct ModuleFileInfo { + /// The numberic ID for this module file. + unsigned ID; + + /// The set of modules on which this module depends. Each entry is + /// a module ID. + SmallVector<unsigned, 4> Dependencies; + ASTFileSignature Signature; + }; + + struct ImportedModuleFileInfo { + off_t StoredSize; + time_t StoredModTime; + ASTFileSignature StoredSignature; + ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig) + : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {} + }; + + /// Builder that generates the global module index file. + class GlobalModuleIndexBuilder { + FileManager &FileMgr; + const PCHContainerReader &PCHContainerRdr; + + /// Mapping from files to module file information. + typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap; + + /// Information about each of the known module files. + ModuleFilesMap ModuleFiles; + + /// Mapping from the imported module file to the imported + /// information. + typedef std::multimap<const FileEntry *, ImportedModuleFileInfo> + ImportedModuleFilesMap; + + /// Information about each importing of a module file. + ImportedModuleFilesMap ImportedModuleFiles; + + /// Mapping from identifiers to the list of module file IDs that + /// consider this identifier to be interesting. + typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; + + /// A mapping from all interesting identifiers to the set of module + /// files in which those identifiers are considered interesting. + InterestingIdentifierMap InterestingIdentifiers; + + /// Write the block-info block for the global module index file. + void emitBlockInfoBlock(llvm::BitstreamWriter &Stream); + + /// 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, const PCHContainerReader &PCHContainerRdr) + : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {} + + /// Load the contents of the given module file into the builder. + /// + /// \returns true if an error occurred, false otherwise. + bool loadModuleFile(const FileEntry *File); + + /// Write the index to the given bitstream. + /// \returns true if an error occurred, false otherwise. + bool 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.EnterBlockInfoBlock(); + +#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: + /// 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::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer)); + + // 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, DiagnosticOptionsBlock } 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 (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) { + if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID)) + return true; + + // Found the Diagnostic Options block. + State = DiagnosticOptionsBlock; + 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. + ASTFileSignature StoredSignature = { + {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++]}}}; + + // Skip the module name (currently this is only used for prebuilt + // modules while here we are only dealing with cached). + Idx += Record[Idx] + 1; + + // 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) + return true; + + // Save the information in ImportedModuleFileInfo so we can verify after + // loading all pcms. + ImportedModuleFiles.insert(std::make_pair( + DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime, + StoredSignature))); + + // 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]; + } + } + + // Get Signature. + if (State == DiagnosticOptionsBlock && Code == SIGNATURE) + getModuleFileInfo(File).Signature = { + {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], + (uint32_t)Record[3], (uint32_t)Record[4]}}}; + + // We don't care about this record. + } + + return false; +} + +namespace { + +/// 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::djbHash(Key); + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) { + using namespace llvm::support; + endian::Writer LE(Out, little); + 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::write<uint32_t>(Out, Data[I], little); + } +}; + +} + +bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { + for (auto MapEntry : ImportedModuleFiles) { + auto *File = MapEntry.first; + ImportedModuleFileInfo &Info = MapEntry.second; + if (getModuleFileInfo(File).Signature) { + if (getModuleFileInfo(File).Signature != Info.StoredSignature) + // Verify Signature. + return true; + } else if (Info.StoredSize != File->getSize() || + Info.StoredModTime != File->getModificationTime()) + // Verify Size and ModTime. + return true; + } + + 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::write<uint32_t>(Out, 0, little); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + auto Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + // Write the identifier table + uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset}; + Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); + } + + Stream.ExitBlock(); + return false; +} + +GlobalModuleIndex::ErrorCode +GlobalModuleIndex::writeIndex(FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + 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, PCHContainerRdr); + + // 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); + if (Builder.writeIndex(OutputStream)) + return EC_IOError; + } + + // 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 { + /// The current position within the identifier lookup table. + IdentifierIndexTable::key_iterator Current; + + /// 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 000000000000..580e46e4f240 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp @@ -0,0 +1,95 @@ +//===- Module.cpp - Module description ------------------------------------===// +// +// 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 "clang/Serialization/ContinuousRangeMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace serialization; +using namespace reader; + +ModuleFile::~ModuleFile() { + 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; + + using MapType = ContinuousRangeMap<Key, Offset, InitialCapacity>; + + 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"; + } +} + +LLVM_DUMP_METHOD 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/ModuleFileExtension.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleFileExtension.cpp new file mode 100644 index 000000000000..5bd0a1ce660b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleFileExtension.cpp @@ -0,0 +1,21 @@ +//===-- ModuleFileExtension.cpp - Module File Extensions ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/ModuleFileExtension.h" +#include "llvm/ADT/Hashing.h" +using namespace clang; + +ModuleFileExtension::~ModuleFileExtension() { } + +llvm::hash_code ModuleFileExtension::hashExtension(llvm::hash_code Code) const { + return Code; +} + +ModuleFileExtensionWriter::~ModuleFileExtensionWriter() { } + +ModuleFileExtensionReader::~ModuleFileExtensionReader() { } 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 000000000000..54e0c08c5bc9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp @@ -0,0 +1,510 @@ +//===- ModuleManager.cpp - Module Manager ---------------------------------===// +// +// 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/Serialization/ModuleManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/MemoryBufferCache.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/ModuleMap.h" +#include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/PCHContainerOperations.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <algorithm> +#include <cassert> +#include <memory> +#include <string> +#include <system_error> + +using namespace clang; +using namespace serialization; + +ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const { + const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, + /*cacheFailure=*/false); + if (Entry) + return lookup(Entry); + + return nullptr; +} + +ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const { + if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name)) + if (const FileEntry *File = Mod->getASTFile()) + return lookup(File); + + return nullptr; +} + +ModuleFile *ModuleManager::lookup(const FileEntry *File) const { + auto 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]); +} + +static bool checkSignature(ASTFileSignature Signature, + ASTFileSignature ExpectedSignature, + std::string &ErrorStr) { + if (!ExpectedSignature || Signature == ExpectedSignature) + return false; + + ErrorStr = + Signature ? "signature mismatch" : "could not read module signature"; + return true; +} + +static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, + SourceLocation ImportLoc) { + if (ImportedBy) { + MF.ImportedBy.insert(ImportedBy); + ImportedBy->Imports.insert(&MF); + } else { + if (!MF.DirectlyImported) + MF.ImportLoc = ImportLoc; + + MF.DirectlyImported = true; + } +} + +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 || Type == MK_PrebuiltModule) { + // 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 + if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) { + // Check the stored signature. + if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr)) + return OutOfDate; + + Module = ModuleEntry; + updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc); + return AlreadyLoaded; + } + + // Allocate a new module. + auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation); + NewModule->Index = Chain.size(); + NewModule->FileName = FileName.str(); + NewModule->File = Entry; + NewModule->ImportLoc = ImportLoc; + NewModule->InputFilesValidationTimestamp = 0; + + if (NewModule->Kind == MK_ImplicitModule) { + std::string TimestampFilename = NewModule->getTimestampFilename(); + llvm::vfs::Status Status; + // A cached stat value would be fine as well. + if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) + NewModule->InputFilesValidationTimestamp = + llvm::sys::toTimeT(Status.getLastModificationTime()); + } + + // Load the contents of the module + if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { + // The buffer was already provided for us. + NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer)); + // Since the cached buffer is reused, it is safe to close the file + // descriptor that was opened while stat()ing the PCM in + // lookupModuleFile() above, it won't be needed any longer. + Entry->closeFile(); + } else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) { + NewModule->Buffer = Buffer; + // As above, the file descriptor is no longer needed. + Entry->closeFile(); + } else { + // Open the AST file. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code())); + if (FileName == "-") { + Buf = llvm::MemoryBuffer::getSTDIN(); + } else { + // Get a buffer of the file and close the file descriptor when done. + Buf = FileMgr.getBufferForFile(NewModule->File, + /*IsVolatile=*/false, + /*ShouldClose=*/true); + } + + if (!Buf) { + ErrorStr = Buf.getError().message(); + return Missing; + } + + NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf)); + } + + // Initialize the stream. + NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer); + + // Read the signature eagerly now so that we can check it. Avoid calling + // ReadSignature unless there's something to check though. + if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data), + ExpectedSignature, ErrorStr)) { + // Try to remove the buffer. If it can't be removed, then it was already + // validated by this process. + if (!PCMCache->tryToRemoveBuffer(NewModule->FileName)) + FileMgr.invalidateCache(NewModule->File); + return OutOfDate; + } + + // We're keeping this module. Store it everywhere. + Module = Modules[Entry] = NewModule.get(); + + updateModuleImports(*NewModule, ImportedBy, ImportLoc); + + if (!NewModule->isModule()) + PCHChain.push_back(NewModule.get()); + if (!ImportedBy) + Roots.push_back(NewModule.get()); + + Chain.push_back(std::move(NewModule)); + return NewlyLoaded; +} + +void ModuleManager::removeModules( + ModuleIterator First, + llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully, + ModuleMap *modMap) { + auto Last = end(); + if (First == Last) + return; + + // Explicitly clear VisitOrder since we might not notice it is stale. + VisitOrder.clear(); + + // Collect the set of module file pointers that we'll be removing. + llvm::SmallPtrSet<ModuleFile *, 4> victimSet( + (llvm::pointer_iterator<ModuleIterator>(First)), + (llvm::pointer_iterator<ModuleIterator>(Last))); + + auto IsVictim = [&](ModuleFile *MF) { + return victimSet.count(MF); + }; + // Remove any references to the now-destroyed modules. + for (auto I = begin(); I != First; ++I) { + I->Imports.remove_if(IsVictim); + I->ImportedBy.remove_if(IsVictim); + } + Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim), + Roots.end()); + + // Remove the modules from the PCH chain. + for (auto I = First; I != Last; ++I) { + if (!I->isModule()) { + PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I), + PCHChain.end()); + break; + } + } + + // 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. + // + // The PCMCache tracks whether the module was successfully loaded in another + // thread/context; in that case, it won't need to be rebuilt (and we can't + // safely invalidate it anyway). + if (LoadedSuccessfully.count(&*victim) == 0 && + !PCMCache->tryToRemoveBuffer(victim->FileName)) + FileMgr.invalidateCache(victim->File); + } + + // Delete the modules. + Chain.erase(Chain.begin() + (First - begin()), Chain.end()); +} + +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); +} + +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 (ModuleFile &M : *this) + if (!GlobalIndex->loadedModuleFile(&M)) + ModulesInCommonWithGlobalIndex.push_back(&M); +} + +void ModuleManager::moduleFileAccepted(ModuleFile *MF) { + if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) + return; + + ModulesInCommonWithGlobalIndex.push_back(MF); +} + +ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, + const PCHContainerReader &PCHContainerRdr, + const HeaderSearch& HeaderSearchInfo) + : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr), + HeaderSearchInfo(HeaderSearchInfo) {} + +ModuleManager::~ModuleManager() { delete FirstVisitState; } + +void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, + 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.resize(size()); + for (ModuleFile &M : llvm::reverse(*this)) { + unsigned Size = M.ImportedBy.size(); + UnusedIncomingEdges[M.Index] = Size; + if (!Size) + Queue.push_back(&M); + } + + // Traverse the graph, making sure to visit a module before visiting any + // of its dependencies. + while (!Queue.empty()) { + ModuleFile *CurrentModule = Queue.pop_back_val(); + 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 (auto M = CurrentModule->Imports.rbegin(), + MEnd = CurrentModule->Imports.rend(); + 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)) + 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); +} + +bool ModuleManager::lookupModuleFile(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + const FileEntry *&File) { + if (FileName == "-") { + File = nullptr; + return false; + } + + // 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) + 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> { + using NodeRef = ModuleFile *; + using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator; + using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>; + + static ChildIteratorType child_begin(NodeRef Node) { + return Node->Imports.begin(); + } + + static ChildIteratorType child_end(NodeRef Node) { + return Node->Imports.end(); + } + + static nodes_iterator nodes_begin(const ModuleManager &Manager) { + return nodes_iterator(Manager.begin()); + } + + static nodes_iterator nodes_end(const ModuleManager &Manager) { + return nodes_iterator(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; + } + }; + +} // namespace llvm + +void ModuleManager::viewGraph() { + llvm::ViewGraph(*this, "Modules"); +} +#endif diff --git a/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h new file mode 100644 index 000000000000..ded7cd146449 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h @@ -0,0 +1,347 @@ +//===- MultiOnDiskHashTable.h - Merged set of hash tables -------*- 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 a hash table data structure suitable for incremental and +// distributed storage across a set of files. +// +// Multiple hash tables from different files are implicitly merged to improve +// performance, and on reload the merged table will override those from other +// files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H +#define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/OnDiskHashTable.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <vector> + +namespace clang { +namespace serialization { + +/// A collection of on-disk hash tables, merged when relevant for performance. +template<typename Info> class MultiOnDiskHashTable { +public: + /// A handle to a file, used when overriding tables. + using file_type = typename Info::file_type; + + /// A pointer to an on-disk representation of the hash table. + using storage_type = const unsigned char *; + + using external_key_type = typename Info::external_key_type; + using internal_key_type = typename Info::internal_key_type; + using data_type = typename Info::data_type; + using data_type_builder = typename Info::data_type_builder; + using hash_value_type = unsigned; + +private: + /// The generator is permitted to read our merged table. + template<typename ReaderInfo, typename WriterInfo> + friend class MultiOnDiskHashTableGenerator; + + /// A hash table stored on disk. + struct OnDiskTable { + using HashTable = llvm::OnDiskIterableChainedHashTable<Info>; + + file_type File; + HashTable Table; + + OnDiskTable(file_type File, unsigned NumBuckets, unsigned NumEntries, + storage_type Buckets, storage_type Payload, storage_type Base, + const Info &InfoObj) + : File(File), + Table(NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj) {} + }; + + struct MergedTable { + std::vector<file_type> Files; + llvm::DenseMap<internal_key_type, data_type> Data; + }; + + using Table = llvm::PointerUnion<OnDiskTable *, MergedTable *>; + using TableVector = llvm::TinyPtrVector<void *>; + + /// The current set of on-disk and merged tables. + /// We manually store the opaque value of the Table because TinyPtrVector + /// can't cope with holding a PointerUnion directly. + /// There can be at most one MergedTable in this vector, and if present, + /// it is the first table. + TableVector Tables; + + /// Files corresponding to overridden tables that we've not yet + /// discarded. + llvm::TinyPtrVector<file_type> PendingOverrides; + + struct AsOnDiskTable { + using result_type = OnDiskTable *; + + result_type operator()(void *P) const { + return Table::getFromOpaqueValue(P).template get<OnDiskTable *>(); + } + }; + + using table_iterator = + llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable>; + using table_range = llvm::iterator_range<table_iterator>; + + /// The current set of on-disk tables. + table_range tables() { + auto Begin = Tables.begin(), End = Tables.end(); + if (getMergedTable()) + ++Begin; + return llvm::make_range(llvm::map_iterator(Begin, AsOnDiskTable()), + llvm::map_iterator(End, AsOnDiskTable())); + } + + MergedTable *getMergedTable() const { + // If we already have a merged table, it's the first one. + return Tables.empty() ? nullptr : Table::getFromOpaqueValue(*Tables.begin()) + .template dyn_cast<MergedTable*>(); + } + + /// Delete all our current on-disk tables. + void clear() { + for (auto *T : tables()) + delete T; + if (auto *M = getMergedTable()) + delete M; + Tables.clear(); + } + + void removeOverriddenTables() { + llvm::DenseSet<file_type> Files; + Files.insert(PendingOverrides.begin(), PendingOverrides.end()); + // Explicitly capture Files to work around an MSVC 2015 rejects-valid bug. + auto ShouldRemove = [&Files](void *T) -> bool { + auto *ODT = Table::getFromOpaqueValue(T).template get<OnDiskTable *>(); + bool Remove = Files.count(ODT->File); + if (Remove) + delete ODT; + return Remove; + }; + Tables.erase(std::remove_if(tables().begin().getCurrent(), Tables.end(), + ShouldRemove), + Tables.end()); + PendingOverrides.clear(); + } + + void condense() { + MergedTable *Merged = getMergedTable(); + if (!Merged) + Merged = new MergedTable; + + // Read in all the tables and merge them together. + // FIXME: Be smarter about which tables we merge. + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + Info &InfoObj = HT.getInfoObj(); + + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { + auto *LocalPtr = I.getItem(); + + // FIXME: Don't rely on the OnDiskHashTable format here. + auto L = InfoObj.ReadKeyDataLength(LocalPtr); + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); + data_type_builder ValueBuilder(Merged->Data[Key]); + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, + ValueBuilder); + } + + Merged->Files.push_back(ODT->File); + delete ODT; + } + + Tables.clear(); + Tables.push_back(Table(Merged).getOpaqueValue()); + } + +public: + MultiOnDiskHashTable() = default; + + MultiOnDiskHashTable(MultiOnDiskHashTable &&O) + : Tables(std::move(O.Tables)), + PendingOverrides(std::move(O.PendingOverrides)) { + O.Tables.clear(); + } + + MultiOnDiskHashTable &operator=(MultiOnDiskHashTable &&O) { + if (&O == this) + return *this; + clear(); + Tables = std::move(O.Tables); + O.Tables.clear(); + PendingOverrides = std::move(O.PendingOverrides); + return *this; + } + + ~MultiOnDiskHashTable() { clear(); } + + /// Add the table \p Data loaded from file \p File. + void add(file_type File, storage_type Data, Info InfoObj = Info()) { + using namespace llvm::support; + + storage_type Ptr = Data; + + uint32_t BucketOffset = endian::readNext<uint32_t, little, unaligned>(Ptr); + + // Read the list of overridden files. + uint32_t NumFiles = endian::readNext<uint32_t, little, unaligned>(Ptr); + // FIXME: Add a reserve() to TinyPtrVector so that we don't need to make + // an additional copy. + llvm::SmallVector<file_type, 16> OverriddenFiles; + OverriddenFiles.reserve(NumFiles); + for (/**/; NumFiles != 0; --NumFiles) + OverriddenFiles.push_back(InfoObj.ReadFileRef(Ptr)); + PendingOverrides.insert(PendingOverrides.end(), OverriddenFiles.begin(), + OverriddenFiles.end()); + + // Read the OnDiskChainedHashTable header. + storage_type Buckets = Data + BucketOffset; + auto NumBucketsAndEntries = + OnDiskTable::HashTable::readNumBucketsAndEntries(Buckets); + + // Register the table. + Table NewTable = new OnDiskTable(File, NumBucketsAndEntries.first, + NumBucketsAndEntries.second, + Buckets, Ptr, Data, std::move(InfoObj)); + Tables.push_back(NewTable.getOpaqueValue()); + } + + /// Find and read the lookup results for \p EKey. + data_type find(const external_key_type &EKey) { + data_type Result; + + if (!PendingOverrides.empty()) + removeOverriddenTables(); + + if (Tables.size() > static_cast<unsigned>(Info::MaxTables)) + condense(); + + internal_key_type Key = Info::GetInternalKey(EKey); + auto KeyHash = Info::ComputeHash(Key); + + if (MergedTable *M = getMergedTable()) { + auto It = M->Data.find(Key); + if (It != M->Data.end()) + Result = It->second; + } + + data_type_builder ResultBuilder(Result); + + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + auto It = HT.find_hashed(Key, KeyHash); + if (It != HT.end()) + HT.getInfoObj().ReadDataInto(Key, It.getDataPtr(), It.getDataLen(), + ResultBuilder); + } + + return Result; + } + + /// Read all the lookup results into a single value. This only makes + /// sense if merging values across keys is meaningful. + data_type findAll() { + data_type Result; + data_type_builder ResultBuilder(Result); + + if (!PendingOverrides.empty()) + removeOverriddenTables(); + + if (MergedTable *M = getMergedTable()) { + for (auto &KV : M->Data) + Info::MergeDataInto(KV.second, ResultBuilder); + } + + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + Info &InfoObj = HT.getInfoObj(); + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { + auto *LocalPtr = I.getItem(); + + // FIXME: Don't rely on the OnDiskHashTable format here. + auto L = InfoObj.ReadKeyDataLength(LocalPtr); + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, ResultBuilder); + } + } + + return Result; + } +}; + +/// Writer for the on-disk hash table. +template<typename ReaderInfo, typename WriterInfo> +class MultiOnDiskHashTableGenerator { + using BaseTable = MultiOnDiskHashTable<ReaderInfo>; + using Generator = llvm::OnDiskChainedHashTableGenerator<WriterInfo>; + + Generator Gen; + +public: + MultiOnDiskHashTableGenerator() : Gen() {} + + void insert(typename WriterInfo::key_type_ref Key, + typename WriterInfo::data_type_ref Data, WriterInfo &Info) { + Gen.insert(Key, Data, Info); + } + + void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info, + const BaseTable *Base) { + using namespace llvm::support; + + llvm::raw_svector_ostream OutStream(Out); + + // Write our header information. + { + endian::Writer Writer(OutStream, little); + + // Reserve four bytes for the bucket offset. + Writer.write<uint32_t>(0); + + if (auto *Merged = Base ? Base->getMergedTable() : nullptr) { + // Write list of overridden files. + Writer.write<uint32_t>(Merged->Files.size()); + for (const auto &F : Merged->Files) + Info.EmitFileRef(OutStream, F); + + // Add all merged entries from Base to the generator. + for (auto &KV : Merged->Data) { + if (!Gen.contains(KV.first, Info)) + Gen.insert(KV.first, Info.ImportData(KV.second), Info); + } + } else { + Writer.write<uint32_t>(0); + } + } + + // Write the table itself. + uint32_t BucketOffset = Gen.Emit(OutStream, Info); + + // Replace the first four bytes with the bucket offset. + endian::write32le(Out.data(), BucketOffset); + } +}; + +} // namespace serialization +} // namespace clang + +#endif // LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H diff --git a/contrib/llvm/tools/clang/lib/Serialization/PCHContainerOperations.cpp b/contrib/llvm/tools/clang/lib/Serialization/PCHContainerOperations.cpp new file mode 100644 index 000000000000..fbc613efeb63 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/PCHContainerOperations.cpp @@ -0,0 +1,69 @@ +//=== Serialization/PCHContainerOperations.cpp - PCH Containers -*- 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 PCHContainerOperations and RawPCHContainerOperation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Serialization/PCHContainerOperations.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/ModuleLoader.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/raw_ostream.h" +#include <utility> + +using namespace clang; + +PCHContainerWriter::~PCHContainerWriter() {} +PCHContainerReader::~PCHContainerReader() {} + +namespace { + +/// A PCHContainerGenerator that writes out the PCH to a flat file. +class RawPCHContainerGenerator : public ASTConsumer { + std::shared_ptr<PCHBuffer> Buffer; + std::unique_ptr<raw_pwrite_stream> OS; + +public: + RawPCHContainerGenerator(std::unique_ptr<llvm::raw_pwrite_stream> OS, + std::shared_ptr<PCHBuffer> Buffer) + : Buffer(std::move(Buffer)), OS(std::move(OS)) {} + + ~RawPCHContainerGenerator() override = default; + + void HandleTranslationUnit(ASTContext &Ctx) override { + if (Buffer->IsComplete) { + // Make sure it hits disk now. + *OS << Buffer->Data; + OS->flush(); + } + // Free the space of the temporary buffer. + llvm::SmallVector<char, 0> Empty; + Buffer->Data = std::move(Empty); + } +}; + +} // anonymous namespace + +std::unique_ptr<ASTConsumer> RawPCHContainerWriter::CreatePCHContainerGenerator( + CompilerInstance &CI, const std::string &MainFileName, + const std::string &OutputFileName, std::unique_ptr<llvm::raw_pwrite_stream> OS, + std::shared_ptr<PCHBuffer> Buffer) const { + return llvm::make_unique<RawPCHContainerGenerator>(std::move(OS), Buffer); +} + +StringRef +RawPCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const { + return Buffer.getBuffer(); +} + +PCHContainerOperations::PCHContainerOperations() { + registerWriter(llvm::make_unique<RawPCHContainerWriter>()); + registerReader(llvm::make_unique<RawPCHContainerReader>()); +} |