diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 19 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 7154 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 3443 | ||||
-rw-r--r-- | clang/lib/AST/NSAPI.cpp | 834 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/TypeLoc.cpp | 728 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.cpp | 5636 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.h | 655 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenCLRuntime.cpp | 87 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenCLRuntime.h | 98 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGRTTI.cpp | 2028 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 48 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 3154 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTCommon.cpp | 166 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 13990 |
20 files changed, 18926 insertions, 19180 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b04b830c852..f3fa13584de 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -874,15 +874,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); - - if (LangOpts.OpenCL) { - InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d); - InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray); - InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer); - InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d); - InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray); - InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d); - } // Builtin type for __objc_yes and __objc_no ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? @@ -1421,16 +1412,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; - case BuiltinType::OCLImage1d: - case BuiltinType::OCLImage1dArray: - case BuiltinType::OCLImage1dBuffer: - case BuiltinType::OCLImage2d: - case BuiltinType::OCLImage2dArray: - case BuiltinType::OCLImage3d: - // Currently these types are pointers to opaque types. - Width = Target->getPointerWidth(0); - Align = Target->getPointerAlign(0); - break; } break; case Type::ObjCObjectPointer: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 65907f909bb..566a3894cb9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1,3580 +1,3574 @@ -//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implements C++ name mangling according to the Itanium C++ ABI,
-// which is used in GCC 3.2 and newer (and many compilers that are
-// ABI-compatible with GCC):
-//
-// http://www.codesourcery.com/public/cxx-abi/abi.html
-//
-//===----------------------------------------------------------------------===//
-#include "clang/AST/Mangle.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-
-#define MANGLE_CHECKER 0
-
-#if MANGLE_CHECKER
-#include <cxxabi.h>
-#endif
-
-using namespace clang;
-
-namespace {
-
-/// \brief Retrieve the declaration context that should be used when mangling
-/// the given declaration.
-static const DeclContext *getEffectiveDeclContext(const Decl *D) {
- // The ABI assumes that lambda closure types that occur within
- // default arguments live in the context of the function. However, due to
- // the way in which Clang parses and creates function declarations, this is
- // not the case: the lambda closure type ends up living in the context
- // where the function itself resides, because the function declaration itself
- // had not yet been created. Fix the context here.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (RD->isLambda())
- if (ParmVarDecl *ContextParam
- = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
- return ContextParam->getDeclContext();
- }
-
- return D->getDeclContext();
-}
-
-static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
- return getEffectiveDeclContext(cast<Decl>(DC));
-}
-
-static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
- const DeclContext *DC = dyn_cast<DeclContext>(ND);
- if (!DC)
- DC = getEffectiveDeclContext(ND);
- while (!DC->isNamespace() && !DC->isTranslationUnit()) {
- const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
- if (isa<FunctionDecl>(Parent))
- return dyn_cast<CXXRecordDecl>(DC);
- DC = Parent;
- }
- return 0;
-}
-
-static const FunctionDecl *getStructor(const FunctionDecl *fn) {
- if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
- return ftd->getTemplatedDecl();
-
- return fn;
-}
-
-static const NamedDecl *getStructor(const NamedDecl *decl) {
- const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
- return (fn ? getStructor(fn) : decl);
-}
-
-static const unsigned UnknownArity = ~0U;
-
-class ItaniumMangleContext : public MangleContext {
- llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
- unsigned Discriminator;
- llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
-
-public:
- explicit ItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags)
- : MangleContext(Context, Diags) { }
-
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *,
- uint64_t>::iterator, bool> Result =
- AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
- return Result.first->second;
- }
-
- void startNewFunction() {
- MangleContext::startNewFunction();
- mangleInitDiscriminator();
- }
-
- /// @name Mangler Entry Points
- /// @{
-
- bool shouldMangleDeclName(const NamedDecl *D);
- void mangleName(const NamedDecl *D, raw_ostream &);
- void mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &);
- void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &);
- void mangleReferenceTemporary(const VarDecl *D,
- raw_ostream &);
- void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &);
- void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &);
- void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &);
- void mangleCXXRTTI(QualType T, raw_ostream &);
- void mangleCXXRTTIName(QualType T, raw_ostream &);
- void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- raw_ostream &);
- void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- raw_ostream &);
-
- void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
-
- void mangleInitDiscriminator() {
- Discriminator = 0;
- }
-
- bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
- // Lambda closure types with external linkage (indicated by a
- // non-zero lambda mangling number) have their own numbering scheme, so
- // they do not need a discriminator.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
- if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
- return false;
-
- unsigned &discriminator = Uniquifier[ND];
- if (!discriminator)
- discriminator = ++Discriminator;
- if (discriminator == 1)
- return false;
- disc = discriminator-2;
- return true;
- }
- /// @}
-};
-
-/// CXXNameMangler - Manage the mangling of a single name.
-class CXXNameMangler {
- ItaniumMangleContext &Context;
- raw_ostream &Out;
-
- /// The "structor" is the top-level declaration being mangled, if
- /// that's not a template specialization; otherwise it's the pattern
- /// for that specialization.
- const NamedDecl *Structor;
- unsigned StructorType;
-
- /// SeqID - The next subsitution sequence number.
- unsigned SeqID;
-
- class FunctionTypeDepthState {
- unsigned Bits;
-
- enum { InResultTypeMask = 1 };
-
- public:
- FunctionTypeDepthState() : Bits(0) {}
-
- /// The number of function types we're inside.
- unsigned getDepth() const {
- return Bits >> 1;
- }
-
- /// True if we're in the return type of the innermost function type.
- bool isInResultType() const {
- return Bits & InResultTypeMask;
- }
-
- FunctionTypeDepthState push() {
- FunctionTypeDepthState tmp = *this;
- Bits = (Bits & ~InResultTypeMask) + 2;
- return tmp;
- }
-
- void enterResultType() {
- Bits |= InResultTypeMask;
- }
-
- void leaveResultType() {
- Bits &= ~InResultTypeMask;
- }
-
- void pop(FunctionTypeDepthState saved) {
- assert(getDepth() == saved.getDepth() + 1);
- Bits = saved.Bits;
- }
-
- } FunctionTypeDepth;
-
- llvm::DenseMap<uintptr_t, unsigned> Substitutions;
-
- ASTContext &getASTContext() const { return Context.getASTContext(); }
-
-public:
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
- const NamedDecl *D = 0)
- : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
- SeqID(0) {
- // These can't be mangled without a ctor type or dtor type.
- assert(!D || (!isa<CXXDestructorDecl>(D) &&
- !isa<CXXConstructorDecl>(D)));
- }
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
- const CXXConstructorDecl *D, CXXCtorType Type)
- : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
- const CXXDestructorDecl *D, CXXDtorType Type)
- : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
-
-#if MANGLE_CHECKER
- ~CXXNameMangler() {
- if (Out.str()[0] == '\01')
- return;
-
- int status = 0;
- char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
- assert(status == 0 && "Could not demangle mangled name!");
- free(result);
- }
-#endif
- raw_ostream &getStream() { return Out; }
-
- void mangle(const NamedDecl *D, StringRef Prefix = "_Z");
- void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
- void mangleNumber(const llvm::APSInt &I);
- void mangleNumber(int64_t Number);
- void mangleFloat(const llvm::APFloat &F);
- void mangleFunctionEncoding(const FunctionDecl *FD);
- void mangleName(const NamedDecl *ND);
- void mangleType(QualType T);
- void mangleNameOrStandardSubstitution(const NamedDecl *ND);
-
-private:
- bool mangleSubstitution(const NamedDecl *ND);
- bool mangleSubstitution(QualType T);
- bool mangleSubstitution(TemplateName Template);
- bool mangleSubstitution(uintptr_t Ptr);
-
- void mangleExistingSubstitution(QualType type);
- void mangleExistingSubstitution(TemplateName name);
-
- bool mangleStandardSubstitution(const NamedDecl *ND);
-
- void addSubstitution(const NamedDecl *ND) {
- ND = cast<NamedDecl>(ND->getCanonicalDecl());
-
- addSubstitution(reinterpret_cast<uintptr_t>(ND));
- }
- void addSubstitution(QualType T);
- void addSubstitution(TemplateName Template);
- void addSubstitution(uintptr_t Ptr);
-
- void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- bool recursive = false);
- void mangleUnresolvedName(NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- DeclarationName name,
- unsigned KnownArity = UnknownArity);
-
- void mangleName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND) {
- mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
- }
- void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
- unsigned KnownArity);
- void mangleUnscopedName(const NamedDecl *ND);
- void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleUnscopedTemplateName(TemplateName);
- void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const NamedDecl *ND);
- void mangleLambda(const CXXRecordDecl *Lambda);
- void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
- bool NoFunction=false);
- void mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void manglePrefix(NestedNameSpecifier *qualifier);
- void manglePrefix(const DeclContext *DC, bool NoFunction=false);
- void manglePrefix(QualType type);
- void mangleTemplatePrefix(const TemplateDecl *ND);
- void mangleTemplatePrefix(TemplateName Template);
- void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
- void mangleQualifiers(Qualifiers Quals);
- void mangleRefQualifier(RefQualifierKind RefQualifier);
-
- void mangleObjCMethodName(const ObjCMethodDecl *MD);
-
- // Declare manglers for every type class.
-#define ABSTRACT_TYPE(CLASS, PARENT)
-#define NON_CANONICAL_TYPE(CLASS, PARENT)
-#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
-#include "clang/AST/TypeNodes.def"
-
- void mangleType(const TagType*);
- void mangleType(TemplateName);
- void mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType);
- void mangleNeonVectorType(const VectorType *T);
-
- void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
- void mangleMemberExpr(const Expr *base, bool isArrow,
- NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- DeclarationName name,
- unsigned knownArity);
- void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
- void mangleCXXCtorType(CXXCtorType T);
- void mangleCXXDtorType(CXXDtorType T);
-
- void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
- void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateArgumentList &AL);
- void mangleTemplateArg(TemplateArgument A);
-
- void mangleTemplateParameter(unsigned Index);
-
- void mangleFunctionParam(const ParmVarDecl *parm);
-};
-
-}
-
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = getEffectiveDeclContext(D);
- !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
-
- return false;
-}
-
-bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
-
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
-
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
-
- // Otherwise, no mangling is done outside C++ mode.
- if (!getASTContext().getLangOpts().CPlusPlus)
- return false;
-
- // Variables at global scope with non-internal linkage are not mangled
- if (!FD) {
- const DeclContext *DC = getEffectiveDeclContext(D);
- // Check for extern variable declared locally.
- if (DC->isFunctionOrMethod() && D->hasLinkage())
- while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = getEffectiveParentContext(DC);
- if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
- return false;
- }
-
- // Class members are always mangled.
- if (getEffectiveDeclContext(D)->isRecord())
- return true;
-
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
-
- return true;
-}
-
-void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
-
- // Adding the prefix can cause problems when one file has a "foo" and
- // another has a "\01foo". That is known to happen on ELF with the
- // tricks normally used for producing aliases (PR9177). Fortunately the
- // llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker. We also avoid adding the marker if this is an alias for an
- // LLVM intrinsic.
- StringRef UserLabelPrefix =
- getASTContext().getTargetInfo().getUserLabelPrefix();
- if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
- Out << '\01'; // LLVM IR Marker for __asm("foo")
-
- Out << ALA->getLabel();
- return;
- }
-
- // <mangled-name> ::= _Z <encoding>
- // ::= <data name>
- // ::= <special-name>
- Out << Prefix;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- mangleFunctionEncoding(FD);
- else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- mangleName(VD);
- else
- mangleName(cast<FieldDecl>(D));
-}
-
-void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
- // <encoding> ::= <function name> <bare-function-type>
- mangleName(FD);
-
- // Don't mangle in the type if this isn't a decl we should typically mangle.
- if (!Context.shouldMangleDeclName(FD))
- return;
-
- // Whether the mangling of a function type includes the return type depends on
- // the context and the nature of the function. The rules for deciding whether
- // the return type is included are:
- //
- // 1. Template functions (names or types) have return types encoded, with
- // the exceptions listed below.
- // 2. Function types not appearing as part of a function name mangling,
- // e.g. parameters, pointer types, etc., have return type encoded, with the
- // exceptions listed below.
- // 3. Non-template function names do not have return types encoded.
- //
- // The exceptions mentioned in (1) and (2) above, for which the return type is
- // never included, are
- // 1. Constructors.
- // 2. Destructors.
- // 3. Conversion operator functions, e.g. operator int.
- bool MangleReturnType = false;
- if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) {
- if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
- isa<CXXConversionDecl>(FD)))
- MangleReturnType = true;
-
- // Mangle the type of the primary template.
- FD = PrimaryTemplate->getTemplatedDecl();
- }
-
- mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
- MangleReturnType);
-}
-
-static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
- while (isa<LinkageSpecDecl>(DC)) {
- DC = getEffectiveParentContext(DC);
- }
-
- return DC;
-}
-
-/// isStd - Return whether a given namespace is the 'std' namespace.
-static bool isStd(const NamespaceDecl *NS) {
- if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS))
- ->isTranslationUnit())
- return false;
-
- const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
- return II && II->isStr("std");
-}
-
-// isStdNamespace - Return whether a given decl context is a toplevel 'std'
-// namespace.
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace())
- return false;
-
- return isStd(cast<NamespaceDecl>(DC));
-}
-
-static const TemplateDecl *
-isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
- // Check if we have a function template.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
- if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
- TemplateArgs = FD->getTemplateSpecializationArgs();
- return TD;
- }
- }
-
- // Check if we have a class template.
- if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- TemplateArgs = &Spec->getTemplateArgs();
- return Spec->getSpecializedTemplate();
- }
-
- return 0;
-}
-
-static bool isLambda(const NamedDecl *ND) {
- const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
- if (!Record)
- return false;
-
- return Record->isLambda();
-}
-
-void CXXNameMangler::mangleName(const NamedDecl *ND) {
- // <name> ::= <nested-name>
- // ::= <unscoped-name>
- // ::= <unscoped-template-name> <template-args>
- // ::= <local-name>
- //
- const DeclContext *DC = getEffectiveDeclContext(ND);
-
- // If this is an extern variable declared locally, the relevant DeclContext
- // is that of the containing namespace, or the translation unit.
- // FIXME: This is a hack; extern variables declared locally should have
- // a proper semantic declaration context!
- if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
- while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = getEffectiveParentContext(DC);
- else if (GetLocalClassDecl(ND)) {
- mangleLocalName(ND);
- return;
- }
-
- DC = IgnoreLinkageSpecDecls(DC);
-
- if (DC->isTranslationUnit() || isStdNamespace(DC)) {
- // Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(*TemplateArgs);
- return;
- }
-
- mangleUnscopedName(ND);
- return;
- }
-
- if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
- mangleLocalName(ND);
- return;
- }
-
- mangleNestedName(ND, DC);
-}
-void CXXNameMangler::mangleName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD));
-
- if (DC->isTranslationUnit() || isStdNamespace(DC)) {
- mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
- } else {
- mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
- }
-}
-
-void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
- // <unscoped-name> ::= <unqualified-name>
- // ::= St <unqualified-name> # ::std::
-
- if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND))))
- Out << "St";
-
- mangleUnqualifiedName(ND);
-}
-
-void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
- // <unscoped-template-name> ::= <unscoped-name>
- // ::= <substitution>
- if (mangleSubstitution(ND))
- return;
-
- // <template-template-param> ::= <template-param>
- if (const TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(ND)) {
- mangleTemplateParameter(TTP->getIndex());
- return;
- }
-
- mangleUnscopedName(ND->getTemplatedDecl());
- addSubstitution(ND);
-}
-
-void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
- // <unscoped-template-name> ::= <unscoped-name>
- // ::= <substitution>
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleUnscopedTemplateName(TD);
-
- if (mangleSubstitution(Template))
- return;
-
- DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
- assert(Dependent && "Not a dependent template name?");
- if (const IdentifierInfo *Id = Dependent->getIdentifier())
- mangleSourceName(Id);
- else
- mangleOperatorName(Dependent->getOperator(), UnknownArity);
-
- addSubstitution(Template);
-}
-
-void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
- // ABI:
- // Floating-point literals are encoded using a fixed-length
- // lowercase hexadecimal string corresponding to the internal
- // representation (IEEE on Itanium), high-order bytes first,
- // without leading zeroes. For example: "Lf bf800000 E" is -1.0f
- // on Itanium.
- // The 'without leading zeroes' thing seems to be an editorial
- // mistake; see the discussion on cxx-abi-dev beginning on
- // 2012-01-16.
-
- // Our requirements here are just barely weird enough to justify
- // using a custom algorithm instead of post-processing APInt::toString().
-
- llvm::APInt valueBits = f.bitcastToAPInt();
- unsigned numCharacters = (valueBits.getBitWidth() + 3) / 4;
- assert(numCharacters != 0);
-
- // Allocate a buffer of the right number of characters.
- llvm::SmallVector<char, 20> buffer;
- buffer.set_size(numCharacters);
-
- // Fill the buffer left-to-right.
- for (unsigned stringIndex = 0; stringIndex != numCharacters; ++stringIndex) {
- // The bit-index of the next hex digit.
- unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1);
-
- // Project out 4 bits starting at 'digitIndex'.
- llvm::integerPart hexDigit
- = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth];
- hexDigit >>= (digitBitIndex % llvm::integerPartWidth);
- hexDigit &= 0xF;
-
- // Map that over to a lowercase hex digit.
- static const char charForHex[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
- };
- buffer[stringIndex] = charForHex[hexDigit];
- }
-
- Out.write(buffer.data(), numCharacters);
-}
-
-void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
- if (Value.isSigned() && Value.isNegative()) {
- Out << 'n';
- Value.abs().print(Out, /*signed*/ false);
- } else {
- Value.print(Out, /*signed*/ false);
- }
-}
-
-void CXXNameMangler::mangleNumber(int64_t Number) {
- // <number> ::= [n] <non-negative decimal integer>
- if (Number < 0) {
- Out << 'n';
- Number = -Number;
- }
-
- Out << Number;
-}
-
-void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
- // <call-offset> ::= h <nv-offset> _
- // ::= v <v-offset> _
- // <nv-offset> ::= <offset number> # non-virtual base override
- // <v-offset> ::= <offset number> _ <virtual offset number>
- // # virtual base override, with vcall offset
- if (!Virtual) {
- Out << 'h';
- mangleNumber(NonVirtual);
- Out << '_';
- return;
- }
-
- Out << 'v';
- mangleNumber(NonVirtual);
- Out << '_';
- mangleNumber(Virtual);
- Out << '_';
-}
-
-void CXXNameMangler::manglePrefix(QualType type) {
- if (const TemplateSpecializationType *TST =
- type->getAs<TemplateSpecializationType>()) {
- if (!mangleSubstitution(QualType(TST, 0))) {
- mangleTemplatePrefix(TST->getTemplateName());
-
- // FIXME: GCC does not appear to mangle the template arguments when
- // the template in question is a dependent template name. Should we
- // emulate that badness?
- mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
- addSubstitution(QualType(TST, 0));
- }
- } else if (const DependentTemplateSpecializationType *DTST
- = type->getAs<DependentTemplateSpecializationType>()) {
- TemplateName Template
- = getASTContext().getDependentTemplateName(DTST->getQualifier(),
- DTST->getIdentifier());
- mangleTemplatePrefix(Template);
-
- // FIXME: GCC does not appear to mangle the template arguments when
- // the template in question is a dependent template name. Should we
- // emulate that badness?
- mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
- } else {
- // We use the QualType mangle type variant here because it handles
- // substitutions.
- mangleType(type);
- }
-}
-
-/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
-///
-/// \param firstQualifierLookup - the entity found by unqualified lookup
-/// for the first name in the qualifier, if this is for a member expression
-/// \param recursive - true if this is being called recursively,
-/// i.e. if there is more prefix "to the right".
-void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- bool recursive) {
-
- // x, ::x
- // <unresolved-name> ::= [gs] <base-unresolved-name>
-
- // T::x / decltype(p)::x
- // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name>
-
- // T::N::x /decltype(p)::N::x
- // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
- // <base-unresolved-name>
-
- // A::x, N::y, A<T>::z; "gs" means leading "::"
- // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E
- // <base-unresolved-name>
-
- switch (qualifier->getKind()) {
- case NestedNameSpecifier::Global:
- Out << "gs";
-
- // We want an 'sr' unless this is the entire NNS.
- if (recursive)
- Out << "sr";
-
- // We never want an 'E' here.
- return;
-
- case NestedNameSpecifier::Namespace:
- if (qualifier->getPrefix())
- mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
- /*recursive*/ true);
- else
- Out << "sr";
- mangleSourceName(qualifier->getAsNamespace()->getIdentifier());
- break;
- case NestedNameSpecifier::NamespaceAlias:
- if (qualifier->getPrefix())
- mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
- /*recursive*/ true);
- else
- Out << "sr";
- mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier());
- break;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *type = qualifier->getAsType();
-
- // We only want to use an unresolved-type encoding if this is one of:
- // - a decltype
- // - a template type parameter
- // - a template template parameter with arguments
- // In all of these cases, we should have no prefix.
- if (qualifier->getPrefix()) {
- mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
- /*recursive*/ true);
- } else {
- // Otherwise, all the cases want this.
- Out << "sr";
- }
-
- // Only certain other types are valid as prefixes; enumerate them.
- switch (type->getTypeClass()) {
- case Type::Builtin:
- case Type::Complex:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::DependentSizedArray:
- case Type::DependentSizedExtVector:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Enum:
- case Type::Paren:
- case Type::Elaborated:
- case Type::Attributed:
- case Type::Auto:
- case Type::PackExpansion:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::ObjCObjectPointer:
- case Type::Atomic:
- llvm_unreachable("type is illegal as a nested name specifier");
-
- case Type::SubstTemplateTypeParmPack:
- // FIXME: not clear how to mangle this!
- // template <class T...> class A {
- // template <class U...> void foo(decltype(T::foo(U())) x...);
- // };
- Out << "_SUBSTPACK_";
- break;
-
- // <unresolved-type> ::= <template-param>
- // ::= <decltype>
- // ::= <template-template-param> <template-args>
- // (this last is not official yet)
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::TemplateTypeParm:
- case Type::UnaryTransform:
- case Type::SubstTemplateTypeParm:
- unresolvedType:
- assert(!qualifier->getPrefix());
-
- // We only get here recursively if we're followed by identifiers.
- if (recursive) Out << 'N';
-
- // This seems to do everything we want. It's not really
- // sanctioned for a substituted template parameter, though.
- mangleType(QualType(type, 0));
-
- // We never want to print 'E' directly after an unresolved-type,
- // so we return directly.
- return;
-
- case Type::Typedef:
- mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier());
- break;
-
- case Type::UnresolvedUsing:
- mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl()
- ->getIdentifier());
- break;
-
- case Type::Record:
- mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier());
- break;
-
- case Type::TemplateSpecialization: {
- const TemplateSpecializationType *tst
- = cast<TemplateSpecializationType>(type);
- TemplateName name = tst->getTemplateName();
- switch (name.getKind()) {
- case TemplateName::Template:
- case TemplateName::QualifiedTemplate: {
- TemplateDecl *temp = name.getAsTemplateDecl();
-
- // If the base is a template template parameter, this is an
- // unresolved type.
- assert(temp && "no template for template specialization type");
- if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType;
-
- mangleSourceName(temp->getIdentifier());
- break;
- }
-
- case TemplateName::OverloadedTemplate:
- case TemplateName::DependentTemplate:
- llvm_unreachable("invalid base for a template specialization type");
-
- case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *subst
- = name.getAsSubstTemplateTemplateParm();
- mangleExistingSubstitution(subst->getReplacement());
- break;
- }
-
- case TemplateName::SubstTemplateTemplateParmPack: {
- // FIXME: not clear how to mangle this!
- // template <template <class U> class T...> class A {
- // template <class U...> void foo(decltype(T<U>::foo) x...);
- // };
- Out << "_SUBSTPACK_";
- break;
- }
- }
-
- mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
- break;
- }
-
- case Type::InjectedClassName:
- mangleSourceName(cast<InjectedClassNameType>(type)->getDecl()
- ->getIdentifier());
- break;
-
- case Type::DependentName:
- mangleSourceName(cast<DependentNameType>(type)->getIdentifier());
- break;
-
- case Type::DependentTemplateSpecialization: {
- const DependentTemplateSpecializationType *tst
- = cast<DependentTemplateSpecializationType>(type);
- mangleSourceName(tst->getIdentifier());
- mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
- break;
- }
- }
- break;
- }
-
- case NestedNameSpecifier::Identifier:
- // Member expressions can have these without prefixes.
- if (qualifier->getPrefix()) {
- mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
- /*recursive*/ true);
- } else if (firstQualifierLookup) {
-
- // Try to make a proper qualifier out of the lookup result, and
- // then just recurse on that.
- NestedNameSpecifier *newQualifier;
- if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) {
- QualType type = getASTContext().getTypeDeclType(typeDecl);
-
- // Pretend we had a different nested name specifier.
- newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
- /*template*/ false,
- type.getTypePtr());
- } else if (NamespaceDecl *nspace =
- dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
- newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
- nspace);
- } else if (NamespaceAliasDecl *alias =
- dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
- newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
- alias);
- } else {
- // No sensible mangling to do here.
- newQualifier = 0;
- }
-
- if (newQualifier)
- return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive);
-
- } else {
- Out << "sr";
- }
-
- mangleSourceName(qualifier->getAsIdentifier());
- break;
- }
-
- // If this was the innermost part of the NNS, and we fell out to
- // here, append an 'E'.
- if (!recursive)
- Out << 'E';
-}
-
-/// Mangle an unresolved-name, which is generally used for names which
-/// weren't resolved to specific entities.
-void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- DeclarationName name,
- unsigned knownArity) {
- if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
- mangleUnqualifiedName(0, name, knownArity);
-}
-
-static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
- assert(RD->isAnonymousStructOrUnion() &&
- "Expected anonymous struct or union!");
-
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
- if (I->getIdentifier())
- return *I;
-
- if (const RecordType *RT = I->getType()->getAs<RecordType>())
- if (const FieldDecl *NamedDataMember =
- FindFirstNamedDataMember(RT->getDecl()))
- return NamedDataMember;
- }
-
- // We didn't find a named data member.
- return 0;
-}
-
-void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
- DeclarationName Name,
- unsigned KnownArity) {
- // <unqualified-name> ::= <operator-name>
- // ::= <ctor-dtor-name>
- // ::= <source-name>
- switch (Name.getNameKind()) {
- case DeclarationName::Identifier: {
- if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- // We must avoid conflicts between internally- and externally-
- // linked variable and function declaration names in the same TU:
- // void test() { extern void foo(); }
- // static void foo();
- // This naming convention is the same as that followed by GCC,
- // though it shouldn't actually matter.
- if (ND && ND->getLinkage() == InternalLinkage &&
- getEffectiveDeclContext(ND)->isFileContext())
- Out << 'L';
-
- mangleSourceName(II);
- break;
- }
-
- // Otherwise, an anonymous entity. We must have a declaration.
- assert(ND && "mangling empty name without declaration");
-
- if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
- if (NS->isAnonymousNamespace()) {
- // This is how gcc mangles these names.
- Out << "12_GLOBAL__N_1";
- break;
- }
- }
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
- // We must have an anonymous union or struct declaration.
- const RecordDecl *RD =
- cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl());
-
- // Itanium C++ ABI 5.1.2:
- //
- // For the purposes of mangling, the name of an anonymous union is
- // considered to be the name of the first named data member found by a
- // pre-order, depth-first, declaration-order walk of the data members of
- // the anonymous union. If there is no such data member (i.e., if all of
- // the data members in the union are unnamed), then there is no way for
- // a program to refer to the anonymous union, and there is therefore no
- // need to mangle its name.
- const FieldDecl *FD = FindFirstNamedDataMember(RD);
-
- // It's actually possible for various reasons for us to get here
- // with an empty anonymous struct / union. Fortunately, it
- // doesn't really matter what name we generate.
- if (!FD) break;
- assert(FD->getIdentifier() && "Data member name isn't an identifier!");
-
- mangleSourceName(FD->getIdentifier());
- break;
- }
-
- // We must have an anonymous struct.
- const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
- assert(TD->getDeclContext() == D->getDeclContext() &&
- "Typedef should not be in another decl context!");
- assert(D->getDeclName().getAsIdentifierInfo() &&
- "Typedef was not named!");
- mangleSourceName(D->getDeclName().getAsIdentifierInfo());
- break;
- }
-
- // <unnamed-type-name> ::= <closure-type-name>
- //
- // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
- // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
- if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
- if (Record->isLambda() && Record->getLambdaManglingNumber()) {
- mangleLambda(Record);
- break;
- }
- }
-
- int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
- if (UnnamedMangle != -1) {
- Out << "Ut";
- if (UnnamedMangle != 0)
- Out << llvm::utostr(UnnamedMangle - 1);
- Out << '_';
- break;
- }
-
- // Get a unique id for the anonymous struct.
- uint64_t AnonStructId = Context.getAnonymousStructId(TD);
-
- // Mangle it as a source name in the form
- // [n] $_<id>
- // where n is the length of the string.
- SmallString<8> Str;
- Str += "$_";
- Str += llvm::utostr(AnonStructId);
-
- Out << Str.size();
- Out << Str.str();
- break;
- }
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- llvm_unreachable("Can't mangle Objective-C selector names here!");
-
- case DeclarationName::CXXConstructorName:
- if (ND == Structor)
- // If the named decl is the C++ constructor we're mangling, use the type
- // we were given.
- mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
- else
- // Otherwise, use the complete constructor name. This is relevant if a
- // class with a constructor is declared within a constructor.
- mangleCXXCtorType(Ctor_Complete);
- break;
-
- case DeclarationName::CXXDestructorName:
- if (ND == Structor)
- // If the named decl is the C++ destructor we're mangling, use the type we
- // were given.
- mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
- else
- // Otherwise, use the complete destructor name. This is relevant if a
- // class with a destructor is declared within a destructor.
- mangleCXXDtorType(Dtor_Complete);
- break;
-
- case DeclarationName::CXXConversionFunctionName:
- // <operator-name> ::= cv <type> # (cast)
- Out << "cv";
- mangleType(Name.getCXXNameType());
- break;
-
- case DeclarationName::CXXOperatorName: {
- unsigned Arity;
- if (ND) {
- Arity = cast<FunctionDecl>(ND)->getNumParams();
-
- // If we have a C++ member function, we need to include the 'this' pointer.
- // FIXME: This does not make sense for operators that are static, but their
- // names stay the same regardless of the arity (operator new for instance).
- if (isa<CXXMethodDecl>(ND))
- Arity++;
- } else
- Arity = KnownArity;
-
- mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
- break;
- }
-
- case DeclarationName::CXXLiteralOperatorName:
- // FIXME: This mangling is not yet official.
- Out << "li";
- mangleSourceName(Name.getCXXLiteralIdentifier());
- break;
-
- case DeclarationName::CXXUsingDirective:
- llvm_unreachable("Can't mangle a using directive name!");
- }
-}
-
-void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
- // <source-name> ::= <positive length number> <identifier>
- // <number> ::= [n] <non-negative decimal integer>
- // <identifier> ::= <unqualified source code identifier>
- Out << II->getLength() << II->getName();
-}
-
-void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
- const DeclContext *DC,
- bool NoFunction) {
- // <nested-name>
- // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
- // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
- // <template-args> E
-
- Out << 'N';
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
- mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
- mangleRefQualifier(Method->getRefQualifier());
- }
-
- // Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD);
- mangleTemplateArgs(*TemplateArgs);
- }
- else {
- manglePrefix(DC, NoFunction);
- mangleUnqualifiedName(ND);
- }
-
- Out << 'E';
-}
-void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
-
- Out << 'N';
-
- mangleTemplatePrefix(TD);
- mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
-
- Out << 'E';
-}
-
-void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
- // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
- // := Z <function encoding> E s [<discriminator>]
- // <local-name> := Z <function encoding> E d [ <parameter number> ]
- // _ <entity name>
- // <discriminator> := _ <non-negative number>
- const DeclContext *DC = getEffectiveDeclContext(ND);
- if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
- // Don't add objc method name mangling to locally declared function
- mangleUnqualifiedName(ND);
- return;
- }
-
- Out << 'Z';
-
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
- mangleObjCMethodName(MD);
- } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
- mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
- Out << 'E';
-
- // The parameter number is omitted for the last parameter, 0 for the
- // second-to-last parameter, 1 for the third-to-last parameter, etc. The
- // <entity name> will of course contain a <closure-type-name>: Its
- // numbering will be local to the particular argument in which it appears
- // -- other default arguments do not affect its encoding.
- bool SkipDiscriminator = false;
- if (RD->isLambda()) {
- if (const ParmVarDecl *Parm
- = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
- if (const FunctionDecl *Func
- = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
- Out << 'd';
- unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
- if (Num > 1)
- mangleNumber(Num - 2);
- Out << '_';
- SkipDiscriminator = true;
- }
- }
- }
-
- // Mangle the name relative to the closest enclosing function.
- if (ND == RD) // equality ok because RD derived from ND above
- mangleUnqualifiedName(ND);
- else
- mangleNestedName(ND, DC, true /*NoFunction*/);
-
- if (!SkipDiscriminator) {
- unsigned disc;
- if (Context.getNextDiscriminator(RD, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
- }
- }
-
- return;
- }
- else
- mangleFunctionEncoding(cast<FunctionDecl>(DC));
-
- Out << 'E';
- mangleUnqualifiedName(ND);
-}
-
-void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
- // If the context of a closure type is an initializer for a class member
- // (static or nonstatic), it is encoded in a qualified name with a final
- // <prefix> of the form:
- //
- // <data-member-prefix> := <member source-name> M
- //
- // Technically, the data-member-prefix is part of the <prefix>. However,
- // since a closure type will always be mangled with a prefix, it's easier
- // to emit that last part of the prefix here.
- if (Decl *Context = Lambda->getLambdaContextDecl()) {
- if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
- Context->getDeclContext()->isRecord()) {
- if (const IdentifierInfo *Name
- = cast<NamedDecl>(Context)->getIdentifier()) {
- mangleSourceName(Name);
- Out << 'M';
- }
- }
- }
-
- Out << "Ul";
- const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
- getAs<FunctionProtoType>();
- mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
- Out << "E";
-
- // The number is omitted for the first closure type with a given
- // <lambda-sig> in a given context; it is n-2 for the nth closure type
- // (in lexical order) with that same <lambda-sig> and context.
- //
- // The AST keeps track of the number for us.
- unsigned Number = Lambda->getLambdaManglingNumber();
- assert(Number > 0 && "Lambda should be mangled as an unnamed class");
- if (Number > 1)
- mangleNumber(Number - 2);
- Out << '_';
-}
-
-void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
- switch (qualifier->getKind()) {
- case NestedNameSpecifier::Global:
- // nothing
- return;
-
- case NestedNameSpecifier::Namespace:
- mangleName(qualifier->getAsNamespace());
- return;
-
- case NestedNameSpecifier::NamespaceAlias:
- mangleName(qualifier->getAsNamespaceAlias()->getNamespace());
- return;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- manglePrefix(QualType(qualifier->getAsType(), 0));
- return;
-
- case NestedNameSpecifier::Identifier:
- // Member expressions can have these without prefixes, but that
- // should end up in mangleUnresolvedPrefix instead.
- assert(qualifier->getPrefix());
- manglePrefix(qualifier->getPrefix());
-
- mangleSourceName(qualifier->getAsIdentifier());
- return;
- }
-
- llvm_unreachable("unexpected nested name specifier");
-}
-
-void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
- // <prefix> ::= <prefix> <unqualified-name>
- // ::= <template-prefix> <template-args>
- // ::= <template-param>
- // ::= # empty
- // ::= <substitution>
-
- DC = IgnoreLinkageSpecDecls(DC);
-
- if (DC->isTranslationUnit())
- return;
-
- if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
- manglePrefix(getEffectiveParentContext(DC), NoFunction);
- SmallString<64> Name;
- llvm::raw_svector_ostream NameStream(Name);
- Context.mangleBlock(Block, NameStream);
- NameStream.flush();
- Out << Name.size() << Name;
- return;
- }
-
- const NamedDecl *ND = cast<NamedDecl>(DC);
- if (mangleSubstitution(ND))
- return;
-
- // Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD);
- mangleTemplateArgs(*TemplateArgs);
- }
- else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
- return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
- mangleObjCMethodName(Method);
- else {
- manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- mangleUnqualifiedName(ND);
- }
-
- addSubstitution(ND);
-}
-
-void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
- // <template-prefix> ::= <prefix> <template unqualified-name>
- // ::= <template-param>
- // ::= <substitution>
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleTemplatePrefix(TD);
-
- if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
- manglePrefix(Qualified->getQualifier());
-
- if (OverloadedTemplateStorage *Overloaded
- = Template.getAsOverloadedTemplate()) {
- mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
- UnknownArity);
- return;
- }
-
- DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
- assert(Dependent && "Unknown template name kind?");
- manglePrefix(Dependent->getQualifier());
- mangleUnscopedTemplateName(Template);
-}
-
-void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
- // <template-prefix> ::= <prefix> <template unqualified-name>
- // ::= <template-param>
- // ::= <substitution>
- // <template-template-param> ::= <template-param>
- // <substitution>
-
- if (mangleSubstitution(ND))
- return;
-
- // <template-template-param> ::= <template-param>
- if (const TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(ND)) {
- mangleTemplateParameter(TTP->getIndex());
- return;
- }
-
- manglePrefix(getEffectiveDeclContext(ND));
- mangleUnqualifiedName(ND->getTemplatedDecl());
- addSubstitution(ND);
-}
-
-/// Mangles a template name under the production <type>. Required for
-/// template template arguments.
-/// <type> ::= <class-enum-type>
-/// ::= <template-param>
-/// ::= <substitution>
-void CXXNameMangler::mangleType(TemplateName TN) {
- if (mangleSubstitution(TN))
- return;
-
- TemplateDecl *TD = 0;
-
- switch (TN.getKind()) {
- case TemplateName::QualifiedTemplate:
- TD = TN.getAsQualifiedTemplateName()->getTemplateDecl();
- goto HaveDecl;
-
- case TemplateName::Template:
- TD = TN.getAsTemplateDecl();
- goto HaveDecl;
-
- HaveDecl:
- if (isa<TemplateTemplateParmDecl>(TD))
- mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
- else
- mangleName(TD);
- break;
-
- case TemplateName::OverloadedTemplate:
- llvm_unreachable("can't mangle an overloaded template name as a <type>");
-
- case TemplateName::DependentTemplate: {
- const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
- assert(Dependent->isIdentifier());
-
- // <class-enum-type> ::= <name>
- // <name> ::= <nested-name>
- mangleUnresolvedPrefix(Dependent->getQualifier(), 0);
- mangleSourceName(Dependent->getIdentifier());
- break;
- }
-
- case TemplateName::SubstTemplateTemplateParm: {
- // Substituted template parameters are mangled as the substituted
- // template. This will check for the substitution twice, which is
- // fine, but we have to return early so that we don't try to *add*
- // the substitution twice.
- SubstTemplateTemplateParmStorage *subst
- = TN.getAsSubstTemplateTemplateParm();
- mangleType(subst->getReplacement());
- return;
- }
-
- case TemplateName::SubstTemplateTemplateParmPack: {
- // FIXME: not clear how to mangle this!
- // template <template <class> class T...> class A {
- // template <template <class> class U...> void foo(B<T,U> x...);
- // };
- Out << "_SUBSTPACK_";
- break;
- }
- }
-
- addSubstitution(TN);
-}
-
-void
-CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
- switch (OO) {
- // <operator-name> ::= nw # new
- case OO_New: Out << "nw"; break;
- // ::= na # new[]
- case OO_Array_New: Out << "na"; break;
- // ::= dl # delete
- case OO_Delete: Out << "dl"; break;
- // ::= da # delete[]
- case OO_Array_Delete: Out << "da"; break;
- // ::= ps # + (unary)
- // ::= pl # + (binary or unknown)
- case OO_Plus:
- Out << (Arity == 1? "ps" : "pl"); break;
- // ::= ng # - (unary)
- // ::= mi # - (binary or unknown)
- case OO_Minus:
- Out << (Arity == 1? "ng" : "mi"); break;
- // ::= ad # & (unary)
- // ::= an # & (binary or unknown)
- case OO_Amp:
- Out << (Arity == 1? "ad" : "an"); break;
- // ::= de # * (unary)
- // ::= ml # * (binary or unknown)
- case OO_Star:
- // Use binary when unknown.
- Out << (Arity == 1? "de" : "ml"); break;
- // ::= co # ~
- case OO_Tilde: Out << "co"; break;
- // ::= dv # /
- case OO_Slash: Out << "dv"; break;
- // ::= rm # %
- case OO_Percent: Out << "rm"; break;
- // ::= or # |
- case OO_Pipe: Out << "or"; break;
- // ::= eo # ^
- case OO_Caret: Out << "eo"; break;
- // ::= aS # =
- case OO_Equal: Out << "aS"; break;
- // ::= pL # +=
- case OO_PlusEqual: Out << "pL"; break;
- // ::= mI # -=
- case OO_MinusEqual: Out << "mI"; break;
- // ::= mL # *=
- case OO_StarEqual: Out << "mL"; break;
- // ::= dV # /=
- case OO_SlashEqual: Out << "dV"; break;
- // ::= rM # %=
- case OO_PercentEqual: Out << "rM"; break;
- // ::= aN # &=
- case OO_AmpEqual: Out << "aN"; break;
- // ::= oR # |=
- case OO_PipeEqual: Out << "oR"; break;
- // ::= eO # ^=
- case OO_CaretEqual: Out << "eO"; break;
- // ::= ls # <<
- case OO_LessLess: Out << "ls"; break;
- // ::= rs # >>
- case OO_GreaterGreater: Out << "rs"; break;
- // ::= lS # <<=
- case OO_LessLessEqual: Out << "lS"; break;
- // ::= rS # >>=
- case OO_GreaterGreaterEqual: Out << "rS"; break;
- // ::= eq # ==
- case OO_EqualEqual: Out << "eq"; break;
- // ::= ne # !=
- case OO_ExclaimEqual: Out << "ne"; break;
- // ::= lt # <
- case OO_Less: Out << "lt"; break;
- // ::= gt # >
- case OO_Greater: Out << "gt"; break;
- // ::= le # <=
- case OO_LessEqual: Out << "le"; break;
- // ::= ge # >=
- case OO_GreaterEqual: Out << "ge"; break;
- // ::= nt # !
- case OO_Exclaim: Out << "nt"; break;
- // ::= aa # &&
- case OO_AmpAmp: Out << "aa"; break;
- // ::= oo # ||
- case OO_PipePipe: Out << "oo"; break;
- // ::= pp # ++
- case OO_PlusPlus: Out << "pp"; break;
- // ::= mm # --
- case OO_MinusMinus: Out << "mm"; break;
- // ::= cm # ,
- case OO_Comma: Out << "cm"; break;
- // ::= pm # ->*
- case OO_ArrowStar: Out << "pm"; break;
- // ::= pt # ->
- case OO_Arrow: Out << "pt"; break;
- // ::= cl # ()
- case OO_Call: Out << "cl"; break;
- // ::= ix # []
- case OO_Subscript: Out << "ix"; break;
-
- // ::= qu # ?
- // The conditional operator can't be overloaded, but we still handle it when
- // mangling expressions.
- case OO_Conditional: Out << "qu"; break;
-
- case OO_None:
- case NUM_OVERLOADED_OPERATORS:
- llvm_unreachable("Not an overloaded operator");
- }
-}
-
-void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
- // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
- if (Quals.hasRestrict())
- Out << 'r';
- if (Quals.hasVolatile())
- Out << 'V';
- if (Quals.hasConst())
- Out << 'K';
-
- if (Quals.hasAddressSpace()) {
- // Extension:
- //
- // <type> ::= U <address-space-number>
- //
- // where <address-space-number> is a source name consisting of 'AS'
- // followed by the address space <number>.
- SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
- Out << 'U' << ASString.size() << ASString;
- }
-
- StringRef LifetimeName;
- switch (Quals.getObjCLifetime()) {
- // Objective-C ARC Extension:
- //
- // <type> ::= U "__strong"
- // <type> ::= U "__weak"
- // <type> ::= U "__autoreleasing"
- case Qualifiers::OCL_None:
- break;
-
- case Qualifiers::OCL_Weak:
- LifetimeName = "__weak";
- break;
-
- case Qualifiers::OCL_Strong:
- LifetimeName = "__strong";
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- LifetimeName = "__autoreleasing";
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- // The __unsafe_unretained qualifier is *not* mangled, so that
- // __unsafe_unretained types in ARC produce the same manglings as the
- // equivalent (but, naturally, unqualified) types in non-ARC, providing
- // better ABI compatibility.
- //
- // It's safe to do this because unqualified 'id' won't show up
- // in any type signatures that need to be mangled.
- break;
- }
- if (!LifetimeName.empty())
- Out << 'U' << LifetimeName.size() << LifetimeName;
-}
-
-void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
- // <ref-qualifier> ::= R # lvalue reference
- // ::= O # rvalue-reference
- // Proposal to Itanium C++ ABI list on 1/26/11
- switch (RefQualifier) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- Out << 'R';
- break;
-
- case RQ_RValue:
- Out << 'O';
- break;
- }
-}
-
-void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
- Context.mangleObjCMethodName(MD, Out);
-}
-
-void CXXNameMangler::mangleType(QualType T) {
- // If our type is instantiation-dependent but not dependent, we mangle
- // it as it was written in the source, removing any top-level sugar.
- // Otherwise, use the canonical type.
- //
- // FIXME: This is an approximation of the instantiation-dependent name
- // mangling rules, since we should really be using the type as written and
- // augmented via semantic analysis (i.e., with implicit conversions and
- // default template arguments) for any instantiation-dependent type.
- // Unfortunately, that requires several changes to our AST:
- // - Instantiation-dependent TemplateSpecializationTypes will need to be
- // uniqued, so that we can handle substitutions properly
- // - Default template arguments will need to be represented in the
- // TemplateSpecializationType, since they need to be mangled even though
- // they aren't written.
- // - Conversions on non-type template arguments need to be expressed, since
- // they can affect the mangling of sizeof/alignof.
- if (!T->isInstantiationDependentType() || T->isDependentType())
- T = T.getCanonicalType();
- else {
- // Desugar any types that are purely sugar.
- do {
- // Don't desugar through template specialization types that aren't
- // type aliases. We need to mangle the template arguments as written.
- if (const TemplateSpecializationType *TST
- = dyn_cast<TemplateSpecializationType>(T))
- if (!TST->isTypeAlias())
- break;
-
- QualType Desugared
- = T.getSingleStepDesugaredType(Context.getASTContext());
- if (Desugared == T)
- break;
-
- T = Desugared;
- } while (true);
- }
- SplitQualType split = T.split();
- Qualifiers quals = split.Quals;
- const Type *ty = split.Ty;
-
- bool isSubstitutable = quals || !isa<BuiltinType>(T);
- if (isSubstitutable && mangleSubstitution(T))
- return;
-
- // If we're mangling a qualified array type, push the qualifiers to
- // the element type.
- if (quals && isa<ArrayType>(T)) {
- ty = Context.getASTContext().getAsArrayType(T);
- quals = Qualifiers();
-
- // Note that we don't update T: we want to add the
- // substitution at the original type.
- }
-
- if (quals) {
- mangleQualifiers(quals);
- // Recurse: even if the qualified type isn't yet substitutable,
- // the unqualified type might be.
- mangleType(QualType(ty, 0));
- } else {
- switch (ty->getTypeClass()) {
-#define ABSTRACT_TYPE(CLASS, PARENT)
-#define NON_CANONICAL_TYPE(CLASS, PARENT) \
- case Type::CLASS: \
- llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
- return;
-#define TYPE(CLASS, PARENT) \
- case Type::CLASS: \
- mangleType(static_cast<const CLASS##Type*>(ty)); \
- break;
-#include "clang/AST/TypeNodes.def"
- }
- }
-
- // Add the substitution.
- if (isSubstitutable)
- addSubstitution(T);
-}
-
-void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
- if (!mangleStandardSubstitution(ND))
- mangleName(ND);
-}
-
-void CXXNameMangler::mangleType(const BuiltinType *T) {
- // <type> ::= <builtin-type>
- // <builtin-type> ::= v # void
- // ::= w # wchar_t
- // ::= b # bool
- // ::= c # char
- // ::= a # signed char
- // ::= h # unsigned char
- // ::= s # short
- // ::= t # unsigned short
- // ::= i # int
- // ::= j # unsigned int
- // ::= l # long
- // ::= m # unsigned long
- // ::= x # long long, __int64
- // ::= y # unsigned long long, __int64
- // ::= n # __int128
- // UNSUPPORTED: ::= o # unsigned __int128
- // ::= f # float
- // ::= d # double
- // ::= e # long double, __float80
- // UNSUPPORTED: ::= g # __float128
- // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits)
- // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
- // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
- // ::= Dh # IEEE 754r half-precision floating point (16 bits)
- // ::= Di # char32_t
- // ::= Ds # char16_t
- // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
- // ::= u <source-name> # vendor extended type
- switch (T->getKind()) {
- case BuiltinType::Void: Out << 'v'; break;
- case BuiltinType::Bool: Out << 'b'; break;
- case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break;
- case BuiltinType::UChar: Out << 'h'; break;
- case BuiltinType::UShort: Out << 't'; break;
- case BuiltinType::UInt: Out << 'j'; break;
- case BuiltinType::ULong: Out << 'm'; break;
- case BuiltinType::ULongLong: Out << 'y'; break;
- case BuiltinType::UInt128: Out << 'o'; break;
- case BuiltinType::SChar: Out << 'a'; break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U: Out << 'w'; break;
- case BuiltinType::Char16: Out << "Ds"; break;
- case BuiltinType::Char32: Out << "Di"; break;
- case BuiltinType::Short: Out << 's'; break;
- case BuiltinType::Int: Out << 'i'; break;
- case BuiltinType::Long: Out << 'l'; break;
- case BuiltinType::LongLong: Out << 'x'; break;
- case BuiltinType::Int128: Out << 'n'; break;
- case BuiltinType::Half: Out << "Dh"; break;
- case BuiltinType::Float: Out << 'f'; break;
- case BuiltinType::Double: Out << 'd'; break;
- case BuiltinType::LongDouble: Out << 'e'; break;
- case BuiltinType::NullPtr: Out << "Dn"; break;
-
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
- llvm_unreachable("mangling a placeholder type");
- case BuiltinType::ObjCId: Out << "11objc_object"; break;
- case BuiltinType::ObjCClass: Out << "10objc_class"; break;
- case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
- case BuiltinType::OCLImage1d: Out << "11ocl_image1d"; break;
- case BuiltinType::OCLImage1dArray: Out << "16ocl_image1darray"; break;
- case BuiltinType::OCLImage1dBuffer: Out << "17ocl_image1dbuffer"; break;
- case BuiltinType::OCLImage2d: Out << "11ocl_image2d"; break;
- case BuiltinType::OCLImage2dArray: Out << "16ocl_image2darray"; break;
- case BuiltinType::OCLImage3d: Out << "11ocl_image3d"; break;
- }
-}
-
-// <type> ::= <function-type>
-// <function-type> ::= [<CV-qualifiers>] F [Y]
-// <bare-function-type> [<ref-qualifier>] E
-// (Proposal to cxx-abi-dev, 2012-05-11)
-void CXXNameMangler::mangleType(const FunctionProtoType *T) {
- // Mangle CV-qualifiers, if present. These are 'this' qualifiers,
- // e.g. "const" in "int (A::*)() const".
- mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals()));
-
- Out << 'F';
-
- // FIXME: We don't have enough information in the AST to produce the 'Y'
- // encoding for extern "C" function types.
- mangleBareFunctionType(T, /*MangleReturnType=*/true);
-
- // Mangle the ref-qualifier, if present.
- mangleRefQualifier(T->getRefQualifier());
-
- Out << 'E';
-}
-void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
- llvm_unreachable("Can't mangle K&R function prototypes");
-}
-void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType) {
- // We should never be mangling something without a prototype.
- const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
-
- // Record that we're in a function type. See mangleFunctionParam
- // for details on what we're trying to achieve here.
- FunctionTypeDepthState saved = FunctionTypeDepth.push();
-
- // <bare-function-type> ::= <signature type>+
- if (MangleReturnType) {
- FunctionTypeDepth.enterResultType();
- mangleType(Proto->getResultType());
- FunctionTypeDepth.leaveResultType();
- }
-
- if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
- // <builtin-type> ::= v # void
- Out << 'v';
-
- FunctionTypeDepth.pop(saved);
- return;
- }
-
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleType(Context.getASTContext().getSignatureParameterType(*Arg));
-
- FunctionTypeDepth.pop(saved);
-
- // <builtin-type> ::= z # ellipsis
- if (Proto->isVariadic())
- Out << 'z';
-}
-
-// <type> ::= <class-enum-type>
-// <class-enum-type> ::= <name>
-void CXXNameMangler::mangleType(const UnresolvedUsingType *T) {
- mangleName(T->getDecl());
-}
-
-// <type> ::= <class-enum-type>
-// <class-enum-type> ::= <name>
-void CXXNameMangler::mangleType(const EnumType *T) {
- mangleType(static_cast<const TagType*>(T));
-}
-void CXXNameMangler::mangleType(const RecordType *T) {
- mangleType(static_cast<const TagType*>(T));
-}
-void CXXNameMangler::mangleType(const TagType *T) {
- mangleName(T->getDecl());
-}
-
-// <type> ::= <array-type>
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
-void CXXNameMangler::mangleType(const ConstantArrayType *T) {
- Out << 'A' << T->getSize() << '_';
- mangleType(T->getElementType());
-}
-void CXXNameMangler::mangleType(const VariableArrayType *T) {
- Out << 'A';
- // decayed vla types (size 0) will just be skipped.
- if (T->getSizeExpr())
- mangleExpression(T->getSizeExpr());
- Out << '_';
- mangleType(T->getElementType());
-}
-void CXXNameMangler::mangleType(const DependentSizedArrayType *T) {
- Out << 'A';
- mangleExpression(T->getSizeExpr());
- Out << '_';
- mangleType(T->getElementType());
-}
-void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
- Out << "A_";
- mangleType(T->getElementType());
-}
-
-// <type> ::= <pointer-to-member-type>
-// <pointer-to-member-type> ::= M <class type> <member type>
-void CXXNameMangler::mangleType(const MemberPointerType *T) {
- Out << 'M';
- mangleType(QualType(T->getClass(), 0));
- QualType PointeeType = T->getPointeeType();
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
- mangleType(FPT);
-
- // Itanium C++ ABI 5.1.8:
- //
- // The type of a non-static member function is considered to be different,
- // for the purposes of substitution, from the type of a namespace-scope or
- // static member function whose type appears similar. The types of two
- // non-static member functions are considered to be different, for the
- // purposes of substitution, if the functions are members of different
- // classes. In other words, for the purposes of substitution, the class of
- // which the function is a member is considered part of the type of
- // function.
-
- // Given that we already substitute member function pointers as a
- // whole, the net effect of this rule is just to unconditionally
- // suppress substitution on the function type in a member pointer.
- // We increment the SeqID here to emulate adding an entry to the
- // substitution table.
- ++SeqID;
- } else
- mangleType(PointeeType);
-}
-
-// <type> ::= <template-param>
-void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
- mangleTemplateParameter(T->getIndex());
-}
-
-// <type> ::= <template-param>
-void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
- // FIXME: not clear how to mangle this!
- // template <class T...> class A {
- // template <class U...> void foo(T(*)(U) x...);
- // };
- Out << "_SUBSTPACK_";
-}
-
-// <type> ::= P <type> # pointer-to
-void CXXNameMangler::mangleType(const PointerType *T) {
- Out << 'P';
- mangleType(T->getPointeeType());
-}
-void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
- Out << 'P';
- mangleType(T->getPointeeType());
-}
-
-// <type> ::= R <type> # reference-to
-void CXXNameMangler::mangleType(const LValueReferenceType *T) {
- Out << 'R';
- mangleType(T->getPointeeType());
-}
-
-// <type> ::= O <type> # rvalue reference-to (C++0x)
-void CXXNameMangler::mangleType(const RValueReferenceType *T) {
- Out << 'O';
- mangleType(T->getPointeeType());
-}
-
-// <type> ::= C <type> # complex pair (C 2000)
-void CXXNameMangler::mangleType(const ComplexType *T) {
- Out << 'C';
- mangleType(T->getElementType());
-}
-
-// ARM's ABI for Neon vector types specifies that they should be mangled as
-// if they are structs (to match ARM's initial implementation). The
-// vector type must be one of the special types predefined by ARM.
-void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
- QualType EltType = T->getElementType();
- assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
- const char *EltName = 0;
- if (T->getVectorKind() == VectorType::NeonPolyVector) {
- switch (cast<BuiltinType>(EltType)->getKind()) {
- case BuiltinType::SChar: EltName = "poly8_t"; break;
- case BuiltinType::Short: EltName = "poly16_t"; break;
- default: llvm_unreachable("unexpected Neon polynomial vector element type");
- }
- } else {
- switch (cast<BuiltinType>(EltType)->getKind()) {
- case BuiltinType::SChar: EltName = "int8_t"; break;
- case BuiltinType::UChar: EltName = "uint8_t"; break;
- case BuiltinType::Short: EltName = "int16_t"; break;
- case BuiltinType::UShort: EltName = "uint16_t"; break;
- case BuiltinType::Int: EltName = "int32_t"; break;
- case BuiltinType::UInt: EltName = "uint32_t"; break;
- case BuiltinType::LongLong: EltName = "int64_t"; break;
- case BuiltinType::ULongLong: EltName = "uint64_t"; break;
- case BuiltinType::Float: EltName = "float32_t"; break;
- default: llvm_unreachable("unexpected Neon vector element type");
- }
- }
- const char *BaseName = 0;
- unsigned BitSize = (T->getNumElements() *
- getASTContext().getTypeSize(EltType));
- if (BitSize == 64)
- BaseName = "__simd64_";
- else {
- assert(BitSize == 128 && "Neon vector type not 64 or 128 bits");
- BaseName = "__simd128_";
- }
- Out << strlen(BaseName) + strlen(EltName);
- Out << BaseName << EltName;
-}
-
-// GNU extension: vector types
-// <type> ::= <vector-type>
-// <vector-type> ::= Dv <positive dimension number> _
-// <extended element type>
-// ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-// ::= p # AltiVec vector pixel
-// ::= b # Altivec vector bool
-void CXXNameMangler::mangleType(const VectorType *T) {
- if ((T->getVectorKind() == VectorType::NeonVector ||
- T->getVectorKind() == VectorType::NeonPolyVector)) {
- mangleNeonVectorType(T);
- return;
- }
- Out << "Dv" << T->getNumElements() << '_';
- if (T->getVectorKind() == VectorType::AltiVecPixel)
- Out << 'p';
- else if (T->getVectorKind() == VectorType::AltiVecBool)
- Out << 'b';
- else
- mangleType(T->getElementType());
-}
-void CXXNameMangler::mangleType(const ExtVectorType *T) {
- mangleType(static_cast<const VectorType*>(T));
-}
-void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
- Out << "Dv";
- mangleExpression(T->getSizeExpr());
- Out << '_';
- mangleType(T->getElementType());
-}
-
-void CXXNameMangler::mangleType(const PackExpansionType *T) {
- // <type> ::= Dp <type> # pack expansion (C++0x)
- Out << "Dp";
- mangleType(T->getPattern());
-}
-
-void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
- mangleSourceName(T->getDecl()->getIdentifier());
-}
-
-void CXXNameMangler::mangleType(const ObjCObjectType *T) {
- // We don't allow overloading by different protocol qualification,
- // so mangling them isn't necessary.
- mangleType(T->getBaseType());
-}
-
-void CXXNameMangler::mangleType(const BlockPointerType *T) {
- Out << "U13block_pointer";
- mangleType(T->getPointeeType());
-}
-
-void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
- // Mangle injected class name types as if the user had written the
- // specialization out fully. It may not actually be possible to see
- // this mangling, though.
- mangleType(T->getInjectedSpecializationType());
-}
-
-void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
- if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
- mangleName(TD, T->getArgs(), T->getNumArgs());
- } else {
- if (mangleSubstitution(QualType(T, 0)))
- return;
-
- mangleTemplatePrefix(T->getTemplateName());
-
- // FIXME: GCC does not appear to mangle the template arguments when
- // the template in question is a dependent template name. Should we
- // emulate that badness?
- mangleTemplateArgs(T->getArgs(), T->getNumArgs());
- addSubstitution(QualType(T, 0));
- }
-}
-
-void CXXNameMangler::mangleType(const DependentNameType *T) {
- // Typename types are always nested
- Out << 'N';
- manglePrefix(T->getQualifier());
- mangleSourceName(T->getIdentifier());
- Out << 'E';
-}
-
-void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
- // Dependently-scoped template types are nested if they have a prefix.
- Out << 'N';
-
- // TODO: avoid making this TemplateName.
- TemplateName Prefix =
- getASTContext().getDependentTemplateName(T->getQualifier(),
- T->getIdentifier());
- mangleTemplatePrefix(Prefix);
-
- // FIXME: GCC does not appear to mangle the template arguments when
- // the template in question is a dependent template name. Should we
- // emulate that badness?
- mangleTemplateArgs(T->getArgs(), T->getNumArgs());
- Out << 'E';
-}
-
-void CXXNameMangler::mangleType(const TypeOfType *T) {
- // FIXME: this is pretty unsatisfactory, but there isn't an obvious
- // "extension with parameters" mangling.
- Out << "u6typeof";
-}
-
-void CXXNameMangler::mangleType(const TypeOfExprType *T) {
- // FIXME: this is pretty unsatisfactory, but there isn't an obvious
- // "extension with parameters" mangling.
- Out << "u6typeof";
-}
-
-void CXXNameMangler::mangleType(const DecltypeType *T) {
- Expr *E = T->getUnderlyingExpr();
-
- // type ::= Dt <expression> E # decltype of an id-expression
- // # or class member access
- // ::= DT <expression> E # decltype of an expression
-
- // This purports to be an exhaustive list of id-expressions and
- // class member accesses. Note that we do not ignore parentheses;
- // parentheses change the semantics of decltype for these
- // expressions (and cause the mangler to use the other form).
- if (isa<DeclRefExpr>(E) ||
- isa<MemberExpr>(E) ||
- isa<UnresolvedLookupExpr>(E) ||
- isa<DependentScopeDeclRefExpr>(E) ||
- isa<CXXDependentScopeMemberExpr>(E) ||
- isa<UnresolvedMemberExpr>(E))
- Out << "Dt";
- else
- Out << "DT";
- mangleExpression(E);
- Out << 'E';
-}
-
-void CXXNameMangler::mangleType(const UnaryTransformType *T) {
- // If this is dependent, we need to record that. If not, we simply
- // mangle it as the underlying type since they are equivalent.
- if (T->isDependentType()) {
- Out << 'U';
-
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- Out << "3eut";
- break;
- }
- }
-
- mangleType(T->getUnderlyingType());
-}
-
-void CXXNameMangler::mangleType(const AutoType *T) {
- QualType D = T->getDeducedType();
- // <builtin-type> ::= Da # dependent auto
- if (D.isNull())
- Out << "Da";
- else
- mangleType(D);
-}
-
-void CXXNameMangler::mangleType(const AtomicType *T) {
- // <type> ::= U <source-name> <type> # vendor extended type qualifier
- // (Until there's a standardized mangling...)
- Out << "U7_Atomic";
- mangleType(T->getValueType());
-}
-
-void CXXNameMangler::mangleIntegerLiteral(QualType T,
- const llvm::APSInt &Value) {
- // <expr-primary> ::= L <type> <value number> E # integer literal
- Out << 'L';
-
- mangleType(T);
- if (T->isBooleanType()) {
- // Boolean values are encoded as 0/1.
- Out << (Value.getBoolValue() ? '1' : '0');
- } else {
- mangleNumber(Value);
- }
- Out << 'E';
-
-}
-
-/// Mangles a member expression.
-void CXXNameMangler::mangleMemberExpr(const Expr *base,
- bool isArrow,
- NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- DeclarationName member,
- unsigned arity) {
- // <expression> ::= dt <expression> <unresolved-name>
- // ::= pt <expression> <unresolved-name>
- if (base) {
- if (base->isImplicitCXXThis()) {
- // Note: GCC mangles member expressions to the implicit 'this' as
- // *this., whereas we represent them as this->. The Itanium C++ ABI
- // does not specify anything here, so we follow GCC.
- Out << "dtdefpT";
- } else {
- Out << (isArrow ? "pt" : "dt");
- mangleExpression(base);
- }
- }
- mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
-}
-
-/// Look at the callee of the given call expression and determine if
-/// it's a parenthesized id-expression which would have triggered ADL
-/// otherwise.
-static bool isParenthesizedADLCallee(const CallExpr *call) {
- const Expr *callee = call->getCallee();
- const Expr *fn = callee->IgnoreParens();
-
- // Must be parenthesized. IgnoreParens() skips __extension__ nodes,
- // too, but for those to appear in the callee, it would have to be
- // parenthesized.
- if (callee == fn) return false;
-
- // Must be an unresolved lookup.
- const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn);
- if (!lookup) return false;
-
- assert(!lookup->requiresADL());
-
- // Must be an unqualified lookup.
- if (lookup->getQualifier()) return false;
-
- // Must not have found a class member. Note that if one is a class
- // member, they're all class members.
- if (lookup->getNumDecls() > 0 &&
- (*lookup->decls_begin())->isCXXClassMember())
- return false;
-
- // Otherwise, ADL would have been triggered.
- return true;
-}
-
-void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
- // <expression> ::= <unary operator-name> <expression>
- // ::= <binary operator-name> <expression> <expression>
- // ::= <trinary operator-name> <expression> <expression> <expression>
- // ::= cv <type> expression # conversion with one argument
- // ::= cv <type> _ <expression>* E # conversion with a different number of arguments
- // ::= st <type> # sizeof (a type)
- // ::= at <type> # alignof (a type)
- // ::= <template-param>
- // ::= <function-param>
- // ::= sr <type> <unqualified-name> # dependent name
- // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
- // ::= ds <expression> <expression> # expr.*expr
- // ::= sZ <template-param> # size of a parameter pack
- // ::= sZ <function-param> # size of a function parameter pack
- // ::= <expr-primary>
- // <expr-primary> ::= L <type> <value number> E # integer literal
- // ::= L <type <value float> E # floating literal
- // ::= L <mangled-name> E # external name
- // ::= fpT # 'this' expression
- QualType ImplicitlyConvertedToType;
-
-recurse:
- switch (E->getStmtClass()) {
- case Expr::NoStmtClass:
-#define ABSTRACT_STMT(Type)
-#define EXPR(Type, Base)
-#define STMT(Type, Base) \
- case Expr::Type##Class:
-#include "clang/AST/StmtNodes.inc"
- // fallthrough
-
- // These all can only appear in local or variable-initialization
- // contexts and so should never appear in a mangling.
- case Expr::AddrLabelExprClass:
- case Expr::DesignatedInitExprClass:
- case Expr::ImplicitValueInitExprClass:
- case Expr::ParenListExprClass:
- case Expr::LambdaExprClass:
- llvm_unreachable("unexpected statement kind");
-
- // FIXME: invent manglings for all these.
- case Expr::BlockExprClass:
- case Expr::CXXPseudoDestructorExprClass:
- case Expr::ChooseExprClass:
- case Expr::CompoundLiteralExprClass:
- case Expr::ExtVectorElementExprClass:
- case Expr::GenericSelectionExprClass:
- case Expr::ObjCEncodeExprClass:
- case Expr::ObjCIsaExprClass:
- case Expr::ObjCIvarRefExprClass:
- case Expr::ObjCMessageExprClass:
- case Expr::ObjCPropertyRefExprClass:
- case Expr::ObjCProtocolExprClass:
- case Expr::ObjCSelectorExprClass:
- case Expr::ObjCStringLiteralClass:
- case Expr::ObjCBoxedExprClass:
- case Expr::ObjCArrayLiteralClass:
- case Expr::ObjCDictionaryLiteralClass:
- case Expr::ObjCSubscriptRefExprClass:
- case Expr::ObjCIndirectCopyRestoreExprClass:
- case Expr::OffsetOfExprClass:
- case Expr::PredefinedExprClass:
- case Expr::ShuffleVectorExprClass:
- case Expr::StmtExprClass:
- case Expr::UnaryTypeTraitExprClass:
- case Expr::BinaryTypeTraitExprClass:
- case Expr::TypeTraitExprClass:
- case Expr::ArrayTypeTraitExprClass:
- case Expr::ExpressionTraitExprClass:
- case Expr::VAArgExprClass:
- case Expr::CXXUuidofExprClass:
- case Expr::CUDAKernelCallExprClass:
- case Expr::AsTypeExprClass:
- case Expr::PseudoObjectExprClass:
- case Expr::AtomicExprClass:
- {
- // As bad as this diagnostic is, it's better than crashing.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet mangle expression type %0");
- Diags.Report(E->getExprLoc(), DiagID)
- << E->getStmtClassName() << E->getSourceRange();
- break;
- }
-
- // Even gcc-4.5 doesn't mangle this.
- case Expr::BinaryConditionalOperatorClass: {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID =
- Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "?: operator with omitted middle operand cannot be mangled");
- Diags.Report(E->getExprLoc(), DiagID)
- << E->getStmtClassName() << E->getSourceRange();
- break;
- }
-
- // These are used for internal purposes and cannot be meaningfully mangled.
- case Expr::OpaqueValueExprClass:
- llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
-
- case Expr::InitListExprClass: {
- // Proposal by Jason Merrill, 2012-01-03
- Out << "il";
- const InitListExpr *InitList = cast<InitListExpr>(E);
- for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
- mangleExpression(InitList->getInit(i));
- Out << "E";
- break;
- }
-
- case Expr::CXXDefaultArgExprClass:
- mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
- break;
-
- case Expr::SubstNonTypeTemplateParmExprClass:
- mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
- Arity);
- break;
-
- case Expr::UserDefinedLiteralClass:
- // We follow g++'s approach of mangling a UDL as a call to the literal
- // operator.
- case Expr::CXXMemberCallExprClass: // fallthrough
- case Expr::CallExprClass: {
- const CallExpr *CE = cast<CallExpr>(E);
-
- // <expression> ::= cp <simple-id> <expression>* E
- // We use this mangling only when the call would use ADL except
- // for being parenthesized. Per discussion with David
- // Vandervoorde, 2011.04.25.
- if (isParenthesizedADLCallee(CE)) {
- Out << "cp";
- // The callee here is a parenthesized UnresolvedLookupExpr with
- // no qualifier and should always get mangled as a <simple-id>
- // anyway.
-
- // <expression> ::= cl <expression>* E
- } else {
- Out << "cl";
- }
-
- mangleExpression(CE->getCallee(), CE->getNumArgs());
- for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
- mangleExpression(CE->getArg(I));
- Out << 'E';
- break;
- }
-
- case Expr::CXXNewExprClass: {
- const CXXNewExpr *New = cast<CXXNewExpr>(E);
- if (New->isGlobalNew()) Out << "gs";
- Out << (New->isArray() ? "na" : "nw");
- for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(),
- E = New->placement_arg_end(); I != E; ++I)
- mangleExpression(*I);
- Out << '_';
- mangleType(New->getAllocatedType());
- if (New->hasInitializer()) {
- // Proposal by Jason Merrill, 2012-01-03
- if (New->getInitializationStyle() == CXXNewExpr::ListInit)
- Out << "il";
- else
- Out << "pi";
- const Expr *Init = New->getInitializer();
- if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
- // Directly inline the initializers.
- for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
- E = CCE->arg_end();
- I != E; ++I)
- mangleExpression(*I);
- } else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
- for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
- mangleExpression(PLE->getExpr(i));
- } else if (New->getInitializationStyle() == CXXNewExpr::ListInit &&
- isa<InitListExpr>(Init)) {
- // Only take InitListExprs apart for list-initialization.
- const InitListExpr *InitList = cast<InitListExpr>(Init);
- for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
- mangleExpression(InitList->getInit(i));
- } else
- mangleExpression(Init);
- }
- Out << 'E';
- break;
- }
-
- case Expr::MemberExprClass: {
- const MemberExpr *ME = cast<MemberExpr>(E);
- mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(),
- Arity);
- break;
- }
-
- case Expr::UnresolvedMemberExprClass: {
- const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
- mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), 0, ME->getMemberName(),
- Arity);
- if (ME->hasExplicitTemplateArgs())
- mangleTemplateArgs(ME->getExplicitTemplateArgs());
- break;
- }
-
- case Expr::CXXDependentScopeMemberExprClass: {
- const CXXDependentScopeMemberExpr *ME
- = cast<CXXDependentScopeMemberExpr>(E);
- mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getFirstQualifierFoundInScope(),
- ME->getMember(), Arity);
- if (ME->hasExplicitTemplateArgs())
- mangleTemplateArgs(ME->getExplicitTemplateArgs());
- break;
- }
-
- case Expr::UnresolvedLookupExprClass: {
- const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
- mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
-
- // All the <unresolved-name> productions end in a
- // base-unresolved-name, where <template-args> are just tacked
- // onto the end.
- if (ULE->hasExplicitTemplateArgs())
- mangleTemplateArgs(ULE->getExplicitTemplateArgs());
- break;
- }
-
- case Expr::CXXUnresolvedConstructExprClass: {
- const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
- unsigned N = CE->arg_size();
-
- Out << "cv";
- mangleType(CE->getType());
- if (N != 1) Out << '_';
- for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << 'E';
- break;
- }
-
- case Expr::CXXTemporaryObjectExprClass:
- case Expr::CXXConstructExprClass: {
- const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
- unsigned N = CE->getNumArgs();
-
- // Proposal by Jason Merrill, 2012-01-03
- if (CE->isListInitialization())
- Out << "tl";
- else
- Out << "cv";
- mangleType(CE->getType());
- if (N != 1) Out << '_';
- for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << 'E';
- break;
- }
-
- case Expr::CXXScalarValueInitExprClass:
- Out <<"cv";
- mangleType(E->getType());
- Out <<"_E";
- break;
-
- case Expr::CXXNoexceptExprClass:
- Out << "nx";
- mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand());
- break;
-
- case Expr::UnaryExprOrTypeTraitExprClass: {
- const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
-
- if (!SAE->isInstantiationDependent()) {
- // Itanium C++ ABI:
- // If the operand of a sizeof or alignof operator is not
- // instantiation-dependent it is encoded as an integer literal
- // reflecting the result of the operator.
- //
- // If the result of the operator is implicitly converted to a known
- // integer type, that type is used for the literal; otherwise, the type
- // of std::size_t or std::ptrdiff_t is used.
- QualType T = (ImplicitlyConvertedToType.isNull() ||
- !ImplicitlyConvertedToType->isIntegerType())? SAE->getType()
- : ImplicitlyConvertedToType;
- llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext());
- mangleIntegerLiteral(T, V);
- break;
- }
-
- switch(SAE->getKind()) {
- case UETT_SizeOf:
- Out << 's';
- break;
- case UETT_AlignOf:
- Out << 'a';
- break;
- case UETT_VecStep:
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet mangle vec_step expression");
- Diags.Report(DiagID);
- return;
- }
- if (SAE->isArgumentType()) {
- Out << 't';
- mangleType(SAE->getArgumentType());
- } else {
- Out << 'z';
- mangleExpression(SAE->getArgumentExpr());
- }
- break;
- }
-
- case Expr::CXXThrowExprClass: {
- const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
- if (TE->getSubExpr()) {
- Out << "tw";
- mangleExpression(TE->getSubExpr());
- } else {
- Out << "tr";
- }
- break;
- }
-
- case Expr::CXXTypeidExprClass: {
- const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
- if (TIE->isTypeOperand()) {
- Out << "ti";
- mangleType(TIE->getTypeOperand());
- } else {
- Out << "te";
- mangleExpression(TIE->getExprOperand());
- }
- break;
- }
-
- case Expr::CXXDeleteExprClass: {
- const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
- if (DE->isGlobalDelete()) Out << "gs";
- Out << (DE->isArrayForm() ? "da" : "dl");
- mangleExpression(DE->getArgument());
- break;
- }
-
- case Expr::UnaryOperatorClass: {
- const UnaryOperator *UO = cast<UnaryOperator>(E);
- mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
- /*Arity=*/1);
- mangleExpression(UO->getSubExpr());
- break;
- }
-
- case Expr::ArraySubscriptExprClass: {
- const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
-
- // Array subscript is treated as a syntactically weird form of
- // binary operator.
- Out << "ix";
- mangleExpression(AE->getLHS());
- mangleExpression(AE->getRHS());
- break;
- }
-
- case Expr::CompoundAssignOperatorClass: // fallthrough
- case Expr::BinaryOperatorClass: {
- const BinaryOperator *BO = cast<BinaryOperator>(E);
- if (BO->getOpcode() == BO_PtrMemD)
- Out << "ds";
- else
- mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
- /*Arity=*/2);
- mangleExpression(BO->getLHS());
- mangleExpression(BO->getRHS());
- break;
- }
-
- case Expr::ConditionalOperatorClass: {
- const ConditionalOperator *CO = cast<ConditionalOperator>(E);
- mangleOperatorName(OO_Conditional, /*Arity=*/3);
- mangleExpression(CO->getCond());
- mangleExpression(CO->getLHS(), Arity);
- mangleExpression(CO->getRHS(), Arity);
- break;
- }
-
- case Expr::ImplicitCastExprClass: {
- ImplicitlyConvertedToType = E->getType();
- E = cast<ImplicitCastExpr>(E)->getSubExpr();
- goto recurse;
- }
-
- case Expr::ObjCBridgedCastExprClass: {
- // Mangle ownership casts as a vendor extended operator __bridge,
- // __bridge_transfer, or __bridge_retain.
- StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
- Out << "v1U" << Kind.size() << Kind;
- }
- // Fall through to mangle the cast itself.
-
- case Expr::CStyleCastExprClass:
- case Expr::CXXStaticCastExprClass:
- case Expr::CXXDynamicCastExprClass:
- case Expr::CXXReinterpretCastExprClass:
- case Expr::CXXConstCastExprClass:
- case Expr::CXXFunctionalCastExprClass: {
- const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
- Out << "cv";
- mangleType(ECE->getType());
- mangleExpression(ECE->getSubExpr());
- break;
- }
-
- case Expr::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
- unsigned NumArgs = CE->getNumArgs();
- mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs);
- // Mangle the arguments.
- for (unsigned i = 0; i != NumArgs; ++i)
- mangleExpression(CE->getArg(i));
- break;
- }
-
- case Expr::ParenExprClass:
- mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
- break;
-
- case Expr::DeclRefExprClass: {
- const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
-
- switch (D->getKind()) {
- default:
- // <expr-primary> ::= L <mangled-name> E # external name
- Out << 'L';
- mangle(D, "_Z");
- Out << 'E';
- break;
-
- case Decl::ParmVar:
- mangleFunctionParam(cast<ParmVarDecl>(D));
- break;
-
- case Decl::EnumConstant: {
- const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
- mangleIntegerLiteral(ED->getType(), ED->getInitVal());
- break;
- }
-
- case Decl::NonTypeTemplateParm: {
- const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
- mangleTemplateParameter(PD->getIndex());
- break;
- }
-
- }
-
- break;
- }
-
- case Expr::SubstNonTypeTemplateParmPackExprClass:
- // FIXME: not clear how to mangle this!
- // template <unsigned N...> class A {
- // template <class U...> void foo(U (&x)[N]...);
- // };
- Out << "_SUBSTPACK_";
- break;
-
- case Expr::FunctionParmPackExprClass: {
- // FIXME: not clear how to mangle this!
- const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
- Out << "v110_SUBSTPACK";
- mangleFunctionParam(FPPE->getParameterPack());
- break;
- }
-
- case Expr::DependentScopeDeclRefExprClass: {
- const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
- mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
-
- // All the <unresolved-name> productions end in a
- // base-unresolved-name, where <template-args> are just tacked
- // onto the end.
- if (DRE->hasExplicitTemplateArgs())
- mangleTemplateArgs(DRE->getExplicitTemplateArgs());
- break;
- }
-
- case Expr::CXXBindTemporaryExprClass:
- mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
- break;
-
- case Expr::ExprWithCleanupsClass:
- mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity);
- break;
-
- case Expr::FloatingLiteralClass: {
- const FloatingLiteral *FL = cast<FloatingLiteral>(E);
- Out << 'L';
- mangleType(FL->getType());
- mangleFloat(FL->getValue());
- Out << 'E';
- break;
- }
-
- case Expr::CharacterLiteralClass:
- Out << 'L';
- mangleType(E->getType());
- Out << cast<CharacterLiteral>(E)->getValue();
- Out << 'E';
- break;
-
- // FIXME. __objc_yes/__objc_no are mangled same as true/false
- case Expr::ObjCBoolLiteralExprClass:
- Out << "Lb";
- Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0');
- Out << 'E';
- break;
-
- case Expr::CXXBoolLiteralExprClass:
- Out << "Lb";
- Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
- Out << 'E';
- break;
-
- case Expr::IntegerLiteralClass: {
- llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue());
- if (E->getType()->isSignedIntegerType())
- Value.setIsSigned(true);
- mangleIntegerLiteral(E->getType(), Value);
- break;
- }
-
- case Expr::ImaginaryLiteralClass: {
- const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E);
- // Mangle as if a complex literal.
- // Proposal from David Vandevoorde, 2010.06.30.
- Out << 'L';
- mangleType(E->getType());
- if (const FloatingLiteral *Imag =
- dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
- // Mangle a floating-point zero of the appropriate type.
- mangleFloat(llvm::APFloat(Imag->getValue().getSemantics()));
- Out << '_';
- mangleFloat(Imag->getValue());
- } else {
- Out << "0_";
- llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue());
- if (IE->getSubExpr()->getType()->isSignedIntegerType())
- Value.setIsSigned(true);
- mangleNumber(Value);
- }
- Out << 'E';
- break;
- }
-
- case Expr::StringLiteralClass: {
- // Revised proposal from David Vandervoorde, 2010.07.15.
- Out << 'L';
- assert(isa<ConstantArrayType>(E->getType()));
- mangleType(E->getType());
- Out << 'E';
- break;
- }
-
- case Expr::GNUNullExprClass:
- // FIXME: should this really be mangled the same as nullptr?
- // fallthrough
-
- case Expr::CXXNullPtrLiteralExprClass: {
- // Proposal from David Vandervoorde, 2010.06.30, as
- // modified by ABI list discussion.
- Out << "LDnE";
- break;
- }
-
- case Expr::PackExpansionExprClass:
- Out << "sp";
- mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
- break;
-
- case Expr::SizeOfPackExprClass: {
- Out << "sZ";
- const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack();
- if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
- mangleTemplateParameter(TTP->getIndex());
- else if (const NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Pack))
- mangleTemplateParameter(NTTP->getIndex());
- else if (const TemplateTemplateParmDecl *TempTP
- = dyn_cast<TemplateTemplateParmDecl>(Pack))
- mangleTemplateParameter(TempTP->getIndex());
- else
- mangleFunctionParam(cast<ParmVarDecl>(Pack));
- break;
- }
-
- case Expr::MaterializeTemporaryExprClass: {
- mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
- break;
- }
-
- case Expr::CXXThisExprClass:
- Out << "fpT";
- break;
- }
-}
-
-/// Mangle an expression which refers to a parameter variable.
-///
-/// <expression> ::= <function-param>
-/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0
-/// <function-param> ::= fp <top-level CV-qualifiers>
-/// <parameter-2 non-negative number> _ # L == 0, I > 0
-/// <function-param> ::= fL <L-1 non-negative number>
-/// p <top-level CV-qualifiers> _ # L > 0, I == 0
-/// <function-param> ::= fL <L-1 non-negative number>
-/// p <top-level CV-qualifiers>
-/// <I-1 non-negative number> _ # L > 0, I > 0
-///
-/// L is the nesting depth of the parameter, defined as 1 if the
-/// parameter comes from the innermost function prototype scope
-/// enclosing the current context, 2 if from the next enclosing
-/// function prototype scope, and so on, with one special case: if
-/// we've processed the full parameter clause for the innermost
-/// function type, then L is one less. This definition conveniently
-/// makes it irrelevant whether a function's result type was written
-/// trailing or leading, but is otherwise overly complicated; the
-/// numbering was first designed without considering references to
-/// parameter in locations other than return types, and then the
-/// mangling had to be generalized without changing the existing
-/// manglings.
-///
-/// I is the zero-based index of the parameter within its parameter
-/// declaration clause. Note that the original ABI document describes
-/// this using 1-based ordinals.
-void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
- unsigned parmDepth = parm->getFunctionScopeDepth();
- unsigned parmIndex = parm->getFunctionScopeIndex();
-
- // Compute 'L'.
- // parmDepth does not include the declaring function prototype.
- // FunctionTypeDepth does account for that.
- assert(parmDepth < FunctionTypeDepth.getDepth());
- unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth;
- if (FunctionTypeDepth.isInResultType())
- nestingDepth--;
-
- if (nestingDepth == 0) {
- Out << "fp";
- } else {
- Out << "fL" << (nestingDepth - 1) << 'p';
- }
-
- // Top-level qualifiers. We don't have to worry about arrays here,
- // because parameters declared as arrays should already have been
- // transformed to have pointer type. FIXME: apparently these don't
- // get mangled if used as an rvalue of a known non-class type?
- assert(!parm->getType()->isArrayType()
- && "parameter's type is still an array type?");
- mangleQualifiers(parm->getType().getQualifiers());
-
- // Parameter index.
- if (parmIndex != 0) {
- Out << (parmIndex - 1);
- }
- Out << '_';
-}
-
-void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
- // <ctor-dtor-name> ::= C1 # complete object constructor
- // ::= C2 # base object constructor
- // ::= C3 # complete object allocating constructor
- //
- switch (T) {
- case Ctor_Complete:
- Out << "C1";
- break;
- case Ctor_Base:
- Out << "C2";
- break;
- case Ctor_CompleteAllocating:
- Out << "C3";
- break;
- }
-}
-
-void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
- // <ctor-dtor-name> ::= D0 # deleting destructor
- // ::= D1 # complete object destructor
- // ::= D2 # base object destructor
- //
- switch (T) {
- case Dtor_Deleting:
- Out << "D0";
- break;
- case Dtor_Complete:
- Out << "D1";
- break;
- case Dtor_Base:
- Out << "D2";
- break;
- }
-}
-
-void CXXNameMangler::mangleTemplateArgs(
- const ASTTemplateArgumentListInfo &TemplateArgs) {
- // <template-args> ::= I <template-arg>+ E
- Out << 'I';
- for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
- mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument());
- Out << 'E';
-}
-
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
- // <template-args> ::= I <template-arg>+ E
- Out << 'I';
- for (unsigned i = 0, e = AL.size(); i != e; ++i)
- mangleTemplateArg(AL[i]);
- Out << 'E';
-}
-
-void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- // <template-args> ::= I <template-arg>+ E
- Out << 'I';
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i]);
- Out << 'E';
-}
-
-void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
- // <template-arg> ::= <type> # type or template
- // ::= X <expression> E # expression
- // ::= <expr-primary> # simple expressions
- // ::= J <template-arg>* E # argument pack
- // ::= sp <expression> # pack expansion of (C++0x)
- if (!A.isInstantiationDependent() || A.isDependent())
- A = Context.getASTContext().getCanonicalTemplateArgument(A);
-
- switch (A.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("Cannot mangle NULL template argument");
-
- case TemplateArgument::Type:
- mangleType(A.getAsType());
- break;
- case TemplateArgument::Template:
- // This is mangled as <type>.
- mangleType(A.getAsTemplate());
- break;
- case TemplateArgument::TemplateExpansion:
- // <type> ::= Dp <type> # pack expansion (C++0x)
- Out << "Dp";
- mangleType(A.getAsTemplateOrTemplatePattern());
- break;
- case TemplateArgument::Expression: {
- // It's possible to end up with a DeclRefExpr here in certain
- // dependent cases, in which case we should mangle as a
- // declaration.
- const Expr *E = A.getAsExpr()->IgnoreParens();
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- const ValueDecl *D = DRE->getDecl();
- if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
- Out << "L";
- mangle(D, "_Z");
- Out << 'E';
- break;
- }
- }
-
- Out << 'X';
- mangleExpression(E);
- Out << 'E';
- break;
- }
- case TemplateArgument::Integral:
- mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
- break;
- case TemplateArgument::Declaration: {
- // <expr-primary> ::= L <mangled-name> E # external name
- // Clang produces AST's where pointer-to-member-function expressions
- // and pointer-to-function expressions are represented as a declaration not
- // an expression. We compensate for it here to produce the correct mangling.
- ValueDecl *D = A.getAsDecl();
- bool compensateMangling = !A.isDeclForReferenceParam();
- if (compensateMangling) {
- Out << 'X';
- mangleOperatorName(OO_Amp, 1);
- }
-
- Out << 'L';
- // References to external entities use the mangled name; if the name would
- // not normally be manged then mangle it as unqualified.
- //
- // FIXME: The ABI specifies that external names here should have _Z, but
- // gcc leaves this off.
- if (compensateMangling)
- mangle(D, "_Z");
- else
- mangle(D, "Z");
- Out << 'E';
-
- if (compensateMangling)
- Out << 'E';
-
- break;
- }
- case TemplateArgument::NullPtr: {
- // <expr-primary> ::= L <type> 0 E
- Out << 'L';
- mangleType(A.getNullPtrType());
- Out << "0E";
- break;
- }
- case TemplateArgument::Pack: {
- // Note: proposal by Mike Herrick on 12/20/10
- Out << 'J';
- for (TemplateArgument::pack_iterator PA = A.pack_begin(),
- PAEnd = A.pack_end();
- PA != PAEnd; ++PA)
- mangleTemplateArg(*PA);
- Out << 'E';
- }
- }
-}
-
-void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
- // <template-param> ::= T_ # first template parameter
- // ::= T <parameter-2 non-negative number> _
- if (Index == 0)
- Out << "T_";
- else
- Out << 'T' << (Index - 1) << '_';
-}
-
-void CXXNameMangler::mangleExistingSubstitution(QualType type) {
- bool result = mangleSubstitution(type);
- assert(result && "no existing substitution for type");
- (void) result;
-}
-
-void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) {
- bool result = mangleSubstitution(tname);
- assert(result && "no existing substitution for template name");
- (void) result;
-}
-
-// <substitution> ::= S <seq-id> _
-// ::= S_
-bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
- // Try one of the standard substitutions first.
- if (mangleStandardSubstitution(ND))
- return true;
-
- ND = cast<NamedDecl>(ND->getCanonicalDecl());
- return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
-}
-
-/// \brief Determine whether the given type has any qualifiers that are
-/// relevant for substitutions.
-static bool hasMangledSubstitutionQualifiers(QualType T) {
- Qualifiers Qs = T.getQualifiers();
- return Qs.getCVRQualifiers() || Qs.hasAddressSpace();
-}
-
-bool CXXNameMangler::mangleSubstitution(QualType T) {
- if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>())
- return mangleSubstitution(RT->getDecl());
- }
-
- uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
-
- return mangleSubstitution(TypePtr);
-}
-
-bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleSubstitution(TD);
-
- Template = Context.getASTContext().getCanonicalTemplateName(Template);
- return mangleSubstitution(
- reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
-}
-
-bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr);
- if (I == Substitutions.end())
- return false;
-
- unsigned SeqID = I->second;
- if (SeqID == 0)
- Out << "S_";
- else {
- SeqID--;
-
- // <seq-id> is encoded in base-36, using digits and upper case letters.
- char Buffer[10];
- char *BufferPtr = llvm::array_endof(Buffer);
-
- if (SeqID == 0) *--BufferPtr = '0';
-
- while (SeqID) {
- assert(BufferPtr > Buffer && "Buffer overflow!");
-
- char c = static_cast<char>(SeqID % 36);
-
- *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
- SeqID /= 36;
- }
-
- Out << 'S'
- << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
- << '_';
- }
-
- return true;
-}
-
-static bool isCharType(QualType T) {
- if (T.isNull())
- return false;
-
- return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
- T->isSpecificBuiltinType(BuiltinType::Char_U);
-}
-
-/// isCharSpecialization - Returns whether a given type is a template
-/// specialization of a given name with a single argument of type char.
-static bool isCharSpecialization(QualType T, const char *Name) {
- if (T.isNull())
- return false;
-
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
-
- const ClassTemplateSpecializationDecl *SD =
- dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
- if (!SD)
- return false;
-
- if (!isStdNamespace(getEffectiveDeclContext(SD)))
- return false;
-
- const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
- if (TemplateArgs.size() != 1)
- return false;
-
- if (!isCharType(TemplateArgs[0].getAsType()))
- return false;
-
- return SD->getIdentifier()->getName() == Name;
-}
-
-template <std::size_t StrLen>
-static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD,
- const char (&Str)[StrLen]) {
- if (!SD->getIdentifier()->isStr(Str))
- return false;
-
- const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
- if (TemplateArgs.size() != 2)
- return false;
-
- if (!isCharType(TemplateArgs[0].getAsType()))
- return false;
-
- if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
- return false;
-
- return true;
-}
-
-bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
- // <substitution> ::= St # ::std::
- if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
- if (isStd(NS)) {
- Out << "St";
- return true;
- }
- }
-
- if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
- if (!isStdNamespace(getEffectiveDeclContext(TD)))
- return false;
-
- // <substitution> ::= Sa # ::std::allocator
- if (TD->getIdentifier()->isStr("allocator")) {
- Out << "Sa";
- return true;
- }
-
- // <<substitution> ::= Sb # ::std::basic_string
- if (TD->getIdentifier()->isStr("basic_string")) {
- Out << "Sb";
- return true;
- }
- }
-
- if (const ClassTemplateSpecializationDecl *SD =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- if (!isStdNamespace(getEffectiveDeclContext(SD)))
- return false;
-
- // <substitution> ::= Ss # ::std::basic_string<char,
- // ::std::char_traits<char>,
- // ::std::allocator<char> >
- if (SD->getIdentifier()->isStr("basic_string")) {
- const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
-
- if (TemplateArgs.size() != 3)
- return false;
-
- if (!isCharType(TemplateArgs[0].getAsType()))
- return false;
-
- if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
- return false;
-
- if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
- return false;
-
- Out << "Ss";
- return true;
- }
-
- // <substitution> ::= Si # ::std::basic_istream<char,
- // ::std::char_traits<char> >
- if (isStreamCharSpecialization(SD, "basic_istream")) {
- Out << "Si";
- return true;
- }
-
- // <substitution> ::= So # ::std::basic_ostream<char,
- // ::std::char_traits<char> >
- if (isStreamCharSpecialization(SD, "basic_ostream")) {
- Out << "So";
- return true;
- }
-
- // <substitution> ::= Sd # ::std::basic_iostream<char,
- // ::std::char_traits<char> >
- if (isStreamCharSpecialization(SD, "basic_iostream")) {
- Out << "Sd";
- return true;
- }
- }
- return false;
-}
-
-void CXXNameMangler::addSubstitution(QualType T) {
- if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>()) {
- addSubstitution(RT->getDecl());
- return;
- }
- }
-
- uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
- addSubstitution(TypePtr);
-}
-
-void CXXNameMangler::addSubstitution(TemplateName Template) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return addSubstitution(TD);
-
- Template = Context.getASTContext().getCanonicalTemplateName(Template);
- addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
-}
-
-void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
- assert(!Substitutions.count(Ptr) && "Substitution already exists!");
- Substitutions[Ptr] = SeqID++;
-}
-
-//
-
-/// \brief Mangles the name of the declaration D and emits that name to the
-/// given output stream.
-///
-/// If the declaration D requires a mangled name, this routine will emit that
-/// mangled name to \p os and return true. Otherwise, \p os will be unchanged
-/// and this routine will return false. In this case, the caller should just
-/// emit the identifier of the declaration (\c D->getIdentifier()) as its
-/// name.
-void ItaniumMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
- assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
- "Invalid mangleName() call, argument is not a variable or function!");
- assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
- "Invalid mangleName() call on 'structor decl!");
-
- PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
- getASTContext().getSourceManager(),
- "Mangling declaration");
-
- CXXNameMangler Mangler(*this, Out, D);
- return Mangler.mangle(D);
-}
-
-void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream &Out) {
- CXXNameMangler Mangler(*this, Out, D, Type);
- Mangler.mangle(D);
-}
-
-void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream &Out) {
- CXXNameMangler Mangler(*this, Out, D, Type);
- Mangler.mangle(D);
-}
-
-void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &Out) {
- // <special-name> ::= T <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- // # first call-offset is 'this' adjustment
- // # second call-offset is result adjustment
-
- assert(!isa<CXXDestructorDecl>(MD) &&
- "Use mangleCXXDtor for destructor decls!");
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZT";
- if (!Thunk.Return.isEmpty())
- Mangler.getStream() << 'c';
-
- // Mangle the 'this' pointer adjustment.
- Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
-
- // Mangle the return pointer adjustment if there is one.
- if (!Thunk.Return.isEmpty())
- Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
-
- Mangler.mangleFunctionEncoding(MD);
-}
-
-void
-ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &Out) {
- // <special-name> ::= T <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- CXXNameMangler Mangler(*this, Out, DD, Type);
- Mangler.getStream() << "_ZT";
-
- // Mangle the 'this' pointer adjustment.
- Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
- ThisAdjustment.VCallOffsetOffset);
-
- Mangler.mangleFunctionEncoding(DD);
-}
-
-/// mangleGuardVariable - Returns the mangled name for a guard variable
-/// for the passed in VarDecl.
-void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
- raw_ostream &Out) {
- // <special-name> ::= GV <object name> # Guard variable for one-time
- // # initialization
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZGV";
- Mangler.mangleName(D);
-}
-
-void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
- raw_ostream &Out) {
- // We match the GCC mangling here.
- // <special-name> ::= GR <object name>
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZGR";
- Mangler.mangleName(D);
-}
-
-void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &Out) {
- // <special-name> ::= TV <type> # virtual table
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZTV";
- Mangler.mangleNameOrStandardSubstitution(RD);
-}
-
-void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &Out) {
- // <special-name> ::= TT <type> # VTT structure
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZTT";
- Mangler.mangleNameOrStandardSubstitution(RD);
-}
-
-void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &Out) {
- // <special-name> ::= TC <type> <offset number> _ <base type>
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZTC";
- Mangler.mangleNameOrStandardSubstitution(RD);
- Mangler.getStream() << Offset;
- Mangler.getStream() << '_';
- Mangler.mangleNameOrStandardSubstitution(Type);
-}
-
-void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
- raw_ostream &Out) {
- // <special-name> ::= TI <type> # typeinfo structure
- assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZTI";
- Mangler.mangleType(Ty);
-}
-
-void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
- raw_ostream &Out) {
- // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
- CXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "_ZTS";
- Mangler.mangleType(Ty);
-}
-
-MangleContext *clang::createItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new ItaniumMangleContext(Context, Diags);
-}
+//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements C++ name mangling according to the Itanium C++ ABI, +// which is used in GCC 3.2 and newer (and many compilers that are +// ABI-compatible with GCC): +// +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + +using namespace clang; + +namespace { + +/// \brief Retrieve the declaration context that should be used when mangling +/// the given declaration. +static const DeclContext *getEffectiveDeclContext(const Decl *D) { + // The ABI assumes that lambda closure types that occur within + // default arguments live in the context of the function. However, due to + // the way in which Clang parses and creates function declarations, this is + // not the case: the lambda closure type ends up living in the context + // where the function itself resides, because the function declaration itself + // had not yet been created. Fix the context here. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (RD->isLambda()) + if (ParmVarDecl *ContextParam + = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) + return ContextParam->getDeclContext(); + } + + return D->getDeclContext(); +} + +static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { + return getEffectiveDeclContext(cast<Decl>(DC)); +} + +static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { + const DeclContext *DC = dyn_cast<DeclContext>(ND); + if (!DC) + DC = getEffectiveDeclContext(ND); + while (!DC->isNamespace() && !DC->isTranslationUnit()) { + const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC)); + if (isa<FunctionDecl>(Parent)) + return dyn_cast<CXXRecordDecl>(DC); + DC = Parent; + } + return 0; +} + +static const FunctionDecl *getStructor(const FunctionDecl *fn) { + if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) + return ftd->getTemplatedDecl(); + + return fn; +} + +static const NamedDecl *getStructor(const NamedDecl *decl) { + const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl); + return (fn ? getStructor(fn) : decl); +} + +static const unsigned UnknownArity = ~0U; + +class ItaniumMangleContext : public MangleContext { + llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; + unsigned Discriminator; + llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + +public: + explicit ItaniumMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags) + : MangleContext(Context, Diags) { } + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair<llvm::DenseMap<const TagDecl *, + uint64_t>::iterator, bool> Result = + AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); + return Result.first->second; + } + + void startNewFunction() { + MangleContext::startNewFunction(); + mangleInitDiscriminator(); + } + + /// @name Mangler Entry Points + /// @{ + + bool shouldMangleDeclName(const NamedDecl *D); + void mangleName(const NamedDecl *D, raw_ostream &); + void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &); + void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &); + void mangleReferenceTemporary(const VarDecl *D, + raw_ostream &); + void mangleCXXVTable(const CXXRecordDecl *RD, + raw_ostream &); + void mangleCXXVTT(const CXXRecordDecl *RD, + raw_ostream &); + void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &); + void mangleCXXRTTI(QualType T, raw_ostream &); + void mangleCXXRTTIName(QualType T, raw_ostream &); + void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + raw_ostream &); + void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + raw_ostream &); + + void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + + void mangleInitDiscriminator() { + Discriminator = 0; + } + + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + // Lambda closure types with external linkage (indicated by a + // non-zero lambda mangling number) have their own numbering scheme, so + // they do not need a discriminator. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) + if (RD->isLambda() && RD->getLambdaManglingNumber() > 0) + return false; + + unsigned &discriminator = Uniquifier[ND]; + if (!discriminator) + discriminator = ++Discriminator; + if (discriminator == 1) + return false; + disc = discriminator-2; + return true; + } + /// @} +}; + +/// CXXNameMangler - Manage the mangling of a single name. +class CXXNameMangler { + ItaniumMangleContext &Context; + raw_ostream &Out; + + /// The "structor" is the top-level declaration being mangled, if + /// that's not a template specialization; otherwise it's the pattern + /// for that specialization. + const NamedDecl *Structor; + unsigned StructorType; + + /// SeqID - The next subsitution sequence number. + unsigned SeqID; + + class FunctionTypeDepthState { + unsigned Bits; + + enum { InResultTypeMask = 1 }; + + public: + FunctionTypeDepthState() : Bits(0) {} + + /// The number of function types we're inside. + unsigned getDepth() const { + return Bits >> 1; + } + + /// True if we're in the return type of the innermost function type. + bool isInResultType() const { + return Bits & InResultTypeMask; + } + + FunctionTypeDepthState push() { + FunctionTypeDepthState tmp = *this; + Bits = (Bits & ~InResultTypeMask) + 2; + return tmp; + } + + void enterResultType() { + Bits |= InResultTypeMask; + } + + void leaveResultType() { + Bits &= ~InResultTypeMask; + } + + void pop(FunctionTypeDepthState saved) { + assert(getDepth() == saved.getDepth() + 1); + Bits = saved.Bits; + } + + } FunctionTypeDepth; + + llvm::DenseMap<uintptr_t, unsigned> Substitutions; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + const NamedDecl *D = 0) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), + SeqID(0) { + // These can't be mangled without a ctor type or dtor type. + assert(!D || (!isa<CXXDestructorDecl>(D) && + !isa<CXXConstructorDecl>(D))); + } + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + const CXXDestructorDecl *D, CXXDtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + +#if MANGLE_CHECKER + ~CXXNameMangler() { + if (Out.str()[0] == '\01') + return; + + int status = 0; + char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); + assert(status == 0 && "Could not demangle mangled name!"); + free(result); + } +#endif + raw_ostream &getStream() { return Out; } + + void mangle(const NamedDecl *D, StringRef Prefix = "_Z"); + void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); + void mangleNumber(const llvm::APSInt &I); + void mangleNumber(int64_t Number); + void mangleFloat(const llvm::APFloat &F); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleType(QualType T); + void mangleNameOrStandardSubstitution(const NamedDecl *ND); + +private: + bool mangleSubstitution(const NamedDecl *ND); + bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); + bool mangleSubstitution(uintptr_t Ptr); + + void mangleExistingSubstitution(QualType type); + void mangleExistingSubstitution(TemplateName name); + + bool mangleStandardSubstitution(const NamedDecl *ND); + + void addSubstitution(const NamedDecl *ND) { + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + + addSubstitution(reinterpret_cast<uintptr_t>(ND)); + } + void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); + void addSubstitution(uintptr_t Ptr); + + void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive = false); + void mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned KnownArity = UnknownArity); + + void mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, + unsigned KnownArity); + void mangleUnscopedName(const NamedDecl *ND); + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); + void mangleSourceName(const IdentifierInfo *II); + void mangleLocalName(const NamedDecl *ND); + void mangleLambda(const CXXRecordDecl *Lambda); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, + bool NoFunction=false); + void mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void manglePrefix(NestedNameSpecifier *qualifier); + void manglePrefix(const DeclContext *DC, bool NoFunction=false); + void manglePrefix(QualType type); + void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleQualifiers(Qualifiers Quals); + void mangleRefQualifier(RefQualifierKind RefQualifier); + + void mangleObjCMethodName(const ObjCMethodDecl *MD); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleType(TemplateName); + void mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType); + void mangleNeonVectorType(const VectorType *T); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); + void mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity); + void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); + void mangleCXXCtorType(CXXCtorType T); + void mangleCXXDtorType(CXXDtorType T); + + void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgs(const TemplateArgumentList &AL); + void mangleTemplateArg(TemplateArgument A); + + void mangleTemplateParameter(unsigned Index); + + void mangleFunctionParam(const ParmVarDecl *parm); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = getEffectiveDeclContext(D); + !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOpts().CPlusPlus) + return false; + + // Variables at global scope with non-internal linkage are not mangled + if (!FD) { + const DeclContext *DC = getEffectiveDeclContext(D); + // Check for extern variable declared locally. + if (DC->isFunctionOrMethod() && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = getEffectiveParentContext(DC); + if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + return false; + } + + // Class members are always mangled. + if (getEffectiveDeclContext(D)->isRecord()) + return true; + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + + // Adding the prefix can cause problems when one file has a "foo" and + // another has a "\01foo". That is known to happen on ELF with the + // tricks normally used for producing aliases (PR9177). Fortunately the + // llvm mangler on ELF is a nop, so we can just avoid adding the \01 + // marker. We also avoid adding the marker if this is an alias for an + // LLVM intrinsic. + StringRef UserLabelPrefix = + getASTContext().getTargetInfo().getUserLabelPrefix(); + if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) + Out << '\01'; // LLVM IR Marker for __asm("foo") + + Out << ALA->getLabel(); + return; + } + + // <mangled-name> ::= _Z <encoding> + // ::= <data name> + // ::= <special-name> + Out << Prefix; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleName(VD); + else + mangleName(cast<FieldDecl>(D)); +} + +void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <encoding> ::= <function name> <bare-function-type> + mangleName(FD); + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // Whether the mangling of a function type includes the return type depends on + // the context and the nature of the function. The rules for deciding whether + // the return type is included are: + // + // 1. Template functions (names or types) have return types encoded, with + // the exceptions listed below. + // 2. Function types not appearing as part of a function name mangling, + // e.g. parameters, pointer types, etc., have return type encoded, with the + // exceptions listed below. + // 3. Non-template function names do not have return types encoded. + // + // The exceptions mentioned in (1) and (2) above, for which the return type is + // never included, are + // 1. Constructors. + // 2. Destructors. + // 3. Conversion operator functions, e.g. operator int. + bool MangleReturnType = false; + if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { + if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) || + isa<CXXConversionDecl>(FD))) + MangleReturnType = true; + + // Mangle the type of the primary template. + FD = PrimaryTemplate->getTemplatedDecl(); + } + + mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), + MangleReturnType); +} + +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa<LinkageSpecDecl>(DC)) { + DC = getEffectiveParentContext(DC); + } + + return DC; +} + +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { + if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS)) + ->isTranslationUnit()) + return false; + + const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); + return II && II->isStr("std"); +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. +static bool isStdNamespace(const DeclContext *DC) { + if (!DC->isNamespace()) + return false; + + return isStd(cast<NamespaceDecl>(DC)); +} + +static const TemplateDecl * +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { + // Check if we have a function template. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ + if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { + TemplateArgs = FD->getTemplateSpecializationArgs(); + return TD; + } + } + + // Check if we have a class template. + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + + return 0; +} + +static bool isLambda(const NamedDecl *ND) { + const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND); + if (!Record) + return false; + + return Record->isLambda(); +} + +void CXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <nested-name> + // ::= <unscoped-name> + // ::= <unscoped-template-name> <template-args> + // ::= <local-name> + // + const DeclContext *DC = getEffectiveDeclContext(ND); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + // FIXME: This is a hack; extern variables declared locally should have + // a proper semantic declaration context! + if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND)) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = getEffectiveParentContext(DC); + else if (GetLocalClassDecl(ND)) { + mangleLocalName(ND); + return; + } + + DC = IgnoreLinkageSpecDecls(DC); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleUnscopedTemplateName(TD); + mangleTemplateArgs(*TemplateArgs); + return; + } + + mangleUnscopedName(ND); + return; + } + + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { + mangleLocalName(ND); + return; + } + + mangleNestedName(ND, DC); +} +void CXXNameMangler::mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD)); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + mangleUnscopedTemplateName(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + } else { + mangleNestedName(TD, TemplateArgs, NumTemplateArgs); + } +} + +void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { + // <unscoped-name> ::= <unqualified-name> + // ::= St <unqualified-name> # ::std:: + + if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND)))) + Out << "St"; + + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + mangleUnscopedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (const IdentifierInfo *Id = Dependent->getIdentifier()) + mangleSourceName(Id); + else + mangleOperatorName(Dependent->getOperator(), UnknownArity); + + addSubstitution(Template); +} + +void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { + // ABI: + // Floating-point literals are encoded using a fixed-length + // lowercase hexadecimal string corresponding to the internal + // representation (IEEE on Itanium), high-order bytes first, + // without leading zeroes. For example: "Lf bf800000 E" is -1.0f + // on Itanium. + // The 'without leading zeroes' thing seems to be an editorial + // mistake; see the discussion on cxx-abi-dev beginning on + // 2012-01-16. + + // Our requirements here are just barely weird enough to justify + // using a custom algorithm instead of post-processing APInt::toString(). + + llvm::APInt valueBits = f.bitcastToAPInt(); + unsigned numCharacters = (valueBits.getBitWidth() + 3) / 4; + assert(numCharacters != 0); + + // Allocate a buffer of the right number of characters. + llvm::SmallVector<char, 20> buffer; + buffer.set_size(numCharacters); + + // Fill the buffer left-to-right. + for (unsigned stringIndex = 0; stringIndex != numCharacters; ++stringIndex) { + // The bit-index of the next hex digit. + unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1); + + // Project out 4 bits starting at 'digitIndex'. + llvm::integerPart hexDigit + = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth]; + hexDigit >>= (digitBitIndex % llvm::integerPartWidth); + hexDigit &= 0xF; + + // Map that over to a lowercase hex digit. + static const char charForHex[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + buffer[stringIndex] = charForHex[hexDigit]; + } + + Out.write(buffer.data(), numCharacters); +} + +void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + if (Value.isSigned() && Value.isNegative()) { + Out << 'n'; + Value.abs().print(Out, /*signed*/ false); + } else { + Value.print(Out, /*signed*/ false); + } +} + +void CXXNameMangler::mangleNumber(int64_t Number) { + // <number> ::= [n] <non-negative decimal integer> + if (Number < 0) { + Out << 'n'; + Number = -Number; + } + + Out << Number; +} + +void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { + // <call-offset> ::= h <nv-offset> _ + // ::= v <v-offset> _ + // <nv-offset> ::= <offset number> # non-virtual base override + // <v-offset> ::= <offset number> _ <virtual offset number> + // # virtual base override, with vcall offset + if (!Virtual) { + Out << 'h'; + mangleNumber(NonVirtual); + Out << '_'; + return; + } + + Out << 'v'; + mangleNumber(NonVirtual); + Out << '_'; + mangleNumber(Virtual); + Out << '_'; +} + +void CXXNameMangler::manglePrefix(QualType type) { + if (const TemplateSpecializationType *TST = + type->getAs<TemplateSpecializationType>()) { + if (!mangleSubstitution(QualType(TST, 0))) { + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } else if (const DependentTemplateSpecializationType *DTST + = type->getAs<DependentTemplateSpecializationType>()) { + TemplateName Template + = getASTContext().getDependentTemplateName(DTST->getQualifier(), + DTST->getIdentifier()); + mangleTemplatePrefix(Template); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + } else { + // We use the QualType mangle type variant here because it handles + // substitutions. + mangleType(type); + } +} + +/// Mangle everything prior to the base-unresolved-name in an unresolved-name. +/// +/// \param firstQualifierLookup - the entity found by unqualified lookup +/// for the first name in the qualifier, if this is for a member expression +/// \param recursive - true if this is being called recursively, +/// i.e. if there is more prefix "to the right". +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive) { + + // x, ::x + // <unresolved-name> ::= [gs] <base-unresolved-name> + + // T::x / decltype(p)::x + // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name> + + // T::N::x /decltype(p)::N::x + // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + // A::x, N::y, A<T>::z; "gs" means leading "::" + // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + switch (qualifier->getKind()) { + case NestedNameSpecifier::Global: + Out << "gs"; + + // We want an 'sr' unless this is the entire NNS. + if (recursive) + Out << "sr"; + + // We never want an 'E' here. + return; + + case NestedNameSpecifier::Namespace: + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespace()->getIdentifier()); + break; + case NestedNameSpecifier::NamespaceAlias: + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *type = qualifier->getAsType(); + + // We only want to use an unresolved-type encoding if this is one of: + // - a decltype + // - a template type parameter + // - a template template parameter with arguments + // In all of these cases, we should have no prefix. + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else { + // Otherwise, all the cases want this. + Out << "sr"; + } + + // Only certain other types are valid as prefixes; enumerate them. + switch (type->getTypeClass()) { + case Type::Builtin: + case Type::Complex: + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Enum: + case Type::Paren: + case Type::Elaborated: + case Type::Attributed: + case Type::Auto: + case Type::PackExpansion: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Atomic: + llvm_unreachable("type is illegal as a nested name specifier"); + + case Type::SubstTemplateTypeParmPack: + // FIXME: not clear how to mangle this! + // template <class T...> class A { + // template <class U...> void foo(decltype(T::foo(U())) x...); + // }; + Out << "_SUBSTPACK_"; + break; + + // <unresolved-type> ::= <template-param> + // ::= <decltype> + // ::= <template-template-param> <template-args> + // (this last is not official yet) + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::TemplateTypeParm: + case Type::UnaryTransform: + case Type::SubstTemplateTypeParm: + unresolvedType: + assert(!qualifier->getPrefix()); + + // We only get here recursively if we're followed by identifiers. + if (recursive) Out << 'N'; + + // This seems to do everything we want. It's not really + // sanctioned for a substituted template parameter, though. + mangleType(QualType(type, 0)); + + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return; + + case Type::Typedef: + mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier()); + break; + + case Type::UnresolvedUsing: + mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl() + ->getIdentifier()); + break; + + case Type::Record: + mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier()); + break; + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *tst + = cast<TemplateSpecializationType>(type); + TemplateName name = tst->getTemplateName(); + switch (name.getKind()) { + case TemplateName::Template: + case TemplateName::QualifiedTemplate: { + TemplateDecl *temp = name.getAsTemplateDecl(); + + // If the base is a template template parameter, this is an + // unresolved type. + assert(temp && "no template for template specialization type"); + if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType; + + mangleSourceName(temp->getIdentifier()); + break; + } + + case TemplateName::OverloadedTemplate: + case TemplateName::DependentTemplate: + llvm_unreachable("invalid base for a template specialization type"); + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = name.getAsSubstTemplateTemplateParm(); + mangleExistingSubstitution(subst->getReplacement()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template <template <class U> class T...> class A { + // template <class U...> void foo(decltype(T<U>::foo) x...); + // }; + Out << "_SUBSTPACK_"; + break; + } + } + + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); + break; + } + + case Type::InjectedClassName: + mangleSourceName(cast<InjectedClassNameType>(type)->getDecl() + ->getIdentifier()); + break; + + case Type::DependentName: + mangleSourceName(cast<DependentNameType>(type)->getIdentifier()); + break; + + case Type::DependentTemplateSpecialization: { + const DependentTemplateSpecializationType *tst + = cast<DependentTemplateSpecializationType>(type); + mangleSourceName(tst->getIdentifier()); + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); + break; + } + } + break; + } + + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes. + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else if (firstQualifierLookup) { + + // Try to make a proper qualifier out of the lookup result, and + // then just recurse on that. + NestedNameSpecifier *newQualifier; + if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) { + QualType type = getASTContext().getTypeDeclType(typeDecl); + + // Pretend we had a different nested name specifier. + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + /*template*/ false, + type.getTypePtr()); + } else if (NamespaceDecl *nspace = + dyn_cast<NamespaceDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + nspace); + } else if (NamespaceAliasDecl *alias = + dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + alias); + } else { + // No sensible mangling to do here. + newQualifier = 0; + } + + if (newQualifier) + return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive); + + } else { + Out << "sr"; + } + + mangleSourceName(qualifier->getAsIdentifier()); + break; + } + + // If this was the innermost part of the NNS, and we fell out to + // here, append an 'E'. + if (!recursive) + Out << 'E'; +} + +/// Mangle an unresolved-name, which is generally used for names which +/// weren't resolved to specific entities. +void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity) { + if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup); + mangleUnqualifiedName(0, name, knownArity); +} + +static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { + assert(RD->isAnonymousStructOrUnion() && + "Expected anonymous struct or union!"); + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) { + if (I->getIdentifier()) + return *I; + + if (const RecordType *RT = I->getType()->getAs<RecordType>()) + if (const FieldDecl *NamedDataMember = + FindFirstNamedDataMember(RT->getDecl())) + return NamedDataMember; + } + + // We didn't find a named data member. + return 0; +} + +void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name, + unsigned KnownArity) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + // We must avoid conflicts between internally- and externally- + // linked variable and function declaration names in the same TU: + // void test() { extern void foo(); } + // static void foo(); + // This naming convention is the same as that followed by GCC, + // though it shouldn't actually matter. + if (ND && ND->getLinkage() == InternalLinkage && + getEffectiveDeclContext(ND)->isFileContext()) + Out << 'L'; + + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + // This is how gcc mangles these names. + Out << "12_GLOBAL__N_1"; + break; + } + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + // We must have an anonymous union or struct declaration. + const RecordDecl *RD = + cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 5.1.2: + // + // For the purposes of mangling, the name of an anonymous union is + // considered to be the name of the first named data member found by a + // pre-order, depth-first, declaration-order walk of the data members of + // the anonymous union. If there is no such data member (i.e., if all of + // the data members in the union are unnamed), then there is no way for + // a program to refer to the anonymous union, and there is therefore no + // need to mangle its name. + const FieldDecl *FD = FindFirstNamedDataMember(RD); + + // It's actually possible for various reasons for us to get here + // with an empty anonymous struct / union. Fortunately, it + // doesn't really matter what name we generate. + if (!FD) break; + assert(FD->getIdentifier() && "Data member name isn't an identifier!"); + + mangleSourceName(FD->getIdentifier()); + break; + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // <unnamed-type-name> ::= <closure-type-name> + // + // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ + // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { + if (Record->isLambda() && Record->getLambdaManglingNumber()) { + mangleLambda(Record); + break; + } + } + + int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD); + if (UnnamedMangle != -1) { + Out << "Ut"; + if (UnnamedMangle != 0) + Out << llvm::utostr(UnnamedMangle - 1); + Out << '_'; + break; + } + + // Get a unique id for the anonymous struct. + uint64_t AnonStructId = Context.getAnonymousStructId(TD); + + // Mangle it as a source name in the form + // [n] $_<id> + // where n is the length of the string. + SmallString<8> Str; + Str += "$_"; + Str += llvm::utostr(AnonStructId); + + Out << Str.size(); + Out << Str.str(); + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + llvm_unreachable("Can't mangle Objective-C selector names here!"); + + case DeclarationName::CXXConstructorName: + if (ND == Structor) + // If the named decl is the C++ constructor we're mangling, use the type + // we were given. + mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); + else + // Otherwise, use the complete constructor name. This is relevant if a + // class with a constructor is declared within a constructor. + mangleCXXCtorType(Ctor_Complete); + break; + + case DeclarationName::CXXDestructorName: + if (ND == Structor) + // If the named decl is the C++ destructor we're mangling, use the type we + // were given. + mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); + else + // Otherwise, use the complete destructor name. This is relevant if a + // class with a destructor is declared within a destructor. + mangleCXXDtorType(Dtor_Complete); + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= cv <type> # (cast) + Out << "cv"; + mangleType(Name.getCXXNameType()); + break; + + case DeclarationName::CXXOperatorName: { + unsigned Arity; + if (ND) { + Arity = cast<FunctionDecl>(ND)->getNumParams(); + + // If we have a C++ member function, we need to include the 'this' pointer. + // FIXME: This does not make sense for operators that are static, but their + // names stay the same regardless of the arity (operator new for instance). + if (isa<CXXMethodDecl>(ND)) + Arity++; + } else + Arity = KnownArity; + + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); + break; + } + + case DeclarationName::CXXLiteralOperatorName: + // FIXME: This mangling is not yet official. + Out << "li"; + mangleSourceName(Name.getCXXLiteralIdentifier()); + break; + + case DeclarationName::CXXUsingDirective: + llvm_unreachable("Can't mangle a using directive name!"); + } +} + +void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source-name> ::= <positive length number> <identifier> + // <number> ::= [n] <non-negative decimal integer> + // <identifier> ::= <unqualified source code identifier> + Out << II->getLength() << II->getName(); +} + +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC, + bool NoFunction) { + // <nested-name> + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> + // <template-args> E + + Out << 'N'; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { + mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + mangleRefQualifier(Method->getRefQualifier()); + } + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplatePrefix(TD); + mangleTemplateArgs(*TemplateArgs); + } + else { + manglePrefix(DC, NoFunction); + mangleUnqualifiedName(ND); + } + + Out << 'E'; +} +void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E + + Out << 'N'; + + mangleTemplatePrefix(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + + Out << 'E'; +} + +void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { + // <local-name> := Z <function encoding> E <entity name> [<discriminator>] + // := Z <function encoding> E s [<discriminator>] + // <local-name> := Z <function encoding> E d [ <parameter number> ] + // _ <entity name> + // <discriminator> := _ <non-negative number> + const DeclContext *DC = getEffectiveDeclContext(ND); + if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) { + // Don't add objc method name mangling to locally declared function + mangleUnqualifiedName(ND); + return; + } + + Out << 'Z'; + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(MD); + } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { + mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD))); + Out << 'E'; + + // The parameter number is omitted for the last parameter, 0 for the + // second-to-last parameter, 1 for the third-to-last parameter, etc. The + // <entity name> will of course contain a <closure-type-name>: Its + // numbering will be local to the particular argument in which it appears + // -- other default arguments do not affect its encoding. + bool SkipDiscriminator = false; + if (RD->isLambda()) { + if (const ParmVarDecl *Parm + = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) { + if (const FunctionDecl *Func + = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { + Out << 'd'; + unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex(); + if (Num > 1) + mangleNumber(Num - 2); + Out << '_'; + SkipDiscriminator = true; + } + } + } + + // Mangle the name relative to the closest enclosing function. + if (ND == RD) // equality ok because RD derived from ND above + mangleUnqualifiedName(ND); + else + mangleNestedName(ND, DC, true /*NoFunction*/); + + if (!SkipDiscriminator) { + unsigned disc; + if (Context.getNextDiscriminator(RD, disc)) { + if (disc < 10) + Out << '_' << disc; + else + Out << "__" << disc << '_'; + } + } + + return; + } + else + mangleFunctionEncoding(cast<FunctionDecl>(DC)); + + Out << 'E'; + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { + // If the context of a closure type is an initializer for a class member + // (static or nonstatic), it is encoded in a qualified name with a final + // <prefix> of the form: + // + // <data-member-prefix> := <member source-name> M + // + // Technically, the data-member-prefix is part of the <prefix>. However, + // since a closure type will always be mangled with a prefix, it's easier + // to emit that last part of the prefix here. + if (Decl *Context = Lambda->getLambdaContextDecl()) { + if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && + Context->getDeclContext()->isRecord()) { + if (const IdentifierInfo *Name + = cast<NamedDecl>(Context)->getIdentifier()) { + mangleSourceName(Name); + Out << 'M'; + } + } + } + + Out << "Ul"; + const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> + getAs<FunctionProtoType>(); + mangleBareFunctionType(Proto, /*MangleReturnType=*/false); + Out << "E"; + + // The number is omitted for the first closure type with a given + // <lambda-sig> in a given context; it is n-2 for the nth closure type + // (in lexical order) with that same <lambda-sig> and context. + // + // The AST keeps track of the number for us. + unsigned Number = Lambda->getLambdaManglingNumber(); + assert(Number > 0 && "Lambda should be mangled as an unnamed class"); + if (Number > 1) + mangleNumber(Number - 2); + Out << '_'; +} + +void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { + switch (qualifier->getKind()) { + case NestedNameSpecifier::Global: + // nothing + return; + + case NestedNameSpecifier::Namespace: + mangleName(qualifier->getAsNamespace()); + return; + + case NestedNameSpecifier::NamespaceAlias: + mangleName(qualifier->getAsNamespaceAlias()->getNamespace()); + return; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + manglePrefix(QualType(qualifier->getAsType(), 0)); + return; + + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes, but that + // should end up in mangleUnresolvedPrefix instead. + assert(qualifier->getPrefix()); + manglePrefix(qualifier->getPrefix()); + + mangleSourceName(qualifier->getAsIdentifier()); + return; + } + + llvm_unreachable("unexpected nested name specifier"); +} + +void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { + // <prefix> ::= <prefix> <unqualified-name> + // ::= <template-prefix> <template-args> + // ::= <template-param> + // ::= # empty + // ::= <substitution> + + DC = IgnoreLinkageSpecDecls(DC); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { + manglePrefix(getEffectiveParentContext(DC), NoFunction); + SmallString<64> Name; + llvm::raw_svector_ostream NameStream(Name); + Context.mangleBlock(Block, NameStream); + NameStream.flush(); + Out << Name.size() << Name; + return; + } + + const NamedDecl *ND = cast<NamedDecl>(DC); + if (mangleSubstitution(ND)) + return; + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplatePrefix(TD); + mangleTemplateArgs(*TemplateArgs); + } + else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) + mangleObjCMethodName(Method); + else { + manglePrefix(getEffectiveDeclContext(ND), NoFunction); + mangleUnqualifiedName(ND); + } + + addSubstitution(ND); +} + +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplatePrefix(TD); + + if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) + manglePrefix(Qualified->getQualifier()); + + if (OverloadedTemplateStorage *Overloaded + = Template.getAsOverloadedTemplate()) { + mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(), + UnknownArity); + return; + } + + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Unknown template name kind?"); + manglePrefix(Dependent->getQualifier()); + mangleUnscopedTemplateName(Template); +} + +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + // <template-template-param> ::= <template-param> + // <substitution> + + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + manglePrefix(getEffectiveDeclContext(ND)); + mangleUnqualifiedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +/// Mangles a template name under the production <type>. Required for +/// template template arguments. +/// <type> ::= <class-enum-type> +/// ::= <template-param> +/// ::= <substitution> +void CXXNameMangler::mangleType(TemplateName TN) { + if (mangleSubstitution(TN)) + return; + + TemplateDecl *TD = 0; + + switch (TN.getKind()) { + case TemplateName::QualifiedTemplate: + TD = TN.getAsQualifiedTemplateName()->getTemplateDecl(); + goto HaveDecl; + + case TemplateName::Template: + TD = TN.getAsTemplateDecl(); + goto HaveDecl; + + HaveDecl: + if (isa<TemplateTemplateParmDecl>(TD)) + mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex()); + else + mangleName(TD); + break; + + case TemplateName::OverloadedTemplate: + llvm_unreachable("can't mangle an overloaded template name as a <type>"); + + case TemplateName::DependentTemplate: { + const DependentTemplateName *Dependent = TN.getAsDependentTemplateName(); + assert(Dependent->isIdentifier()); + + // <class-enum-type> ::= <name> + // <name> ::= <nested-name> + mangleUnresolvedPrefix(Dependent->getQualifier(), 0); + mangleSourceName(Dependent->getIdentifier()); + break; + } + + case TemplateName::SubstTemplateTemplateParm: { + // Substituted template parameters are mangled as the substituted + // template. This will check for the substitution twice, which is + // fine, but we have to return early so that we don't try to *add* + // the substitution twice. + SubstTemplateTemplateParmStorage *subst + = TN.getAsSubstTemplateTemplateParm(); + mangleType(subst->getReplacement()); + return; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template <template <class> class T...> class A { + // template <template <class> class U...> void foo(B<T,U> x...); + // }; + Out << "_SUBSTPACK_"; + break; + } + } + + addSubstitution(TN); +} + +void +CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { + switch (OO) { + // <operator-name> ::= nw # new + case OO_New: Out << "nw"; break; + // ::= na # new[] + case OO_Array_New: Out << "na"; break; + // ::= dl # delete + case OO_Delete: Out << "dl"; break; + // ::= da # delete[] + case OO_Array_Delete: Out << "da"; break; + // ::= ps # + (unary) + // ::= pl # + (binary or unknown) + case OO_Plus: + Out << (Arity == 1? "ps" : "pl"); break; + // ::= ng # - (unary) + // ::= mi # - (binary or unknown) + case OO_Minus: + Out << (Arity == 1? "ng" : "mi"); break; + // ::= ad # & (unary) + // ::= an # & (binary or unknown) + case OO_Amp: + Out << (Arity == 1? "ad" : "an"); break; + // ::= de # * (unary) + // ::= ml # * (binary or unknown) + case OO_Star: + // Use binary when unknown. + Out << (Arity == 1? "de" : "ml"); break; + // ::= co # ~ + case OO_Tilde: Out << "co"; break; + // ::= dv # / + case OO_Slash: Out << "dv"; break; + // ::= rm # % + case OO_Percent: Out << "rm"; break; + // ::= or # | + case OO_Pipe: Out << "or"; break; + // ::= eo # ^ + case OO_Caret: Out << "eo"; break; + // ::= aS # = + case OO_Equal: Out << "aS"; break; + // ::= pL # += + case OO_PlusEqual: Out << "pL"; break; + // ::= mI # -= + case OO_MinusEqual: Out << "mI"; break; + // ::= mL # *= + case OO_StarEqual: Out << "mL"; break; + // ::= dV # /= + case OO_SlashEqual: Out << "dV"; break; + // ::= rM # %= + case OO_PercentEqual: Out << "rM"; break; + // ::= aN # &= + case OO_AmpEqual: Out << "aN"; break; + // ::= oR # |= + case OO_PipeEqual: Out << "oR"; break; + // ::= eO # ^= + case OO_CaretEqual: Out << "eO"; break; + // ::= ls # << + case OO_LessLess: Out << "ls"; break; + // ::= rs # >> + case OO_GreaterGreater: Out << "rs"; break; + // ::= lS # <<= + case OO_LessLessEqual: Out << "lS"; break; + // ::= rS # >>= + case OO_GreaterGreaterEqual: Out << "rS"; break; + // ::= eq # == + case OO_EqualEqual: Out << "eq"; break; + // ::= ne # != + case OO_ExclaimEqual: Out << "ne"; break; + // ::= lt # < + case OO_Less: Out << "lt"; break; + // ::= gt # > + case OO_Greater: Out << "gt"; break; + // ::= le # <= + case OO_LessEqual: Out << "le"; break; + // ::= ge # >= + case OO_GreaterEqual: Out << "ge"; break; + // ::= nt # ! + case OO_Exclaim: Out << "nt"; break; + // ::= aa # && + case OO_AmpAmp: Out << "aa"; break; + // ::= oo # || + case OO_PipePipe: Out << "oo"; break; + // ::= pp # ++ + case OO_PlusPlus: Out << "pp"; break; + // ::= mm # -- + case OO_MinusMinus: Out << "mm"; break; + // ::= cm # , + case OO_Comma: Out << "cm"; break; + // ::= pm # ->* + case OO_ArrowStar: Out << "pm"; break; + // ::= pt # -> + case OO_Arrow: Out << "pt"; break; + // ::= cl # () + case OO_Call: Out << "cl"; break; + // ::= ix # [] + case OO_Subscript: Out << "ix"; break; + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Not an overloaded operator"); + } +} + +void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { + // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals.hasRestrict()) + Out << 'r'; + if (Quals.hasVolatile()) + Out << 'V'; + if (Quals.hasConst()) + Out << 'K'; + + if (Quals.hasAddressSpace()) { + // Extension: + // + // <type> ::= U <address-space-number> + // + // where <address-space-number> is a source name consisting of 'AS' + // followed by the address space <number>. + SmallString<64> ASString; + ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace()); + Out << 'U' << ASString.size() << ASString; + } + + StringRef LifetimeName; + switch (Quals.getObjCLifetime()) { + // Objective-C ARC Extension: + // + // <type> ::= U "__strong" + // <type> ::= U "__weak" + // <type> ::= U "__autoreleasing" + case Qualifiers::OCL_None: + break; + + case Qualifiers::OCL_Weak: + LifetimeName = "__weak"; + break; + + case Qualifiers::OCL_Strong: + LifetimeName = "__strong"; + break; + + case Qualifiers::OCL_Autoreleasing: + LifetimeName = "__autoreleasing"; + break; + + case Qualifiers::OCL_ExplicitNone: + // The __unsafe_unretained qualifier is *not* mangled, so that + // __unsafe_unretained types in ARC produce the same manglings as the + // equivalent (but, naturally, unqualified) types in non-ARC, providing + // better ABI compatibility. + // + // It's safe to do this because unqualified 'id' won't show up + // in any type signatures that need to be mangled. + break; + } + if (!LifetimeName.empty()) + Out << 'U' << LifetimeName.size() << LifetimeName; +} + +void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { + // <ref-qualifier> ::= R # lvalue reference + // ::= O # rvalue-reference + // Proposal to Itanium C++ ABI list on 1/26/11 + switch (RefQualifier) { + case RQ_None: + break; + + case RQ_LValue: + Out << 'R'; + break; + + case RQ_RValue: + Out << 'O'; + break; + } +} + +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +void CXXNameMangler::mangleType(QualType T) { + // If our type is instantiation-dependent but not dependent, we mangle + // it as it was written in the source, removing any top-level sugar. + // Otherwise, use the canonical type. + // + // FIXME: This is an approximation of the instantiation-dependent name + // mangling rules, since we should really be using the type as written and + // augmented via semantic analysis (i.e., with implicit conversions and + // default template arguments) for any instantiation-dependent type. + // Unfortunately, that requires several changes to our AST: + // - Instantiation-dependent TemplateSpecializationTypes will need to be + // uniqued, so that we can handle substitutions properly + // - Default template arguments will need to be represented in the + // TemplateSpecializationType, since they need to be mangled even though + // they aren't written. + // - Conversions on non-type template arguments need to be expressed, since + // they can affect the mangling of sizeof/alignof. + if (!T->isInstantiationDependentType() || T->isDependentType()) + T = T.getCanonicalType(); + else { + // Desugar any types that are purely sugar. + do { + // Don't desugar through template specialization types that aren't + // type aliases. We need to mangle the template arguments as written. + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(T)) + if (!TST->isTypeAlias()) + break; + + QualType Desugared + = T.getSingleStepDesugaredType(Context.getASTContext()); + if (Desugared == T) + break; + + T = Desugared; + } while (true); + } + SplitQualType split = T.split(); + Qualifiers quals = split.Quals; + const Type *ty = split.Ty; + + bool isSubstitutable = quals || !isa<BuiltinType>(T); + if (isSubstitutable && mangleSubstitution(T)) + return; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (quals && isa<ArrayType>(T)) { + ty = Context.getASTContext().getAsArrayType(T); + quals = Qualifiers(); + + // Note that we don't update T: we want to add the + // substitution at the original type. + } + + if (quals) { + mangleQualifiers(quals); + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. + mangleType(QualType(ty, 0)); + } else { + switch (ty->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + return; +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + mangleType(static_cast<const CLASS##Type*>(ty)); \ + break; +#include "clang/AST/TypeNodes.def" + } + } + + // Add the substitution. + if (isSubstitutable) + addSubstitution(T); +} + +void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { + if (!mangleStandardSubstitution(ND)) + mangleName(ND); +} + +void CXXNameMangler::mangleType(const BuiltinType *T) { + // <type> ::= <builtin-type> + // <builtin-type> ::= v # void + // ::= w # wchar_t + // ::= b # bool + // ::= c # char + // ::= a # signed char + // ::= h # unsigned char + // ::= s # short + // ::= t # unsigned short + // ::= i # int + // ::= j # unsigned int + // ::= l # long + // ::= m # unsigned long + // ::= x # long long, __int64 + // ::= y # unsigned long long, __int64 + // ::= n # __int128 + // UNSUPPORTED: ::= o # unsigned __int128 + // ::= f # float + // ::= d # double + // ::= e # long double, __float80 + // UNSUPPORTED: ::= g # __float128 + // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) + // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) + // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) + // ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= Di # char32_t + // ::= Ds # char16_t + // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + // ::= u <source-name> # vendor extended type + switch (T->getKind()) { + case BuiltinType::Void: Out << 'v'; break; + case BuiltinType::Bool: Out << 'b'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break; + case BuiltinType::UChar: Out << 'h'; break; + case BuiltinType::UShort: Out << 't'; break; + case BuiltinType::UInt: Out << 'j'; break; + case BuiltinType::ULong: Out << 'm'; break; + case BuiltinType::ULongLong: Out << 'y'; break; + case BuiltinType::UInt128: Out << 'o'; break; + case BuiltinType::SChar: Out << 'a'; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << 'w'; break; + case BuiltinType::Char16: Out << "Ds"; break; + case BuiltinType::Char32: Out << "Di"; break; + case BuiltinType::Short: Out << 's'; break; + case BuiltinType::Int: Out << 'i'; break; + case BuiltinType::Long: Out << 'l'; break; + case BuiltinType::LongLong: Out << 'x'; break; + case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Half: Out << "Dh"; break; + case BuiltinType::Float: Out << 'f'; break; + case BuiltinType::Double: Out << 'd'; break; + case BuiltinType::LongDouble: Out << 'e'; break; + case BuiltinType::NullPtr: Out << "Dn"; break; + +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: + llvm_unreachable("mangling a placeholder type"); + case BuiltinType::ObjCId: Out << "11objc_object"; break; + case BuiltinType::ObjCClass: Out << "10objc_class"; break; + case BuiltinType::ObjCSel: Out << "13objc_selector"; break; + } +} + +// <type> ::= <function-type> +// <function-type> ::= [<CV-qualifiers>] F [Y] +// <bare-function-type> [<ref-qualifier>] E +// (Proposal to cxx-abi-dev, 2012-05-11) +void CXXNameMangler::mangleType(const FunctionProtoType *T) { + // Mangle CV-qualifiers, if present. These are 'this' qualifiers, + // e.g. "const" in "int (A::*)() const". + mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals())); + + Out << 'F'; + + // FIXME: We don't have enough information in the AST to produce the 'Y' + // encoding for extern "C" function types. + mangleBareFunctionType(T, /*MangleReturnType=*/true); + + // Mangle the ref-qualifier, if present. + mangleRefQualifier(T->getRefQualifier()); + + Out << 'E'; +} +void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} +void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType) { + // We should never be mangling something without a prototype. + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // Record that we're in a function type. See mangleFunctionParam + // for details on what we're trying to achieve here. + FunctionTypeDepthState saved = FunctionTypeDepth.push(); + + // <bare-function-type> ::= <signature type>+ + if (MangleReturnType) { + FunctionTypeDepth.enterResultType(); + mangleType(Proto->getResultType()); + FunctionTypeDepth.leaveResultType(); + } + + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + // <builtin-type> ::= v # void + Out << 'v'; + + FunctionTypeDepth.pop(saved); + return; + } + + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(Context.getASTContext().getSignatureParameterType(*Arg)); + + FunctionTypeDepth.pop(saved); + + // <builtin-type> ::= z # ellipsis + if (Proto->isVariadic()) + Out << 'z'; +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const EnumType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const RecordType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const TagType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= A <positive dimension number> _ <element type> +// ::= A [<dimension expression>] _ <element type> +void CXXNameMangler::mangleType(const ConstantArrayType *T) { + Out << 'A' << T->getSize() << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const VariableArrayType *T) { + Out << 'A'; + // decayed vla types (size 0) will just be skipped. + if (T->getSizeExpr()) + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const DependentSizedArrayType *T) { + Out << 'A'; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const IncompleteArrayType *T) { + Out << "A_"; + mangleType(T->getElementType()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= M <class type> <member type> +void CXXNameMangler::mangleType(const MemberPointerType *T) { + Out << 'M'; + mangleType(QualType(T->getClass(), 0)); + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { + mangleType(FPT); + + // Itanium C++ ABI 5.1.8: + // + // The type of a non-static member function is considered to be different, + // for the purposes of substitution, from the type of a namespace-scope or + // static member function whose type appears similar. The types of two + // non-static member functions are considered to be different, for the + // purposes of substitution, if the functions are members of different + // classes. In other words, for the purposes of substitution, the class of + // which the function is a member is considered part of the type of + // function. + + // Given that we already substitute member function pointers as a + // whole, the net effect of this rule is just to unconditionally + // suppress substitution on the function type in a member pointer. + // We increment the SeqID here to emulate adding an entry to the + // substitution table. + ++SeqID; + } else + mangleType(PointeeType); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { + mangleTemplateParameter(T->getIndex()); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { + // FIXME: not clear how to mangle this! + // template <class T...> class A { + // template <class U...> void foo(T(*)(U) x...); + // }; + Out << "_SUBSTPACK_"; +} + +// <type> ::= P <type> # pointer-to +void CXXNameMangler::mangleType(const PointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} +void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} + +// <type> ::= R <type> # reference-to +void CXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'R'; + mangleType(T->getPointeeType()); +} + +// <type> ::= O <type> # rvalue reference-to (C++0x) +void CXXNameMangler::mangleType(const RValueReferenceType *T) { + Out << 'O'; + mangleType(T->getPointeeType()); +} + +// <type> ::= C <type> # complex pair (C 2000) +void CXXNameMangler::mangleType(const ComplexType *T) { + Out << 'C'; + mangleType(T->getElementType()); +} + +// ARM's ABI for Neon vector types specifies that they should be mangled as +// if they are structs (to match ARM's initial implementation). The +// vector type must be one of the special types predefined by ARM. +void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { + QualType EltType = T->getElementType(); + assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType"); + const char *EltName = 0; + if (T->getVectorKind() == VectorType::NeonPolyVector) { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "poly8_t"; break; + case BuiltinType::Short: EltName = "poly16_t"; break; + default: llvm_unreachable("unexpected Neon polynomial vector element type"); + } + } else { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "int8_t"; break; + case BuiltinType::UChar: EltName = "uint8_t"; break; + case BuiltinType::Short: EltName = "int16_t"; break; + case BuiltinType::UShort: EltName = "uint16_t"; break; + case BuiltinType::Int: EltName = "int32_t"; break; + case BuiltinType::UInt: EltName = "uint32_t"; break; + case BuiltinType::LongLong: EltName = "int64_t"; break; + case BuiltinType::ULongLong: EltName = "uint64_t"; break; + case BuiltinType::Float: EltName = "float32_t"; break; + default: llvm_unreachable("unexpected Neon vector element type"); + } + } + const char *BaseName = 0; + unsigned BitSize = (T->getNumElements() * + getASTContext().getTypeSize(EltType)); + if (BitSize == 64) + BaseName = "__simd64_"; + else { + assert(BitSize == 128 && "Neon vector type not 64 or 128 bits"); + BaseName = "__simd128_"; + } + Out << strlen(BaseName) + strlen(EltName); + Out << BaseName << EltName; +} + +// GNU extension: vector types +// <type> ::= <vector-type> +// <vector-type> ::= Dv <positive dimension number> _ +// <extended element type> +// ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +// ::= p # AltiVec vector pixel +// ::= b # Altivec vector bool +void CXXNameMangler::mangleType(const VectorType *T) { + if ((T->getVectorKind() == VectorType::NeonVector || + T->getVectorKind() == VectorType::NeonPolyVector)) { + mangleNeonVectorType(T); + return; + } + Out << "Dv" << T->getNumElements() << '_'; + if (T->getVectorKind() == VectorType::AltiVecPixel) + Out << 'p'; + else if (T->getVectorKind() == VectorType::AltiVecBool) + Out << 'b'; + else + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const ExtVectorType *T) { + mangleType(static_cast<const VectorType*>(T)); +} +void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { + Out << "Dv"; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} + +void CXXNameMangler::mangleType(const PackExpansionType *T) { + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(T->getPattern()); +} + +void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { + mangleSourceName(T->getDecl()->getIdentifier()); +} + +void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + +void CXXNameMangler::mangleType(const BlockPointerType *T) { + Out << "U13block_pointer"; + mangleType(T->getPointeeType()); +} + +void CXXNameMangler::mangleType(const InjectedClassNameType *T) { + // Mangle injected class name types as if the user had written the + // specialization out fully. It may not actually be possible to see + // this mangling, though. + mangleType(T->getInjectedSpecializationType()); +} + +void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { + mangleName(TD, T->getArgs(), T->getNumArgs()); + } else { + if (mangleSubstitution(QualType(T, 0))) + return; + + mangleTemplatePrefix(T->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); + addSubstitution(QualType(T, 0)); + } +} + +void CXXNameMangler::mangleType(const DependentNameType *T) { + // Typename types are always nested + Out << 'N'; + manglePrefix(T->getQualifier()); + mangleSourceName(T->getIdentifier()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { + // Dependently-scoped template types are nested if they have a prefix. + Out << 'N'; + + // TODO: avoid making this TemplateName. + TemplateName Prefix = + getASTContext().getDependentTemplateName(T->getQualifier(), + T->getIdentifier()); + mangleTemplatePrefix(Prefix); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const TypeOfType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const TypeOfExprType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const DecltypeType *T) { + Expr *E = T->getUnderlyingExpr(); + + // type ::= Dt <expression> E # decltype of an id-expression + // # or class member access + // ::= DT <expression> E # decltype of an expression + + // This purports to be an exhaustive list of id-expressions and + // class member accesses. Note that we do not ignore parentheses; + // parentheses change the semantics of decltype for these + // expressions (and cause the mangler to use the other form). + if (isa<DeclRefExpr>(E) || + isa<MemberExpr>(E) || + isa<UnresolvedLookupExpr>(E) || + isa<DependentScopeDeclRefExpr>(E) || + isa<CXXDependentScopeMemberExpr>(E) || + isa<UnresolvedMemberExpr>(E)) + Out << "Dt"; + else + Out << "DT"; + mangleExpression(E); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const UnaryTransformType *T) { + // If this is dependent, we need to record that. If not, we simply + // mangle it as the underlying type since they are equivalent. + if (T->isDependentType()) { + Out << 'U'; + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + Out << "3eut"; + break; + } + } + + mangleType(T->getUnderlyingType()); +} + +void CXXNameMangler::mangleType(const AutoType *T) { + QualType D = T->getDeducedType(); + // <builtin-type> ::= Da # dependent auto + if (D.isNull()) + Out << "Da"; + else + mangleType(D); +} + +void CXXNameMangler::mangleType(const AtomicType *T) { + // <type> ::= U <source-name> <type> # vendor extended type qualifier + // (Until there's a standardized mangling...) + Out << "U7_Atomic"; + mangleType(T->getValueType()); +} + +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // <expr-primary> ::= L <type> <value number> E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + mangleNumber(Value); + } + Out << 'E'; + +} + +/// Mangles a member expression. +void CXXNameMangler::mangleMemberExpr(const Expr *base, + bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName member, + unsigned arity) { + // <expression> ::= dt <expression> <unresolved-name> + // ::= pt <expression> <unresolved-name> + if (base) { + if (base->isImplicitCXXThis()) { + // Note: GCC mangles member expressions to the implicit 'this' as + // *this., whereas we represent them as this->. The Itanium C++ ABI + // does not specify anything here, so we follow GCC. + Out << "dtdefpT"; + } else { + Out << (isArrow ? "pt" : "dt"); + mangleExpression(base); + } + } + mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); +} + +/// Look at the callee of the given call expression and determine if +/// it's a parenthesized id-expression which would have triggered ADL +/// otherwise. +static bool isParenthesizedADLCallee(const CallExpr *call) { + const Expr *callee = call->getCallee(); + const Expr *fn = callee->IgnoreParens(); + + // Must be parenthesized. IgnoreParens() skips __extension__ nodes, + // too, but for those to appear in the callee, it would have to be + // parenthesized. + if (callee == fn) return false; + + // Must be an unresolved lookup. + const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn); + if (!lookup) return false; + + assert(!lookup->requiresADL()); + + // Must be an unqualified lookup. + if (lookup->getQualifier()) return false; + + // Must not have found a class member. Note that if one is a class + // member, they're all class members. + if (lookup->getNumDecls() > 0 && + (*lookup->decls_begin())->isCXXClassMember()) + return false; + + // Otherwise, ADL would have been triggered. + return true; +} + +void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { + // <expression> ::= <unary operator-name> <expression> + // ::= <binary operator-name> <expression> <expression> + // ::= <trinary operator-name> <expression> <expression> <expression> + // ::= cv <type> expression # conversion with one argument + // ::= cv <type> _ <expression>* E # conversion with a different number of arguments + // ::= st <type> # sizeof (a type) + // ::= at <type> # alignof (a type) + // ::= <template-param> + // ::= <function-param> + // ::= sr <type> <unqualified-name> # dependent name + // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + // ::= ds <expression> <expression> # expr.*expr + // ::= sZ <template-param> # size of a parameter pack + // ::= sZ <function-param> # size of a function parameter pack + // ::= <expr-primary> + // <expr-primary> ::= L <type> <value number> E # integer literal + // ::= L <type <value float> E # floating literal + // ::= L <mangled-name> E # external name + // ::= fpT # 'this' expression + QualType ImplicitlyConvertedToType; + +recurse: + switch (E->getStmtClass()) { + case Expr::NoStmtClass: +#define ABSTRACT_STMT(Type) +#define EXPR(Type, Base) +#define STMT(Type, Base) \ + case Expr::Type##Class: +#include "clang/AST/StmtNodes.inc" + // fallthrough + + // These all can only appear in local or variable-initialization + // contexts and so should never appear in a mangling. + case Expr::AddrLabelExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::LambdaExprClass: + llvm_unreachable("unexpected statement kind"); + + // FIXME: invent manglings for all these. + case Expr::BlockExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::ChooseExprClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::GenericSelectionExprClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCBoxedExprClass: + case Expr::ObjCArrayLiteralClass: + case Expr::ObjCDictionaryLiteralClass: + case Expr::ObjCSubscriptRefExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::OffsetOfExprClass: + case Expr::PredefinedExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::StmtExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: + case Expr::VAArgExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CUDAKernelCallExprClass: + case Expr::AsTypeExprClass: + case Expr::PseudoObjectExprClass: + case Expr::AtomicExprClass: + { + // As bad as this diagnostic is, it's better than crashing. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // Even gcc-4.5 doesn't mangle this. + case Expr::BinaryConditionalOperatorClass: { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = + Diags.getCustomDiagID(DiagnosticsEngine::Error, + "?: operator with omitted middle operand cannot be mangled"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // These are used for internal purposes and cannot be meaningfully mangled. + case Expr::OpaqueValueExprClass: + llvm_unreachable("cannot mangle opaque value; mangling wrong thing?"); + + case Expr::InitListExprClass: { + // Proposal by Jason Merrill, 2012-01-03 + Out << "il"; + const InitListExpr *InitList = cast<InitListExpr>(E); + for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) + mangleExpression(InitList->getInit(i)); + Out << "E"; + break; + } + + case Expr::CXXDefaultArgExprClass: + mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); + break; + + case Expr::SubstNonTypeTemplateParmExprClass: + mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), + Arity); + break; + + case Expr::UserDefinedLiteralClass: + // We follow g++'s approach of mangling a UDL as a call to the literal + // operator. + case Expr::CXXMemberCallExprClass: // fallthrough + case Expr::CallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + + // <expression> ::= cp <simple-id> <expression>* E + // We use this mangling only when the call would use ADL except + // for being parenthesized. Per discussion with David + // Vandervoorde, 2011.04.25. + if (isParenthesizedADLCallee(CE)) { + Out << "cp"; + // The callee here is a parenthesized UnresolvedLookupExpr with + // no qualifier and should always get mangled as a <simple-id> + // anyway. + + // <expression> ::= cl <expression>* E + } else { + Out << "cl"; + } + + mangleExpression(CE->getCallee(), CE->getNumArgs()); + for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) + mangleExpression(CE->getArg(I)); + Out << 'E'; + break; + } + + case Expr::CXXNewExprClass: { + const CXXNewExpr *New = cast<CXXNewExpr>(E); + if (New->isGlobalNew()) Out << "gs"; + Out << (New->isArray() ? "na" : "nw"); + for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(), + E = New->placement_arg_end(); I != E; ++I) + mangleExpression(*I); + Out << '_'; + mangleType(New->getAllocatedType()); + if (New->hasInitializer()) { + // Proposal by Jason Merrill, 2012-01-03 + if (New->getInitializationStyle() == CXXNewExpr::ListInit) + Out << "il"; + else + Out << "pi"; + const Expr *Init = New->getInitializer(); + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { + // Directly inline the initializers. + for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(), + E = CCE->arg_end(); + I != E; ++I) + mangleExpression(*I); + } else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) { + for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i) + mangleExpression(PLE->getExpr(i)); + } else if (New->getInitializationStyle() == CXXNewExpr::ListInit && + isa<InitListExpr>(Init)) { + // Only take InitListExprs apart for list-initialization. + const InitListExpr *InitList = cast<InitListExpr>(Init); + for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) + mangleExpression(InitList->getInit(i)); + } else + mangleExpression(Init); + } + Out << 'E'; + break; + } + + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(), + Arity); + break; + } + + case Expr::UnresolvedMemberExprClass: { + const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), 0, ME->getMemberName(), + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXDependentScopeMemberExprClass: { + const CXXDependentScopeMemberExpr *ME + = cast<CXXDependentScopeMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getFirstQualifierFoundInScope(), + ME->getMember(), Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::UnresolvedLookupExprClass: { + const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); + mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity); + + // All the <unresolved-name> productions end in a + // base-unresolved-name, where <template-args> are just tacked + // onto the end. + if (ULE->hasExplicitTemplateArgs()) + mangleTemplateArgs(ULE->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXUnresolvedConstructExprClass: { + const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); + unsigned N = CE->arg_size(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXConstructExprClass: { + const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); + unsigned N = CE->getNumArgs(); + + // Proposal by Jason Merrill, 2012-01-03 + if (CE->isListInitialization()) + Out << "tl"; + else + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::CXXScalarValueInitExprClass: + Out <<"cv"; + mangleType(E->getType()); + Out <<"_E"; + break; + + case Expr::CXXNoexceptExprClass: + Out << "nx"; + mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand()); + break; + + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); + + if (!SAE->isInstantiationDependent()) { + // Itanium C++ ABI: + // If the operand of a sizeof or alignof operator is not + // instantiation-dependent it is encoded as an integer literal + // reflecting the result of the operator. + // + // If the result of the operator is implicitly converted to a known + // integer type, that type is used for the literal; otherwise, the type + // of std::size_t or std::ptrdiff_t is used. + QualType T = (ImplicitlyConvertedToType.isNull() || + !ImplicitlyConvertedToType->isIntegerType())? SAE->getType() + : ImplicitlyConvertedToType; + llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext()); + mangleIntegerLiteral(T, V); + break; + } + + switch(SAE->getKind()) { + case UETT_SizeOf: + Out << 's'; + break; + case UETT_AlignOf: + Out << 'a'; + break; + case UETT_VecStep: + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle vec_step expression"); + Diags.Report(DiagID); + return; + } + if (SAE->isArgumentType()) { + Out << 't'; + mangleType(SAE->getArgumentType()); + } else { + Out << 'z'; + mangleExpression(SAE->getArgumentExpr()); + } + break; + } + + case Expr::CXXThrowExprClass: { + const CXXThrowExpr *TE = cast<CXXThrowExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TE->getSubExpr()) { + Out << "tw"; + mangleExpression(TE->getSubExpr()); + } else { + Out << "tr"; + } + break; + } + + case Expr::CXXTypeidExprClass: { + const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TIE->isTypeOperand()) { + Out << "ti"; + mangleType(TIE->getTypeOperand()); + } else { + Out << "te"; + mangleExpression(TIE->getExprOperand()); + } + break; + } + + case Expr::CXXDeleteExprClass: { + const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (DE->isGlobalDelete()) Out << "gs"; + Out << (DE->isArrayForm() ? "da" : "dl"); + mangleExpression(DE->getArgument()); + break; + } + + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E); + + // Array subscript is treated as a syntactically weird form of + // binary operator. + Out << "ix"; + mangleExpression(AE->getLHS()); + mangleExpression(AE->getRHS()); + break; + } + + case Expr::CompoundAssignOperatorClass: // fallthrough + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(E); + if (BO->getOpcode() == BO_PtrMemD) + Out << "ds"; + else + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS(), Arity); + mangleExpression(CO->getRHS(), Arity); + break; + } + + case Expr::ImplicitCastExprClass: { + ImplicitlyConvertedToType = E->getType(); + E = cast<ImplicitCastExpr>(E)->getSubExpr(); + goto recurse; + } + + case Expr::ObjCBridgedCastExprClass: { + // Mangle ownership casts as a vendor extended operator __bridge, + // __bridge_transfer, or __bridge_retain. + StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName(); + Out << "v1U" << Kind.size() << Kind; + } + // Fall through to mangle the cast itself. + + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); + Out << "cv"; + mangleType(ECE->getType()); + mangleExpression(ECE->getSubExpr()); + break; + } + + case Expr::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); + unsigned NumArgs = CE->getNumArgs(); + mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs); + // Mangle the arguments. + for (unsigned i = 0; i != NumArgs; ++i) + mangleExpression(CE->getArg(i)); + break; + } + + case Expr::ParenExprClass: + mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); + break; + + case Expr::DeclRefExprClass: { + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); + + switch (D->getKind()) { + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D, "_Z"); + Out << 'E'; + break; + + case Decl::ParmVar: + mangleFunctionParam(cast<ParmVarDecl>(D)); + break; + + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + + case Decl::NonTypeTemplateParm: { + const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); + mangleTemplateParameter(PD->getIndex()); + break; + } + + } + + break; + } + + case Expr::SubstNonTypeTemplateParmPackExprClass: + // FIXME: not clear how to mangle this! + // template <unsigned N...> class A { + // template <class U...> void foo(U (&x)[N]...); + // }; + Out << "_SUBSTPACK_"; + break; + + case Expr::FunctionParmPackExprClass: { + // FIXME: not clear how to mangle this! + const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); + Out << "v110_SUBSTPACK"; + mangleFunctionParam(FPPE->getParameterPack()); + break; + } + + case Expr::DependentScopeDeclRefExprClass: { + const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); + mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity); + + // All the <unresolved-name> productions end in a + // base-unresolved-name, where <template-args> are just tacked + // onto the end. + if (DRE->hasExplicitTemplateArgs()) + mangleTemplateArgs(DRE->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXBindTemporaryExprClass: + mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr()); + break; + + case Expr::ExprWithCleanupsClass: + mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity); + break; + + case Expr::FloatingLiteralClass: { + const FloatingLiteral *FL = cast<FloatingLiteral>(E); + Out << 'L'; + mangleType(FL->getType()); + mangleFloat(FL->getValue()); + Out << 'E'; + break; + } + + case Expr::CharacterLiteralClass: + Out << 'L'; + mangleType(E->getType()); + Out << cast<CharacterLiteral>(E)->getValue(); + Out << 'E'; + break; + + // FIXME. __objc_yes/__objc_no are mangled same as true/false + case Expr::ObjCBoolLiteralExprClass: + Out << "Lb"; + Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0'); + Out << 'E'; + break; + + case Expr::CXXBoolLiteralExprClass: + Out << "Lb"; + Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0'); + Out << 'E'; + break; + + case Expr::IntegerLiteralClass: { + llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue()); + if (E->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleIntegerLiteral(E->getType(), Value); + break; + } + + case Expr::ImaginaryLiteralClass: { + const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E); + // Mangle as if a complex literal. + // Proposal from David Vandevoorde, 2010.06.30. + Out << 'L'; + mangleType(E->getType()); + if (const FloatingLiteral *Imag = + dyn_cast<FloatingLiteral>(IE->getSubExpr())) { + // Mangle a floating-point zero of the appropriate type. + mangleFloat(llvm::APFloat(Imag->getValue().getSemantics())); + Out << '_'; + mangleFloat(Imag->getValue()); + } else { + Out << "0_"; + llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue()); + if (IE->getSubExpr()->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleNumber(Value); + } + Out << 'E'; + break; + } + + case Expr::StringLiteralClass: { + // Revised proposal from David Vandervoorde, 2010.07.15. + Out << 'L'; + assert(isa<ConstantArrayType>(E->getType())); + mangleType(E->getType()); + Out << 'E'; + break; + } + + case Expr::GNUNullExprClass: + // FIXME: should this really be mangled the same as nullptr? + // fallthrough + + case Expr::CXXNullPtrLiteralExprClass: { + // Proposal from David Vandervoorde, 2010.06.30, as + // modified by ABI list discussion. + Out << "LDnE"; + break; + } + + case Expr::PackExpansionExprClass: + Out << "sp"; + mangleExpression(cast<PackExpansionExpr>(E)->getPattern()); + break; + + case Expr::SizeOfPackExprClass: { + Out << "sZ"; + const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack(); + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack)) + mangleTemplateParameter(TTP->getIndex()); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Pack)) + mangleTemplateParameter(NTTP->getIndex()); + else if (const TemplateTemplateParmDecl *TempTP + = dyn_cast<TemplateTemplateParmDecl>(Pack)) + mangleTemplateParameter(TempTP->getIndex()); + else + mangleFunctionParam(cast<ParmVarDecl>(Pack)); + break; + } + + case Expr::MaterializeTemporaryExprClass: { + mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()); + break; + } + + case Expr::CXXThisExprClass: + Out << "fpT"; + break; + } +} + +/// Mangle an expression which refers to a parameter variable. +/// +/// <expression> ::= <function-param> +/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0 +/// <function-param> ::= fp <top-level CV-qualifiers> +/// <parameter-2 non-negative number> _ # L == 0, I > 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> _ # L > 0, I == 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> +/// <I-1 non-negative number> _ # L > 0, I > 0 +/// +/// L is the nesting depth of the parameter, defined as 1 if the +/// parameter comes from the innermost function prototype scope +/// enclosing the current context, 2 if from the next enclosing +/// function prototype scope, and so on, with one special case: if +/// we've processed the full parameter clause for the innermost +/// function type, then L is one less. This definition conveniently +/// makes it irrelevant whether a function's result type was written +/// trailing or leading, but is otherwise overly complicated; the +/// numbering was first designed without considering references to +/// parameter in locations other than return types, and then the +/// mangling had to be generalized without changing the existing +/// manglings. +/// +/// I is the zero-based index of the parameter within its parameter +/// declaration clause. Note that the original ABI document describes +/// this using 1-based ordinals. +void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { + unsigned parmDepth = parm->getFunctionScopeDepth(); + unsigned parmIndex = parm->getFunctionScopeIndex(); + + // Compute 'L'. + // parmDepth does not include the declaring function prototype. + // FunctionTypeDepth does account for that. + assert(parmDepth < FunctionTypeDepth.getDepth()); + unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth; + if (FunctionTypeDepth.isInResultType()) + nestingDepth--; + + if (nestingDepth == 0) { + Out << "fp"; + } else { + Out << "fL" << (nestingDepth - 1) << 'p'; + } + + // Top-level qualifiers. We don't have to worry about arrays here, + // because parameters declared as arrays should already have been + // transformed to have pointer type. FIXME: apparently these don't + // get mangled if used as an rvalue of a known non-class type? + assert(!parm->getType()->isArrayType() + && "parameter's type is still an array type?"); + mangleQualifiers(parm->getType().getQualifiers()); + + // Parameter index. + if (parmIndex != 0) { + Out << (parmIndex - 1); + } + Out << '_'; +} + +void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { + // <ctor-dtor-name> ::= C1 # complete object constructor + // ::= C2 # base object constructor + // ::= C3 # complete object allocating constructor + // + switch (T) { + case Ctor_Complete: + Out << "C1"; + break; + case Ctor_Base: + Out << "C2"; + break; + case Ctor_CompleteAllocating: + Out << "C3"; + break; + } +} + +void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { + // <ctor-dtor-name> ::= D0 # deleting destructor + // ::= D1 # complete object destructor + // ::= D2 # base object destructor + // + switch (T) { + case Dtor_Deleting: + Out << "D0"; + break; + case Dtor_Complete: + Out << "D1"; + break; + case Dtor_Base: + Out << "D2"; + break; + } +} + +void CXXNameMangler::mangleTemplateArgs( + const ASTTemplateArgumentListInfo &TemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) + mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument()); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0, e = AL.size(); i != e; ++i) + mangleTemplateArg(AL[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != NumTemplateArgs; ++i) + mangleTemplateArg(TemplateArgs[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { + // <template-arg> ::= <type> # type or template + // ::= X <expression> E # expression + // ::= <expr-primary> # simple expressions + // ::= J <template-arg>* E # argument pack + // ::= sp <expression> # pack expansion of (C++0x) + if (!A.isInstantiationDependent() || A.isDependent()) + A = Context.getASTContext().getCanonicalTemplateArgument(A); + + switch (A.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Cannot mangle NULL template argument"); + + case TemplateArgument::Type: + mangleType(A.getAsType()); + break; + case TemplateArgument::Template: + // This is mangled as <type>. + mangleType(A.getAsTemplate()); + break; + case TemplateArgument::TemplateExpansion: + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(A.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: { + // It's possible to end up with a DeclRefExpr here in certain + // dependent cases, in which case we should mangle as a + // declaration. + const Expr *E = A.getAsExpr()->IgnoreParens(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + const ValueDecl *D = DRE->getDecl(); + if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) { + Out << "L"; + mangle(D, "_Z"); + Out << 'E'; + break; + } + } + + Out << 'X'; + mangleExpression(E); + Out << 'E'; + break; + } + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral()); + break; + case TemplateArgument::Declaration: { + // <expr-primary> ::= L <mangled-name> E # external name + // Clang produces AST's where pointer-to-member-function expressions + // and pointer-to-function expressions are represented as a declaration not + // an expression. We compensate for it here to produce the correct mangling. + ValueDecl *D = A.getAsDecl(); + bool compensateMangling = !A.isDeclForReferenceParam(); + if (compensateMangling) { + Out << 'X'; + mangleOperatorName(OO_Amp, 1); + } + + Out << 'L'; + // References to external entities use the mangled name; if the name would + // not normally be manged then mangle it as unqualified. + // + // FIXME: The ABI specifies that external names here should have _Z, but + // gcc leaves this off. + if (compensateMangling) + mangle(D, "_Z"); + else + mangle(D, "Z"); + Out << 'E'; + + if (compensateMangling) + Out << 'E'; + + break; + } + case TemplateArgument::NullPtr: { + // <expr-primary> ::= L <type> 0 E + Out << 'L'; + mangleType(A.getNullPtrType()); + Out << "0E"; + break; + } + case TemplateArgument::Pack: { + // Note: proposal by Mike Herrick on 12/20/10 + Out << 'J'; + for (TemplateArgument::pack_iterator PA = A.pack_begin(), + PAEnd = A.pack_end(); + PA != PAEnd; ++PA) + mangleTemplateArg(*PA); + Out << 'E'; + } + } +} + +void CXXNameMangler::mangleTemplateParameter(unsigned Index) { + // <template-param> ::= T_ # first template parameter + // ::= T <parameter-2 non-negative number> _ + if (Index == 0) + Out << "T_"; + else + Out << 'T' << (Index - 1) << '_'; +} + +void CXXNameMangler::mangleExistingSubstitution(QualType type) { + bool result = mangleSubstitution(type); + assert(result && "no existing substitution for type"); + (void) result; +} + +void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { + bool result = mangleSubstitution(tname); + assert(result && "no existing substitution for template name"); + (void) result; +} + +// <substitution> ::= S <seq-id> _ +// ::= S_ +bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { + // Try one of the standard substitutions first. + if (mangleStandardSubstitution(ND)) + return true; + + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); +} + +/// \brief Determine whether the given type has any qualifiers that are +/// relevant for substitutions. +static bool hasMangledSubstitutionQualifiers(QualType T) { + Qualifiers Qs = T.getQualifiers(); + return Qs.getCVRQualifiers() || Qs.hasAddressSpace(); +} + +bool CXXNameMangler::mangleSubstitution(QualType T) { + if (!hasMangledSubstitutionQualifiers(T)) { + if (const RecordType *RT = T->getAs<RecordType>()) + return mangleSubstitution(RT->getDecl()); + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + + return mangleSubstitution(TypePtr); +} + +bool CXXNameMangler::mangleSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + return mangleSubstitution( + reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { + llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr); + if (I == Substitutions.end()) + return false; + + unsigned SeqID = I->second; + if (SeqID == 0) + Out << "S_"; + else { + SeqID--; + + // <seq-id> is encoded in base-36, using digits and upper case letters. + char Buffer[10]; + char *BufferPtr = llvm::array_endof(Buffer); + + if (SeqID == 0) *--BufferPtr = '0'; + + while (SeqID) { + assert(BufferPtr > Buffer && "Buffer overflow!"); + + char c = static_cast<char>(SeqID % 36); + + *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10); + SeqID /= 36; + } + + Out << 'S' + << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) + << '_'; + } + + return true; +} + +static bool isCharType(QualType T) { + if (T.isNull()) + return false; + + return T->isSpecificBuiltinType(BuiltinType::Char_S) || + T->isSpecificBuiltinType(BuiltinType::Char_U); +} + +/// isCharSpecialization - Returns whether a given type is a template +/// specialization of a given name with a single argument of type char. +static bool isCharSpecialization(QualType T, const char *Name) { + if (T.isNull()) + return false; + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + if (!SD) + return false; + + if (!isStdNamespace(getEffectiveDeclContext(SD))) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 1) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + return SD->getIdentifier()->getName() == Name; +} + +template <std::size_t StrLen> +static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + +bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { + // <substitution> ::= St # ::std:: + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (isStd(NS)) { + Out << "St"; + return true; + } + } + + if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) { + if (!isStdNamespace(getEffectiveDeclContext(TD))) + return false; + + // <substitution> ::= Sa # ::std::allocator + if (TD->getIdentifier()->isStr("allocator")) { + Out << "Sa"; + return true; + } + + // <<substitution> ::= Sb # ::std::basic_string + if (TD->getIdentifier()->isStr("basic_string")) { + Out << "Sb"; + return true; + } + } + + if (const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + if (!isStdNamespace(getEffectiveDeclContext(SD))) + return false; + + // <substitution> ::= Ss # ::std::basic_string<char, + // ::std::char_traits<char>, + // ::std::allocator<char> > + if (SD->getIdentifier()->isStr("basic_string")) { + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + + if (TemplateArgs.size() != 3) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator")) + return false; + + Out << "Ss"; + return true; + } + + // <substitution> ::= Si # ::std::basic_istream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + + // <substitution> ::= So # ::std::basic_ostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_ostream")) { + Out << "So"; + return true; + } + + // <substitution> ::= Sd # ::std::basic_iostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } + } + return false; +} + +void CXXNameMangler::addSubstitution(QualType T) { + if (!hasMangledSubstitutionQualifiers(T)) { + if (const RecordType *RT = T->getAs<RecordType>()) { + addSubstitution(RT->getDecl()); + return; + } + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + addSubstitution(TypePtr); +} + +void CXXNameMangler::addSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return addSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +void CXXNameMangler::addSubstitution(uintptr_t Ptr) { + assert(!Substitutions.count(Ptr) && "Substitution already exists!"); + Substitutions[Ptr] = SeqID++; +} + +// + +/// \brief Mangles the name of the declaration D and emits that name to the +/// given output stream. +/// +/// If the declaration D requires a mangled name, this routine will emit that +/// mangled name to \p os and return true. Otherwise, \p os will be unchanged +/// and this routine will return false. In this case, the caller should just +/// emit the identifier of the declaration (\c D->getIdentifier()) as its +/// name. +void ItaniumMangleContext::mangleName(const NamedDecl *D, + raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + CXXNameMangler Mangler(*this, Out, D); + return Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + + assert(!isa<CXXDestructorDecl>(MD) && + "Use mangleCXXDtor for destructor decls!"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZT"; + if (!Thunk.Return.isEmpty()) + Mangler.getStream() << 'c'; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); + + // Mangle the return pointer adjustment if there is one. + if (!Thunk.Return.isEmpty()) + Mangler.mangleCallOffset(Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + Mangler.mangleFunctionEncoding(MD); +} + +void +ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Out, DD, Type); + Mangler.getStream() << "_ZT"; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, + ThisAdjustment.VCallOffsetOffset); + + Mangler.mangleFunctionEncoding(DD); +} + +/// mangleGuardVariable - Returns the mangled name for a guard variable +/// for the passed in VarDecl. +void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, + raw_ostream &Out) { + // <special-name> ::= GV <object name> # Guard variable for one-time + // # initialization + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGV"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, + raw_ostream &Out) { + // We match the GCC mangling here. + // <special-name> ::= GR <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGR"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + raw_ostream &Out) { + // <special-name> ::= TV <type> # virtual table + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTV"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + raw_ostream &Out) { + // <special-name> ::= TT <type> # VTT structure + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTT"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &Out) { + // <special-name> ::= TC <type> <offset number> _ <base type> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTC"; + Mangler.mangleNameOrStandardSubstitution(RD); + Mangler.getStream() << Offset; + Mangler.getStream() << '_'; + Mangler.mangleNameOrStandardSubstitution(Type); +} + +void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, + raw_ostream &Out) { + // <special-name> ::= TI <type> # typeinfo structure + assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTI"; + Mangler.mangleType(Ty); +} + +void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, + raw_ostream &Out) { + // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTS"; + Mangler.mangleType(Ty); +} + +MangleContext *clang::createItaniumMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags) { + return new ItaniumMangleContext(Context, Diags); +} diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index a8737e73e9d..0da7f516db9 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1,1725 +1,1718 @@ -//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides C++ name mangling targeting the Microsoft Visual C++ ABI.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/Mangle.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include <map>
-
-using namespace clang;
-
-namespace {
-
-/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
-/// Microsoft Visual C++ ABI.
-class MicrosoftCXXNameMangler {
- MangleContext &Context;
- raw_ostream &Out;
-
- // FIXME: audit the performance of BackRefMap as it might do way too many
- // copying of strings.
- typedef std::map<std::string, unsigned> BackRefMap;
- BackRefMap NameBackReferences;
- bool UseNameBackReferences;
-
- typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap;
- ArgBackRefMap TypeBackReferences;
-
- ASTContext &getASTContext() const { return Context.getASTContext(); }
-
-public:
- MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
- : Context(C), Out(Out_), UseNameBackReferences(true) { }
-
- raw_ostream &getStream() const { return Out; }
-
- void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
- void mangleName(const NamedDecl *ND);
- void mangleFunctionEncoding(const FunctionDecl *FD);
- void mangleVariableEncoding(const VarDecl *VD);
- void mangleNumber(int64_t Number);
- void mangleNumber(const llvm::APSInt &Value);
- void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true);
-
-private:
- void disableBackReferences() { UseNameBackReferences = false; }
- void mangleUnqualifiedName(const NamedDecl *ND) {
- mangleUnqualifiedName(ND, ND->getDeclName());
- }
- void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
- void mangleSourceName(const IdentifierInfo *II);
- void manglePostfix(const DeclContext *DC, bool NoFunction=false);
- void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
- void mangleQualifiers(Qualifiers Quals, bool IsMember);
- void manglePointerQualifiers(Qualifiers Quals);
-
- void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
- void mangleObjCMethodName(const ObjCMethodDecl *MD);
- void mangleLocalName(const FunctionDecl *FD);
-
- void mangleArgumentType(QualType T, SourceRange Range);
-
- // Declare manglers for every type class.
-#define ABSTRACT_TYPE(CLASS, PARENT)
-#define NON_CANONICAL_TYPE(CLASS, PARENT)
-#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \
- SourceRange Range);
-#include "clang/AST/TypeNodes.def"
-#undef ABSTRACT_TYPE
-#undef NON_CANONICAL_TYPE
-#undef TYPE
-
- void mangleType(const TagType*);
- void mangleType(const FunctionType *T, const FunctionDecl *D,
- bool IsStructor, bool IsInstMethod);
- void mangleType(const ArrayType *T, bool IsGlobal);
- void mangleExtraDimensions(QualType T);
- void mangleFunctionClass(const FunctionDecl *FD);
- void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
- void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
- void mangleExpression(const Expr *E);
- void mangleThrowSpecification(const FunctionProtoType *T);
-
- void mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
-
-};
-
-/// MicrosoftMangleContext - Overrides the default MangleContext for the
-/// Microsoft Visual C++ ABI.
-class MicrosoftMangleContext : public MangleContext {
-public:
- MicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
- virtual bool shouldMangleDeclName(const NamedDecl *D);
- virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
- virtual void mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &);
- virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &);
- virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &);
- virtual void mangleCXXRTTI(QualType T, raw_ostream &);
- virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
- virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- raw_ostream &);
- virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- raw_ostream &);
- virtual void mangleReferenceTemporary(const clang::VarDecl *,
- raw_ostream &);
-};
-
-}
-
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = D->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
-
- return false;
-}
-
-bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
-
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
-
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
-
- // Otherwise, no mangling is done outside C++ mode.
- if (!getASTContext().getLangOpts().CPlusPlus)
- return false;
-
- // Variables at global scope with internal linkage are not mangled.
- if (!FD) {
- const DeclContext *DC = D->getDeclContext();
- if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage)
- return false;
- }
-
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
-
- return true;
-}
-
-void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
- StringRef Prefix) {
- // MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
- // Therefore it's really important that we don't decorate the
- // name with leading underscores or leading/trailing at signs. So, by
- // default, we emit an asm marker at the start so we get the name right.
- // Callers can override this with a custom prefix.
-
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
- Out << '\01' << ALA->getLabel();
- return;
- }
-
- // <mangled-name> ::= ? <name> <type-encoding>
- Out << Prefix;
- mangleName(D);
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- mangleFunctionEncoding(FD);
- else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- mangleVariableEncoding(VD);
- else {
- // TODO: Fields? Can MSVC even mangle them?
- // Issue a diagnostic for now.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this declaration yet");
- Diags.Report(D->getLocation(), DiagID)
- << D->getSourceRange();
- }
-}
-
-void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
- // <type-encoding> ::= <function-class> <function-type>
-
- // Don't mangle in the type if this isn't a decl we should typically mangle.
- if (!Context.shouldMangleDeclName(FD))
- return;
-
- // We should never ever see a FunctionNoProtoType at this point.
- // We don't even know how to mangle their types anyway :).
- const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
-
- bool InStructor = false, InInstMethod = false;
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- if (MD) {
- if (MD->isInstance())
- InInstMethod = true;
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- InStructor = true;
- }
-
- // First, the function class.
- mangleFunctionClass(FD);
-
- mangleType(FT, FD, InStructor, InInstMethod);
-}
-
-void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
- // <type-encoding> ::= <storage-class> <variable-type>
- // <storage-class> ::= 0 # private static member
- // ::= 1 # protected static member
- // ::= 2 # public static member
- // ::= 3 # global
- // ::= 4 # static local
-
- // The first character in the encoding (after the name) is the storage class.
- if (VD->isStaticDataMember()) {
- // If it's a static member, it also encodes the access level.
- switch (VD->getAccess()) {
- default:
- case AS_private: Out << '0'; break;
- case AS_protected: Out << '1'; break;
- case AS_public: Out << '2'; break;
- }
- }
- else if (!VD->isStaticLocal())
- Out << '3';
- else
- Out << '4';
- // Now mangle the type.
- // <variable-type> ::= <type> <cvr-qualifiers>
- // ::= <type> <pointee-cvr-qualifiers> # pointers, references
- // Pointers and references are odd. The type of 'int * const foo;' gets
- // mangled as 'QAHA' instead of 'PAHB', for example.
- TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
- QualType Ty = TL.getType();
- if (Ty->isPointerType() || Ty->isReferenceType()) {
- mangleType(Ty, TL.getSourceRange());
- mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
- } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
- // Global arrays are funny, too.
- mangleType(AT, true);
- mangleQualifiers(Ty.getQualifiers(), false);
- } else {
- mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange());
- mangleQualifiers(Ty.getLocalQualifiers(), false);
- }
-}
-
-void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
- // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
- const DeclContext *DC = ND->getDeclContext();
-
- // Always start with the unqualified name.
- mangleUnqualifiedName(ND);
-
- // If this is an extern variable declared locally, the relevant DeclContext
- // is that of the containing namespace, or the translation unit.
- if (isa<FunctionDecl>(DC) && ND->hasLinkage())
- while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
-
- manglePostfix(DC);
-
- // Terminate the whole name with an '@'.
- Out << '@';
-}
-
-void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
- APSNumber = Number;
- mangleNumber(APSNumber);
-}
-
-void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
- // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
- // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
- // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
- if (Value.isSigned() && Value.isNegative()) {
- Out << '?';
- mangleNumber(llvm::APSInt(Value.abs()));
- return;
- }
- llvm::APSInt Temp(Value);
- // There's a special shorter mangling for 0, but Microsoft
- // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
- if (Value.uge(1) && Value.ule(10)) {
- --Temp;
- Temp.print(Out, false);
- } else {
- // We have to build up the encoding in reverse order, so it will come
- // out right when we write it out.
- char Encoding[64];
- char *EndPtr = Encoding+sizeof(Encoding);
- char *CurPtr = EndPtr;
- llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
- NibbleMask = 0xf;
- do {
- *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
- Temp = Temp.lshr(4);
- } while (Temp != 0);
- Out.write(CurPtr, EndPtr-CurPtr);
- Out << '@';
- }
-}
-
-static const TemplateDecl *
-isTemplate(const NamedDecl *ND,
- SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
- // Check if we have a function template.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
- if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
- if (FD->getTemplateSpecializationArgsAsWritten()) {
- const ASTTemplateArgumentListInfo *ArgList =
- FD->getTemplateSpecializationArgsAsWritten();
- TemplateArgs.append(ArgList->getTemplateArgs(),
- ArgList->getTemplateArgs() +
- ArgList->NumTemplateArgs);
- } else {
- const TemplateArgumentList *ArgList =
- FD->getTemplateSpecializationArgs();
- TemplateArgumentListInfo LI;
- for (unsigned i = 0, e = ArgList->size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i),
- FD->getTypeSourceInfo()));
- }
- return TD;
- }
- }
-
- // Check if we have a class template.
- if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- TypeSourceInfo *TSI = Spec->getTypeAsWritten();
- if (TSI) {
- TemplateSpecializationTypeLoc TSTL =
- cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
- TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
- for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
- TemplateArgs.push_back(TSTL.getArgLoc(i));
- } else {
- TemplateArgumentListInfo LI;
- const TemplateArgumentList &ArgList =
- Spec->getTemplateArgs();
- for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i],
- TemplateArgumentLocInfo()));
- }
- return Spec->getSpecializedTemplate();
- }
-
- return 0;
-}
-
-void
-MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
- DeclarationName Name) {
- // <unqualified-name> ::= <operator-name>
- // ::= <ctor-dtor-name>
- // ::= <source-name>
- // ::= <template-name>
- SmallVector<TemplateArgumentLoc, 2> TemplateArgs;
- // Check if we have a template.
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- // We have a template.
- // Here comes the tricky thing: if we need to mangle something like
- // void foo(A::X<Y>, B::X<Y>),
- // the X<Y> part is aliased. However, if you need to mangle
- // void foo(A::X<A::Y>, A::X<B::Y>),
- // the A::X<> part is not aliased.
- // That said, from the mangler's perspective we have a structure like this:
- // namespace[s] -> type[ -> template-parameters]
- // but from the Clang perspective we have
- // type [ -> template-parameters]
- // \-> namespace[s]
- // What we do is we create a new mangler, mangle the same type (without
- // a namespace suffix) using the extra mangler with back references
- // disabled (to avoid infinite recursion) and then use the mangled type
- // name as a key to check the mangling of different types for aliasing.
-
- std::string BackReferenceKey;
- BackRefMap::iterator Found;
- if (UseNameBackReferences) {
- llvm::raw_string_ostream Stream(BackReferenceKey);
- MicrosoftCXXNameMangler Extra(Context, Stream);
- Extra.disableBackReferences();
- Extra.mangleUnqualifiedName(ND, Name);
- Stream.flush();
-
- Found = NameBackReferences.find(BackReferenceKey);
- }
- if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- mangleTemplateInstantiationName(TD, TemplateArgs);
- if (UseNameBackReferences && NameBackReferences.size() < 10) {
- size_t Size = NameBackReferences.size();
- NameBackReferences[BackReferenceKey] = Size;
- }
- } else {
- Out << Found->second;
- }
- return;
- }
-
- switch (Name.getNameKind()) {
- case DeclarationName::Identifier: {
- if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- mangleSourceName(II);
- break;
- }
-
- // Otherwise, an anonymous entity. We must have a declaration.
- assert(ND && "mangling empty name without declaration");
-
- if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
- if (NS->isAnonymousNamespace()) {
- Out << "?A@";
- break;
- }
- }
-
- // We must have an anonymous struct.
- const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
- assert(TD->getDeclContext() == D->getDeclContext() &&
- "Typedef should not be in another decl context!");
- assert(D->getDeclName().getAsIdentifierInfo() &&
- "Typedef was not named!");
- mangleSourceName(D->getDeclName().getAsIdentifierInfo());
- break;
- }
-
- // When VC encounters an anonymous type with no tag and no typedef,
- // it literally emits '<unnamed-tag>'.
- Out << "<unnamed-tag>";
- break;
- }
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- llvm_unreachable("Can't mangle Objective-C selector names here!");
-
- case DeclarationName::CXXConstructorName:
- Out << "?0";
- break;
-
- case DeclarationName::CXXDestructorName:
- Out << "?1";
- break;
-
- case DeclarationName::CXXConversionFunctionName:
- // <operator-name> ::= ?B # (cast)
- // The target type is encoded as the return type.
- Out << "?B";
- break;
-
- case DeclarationName::CXXOperatorName:
- mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation());
- break;
-
- case DeclarationName::CXXLiteralOperatorName: {
- // FIXME: Was this added in VS2010? Does MS even know how to mangle this?
- DiagnosticsEngine Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this literal operator yet");
- Diags.Report(ND->getLocation(), DiagID);
- break;
- }
-
- case DeclarationName::CXXUsingDirective:
- llvm_unreachable("Can't mangle a using directive name!");
- }
-}
-
-void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
- bool NoFunction) {
- // <postfix> ::= <unqualified-name> [<postfix>]
- // ::= <substitution> [<postfix>]
-
- if (!DC) return;
-
- while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
-
- if (DC->isTranslationUnit())
- return;
-
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- Context.mangleBlock(BD, Out);
- Out << '@';
- return manglePostfix(DC->getParent(), NoFunction);
- }
-
- if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
- return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
- mangleObjCMethodName(Method);
- else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC))
- mangleLocalName(Func);
- else {
- mangleUnqualifiedName(cast<NamedDecl>(DC));
- manglePostfix(DC->getParent(), NoFunction);
- }
-}
-
-void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
- SourceLocation Loc) {
- switch (OO) {
- // ?0 # constructor
- // ?1 # destructor
- // <operator-name> ::= ?2 # new
- case OO_New: Out << "?2"; break;
- // <operator-name> ::= ?3 # delete
- case OO_Delete: Out << "?3"; break;
- // <operator-name> ::= ?4 # =
- case OO_Equal: Out << "?4"; break;
- // <operator-name> ::= ?5 # >>
- case OO_GreaterGreater: Out << "?5"; break;
- // <operator-name> ::= ?6 # <<
- case OO_LessLess: Out << "?6"; break;
- // <operator-name> ::= ?7 # !
- case OO_Exclaim: Out << "?7"; break;
- // <operator-name> ::= ?8 # ==
- case OO_EqualEqual: Out << "?8"; break;
- // <operator-name> ::= ?9 # !=
- case OO_ExclaimEqual: Out << "?9"; break;
- // <operator-name> ::= ?A # []
- case OO_Subscript: Out << "?A"; break;
- // ?B # conversion
- // <operator-name> ::= ?C # ->
- case OO_Arrow: Out << "?C"; break;
- // <operator-name> ::= ?D # *
- case OO_Star: Out << "?D"; break;
- // <operator-name> ::= ?E # ++
- case OO_PlusPlus: Out << "?E"; break;
- // <operator-name> ::= ?F # --
- case OO_MinusMinus: Out << "?F"; break;
- // <operator-name> ::= ?G # -
- case OO_Minus: Out << "?G"; break;
- // <operator-name> ::= ?H # +
- case OO_Plus: Out << "?H"; break;
- // <operator-name> ::= ?I # &
- case OO_Amp: Out << "?I"; break;
- // <operator-name> ::= ?J # ->*
- case OO_ArrowStar: Out << "?J"; break;
- // <operator-name> ::= ?K # /
- case OO_Slash: Out << "?K"; break;
- // <operator-name> ::= ?L # %
- case OO_Percent: Out << "?L"; break;
- // <operator-name> ::= ?M # <
- case OO_Less: Out << "?M"; break;
- // <operator-name> ::= ?N # <=
- case OO_LessEqual: Out << "?N"; break;
- // <operator-name> ::= ?O # >
- case OO_Greater: Out << "?O"; break;
- // <operator-name> ::= ?P # >=
- case OO_GreaterEqual: Out << "?P"; break;
- // <operator-name> ::= ?Q # ,
- case OO_Comma: Out << "?Q"; break;
- // <operator-name> ::= ?R # ()
- case OO_Call: Out << "?R"; break;
- // <operator-name> ::= ?S # ~
- case OO_Tilde: Out << "?S"; break;
- // <operator-name> ::= ?T # ^
- case OO_Caret: Out << "?T"; break;
- // <operator-name> ::= ?U # |
- case OO_Pipe: Out << "?U"; break;
- // <operator-name> ::= ?V # &&
- case OO_AmpAmp: Out << "?V"; break;
- // <operator-name> ::= ?W # ||
- case OO_PipePipe: Out << "?W"; break;
- // <operator-name> ::= ?X # *=
- case OO_StarEqual: Out << "?X"; break;
- // <operator-name> ::= ?Y # +=
- case OO_PlusEqual: Out << "?Y"; break;
- // <operator-name> ::= ?Z # -=
- case OO_MinusEqual: Out << "?Z"; break;
- // <operator-name> ::= ?_0 # /=
- case OO_SlashEqual: Out << "?_0"; break;
- // <operator-name> ::= ?_1 # %=
- case OO_PercentEqual: Out << "?_1"; break;
- // <operator-name> ::= ?_2 # >>=
- case OO_GreaterGreaterEqual: Out << "?_2"; break;
- // <operator-name> ::= ?_3 # <<=
- case OO_LessLessEqual: Out << "?_3"; break;
- // <operator-name> ::= ?_4 # &=
- case OO_AmpEqual: Out << "?_4"; break;
- // <operator-name> ::= ?_5 # |=
- case OO_PipeEqual: Out << "?_5"; break;
- // <operator-name> ::= ?_6 # ^=
- case OO_CaretEqual: Out << "?_6"; break;
- // ?_7 # vftable
- // ?_8 # vbtable
- // ?_9 # vcall
- // ?_A # typeof
- // ?_B # local static guard
- // ?_C # string
- // ?_D # vbase destructor
- // ?_E # vector deleting destructor
- // ?_F # default constructor closure
- // ?_G # scalar deleting destructor
- // ?_H # vector constructor iterator
- // ?_I # vector destructor iterator
- // ?_J # vector vbase constructor iterator
- // ?_K # virtual displacement map
- // ?_L # eh vector constructor iterator
- // ?_M # eh vector destructor iterator
- // ?_N # eh vector vbase constructor iterator
- // ?_O # copy constructor closure
- // ?_P<name> # udt returning <name>
- // ?_Q # <unknown>
- // ?_R0 # RTTI Type Descriptor
- // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)
- // ?_R2 # RTTI Base Class Array
- // ?_R3 # RTTI Class Hierarchy Descriptor
- // ?_R4 # RTTI Complete Object Locator
- // ?_S # local vftable
- // ?_T # local vftable constructor closure
- // <operator-name> ::= ?_U # new[]
- case OO_Array_New: Out << "?_U"; break;
- // <operator-name> ::= ?_V # delete[]
- case OO_Array_Delete: Out << "?_V"; break;
-
- case OO_Conditional: {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this conditional operator yet");
- Diags.Report(Loc, DiagID);
- break;
- }
-
- case OO_None:
- case NUM_OVERLOADED_OPERATORS:
- llvm_unreachable("Not an overloaded operator");
- }
-}
-
-void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
- // <source name> ::= <identifier> @
- std::string key = II->getNameStart();
- BackRefMap::iterator Found;
- if (UseNameBackReferences)
- Found = NameBackReferences.find(key);
- if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- Out << II->getName() << '@';
- if (UseNameBackReferences && NameBackReferences.size() < 10) {
- size_t Size = NameBackReferences.size();
- NameBackReferences[key] = Size;
- }
- } else {
- Out << Found->second;
- }
-}
-
-void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
- Context.mangleObjCMethodName(MD, Out);
-}
-
-// Find out how many function decls live above this one and return an integer
-// suitable for use as the number in a numbered anonymous scope.
-// TODO: Memoize.
-static unsigned getLocalNestingLevel(const FunctionDecl *FD) {
- const DeclContext *DC = FD->getParent();
- int level = 1;
-
- while (DC && !DC->isTranslationUnit()) {
- if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++;
- DC = DC->getParent();
- }
-
- return 2*level;
-}
-
-void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
- // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name>
- // <numbered-anonymous-scope> ::= ? <number>
- // Even though the name is rendered in reverse order (e.g.
- // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to
- // innermost. So a method bar in class C local to function foo gets mangled
- // as something like:
- // ?bar@C@?1??foo@@YAXXZ@QAEXXZ
- // This is more apparent when you have a type nested inside a method of a
- // type nested inside a function. A method baz in class D local to method
- // bar of class C local to function foo gets mangled as:
- // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ
- // This scheme is general enough to support GCC-style nested
- // functions. You could have a method baz of class C inside a function bar
- // inside a function foo, like so:
- // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
- int NestLevel = getLocalNestingLevel(FD);
- Out << '?';
- mangleNumber(NestLevel);
- Out << '?';
- mangle(FD, "?");
-}
-
-void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
- const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
- // <template-name> ::= <unscoped-template-name> <template-args>
- // ::= <substitution>
- // Always start with the unqualified name.
-
- // Templates have their own context for back references.
- ArgBackRefMap OuterArgsContext;
- BackRefMap OuterTemplateContext;
- NameBackReferences.swap(OuterTemplateContext);
- TypeBackReferences.swap(OuterArgsContext);
-
- mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs);
-
- // Restore the previous back reference contexts.
- NameBackReferences.swap(OuterTemplateContext);
- TypeBackReferences.swap(OuterArgsContext);
-}
-
-void
-MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
- // <unscoped-template-name> ::= ?$ <unqualified-name>
- Out << "?$";
- mangleUnqualifiedName(TD);
-}
-
-void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
- bool IsBoolean) {
- // <integer-literal> ::= $0 <number>
- Out << "$0";
- // Make sure booleans are encoded as 0/1.
- if (IsBoolean && Value.getBoolValue())
- mangleNumber(1);
- else
- mangleNumber(Value);
-}
-
-void
-MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
- // See if this is a constant expression.
- llvm::APSInt Value;
- if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(Value, E->getType()->isBooleanType());
- return;
- }
-
- // As bad as this diagnostic is, it's better than crashing.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet mangle expression type %0");
- Diags.Report(E->getExprLoc(), DiagID)
- << E->getStmtClassName() << E->getSourceRange();
-}
-
-void
-MicrosoftCXXNameMangler::mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
- // <template-args> ::= {<type> | <integer-literal>}+ @
- unsigned NumTemplateArgs = TemplateArgs.size();
- for (unsigned i = 0; i < NumTemplateArgs; ++i) {
- const TemplateArgumentLoc &TAL = TemplateArgs[i];
- const TemplateArgument &TA = TAL.getArgument();
- switch (TA.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("Can't mangle null template arguments!");
- case TemplateArgument::Type:
- mangleType(TA.getAsType(), TAL.getSourceRange());
- break;
- case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getAsIntegral(),
- TA.getIntegralType()->isBooleanType());
- break;
- case TemplateArgument::Expression:
- mangleExpression(TA.getAsExpr());
- break;
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Pack: {
- // Issue a diagnostic.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
- "integral|template|template pack expansion|ERROR|parameter pack}0 "
- "template argument yet");
- Diags.Report(TAL.getLocation(), DiagID)
- << TA.getKind()
- << TAL.getSourceRange();
- }
- }
- }
- Out << '@';
-}
-
-void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
- bool IsMember) {
- // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
- // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only);
- // 'I' means __restrict (32/64-bit).
- // Note that the MSVC __restrict keyword isn't the same as the C99 restrict
- // keyword!
- // <base-cvr-qualifiers> ::= A # near
- // ::= B # near const
- // ::= C # near volatile
- // ::= D # near const volatile
- // ::= E # far (16-bit)
- // ::= F # far const (16-bit)
- // ::= G # far volatile (16-bit)
- // ::= H # far const volatile (16-bit)
- // ::= I # huge (16-bit)
- // ::= J # huge const (16-bit)
- // ::= K # huge volatile (16-bit)
- // ::= L # huge const volatile (16-bit)
- // ::= M <basis> # based
- // ::= N <basis> # based const
- // ::= O <basis> # based volatile
- // ::= P <basis> # based const volatile
- // ::= Q # near member
- // ::= R # near const member
- // ::= S # near volatile member
- // ::= T # near const volatile member
- // ::= U # far member (16-bit)
- // ::= V # far const member (16-bit)
- // ::= W # far volatile member (16-bit)
- // ::= X # far const volatile member (16-bit)
- // ::= Y # huge member (16-bit)
- // ::= Z # huge const member (16-bit)
- // ::= 0 # huge volatile member (16-bit)
- // ::= 1 # huge const volatile member (16-bit)
- // ::= 2 <basis> # based member
- // ::= 3 <basis> # based const member
- // ::= 4 <basis> # based volatile member
- // ::= 5 <basis> # based const volatile member
- // ::= 6 # near function (pointers only)
- // ::= 7 # far function (pointers only)
- // ::= 8 # near method (pointers only)
- // ::= 9 # far method (pointers only)
- // ::= _A <basis> # based function (pointers only)
- // ::= _B <basis> # based function (far?) (pointers only)
- // ::= _C <basis> # based method (pointers only)
- // ::= _D <basis> # based method (far?) (pointers only)
- // ::= _E # block (Clang)
- // <basis> ::= 0 # __based(void)
- // ::= 1 # __based(segment)?
- // ::= 2 <name> # __based(name)
- // ::= 3 # ?
- // ::= 4 # ?
- // ::= 5 # not really based
- bool HasConst = Quals.hasConst(),
- HasVolatile = Quals.hasVolatile();
- if (!IsMember) {
- if (HasConst && HasVolatile) {
- Out << 'D';
- } else if (HasVolatile) {
- Out << 'C';
- } else if (HasConst) {
- Out << 'B';
- } else {
- Out << 'A';
- }
- } else {
- if (HasConst && HasVolatile) {
- Out << 'T';
- } else if (HasVolatile) {
- Out << 'S';
- } else if (HasConst) {
- Out << 'R';
- } else {
- Out << 'Q';
- }
- }
-
- // FIXME: For now, just drop all extension qualifiers on the floor.
-}
-
-void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
- // <pointer-cvr-qualifiers> ::= P # no qualifiers
- // ::= Q # const
- // ::= R # volatile
- // ::= S # const volatile
- bool HasConst = Quals.hasConst(),
- HasVolatile = Quals.hasVolatile();
- if (HasConst && HasVolatile) {
- Out << 'S';
- } else if (HasVolatile) {
- Out << 'R';
- } else if (HasConst) {
- Out << 'Q';
- } else {
- Out << 'P';
- }
-}
-
-void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
- SourceRange Range) {
- void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
- ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
-
- if (Found == TypeBackReferences.end()) {
- size_t OutSizeBefore = Out.GetNumBytesInBuffer();
-
- mangleType(T, Range, false);
-
- // See if it's worth creating a back reference.
- // Only types longer than 1 character are considered
- // and only 10 back references slots are available:
- bool LongerThanOneChar = (Out.GetNumBytesInBuffer() - OutSizeBefore > 1);
- if (LongerThanOneChar && TypeBackReferences.size() < 10) {
- size_t Size = TypeBackReferences.size();
- TypeBackReferences[TypePtr] = Size;
- }
- } else {
- Out << Found->second;
- }
-}
-
-void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
- bool MangleQualifiers) {
- // Only operate on the canonical type!
- T = getASTContext().getCanonicalType(T);
-
- Qualifiers Quals = T.getLocalQualifiers();
- // We have to mangle these now, while we still have enough information.
- if (T->isAnyPointerType() || T->isMemberPointerType() ||
- T->isBlockPointerType()) {
- manglePointerQualifiers(Quals);
- } else if (Quals && MangleQualifiers) {
- mangleQualifiers(Quals, false);
- }
-
- SplitQualType split = T.split();
- const Type *ty = split.Ty;
-
- // If we're mangling a qualified array type, push the qualifiers to
- // the element type.
- if (split.Quals && isa<ArrayType>(T)) {
- ty = Context.getASTContext().getAsArrayType(T);
- }
-
- switch (ty->getTypeClass()) {
-#define ABSTRACT_TYPE(CLASS, PARENT)
-#define NON_CANONICAL_TYPE(CLASS, PARENT) \
- case Type::CLASS: \
- llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
- return;
-#define TYPE(CLASS, PARENT) \
- case Type::CLASS: \
- mangleType(cast<CLASS##Type>(ty), Range); \
- break;
-#include "clang/AST/TypeNodes.def"
-#undef ABSTRACT_TYPE
-#undef NON_CANONICAL_TYPE
-#undef TYPE
- }
-}
-
-void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
- SourceRange Range) {
- // <type> ::= <builtin-type>
- // <builtin-type> ::= X # void
- // ::= C # signed char
- // ::= D # char
- // ::= E # unsigned char
- // ::= F # short
- // ::= G # unsigned short (or wchar_t if it's not a builtin)
- // ::= H # int
- // ::= I # unsigned int
- // ::= J # long
- // ::= K # unsigned long
- // L # <none>
- // ::= M # float
- // ::= N # double
- // ::= O # long double (__float80 is mangled differently)
- // ::= _J # long long, __int64
- // ::= _K # unsigned long long, __int64
- // ::= _L # __int128
- // ::= _M # unsigned __int128
- // ::= _N # bool
- // _O # <array in parameter>
- // ::= _T # __float80 (Intel)
- // ::= _W # wchar_t
- // ::= _Z # __float80 (Digital Mars)
- switch (T->getKind()) {
- case BuiltinType::Void: Out << 'X'; break;
- case BuiltinType::SChar: Out << 'C'; break;
- case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break;
- case BuiltinType::UChar: Out << 'E'; break;
- case BuiltinType::Short: Out << 'F'; break;
- case BuiltinType::UShort: Out << 'G'; break;
- case BuiltinType::Int: Out << 'H'; break;
- case BuiltinType::UInt: Out << 'I'; break;
- case BuiltinType::Long: Out << 'J'; break;
- case BuiltinType::ULong: Out << 'K'; break;
- case BuiltinType::Float: Out << 'M'; break;
- case BuiltinType::Double: Out << 'N'; break;
- // TODO: Determine size and mangle accordingly
- case BuiltinType::LongDouble: Out << 'O'; break;
- case BuiltinType::LongLong: Out << "_J"; break;
- case BuiltinType::ULongLong: Out << "_K"; break;
- case BuiltinType::Int128: Out << "_L"; break;
- case BuiltinType::UInt128: Out << "_M"; break;
- case BuiltinType::Bool: Out << "_N"; break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U: Out << "_W"; break;
-
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
- llvm_unreachable("placeholder types shouldn't get to name mangling");
-
- case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
- case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
- case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
-
- case BuiltinType::OCLImage1d: Out << "PAUocl_image1d@@"; break;
- case BuiltinType::OCLImage1dArray: Out << "PAUocl_image1darray@@"; break;
- case BuiltinType::OCLImage1dBuffer: Out << "PAUocl_image1dbuffer@@"; break;
- case BuiltinType::OCLImage2d: Out << "PAUocl_image2d@@"; break;
- case BuiltinType::OCLImage2dArray: Out << "PAUocl_image2darray@@"; break;
- case BuiltinType::OCLImage3d: Out << "PAUocl_image3d@@"; break;
-
- case BuiltinType::NullPtr: Out << "$$T"; break;
-
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Half: {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this built-in %0 type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << T->getName(Context.getASTContext().getPrintingPolicy())
- << Range;
- break;
- }
- }
-}
-
-// <type> ::= <function-type>
-void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
- SourceRange) {
- // Structors only appear in decls, so at this point we know it's not a
- // structor type.
- // FIXME: This may not be lambda-friendly.
- Out << "$$A6";
- mangleType(T, NULL, false, false);
-}
-void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
- SourceRange) {
- llvm_unreachable("Can't mangle K&R function prototypes");
-}
-
-void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
- const FunctionDecl *D,
- bool IsStructor,
- bool IsInstMethod) {
- // <function-type> ::= <this-cvr-qualifiers> <calling-convention>
- // <return-type> <argument-list> <throw-spec>
- const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
-
- // If this is a C++ instance method, mangle the CVR qualifiers for the
- // this pointer.
- if (IsInstMethod)
- mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
-
- mangleCallingConvention(T, IsInstMethod);
-
- // <return-type> ::= <type>
- // ::= @ # structors (they have no declared return type)
- if (IsStructor)
- Out << '@';
- else {
- QualType Result = Proto->getResultType();
- const Type* RT = Result.getTypePtr();
- if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
- if (Result.hasQualifiers() || !RT->isBuiltinType())
- Out << '?';
- if (!RT->isBuiltinType() && !Result.hasQualifiers()) {
- // Lack of qualifiers for user types is mangled as 'A'.
- Out << 'A';
- }
- }
-
- // FIXME: Get the source range for the result type. Or, better yet,
- // implement the unimplemented stuff so we don't need accurate source
- // location info anymore :).
- mangleType(Result, SourceRange());
- }
-
- // <argument-list> ::= X # void
- // ::= <type>+ @
- // ::= <type>* Z # varargs
- if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
- Out << 'X';
- } else {
- if (D) {
- // If we got a decl, use the type-as-written to make sure arrays
- // get mangled right. Note that we can't rely on the TSI
- // existing if (for example) the parameter was synthesized.
- for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
- ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
- TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
- QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
- mangleArgumentType(Type, (*Parm)->getSourceRange());
- }
- } else {
- // Happens for function pointer type arguments for example.
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleArgumentType(*Arg, SourceRange());
- }
- // <builtin-type> ::= Z # ellipsis
- if (Proto->isVariadic())
- Out << 'Z';
- else
- Out << '@';
- }
-
- mangleThrowSpecification(Proto);
-}
-
-void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
- // <function-class> ::= A # private: near
- // ::= B # private: far
- // ::= C # private: static near
- // ::= D # private: static far
- // ::= E # private: virtual near
- // ::= F # private: virtual far
- // ::= G # private: thunk near
- // ::= H # private: thunk far
- // ::= I # protected: near
- // ::= J # protected: far
- // ::= K # protected: static near
- // ::= L # protected: static far
- // ::= M # protected: virtual near
- // ::= N # protected: virtual far
- // ::= O # protected: thunk near
- // ::= P # protected: thunk far
- // ::= Q # public: near
- // ::= R # public: far
- // ::= S # public: static near
- // ::= T # public: static far
- // ::= U # public: virtual near
- // ::= V # public: virtual far
- // ::= W # public: thunk near
- // ::= X # public: thunk far
- // ::= Y # global near
- // ::= Z # global far
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- switch (MD->getAccess()) {
- default:
- case AS_private:
- if (MD->isStatic())
- Out << 'C';
- else if (MD->isVirtual())
- Out << 'E';
- else
- Out << 'A';
- break;
- case AS_protected:
- if (MD->isStatic())
- Out << 'K';
- else if (MD->isVirtual())
- Out << 'M';
- else
- Out << 'I';
- break;
- case AS_public:
- if (MD->isStatic())
- Out << 'S';
- else if (MD->isVirtual())
- Out << 'U';
- else
- Out << 'Q';
- }
- } else
- Out << 'Y';
-}
-void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
- bool IsInstMethod) {
- // <calling-convention> ::= A # __cdecl
- // ::= B # __export __cdecl
- // ::= C # __pascal
- // ::= D # __export __pascal
- // ::= E # __thiscall
- // ::= F # __export __thiscall
- // ::= G # __stdcall
- // ::= H # __export __stdcall
- // ::= I # __fastcall
- // ::= J # __export __fastcall
- // The 'export' calling conventions are from a bygone era
- // (*cough*Win16*cough*) when functions were declared for export with
- // that keyword. (It didn't actually export them, it just made them so
- // that they could be in a DLL and somebody from another module could call
- // them.)
- CallingConv CC = T->getCallConv();
- if (CC == CC_Default) {
- if (IsInstMethod) {
- const FunctionProtoType *FPT =
- T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
- bool isVariadic = FPT->isVariadic();
- CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
- } else {
- CC = CC_C;
- }
- }
- switch (CC) {
- default:
- llvm_unreachable("Unsupported CC for mangling");
- case CC_Default:
- case CC_C: Out << 'A'; break;
- case CC_X86Pascal: Out << 'C'; break;
- case CC_X86ThisCall: Out << 'E'; break;
- case CC_X86StdCall: Out << 'G'; break;
- case CC_X86FastCall: Out << 'I'; break;
- }
-}
-void MicrosoftCXXNameMangler::mangleThrowSpecification(
- const FunctionProtoType *FT) {
- // <throw-spec> ::= Z # throw(...) (default)
- // ::= @ # throw() or __declspec/__attribute__((nothrow))
- // ::= <type>+
- // NOTE: Since the Microsoft compiler ignores throw specifications, they are
- // all actually mangled as 'Z'. (They're ignored because their associated
- // functionality isn't implemented, and probably never will be.)
- Out << 'Z';
-}
-
-void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
- SourceRange Range) {
- // Probably should be mangled as a template instantiation; need to see what
- // VC does first.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this unresolved dependent type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type>
-// <union-type> ::= T <name>
-// <struct-type> ::= U <name>
-// <class-type> ::= V <name>
-// <enum-type> ::= W <size> <name>
-void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
- mangleType(cast<TagType>(T));
-}
-void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
- mangleType(cast<TagType>(T));
-}
-void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
- switch (T->getDecl()->getTagKind()) {
- case TTK_Union:
- Out << 'T';
- break;
- case TTK_Struct:
- case TTK_Interface:
- Out << 'U';
- break;
- case TTK_Class:
- Out << 'V';
- break;
- case TTK_Enum:
- Out << 'W';
- Out << getASTContext().getTypeSizeInChars(
- cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity();
- break;
- }
- mangleName(T->getDecl());
-}
-
-// <type> ::= <array-type>
-// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
-// [Y <dimension-count> <dimension>+]
-// <element-type> # as global
-// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as param
-// It's supposed to be the other way around, but for some strange reason, it
-// isn't. Today this behavior is retained for the sole purpose of backwards
-// compatibility.
-void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) {
- // This isn't a recursive mangling, so now we have to do it all in this
- // one call.
- if (IsGlobal) {
- manglePointerQualifiers(T->getElementType().getQualifiers());
- } else {
- Out << 'Q';
- }
- mangleExtraDimensions(T->getElementType());
-}
-void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
- SourceRange) {
- mangleType(cast<ArrayType>(T), false);
-}
-void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T,
- SourceRange) {
- mangleType(cast<ArrayType>(T), false);
-}
-void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T,
- SourceRange) {
- mangleType(cast<ArrayType>(T), false);
-}
-void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
- SourceRange) {
- mangleType(cast<ArrayType>(T), false);
-}
-void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
- SmallVector<llvm::APInt, 3> Dimensions;
- for (;;) {
- if (const ConstantArrayType *CAT =
- getASTContext().getAsConstantArrayType(ElementTy)) {
- Dimensions.push_back(CAT->getSize());
- ElementTy = CAT->getElementType();
- } else if (ElementTy->isVariableArrayType()) {
- const VariableArrayType *VAT =
- getASTContext().getAsVariableArrayType(ElementTy);
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this variable-length array yet");
- Diags.Report(VAT->getSizeExpr()->getExprLoc(), DiagID)
- << VAT->getBracketsRange();
- return;
- } else if (ElementTy->isDependentSizedArrayType()) {
- // The dependent expression has to be folded into a constant (TODO).
- const DependentSizedArrayType *DSAT =
- getASTContext().getAsDependentSizedArrayType(ElementTy);
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this dependent-length array yet");
- Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID)
- << DSAT->getBracketsRange();
- return;
- } else if (ElementTy->isIncompleteArrayType()) continue;
- else break;
- }
- mangleQualifiers(ElementTy.getQualifiers(), false);
- // If there are any additional dimensions, mangle them now.
- if (Dimensions.size() > 0) {
- Out << 'Y';
- // <dimension-count> ::= <number> # number of extra dimensions
- mangleNumber(Dimensions.size());
- for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) {
- mangleNumber(Dimensions[Dim].getLimitedValue());
- }
- }
- mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange());
-}
-
-// <type> ::= <pointer-to-member-type>
-// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
-// <class name> <type>
-void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
- SourceRange Range) {
- QualType PointeeType = T->getPointeeType();
- if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
- Out << '8';
- mangleName(T->getClass()->castAs<RecordType>()->getDecl());
- mangleType(FPT, NULL, false, true);
- } else {
- mangleQualifiers(PointeeType.getQualifiers(), true);
- mangleName(T->getClass()->castAs<RecordType>()->getDecl());
- mangleType(PointeeType.getLocalUnqualifiedType(), Range);
- }
-}
-
-void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this template type parameter type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(
- const SubstTemplateTypeParmPackType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this substituted parameter pack yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-// <type> ::= <pointer-type>
-// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
-void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
- SourceRange Range) {
- QualType PointeeTy = T->getPointeeType();
- if (PointeeTy->isArrayType()) {
- // Pointers to arrays are mangled like arrays.
- mangleExtraDimensions(PointeeTy);
- } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) {
- // Function pointers are special.
- Out << '6';
- mangleType(FT, NULL, false, false);
- } else {
- mangleQualifiers(PointeeTy.getQualifiers(), false);
- mangleType(PointeeTy, Range, false);
- }
-}
-void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
- SourceRange Range) {
- // Object pointers never have qualifiers.
- Out << 'A';
- mangleType(T->getPointeeType(), Range);
-}
-
-// <type> ::= <reference-type>
-// <reference-type> ::= A <cvr-qualifiers> <type>
-void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
- SourceRange Range) {
- Out << 'A';
- QualType PointeeTy = T->getPointeeType();
- if (!PointeeTy.hasQualifiers())
- // Lack of qualifiers is mangled as 'A'.
- Out << 'A';
- mangleType(PointeeTy, Range);
-}
-
-// <type> ::= <r-value-reference-type>
-// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type>
-void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
- SourceRange Range) {
- Out << "$$Q";
- QualType PointeeTy = T->getPointeeType();
- if (!PointeeTy.hasQualifiers())
- // Lack of qualifiers is mangled as 'A'.
- Out << 'A';
- mangleType(PointeeTy, Range);
-}
-
-void MicrosoftCXXNameMangler::mangleType(const ComplexType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this complex number type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const VectorType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this extended vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this dependent-sized extended vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T,
- SourceRange) {
- // ObjC interfaces have structs underlying them.
- Out << 'U';
- mangleName(T->getDecl());
-}
-
-void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
- SourceRange Range) {
- // We don't allow overloading by different protocol qualification,
- // so mangling them isn't necessary.
- mangleType(T->getBaseType(), Range);
-}
-
-void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
- SourceRange Range) {
- Out << "_E";
-
- QualType pointee = T->getPointeeType();
- mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
-}
-
-void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this injected class name type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this template specialization type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this dependent name type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(
- const DependentTemplateSpecializationType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this dependent template specialization type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this pack expansion yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this typeof(type) yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this typeof(expression) yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this decltype() yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this unary transform type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this 'auto' type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftCXXNameMangler::mangleType(const AtomicType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this C11 atomic type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
-}
-
-void MicrosoftMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
- assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
- "Invalid mangleName() call, argument is not a variable or function!");
- assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
- "Invalid mangleName() call on 'structor decl!");
-
- PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
- getASTContext().getSourceManager(),
- "Mangling declaration");
-
- MicrosoftCXXNameMangler Mangler(*this, Out);
- return Mangler.mangle(D);
-}
-void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this method yet");
- getDiags().Report(MD->getLocation(), DiagID);
-}
-void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this destructor yet");
- getDiags().Report(DD->getLocation(), DiagID);
-}
-void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &Out) {
- // <mangled-name> ::= ? <operator-name> <class-name> <storage-class>
- // <cvr-qualifiers> [<name>] @
- // <operator-name> ::= _7 # vftable
- // ::= _8 # vbtable
- // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
- // is always '6' for vftables and '7' for vbtables. (The difference is
- // beyond me.)
- // TODO: vbtables.
- MicrosoftCXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "\01??_7";
- Mangler.mangleName(RD);
- Mangler.getStream() << "6B";
- // TODO: If the class has more than one vtable, mangle in the class it came
- // from.
- Mangler.getStream() << '@';
-}
-void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have virtual table tables!");
-}
-void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
-}
-void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
- raw_ostream &) {
- // FIXME: Give a location...
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle RTTI descriptors for type %0 yet");
- getDiags().Report(DiagID)
- << T.getBaseTypeIdentifier();
-}
-void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
- raw_ostream &) {
- // FIXME: Give a location...
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle the name of type %0 into RTTI descriptors yet");
- getDiags().Report(DiagID)
- << T.getBaseTypeIdentifier();
-}
-void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream & Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
- mangler.mangle(D);
-}
-void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream & Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
- mangler.mangle(D);
-}
-void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this reference temporary yet");
- getDiags().Report(VD->getLocation(), DiagID);
-}
-
-MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new MicrosoftMangleContext(Context, Diags);
-}
+//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ name mangling targeting the Microsoft Visual C++ ABI. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/DiagnosticOptions.h" +#include <map> + +using namespace clang; + +namespace { + +/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the +/// Microsoft Visual C++ ABI. +class MicrosoftCXXNameMangler { + MangleContext &Context; + raw_ostream &Out; + + // FIXME: audit the performance of BackRefMap as it might do way too many + // copying of strings. + typedef std::map<std::string, unsigned> BackRefMap; + BackRefMap NameBackReferences; + bool UseNameBackReferences; + + typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap; + ArgBackRefMap TypeBackReferences; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) + : Context(C), Out(Out_), UseNameBackReferences(true) { } + + raw_ostream &getStream() const { return Out; } + + void mangle(const NamedDecl *D, StringRef Prefix = "\01?"); + void mangleName(const NamedDecl *ND); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleVariableEncoding(const VarDecl *VD); + void mangleNumber(int64_t Number); + void mangleNumber(const llvm::APSInt &Value); + void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); + +private: + void disableBackReferences() { UseNameBackReferences = false; } + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName()); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); + void mangleSourceName(const IdentifierInfo *II); + void manglePostfix(const DeclContext *DC, bool NoFunction=false); + void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); + void mangleQualifiers(Qualifiers Quals, bool IsMember); + void manglePointerQualifiers(Qualifiers Quals); + + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleTemplateInstantiationName(const TemplateDecl *TD, + const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + void mangleObjCMethodName(const ObjCMethodDecl *MD); + void mangleLocalName(const FunctionDecl *FD); + + void mangleArgumentType(QualType T, SourceRange Range); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \ + SourceRange Range); +#include "clang/AST/TypeNodes.def" +#undef ABSTRACT_TYPE +#undef NON_CANONICAL_TYPE +#undef TYPE + + void mangleType(const TagType*); + void mangleType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleType(const ArrayType *T, bool IsGlobal); + void mangleExtraDimensions(QualType T); + void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); + void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); + void mangleExpression(const Expr *E); + void mangleThrowSpecification(const FunctionProtoType *T); + + void mangleTemplateArgs( + const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + +}; + +/// MicrosoftMangleContext - Overrides the default MangleContext for the +/// Microsoft Visual C++ ABI. +class MicrosoftMangleContext : public MangleContext { +public: + MicrosoftMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { } + virtual bool shouldMangleDeclName(const NamedDecl *D); + virtual void mangleName(const NamedDecl *D, raw_ostream &Out); + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &); + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &); + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + raw_ostream &); + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + raw_ostream &); + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &); + virtual void mangleCXXRTTI(QualType T, raw_ostream &); + virtual void mangleCXXRTTIName(QualType T, raw_ostream &); + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + raw_ostream &); + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + raw_ostream &); + virtual void mangleReferenceTemporary(const clang::VarDecl *, + raw_ostream &); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = D->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOpts().CPlusPlus) + return false; + + // Variables at global scope with internal linkage are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, + StringRef Prefix) { + // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. + // Therefore it's really important that we don't decorate the + // name with leading underscores or leading/trailing at signs. So, by + // default, we emit an asm marker at the start so we get the name right. + // Callers can override this with a custom prefix. + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + Out << '\01' << ALA->getLabel(); + return; + } + + // <mangled-name> ::= ? <name> <type-encoding> + Out << Prefix; + mangleName(D); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleVariableEncoding(VD); + else { + // TODO: Fields? Can MSVC even mangle them? + // Issue a diagnostic for now. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this declaration yet"); + Diags.Report(D->getLocation(), DiagID) + << D->getSourceRange(); + } +} + +void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <type-encoding> ::= <function-class> <function-type> + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // We should never ever see a FunctionNoProtoType at this point. + // We don't even know how to mangle their types anyway :). + const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>(); + + bool InStructor = false, InInstMethod = false; + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); + if (MD) { + if (MD->isInstance()) + InInstMethod = true; + if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + InStructor = true; + } + + // First, the function class. + mangleFunctionClass(FD); + + mangleType(FT, FD, InStructor, InInstMethod); +} + +void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { + // <type-encoding> ::= <storage-class> <variable-type> + // <storage-class> ::= 0 # private static member + // ::= 1 # protected static member + // ::= 2 # public static member + // ::= 3 # global + // ::= 4 # static local + + // The first character in the encoding (after the name) is the storage class. + if (VD->isStaticDataMember()) { + // If it's a static member, it also encodes the access level. + switch (VD->getAccess()) { + default: + case AS_private: Out << '0'; break; + case AS_protected: Out << '1'; break; + case AS_public: Out << '2'; break; + } + } + else if (!VD->isStaticLocal()) + Out << '3'; + else + Out << '4'; + // Now mangle the type. + // <variable-type> ::= <type> <cvr-qualifiers> + // ::= <type> <pointee-cvr-qualifiers> # pointers, references + // Pointers and references are odd. The type of 'int * const foo;' gets + // mangled as 'QAHA' instead of 'PAHB', for example. + TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); + QualType Ty = TL.getType(); + if (Ty->isPointerType() || Ty->isReferenceType()) { + mangleType(Ty, TL.getSourceRange()); + mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); + } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { + // Global arrays are funny, too. + mangleType(AT, true); + mangleQualifiers(Ty.getQualifiers(), false); + } else { + mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); + mangleQualifiers(Ty.getLocalQualifiers(), false); + } +} + +void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ + const DeclContext *DC = ND->getDeclContext(); + + // Always start with the unqualified name. + mangleUnqualifiedName(ND); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + + manglePostfix(DC); + + // Terminate the whole name with an '@'. + Out << '@'; +} + +void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { + llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); + APSNumber = Number; + mangleNumber(APSNumber); +} + +void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 + // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... + // ::= [?] @ # 0 (alternate mangling, not emitted by VC) + if (Value.isSigned() && Value.isNegative()) { + Out << '?'; + mangleNumber(llvm::APSInt(Value.abs())); + return; + } + llvm::APSInt Temp(Value); + // There's a special shorter mangling for 0, but Microsoft + // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... + if (Value.uge(1) && Value.ule(10)) { + --Temp; + Temp.print(Out, false); + } else { + // We have to build up the encoding in reverse order, so it will come + // out right when we write it out. + char Encoding[64]; + char *EndPtr = Encoding+sizeof(Encoding); + char *CurPtr = EndPtr; + llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned()); + NibbleMask = 0xf; + do { + *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf); + Temp = Temp.lshr(4); + } while (Temp != 0); + Out.write(CurPtr, EndPtr-CurPtr); + Out << '@'; + } +} + +static const TemplateDecl * +isTemplate(const NamedDecl *ND, + SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + // Check if we have a function template. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ + if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { + if (FD->getTemplateSpecializationArgsAsWritten()) { + const ASTTemplateArgumentListInfo *ArgList = + FD->getTemplateSpecializationArgsAsWritten(); + TemplateArgs.append(ArgList->getTemplateArgs(), + ArgList->getTemplateArgs() + + ArgList->NumTemplateArgs); + } else { + const TemplateArgumentList *ArgList = + FD->getTemplateSpecializationArgs(); + TemplateArgumentListInfo LI; + for (unsigned i = 0, e = ArgList->size(); i != e; ++i) + TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i), + FD->getTypeSourceInfo())); + } + return TD; + } + } + + // Check if we have a class template. + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TypeSourceInfo *TSI = Spec->getTypeAsWritten(); + if (TSI) { + TemplateSpecializationTypeLoc TSTL = + cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); + TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); + for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) + TemplateArgs.push_back(TSTL.getArgLoc(i)); + } else { + TemplateArgumentListInfo LI; + const TemplateArgumentList &ArgList = + Spec->getTemplateArgs(); + for (unsigned i = 0, e = ArgList.size(); i != e; ++i) + TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i], + TemplateArgumentLocInfo())); + } + return Spec->getSpecializedTemplate(); + } + + return 0; +} + +void +MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + // ::= <template-name> + SmallVector<TemplateArgumentLoc, 2> TemplateArgs; + // Check if we have a template. + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + // We have a template. + // Here comes the tricky thing: if we need to mangle something like + // void foo(A::X<Y>, B::X<Y>), + // the X<Y> part is aliased. However, if you need to mangle + // void foo(A::X<A::Y>, A::X<B::Y>), + // the A::X<> part is not aliased. + // That said, from the mangler's perspective we have a structure like this: + // namespace[s] -> type[ -> template-parameters] + // but from the Clang perspective we have + // type [ -> template-parameters] + // \-> namespace[s] + // What we do is we create a new mangler, mangle the same type (without + // a namespace suffix) using the extra mangler with back references + // disabled (to avoid infinite recursion) and then use the mangled type + // name as a key to check the mangling of different types for aliasing. + + std::string BackReferenceKey; + BackRefMap::iterator Found; + if (UseNameBackReferences) { + llvm::raw_string_ostream Stream(BackReferenceKey); + MicrosoftCXXNameMangler Extra(Context, Stream); + Extra.disableBackReferences(); + Extra.mangleUnqualifiedName(ND, Name); + Stream.flush(); + + Found = NameBackReferences.find(BackReferenceKey); + } + if (!UseNameBackReferences || Found == NameBackReferences.end()) { + mangleTemplateInstantiationName(TD, TemplateArgs); + if (UseNameBackReferences && NameBackReferences.size() < 10) { + size_t Size = NameBackReferences.size(); + NameBackReferences[BackReferenceKey] = Size; + } + } else { + Out << Found->second; + } + return; + } + + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + Out << "?A@"; + break; + } + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // When VC encounters an anonymous type with no tag and no typedef, + // it literally emits '<unnamed-tag>'. + Out << "<unnamed-tag>"; + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + llvm_unreachable("Can't mangle Objective-C selector names here!"); + + case DeclarationName::CXXConstructorName: + Out << "?0"; + break; + + case DeclarationName::CXXDestructorName: + Out << "?1"; + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= ?B # (cast) + // The target type is encoded as the return type. + Out << "?B"; + break; + + case DeclarationName::CXXOperatorName: + mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation()); + break; + + case DeclarationName::CXXLiteralOperatorName: { + // FIXME: Was this added in VS2010? Does MS even know how to mangle this? + DiagnosticsEngine Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this literal operator yet"); + Diags.Report(ND->getLocation(), DiagID); + break; + } + + case DeclarationName::CXXUsingDirective: + llvm_unreachable("Can't mangle a using directive name!"); + } +} + +void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, + bool NoFunction) { + // <postfix> ::= <unqualified-name> [<postfix>] + // ::= <substitution> [<postfix>] + + if (!DC) return; + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { + Context.mangleBlock(BD, Out); + Out << '@'; + return manglePostfix(DC->getParent(), NoFunction); + } + + if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC)) + mangleLocalName(Func); + else { + mangleUnqualifiedName(cast<NamedDecl>(DC)); + manglePostfix(DC->getParent(), NoFunction); + } +} + +void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, + SourceLocation Loc) { + switch (OO) { + // ?0 # constructor + // ?1 # destructor + // <operator-name> ::= ?2 # new + case OO_New: Out << "?2"; break; + // <operator-name> ::= ?3 # delete + case OO_Delete: Out << "?3"; break; + // <operator-name> ::= ?4 # = + case OO_Equal: Out << "?4"; break; + // <operator-name> ::= ?5 # >> + case OO_GreaterGreater: Out << "?5"; break; + // <operator-name> ::= ?6 # << + case OO_LessLess: Out << "?6"; break; + // <operator-name> ::= ?7 # ! + case OO_Exclaim: Out << "?7"; break; + // <operator-name> ::= ?8 # == + case OO_EqualEqual: Out << "?8"; break; + // <operator-name> ::= ?9 # != + case OO_ExclaimEqual: Out << "?9"; break; + // <operator-name> ::= ?A # [] + case OO_Subscript: Out << "?A"; break; + // ?B # conversion + // <operator-name> ::= ?C # -> + case OO_Arrow: Out << "?C"; break; + // <operator-name> ::= ?D # * + case OO_Star: Out << "?D"; break; + // <operator-name> ::= ?E # ++ + case OO_PlusPlus: Out << "?E"; break; + // <operator-name> ::= ?F # -- + case OO_MinusMinus: Out << "?F"; break; + // <operator-name> ::= ?G # - + case OO_Minus: Out << "?G"; break; + // <operator-name> ::= ?H # + + case OO_Plus: Out << "?H"; break; + // <operator-name> ::= ?I # & + case OO_Amp: Out << "?I"; break; + // <operator-name> ::= ?J # ->* + case OO_ArrowStar: Out << "?J"; break; + // <operator-name> ::= ?K # / + case OO_Slash: Out << "?K"; break; + // <operator-name> ::= ?L # % + case OO_Percent: Out << "?L"; break; + // <operator-name> ::= ?M # < + case OO_Less: Out << "?M"; break; + // <operator-name> ::= ?N # <= + case OO_LessEqual: Out << "?N"; break; + // <operator-name> ::= ?O # > + case OO_Greater: Out << "?O"; break; + // <operator-name> ::= ?P # >= + case OO_GreaterEqual: Out << "?P"; break; + // <operator-name> ::= ?Q # , + case OO_Comma: Out << "?Q"; break; + // <operator-name> ::= ?R # () + case OO_Call: Out << "?R"; break; + // <operator-name> ::= ?S # ~ + case OO_Tilde: Out << "?S"; break; + // <operator-name> ::= ?T # ^ + case OO_Caret: Out << "?T"; break; + // <operator-name> ::= ?U # | + case OO_Pipe: Out << "?U"; break; + // <operator-name> ::= ?V # && + case OO_AmpAmp: Out << "?V"; break; + // <operator-name> ::= ?W # || + case OO_PipePipe: Out << "?W"; break; + // <operator-name> ::= ?X # *= + case OO_StarEqual: Out << "?X"; break; + // <operator-name> ::= ?Y # += + case OO_PlusEqual: Out << "?Y"; break; + // <operator-name> ::= ?Z # -= + case OO_MinusEqual: Out << "?Z"; break; + // <operator-name> ::= ?_0 # /= + case OO_SlashEqual: Out << "?_0"; break; + // <operator-name> ::= ?_1 # %= + case OO_PercentEqual: Out << "?_1"; break; + // <operator-name> ::= ?_2 # >>= + case OO_GreaterGreaterEqual: Out << "?_2"; break; + // <operator-name> ::= ?_3 # <<= + case OO_LessLessEqual: Out << "?_3"; break; + // <operator-name> ::= ?_4 # &= + case OO_AmpEqual: Out << "?_4"; break; + // <operator-name> ::= ?_5 # |= + case OO_PipeEqual: Out << "?_5"; break; + // <operator-name> ::= ?_6 # ^= + case OO_CaretEqual: Out << "?_6"; break; + // ?_7 # vftable + // ?_8 # vbtable + // ?_9 # vcall + // ?_A # typeof + // ?_B # local static guard + // ?_C # string + // ?_D # vbase destructor + // ?_E # vector deleting destructor + // ?_F # default constructor closure + // ?_G # scalar deleting destructor + // ?_H # vector constructor iterator + // ?_I # vector destructor iterator + // ?_J # vector vbase constructor iterator + // ?_K # virtual displacement map + // ?_L # eh vector constructor iterator + // ?_M # eh vector destructor iterator + // ?_N # eh vector vbase constructor iterator + // ?_O # copy constructor closure + // ?_P<name> # udt returning <name> + // ?_Q # <unknown> + // ?_R0 # RTTI Type Descriptor + // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d) + // ?_R2 # RTTI Base Class Array + // ?_R3 # RTTI Class Hierarchy Descriptor + // ?_R4 # RTTI Complete Object Locator + // ?_S # local vftable + // ?_T # local vftable constructor closure + // <operator-name> ::= ?_U # new[] + case OO_Array_New: Out << "?_U"; break; + // <operator-name> ::= ?_V # delete[] + case OO_Array_Delete: Out << "?_V"; break; + + case OO_Conditional: { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this conditional operator yet"); + Diags.Report(Loc, DiagID); + break; + } + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Not an overloaded operator"); + } +} + +void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source name> ::= <identifier> @ + std::string key = II->getNameStart(); + BackRefMap::iterator Found; + if (UseNameBackReferences) + Found = NameBackReferences.find(key); + if (!UseNameBackReferences || Found == NameBackReferences.end()) { + Out << II->getName() << '@'; + if (UseNameBackReferences && NameBackReferences.size() < 10) { + size_t Size = NameBackReferences.size(); + NameBackReferences[key] = Size; + } + } else { + Out << Found->second; + } +} + +void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +// Find out how many function decls live above this one and return an integer +// suitable for use as the number in a numbered anonymous scope. +// TODO: Memoize. +static unsigned getLocalNestingLevel(const FunctionDecl *FD) { + const DeclContext *DC = FD->getParent(); + int level = 1; + + while (DC && !DC->isTranslationUnit()) { + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++; + DC = DC->getParent(); + } + + return 2*level; +} + +void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { + // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name> + // <numbered-anonymous-scope> ::= ? <number> + // Even though the name is rendered in reverse order (e.g. + // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to + // innermost. So a method bar in class C local to function foo gets mangled + // as something like: + // ?bar@C@?1??foo@@YAXXZ@QAEXXZ + // This is more apparent when you have a type nested inside a method of a + // type nested inside a function. A method baz in class D local to method + // bar of class C local to function foo gets mangled as: + // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ + // This scheme is general enough to support GCC-style nested + // functions. You could have a method baz of class C inside a function bar + // inside a function foo, like so: + // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ + int NestLevel = getLocalNestingLevel(FD); + Out << '?'; + mangleNumber(NestLevel); + Out << '?'; + mangle(FD, "?"); +} + +void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( + const TemplateDecl *TD, + const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + // <template-name> ::= <unscoped-template-name> <template-args> + // ::= <substitution> + // Always start with the unqualified name. + + // Templates have their own context for back references. + ArgBackRefMap OuterArgsContext; + BackRefMap OuterTemplateContext; + NameBackReferences.swap(OuterTemplateContext); + TypeBackReferences.swap(OuterArgsContext); + + mangleUnscopedTemplateName(TD); + mangleTemplateArgs(TemplateArgs); + + // Restore the previous back reference contexts. + NameBackReferences.swap(OuterTemplateContext); + TypeBackReferences.swap(OuterArgsContext); +} + +void +MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) { + // <unscoped-template-name> ::= ?$ <unqualified-name> + Out << "?$"; + mangleUnqualifiedName(TD); +} + +void +MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value, + bool IsBoolean) { + // <integer-literal> ::= $0 <number> + Out << "$0"; + // Make sure booleans are encoded as 0/1. + if (IsBoolean && Value.getBoolValue()) + mangleNumber(1); + else + mangleNumber(Value); +} + +void +MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { + // See if this is a constant expression. + llvm::APSInt Value; + if (E->isIntegerConstantExpr(Value, Context.getASTContext())) { + mangleIntegerLiteral(Value, E->getType()->isBooleanType()); + return; + } + + // As bad as this diagnostic is, it's better than crashing. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); +} + +void +MicrosoftCXXNameMangler::mangleTemplateArgs( + const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + // <template-args> ::= {<type> | <integer-literal>}+ @ + unsigned NumTemplateArgs = TemplateArgs.size(); + for (unsigned i = 0; i < NumTemplateArgs; ++i) { + const TemplateArgumentLoc &TAL = TemplateArgs[i]; + const TemplateArgument &TA = TAL.getArgument(); + switch (TA.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't mangle null template arguments!"); + case TemplateArgument::Type: + mangleType(TA.getAsType(), TAL.getSourceRange()); + break; + case TemplateArgument::Integral: + mangleIntegerLiteral(TA.getAsIntegral(), + TA.getIntegralType()->isBooleanType()); + break; + case TemplateArgument::Expression: + mangleExpression(TA.getAsExpr()); + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::Pack: { + // Issue a diagnostic. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|" + "integral|template|template pack expansion|ERROR|parameter pack}0 " + "template argument yet"); + Diags.Report(TAL.getLocation(), DiagID) + << TA.getKind() + << TAL.getSourceRange(); + } + } + } + Out << '@'; +} + +void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, + bool IsMember) { + // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> + // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only); + // 'I' means __restrict (32/64-bit). + // Note that the MSVC __restrict keyword isn't the same as the C99 restrict + // keyword! + // <base-cvr-qualifiers> ::= A # near + // ::= B # near const + // ::= C # near volatile + // ::= D # near const volatile + // ::= E # far (16-bit) + // ::= F # far const (16-bit) + // ::= G # far volatile (16-bit) + // ::= H # far const volatile (16-bit) + // ::= I # huge (16-bit) + // ::= J # huge const (16-bit) + // ::= K # huge volatile (16-bit) + // ::= L # huge const volatile (16-bit) + // ::= M <basis> # based + // ::= N <basis> # based const + // ::= O <basis> # based volatile + // ::= P <basis> # based const volatile + // ::= Q # near member + // ::= R # near const member + // ::= S # near volatile member + // ::= T # near const volatile member + // ::= U # far member (16-bit) + // ::= V # far const member (16-bit) + // ::= W # far volatile member (16-bit) + // ::= X # far const volatile member (16-bit) + // ::= Y # huge member (16-bit) + // ::= Z # huge const member (16-bit) + // ::= 0 # huge volatile member (16-bit) + // ::= 1 # huge const volatile member (16-bit) + // ::= 2 <basis> # based member + // ::= 3 <basis> # based const member + // ::= 4 <basis> # based volatile member + // ::= 5 <basis> # based const volatile member + // ::= 6 # near function (pointers only) + // ::= 7 # far function (pointers only) + // ::= 8 # near method (pointers only) + // ::= 9 # far method (pointers only) + // ::= _A <basis> # based function (pointers only) + // ::= _B <basis> # based function (far?) (pointers only) + // ::= _C <basis> # based method (pointers only) + // ::= _D <basis> # based method (far?) (pointers only) + // ::= _E # block (Clang) + // <basis> ::= 0 # __based(void) + // ::= 1 # __based(segment)? + // ::= 2 <name> # __based(name) + // ::= 3 # ? + // ::= 4 # ? + // ::= 5 # not really based + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); + if (!IsMember) { + if (HasConst && HasVolatile) { + Out << 'D'; + } else if (HasVolatile) { + Out << 'C'; + } else if (HasConst) { + Out << 'B'; + } else { + Out << 'A'; + } + } else { + if (HasConst && HasVolatile) { + Out << 'T'; + } else if (HasVolatile) { + Out << 'S'; + } else if (HasConst) { + Out << 'R'; + } else { + Out << 'Q'; + } + } + + // FIXME: For now, just drop all extension qualifiers on the floor. +} + +void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) { + // <pointer-cvr-qualifiers> ::= P # no qualifiers + // ::= Q # const + // ::= R # volatile + // ::= S # const volatile + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); + if (HasConst && HasVolatile) { + Out << 'S'; + } else if (HasVolatile) { + Out << 'R'; + } else if (HasConst) { + Out << 'Q'; + } else { + Out << 'P'; + } +} + +void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, + SourceRange Range) { + void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr(); + ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); + + if (Found == TypeBackReferences.end()) { + size_t OutSizeBefore = Out.GetNumBytesInBuffer(); + + mangleType(T, Range, false); + + // See if it's worth creating a back reference. + // Only types longer than 1 character are considered + // and only 10 back references slots are available: + bool LongerThanOneChar = (Out.GetNumBytesInBuffer() - OutSizeBefore > 1); + if (LongerThanOneChar && TypeBackReferences.size() < 10) { + size_t Size = TypeBackReferences.size(); + TypeBackReferences[TypePtr] = Size; + } + } else { + Out << Found->second; + } +} + +void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, + bool MangleQualifiers) { + // Only operate on the canonical type! + T = getASTContext().getCanonicalType(T); + + Qualifiers Quals = T.getLocalQualifiers(); + // We have to mangle these now, while we still have enough information. + if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + manglePointerQualifiers(Quals); + } else if (Quals && MangleQualifiers) { + mangleQualifiers(Quals, false); + } + + SplitQualType split = T.split(); + const Type *ty = split.Ty; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (split.Quals && isa<ArrayType>(T)) { + ty = Context.getASTContext().getAsArrayType(T); + } + + switch (ty->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + return; +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + mangleType(cast<CLASS##Type>(ty), Range); \ + break; +#include "clang/AST/TypeNodes.def" +#undef ABSTRACT_TYPE +#undef NON_CANONICAL_TYPE +#undef TYPE + } +} + +void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, + SourceRange Range) { + // <type> ::= <builtin-type> + // <builtin-type> ::= X # void + // ::= C # signed char + // ::= D # char + // ::= E # unsigned char + // ::= F # short + // ::= G # unsigned short (or wchar_t if it's not a builtin) + // ::= H # int + // ::= I # unsigned int + // ::= J # long + // ::= K # unsigned long + // L # <none> + // ::= M # float + // ::= N # double + // ::= O # long double (__float80 is mangled differently) + // ::= _J # long long, __int64 + // ::= _K # unsigned long long, __int64 + // ::= _L # __int128 + // ::= _M # unsigned __int128 + // ::= _N # bool + // _O # <array in parameter> + // ::= _T # __float80 (Intel) + // ::= _W # wchar_t + // ::= _Z # __float80 (Digital Mars) + switch (T->getKind()) { + case BuiltinType::Void: Out << 'X'; break; + case BuiltinType::SChar: Out << 'C'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break; + case BuiltinType::UChar: Out << 'E'; break; + case BuiltinType::Short: Out << 'F'; break; + case BuiltinType::UShort: Out << 'G'; break; + case BuiltinType::Int: Out << 'H'; break; + case BuiltinType::UInt: Out << 'I'; break; + case BuiltinType::Long: Out << 'J'; break; + case BuiltinType::ULong: Out << 'K'; break; + case BuiltinType::Float: Out << 'M'; break; + case BuiltinType::Double: Out << 'N'; break; + // TODO: Determine size and mangle accordingly + case BuiltinType::LongDouble: Out << 'O'; break; + case BuiltinType::LongLong: Out << "_J"; break; + case BuiltinType::ULongLong: Out << "_K"; break; + case BuiltinType::Int128: Out << "_L"; break; + case BuiltinType::UInt128: Out << "_M"; break; + case BuiltinType::Bool: Out << "_N"; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << "_W"; break; + +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: + llvm_unreachable("placeholder types shouldn't get to name mangling"); + + case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break; + case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break; + case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break; + + case BuiltinType::NullPtr: Out << "$$T"; break; + + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Half: { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this built-in %0 type yet"); + Diags.Report(Range.getBegin(), DiagID) + << T->getName(Context.getASTContext().getPrintingPolicy()) + << Range; + break; + } + } +} + +// <type> ::= <function-type> +void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, + SourceRange) { + // Structors only appear in decls, so at this point we know it's not a + // structor type. + // FIXME: This may not be lambda-friendly. + Out << "$$A6"; + mangleType(T, NULL, false, false); +} +void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, + SourceRange) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} + +void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { + // <function-type> ::= <this-cvr-qualifiers> <calling-convention> + // <return-type> <argument-list> <throw-spec> + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // If this is a C++ instance method, mangle the CVR qualifiers for the + // this pointer. + if (IsInstMethod) + mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); + + mangleCallingConvention(T, IsInstMethod); + + // <return-type> ::= <type> + // ::= @ # structors (they have no declared return type) + if (IsStructor) + Out << '@'; + else { + QualType Result = Proto->getResultType(); + const Type* RT = Result.getTypePtr(); + if (!RT->isAnyPointerType() && !RT->isReferenceType()) { + if (Result.hasQualifiers() || !RT->isBuiltinType()) + Out << '?'; + if (!RT->isBuiltinType() && !Result.hasQualifiers()) { + // Lack of qualifiers for user types is mangled as 'A'. + Out << 'A'; + } + } + + // FIXME: Get the source range for the result type. Or, better yet, + // implement the unimplemented stuff so we don't need accurate source + // location info anymore :). + mangleType(Result, SourceRange()); + } + + // <argument-list> ::= X # void + // ::= <type>+ @ + // ::= <type>* Z # varargs + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + Out << 'X'; + } else { + if (D) { + // If we got a decl, use the type-as-written to make sure arrays + // get mangled right. Note that we can't rely on the TSI + // existing if (for example) the parameter was synthesized. + for (FunctionDecl::param_const_iterator Parm = D->param_begin(), + ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) { + TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo(); + QualType Type = TSI ? TSI->getType() : (*Parm)->getType(); + mangleArgumentType(Type, (*Parm)->getSourceRange()); + } + } else { + // Happens for function pointer type arguments for example. + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleArgumentType(*Arg, SourceRange()); + } + // <builtin-type> ::= Z # ellipsis + if (Proto->isVariadic()) + Out << 'Z'; + else + Out << '@'; + } + + mangleThrowSpecification(Proto); +} + +void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { + // <function-class> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // ::= Y # global near + // ::= Z # global far + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + switch (MD->getAccess()) { + default: + case AS_private: + if (MD->isStatic()) + Out << 'C'; + else if (MD->isVirtual()) + Out << 'E'; + else + Out << 'A'; + break; + case AS_protected: + if (MD->isStatic()) + Out << 'K'; + else if (MD->isVirtual()) + Out << 'M'; + else + Out << 'I'; + break; + case AS_public: + if (MD->isStatic()) + Out << 'S'; + else if (MD->isVirtual()) + Out << 'U'; + else + Out << 'Q'; + } + } else + Out << 'Y'; +} +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, + bool IsInstMethod) { + // <calling-convention> ::= A # __cdecl + // ::= B # __export __cdecl + // ::= C # __pascal + // ::= D # __export __pascal + // ::= E # __thiscall + // ::= F # __export __thiscall + // ::= G # __stdcall + // ::= H # __export __stdcall + // ::= I # __fastcall + // ::= J # __export __fastcall + // The 'export' calling conventions are from a bygone era + // (*cough*Win16*cough*) when functions were declared for export with + // that keyword. (It didn't actually export them, it just made them so + // that they could be in a DLL and somebody from another module could call + // them.) + CallingConv CC = T->getCallConv(); + if (CC == CC_Default) { + if (IsInstMethod) { + const FunctionProtoType *FPT = + T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>(); + bool isVariadic = FPT->isVariadic(); + CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); + } else { + CC = CC_C; + } + } + switch (CC) { + default: + llvm_unreachable("Unsupported CC for mangling"); + case CC_Default: + case CC_C: Out << 'A'; break; + case CC_X86Pascal: Out << 'C'; break; + case CC_X86ThisCall: Out << 'E'; break; + case CC_X86StdCall: Out << 'G'; break; + case CC_X86FastCall: Out << 'I'; break; + } +} +void MicrosoftCXXNameMangler::mangleThrowSpecification( + const FunctionProtoType *FT) { + // <throw-spec> ::= Z # throw(...) (default) + // ::= @ # throw() or __declspec/__attribute__((nothrow)) + // ::= <type>+ + // NOTE: Since the Microsoft compiler ignores throw specifications, they are + // all actually mangled as 'Z'. (They're ignored because their associated + // functionality isn't implemented, and probably never will be.) + Out << 'Z'; +} + +void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, + SourceRange Range) { + // Probably should be mangled as a template instantiation; need to see what + // VC does first. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this unresolved dependent type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type> +// <union-type> ::= T <name> +// <struct-type> ::= U <name> +// <class-type> ::= V <name> +// <enum-type> ::= W <size> <name> +void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { + mangleType(cast<TagType>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { + mangleType(cast<TagType>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const TagType *T) { + switch (T->getDecl()->getTagKind()) { + case TTK_Union: + Out << 'T'; + break; + case TTK_Struct: + case TTK_Interface: + Out << 'U'; + break; + case TTK_Class: + Out << 'V'; + break; + case TTK_Enum: + Out << 'W'; + Out << getASTContext().getTypeSizeInChars( + cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity(); + break; + } + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// [Y <dimension-count> <dimension>+] +// <element-type> # as global +// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as param +// It's supposed to be the other way around, but for some strange reason, it +// isn't. Today this behavior is retained for the sole purpose of backwards +// compatibility. +void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { + // This isn't a recursive mangling, so now we have to do it all in this + // one call. + if (IsGlobal) { + manglePointerQualifiers(T->getElementType().getQualifiers()); + } else { + Out << 'Q'; + } + mangleExtraDimensions(T->getElementType()); +} +void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, + SourceRange) { + mangleType(cast<ArrayType>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, + SourceRange) { + mangleType(cast<ArrayType>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, + SourceRange) { + mangleType(cast<ArrayType>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, + SourceRange) { + mangleType(cast<ArrayType>(T), false); +} +void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { + SmallVector<llvm::APInt, 3> Dimensions; + for (;;) { + if (const ConstantArrayType *CAT = + getASTContext().getAsConstantArrayType(ElementTy)) { + Dimensions.push_back(CAT->getSize()); + ElementTy = CAT->getElementType(); + } else if (ElementTy->isVariableArrayType()) { + const VariableArrayType *VAT = + getASTContext().getAsVariableArrayType(ElementTy); + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this variable-length array yet"); + Diags.Report(VAT->getSizeExpr()->getExprLoc(), DiagID) + << VAT->getBracketsRange(); + return; + } else if (ElementTy->isDependentSizedArrayType()) { + // The dependent expression has to be folded into a constant (TODO). + const DependentSizedArrayType *DSAT = + getASTContext().getAsDependentSizedArrayType(ElementTy); + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent-length array yet"); + Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) + << DSAT->getBracketsRange(); + return; + } else if (ElementTy->isIncompleteArrayType()) continue; + else break; + } + mangleQualifiers(ElementTy.getQualifiers(), false); + // If there are any additional dimensions, mangle them now. + if (Dimensions.size() > 0) { + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { + mangleNumber(Dimensions[Dim].getLimitedValue()); + } + } + mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// <class name> <type> +void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, + SourceRange Range) { + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { + Out << '8'; + mangleName(T->getClass()->castAs<RecordType>()->getDecl()); + mangleType(FPT, NULL, false, true); + } else { + mangleQualifiers(PointeeType.getQualifiers(), true); + mangleName(T->getClass()->castAs<RecordType>()->getDecl()); + mangleType(PointeeType.getLocalUnqualifiedType(), Range); + } +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this template type parameter type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType( + const SubstTemplateTypeParmPackType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this substituted parameter pack yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +// <type> ::= <pointer-type> +// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const PointerType *T, + SourceRange Range) { + QualType PointeeTy = T->getPointeeType(); + if (PointeeTy->isArrayType()) { + // Pointers to arrays are mangled like arrays. + mangleExtraDimensions(PointeeTy); + } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { + // Function pointers are special. + Out << '6'; + mangleType(FT, NULL, false, false); + } else { + mangleQualifiers(PointeeTy.getQualifiers(), false); + mangleType(PointeeTy, Range, false); + } +} +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, + SourceRange Range) { + // Object pointers never have qualifiers. + Out << 'A'; + mangleType(T->getPointeeType(), Range); +} + +// <type> ::= <reference-type> +// <reference-type> ::= A <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, + SourceRange Range) { + Out << 'A'; + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy, Range); +} + +// <type> ::= <r-value-reference-type> +// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, + SourceRange Range) { + Out << "$$Q"; + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy, Range); +} + +void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this complex number type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const VectorType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this vector type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} +void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this extended vector type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent-sized extended vector type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, + SourceRange) { + // ObjC interfaces have structs underlying them. + Out << 'U'; + mangleName(T->getDecl()); +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, + SourceRange Range) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType(), Range); +} + +void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, + SourceRange Range) { + Out << "_E"; + + QualType pointee = T->getPointeeType(); + mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); +} + +void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this injected class name type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent name type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType( + const DependentTemplateSpecializationType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this pack expansion yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this typeof(type) yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this typeof(expression) yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this decltype() yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this unary transform type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this 'auto' type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this C11 atomic type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + +void MicrosoftMangleContext::mangleName(const NamedDecl *D, + raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + MicrosoftCXXNameMangler Mangler(*this, Out); + return Mangler.mangle(D); +} +void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &) { + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle thunk for this method yet"); + getDiags().Report(MD->getLocation(), DiagID); +} +void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &, + raw_ostream &) { + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle thunk for this destructor yet"); + getDiags().Report(DD->getLocation(), DiagID); +} +void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + raw_ostream &Out) { + // <mangled-name> ::= ? <operator-name> <class-name> <storage-class> + // <cvr-qualifiers> [<name>] @ + // <operator-name> ::= _7 # vftable + // ::= _8 # vbtable + // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class> + // is always '6' for vftables and '7' for vbtables. (The difference is + // beyond me.) + // TODO: vbtables. + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??_7"; + Mangler.mangleName(RD); + Mangler.getStream() << "6B"; + // TODO: If the class has more than one vtable, mangle in the class it came + // from. + Mangler.getStream() << '@'; +} +void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have virtual table tables!"); +} +void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); +} +void MicrosoftMangleContext::mangleCXXRTTI(QualType T, + raw_ostream &) { + // FIXME: Give a location... + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle RTTI descriptors for type %0 yet"); + getDiags().Report(DiagID) + << T.getBaseTypeIdentifier(); +} +void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, + raw_ostream &) { + // FIXME: Give a location... + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle the name of type %0 into RTTI descriptors yet"); + getDiags().Report(DiagID) + << T.getBaseTypeIdentifier(); +} +void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + raw_ostream & Out) { + MicrosoftCXXNameMangler mangler(*this, Out); + mangler.mangle(D); +} +void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + raw_ostream & Out) { + MicrosoftCXXNameMangler mangler(*this, Out); + mangler.mangle(D); +} +void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, + raw_ostream &) { + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this reference temporary yet"); + getDiags().Report(VD->getLocation(), DiagID); +} + +MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags) { + return new MicrosoftMangleContext(Context, Diags); +} diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 6218da20d81..0837509194b 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -1,420 +1,414 @@ -//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/NSAPI.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-
-using namespace clang;
-
-NSAPI::NSAPI(ASTContext &ctx)
- : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0),
- NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
-}
-
-IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
- static const char *ClassName[NumClassIds] = {
- "NSObject",
- "NSString",
- "NSArray",
- "NSMutableArray",
- "NSDictionary",
- "NSMutableDictionary",
- "NSNumber"
- };
-
- if (!ClassIds[K])
- return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
-
- return ClassIds[K];
-}
-
-Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
- if (NSStringSelectors[MK].isNull()) {
- Selector Sel;
- switch (MK) {
- case NSStr_stringWithString:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
- break;
- case NSStr_stringWithUTF8String:
- Sel = Ctx.Selectors.getUnarySelector(
- &Ctx.Idents.get("stringWithUTF8String"));
- break;
- case NSStr_stringWithCStringEncoding: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("stringWithCString"),
- &Ctx.Idents.get("encoding")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- case NSStr_stringWithCString:
- Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
- break;
- case NSStr_initWithString:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
- break;
- }
- return (NSStringSelectors[MK] = Sel);
- }
-
- return NSStringSelectors[MK];
-}
-
-llvm::Optional<NSAPI::NSStringMethodKind>
-NSAPI::getNSStringMethodKind(Selector Sel) const {
- for (unsigned i = 0; i != NumNSStringMethods; ++i) {
- NSStringMethodKind MK = NSStringMethodKind(i);
- if (Sel == getNSStringSelector(MK))
- return MK;
- }
-
- return llvm::Optional<NSStringMethodKind>();
-}
-
-Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
- if (NSArraySelectors[MK].isNull()) {
- Selector Sel;
- switch (MK) {
- case NSArr_array:
- Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
- break;
- case NSArr_arrayWithArray:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
- break;
- case NSArr_arrayWithObject:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
- break;
- case NSArr_arrayWithObjects:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
- break;
- case NSArr_arrayWithObjectsCount: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("arrayWithObjects"),
- &Ctx.Idents.get("count")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- case NSArr_initWithArray:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
- break;
- case NSArr_initWithObjects:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
- break;
- case NSArr_objectAtIndex:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
- break;
- case NSMutableArr_replaceObjectAtIndex: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("replaceObjectAtIndex"),
- &Ctx.Idents.get("withObject")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- }
- return (NSArraySelectors[MK] = Sel);
- }
-
- return NSArraySelectors[MK];
-}
-
-llvm::Optional<NSAPI::NSArrayMethodKind>
-NSAPI::getNSArrayMethodKind(Selector Sel) {
- for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
- NSArrayMethodKind MK = NSArrayMethodKind(i);
- if (Sel == getNSArraySelector(MK))
- return MK;
- }
-
- return llvm::Optional<NSArrayMethodKind>();
-}
-
-Selector NSAPI::getNSDictionarySelector(
- NSDictionaryMethodKind MK) const {
- if (NSDictionarySelectors[MK].isNull()) {
- Selector Sel;
- switch (MK) {
- case NSDict_dictionary:
- Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
- break;
- case NSDict_dictionaryWithDictionary:
- Sel = Ctx.Selectors.getUnarySelector(
- &Ctx.Idents.get("dictionaryWithDictionary"));
- break;
- case NSDict_dictionaryWithObjectForKey: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("dictionaryWithObject"),
- &Ctx.Idents.get("forKey")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- case NSDict_dictionaryWithObjectsForKeys: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("dictionaryWithObjects"),
- &Ctx.Idents.get("forKeys")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- case NSDict_dictionaryWithObjectsForKeysCount: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("dictionaryWithObjects"),
- &Ctx.Idents.get("forKeys"),
- &Ctx.Idents.get("count")
- };
- Sel = Ctx.Selectors.getSelector(3, KeyIdents);
- break;
- }
- case NSDict_dictionaryWithObjectsAndKeys:
- Sel = Ctx.Selectors.getUnarySelector(
- &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
- break;
- case NSDict_initWithDictionary:
- Sel = Ctx.Selectors.getUnarySelector(
- &Ctx.Idents.get("initWithDictionary"));
- break;
- case NSDict_initWithObjectsAndKeys:
- Sel = Ctx.Selectors.getUnarySelector(
- &Ctx.Idents.get("initWithObjectsAndKeys"));
- break;
- case NSDict_objectForKey:
- Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
- break;
- case NSMutableDict_setObjectForKey: {
- IdentifierInfo *KeyIdents[] = {
- &Ctx.Idents.get("setObject"),
- &Ctx.Idents.get("forKey")
- };
- Sel = Ctx.Selectors.getSelector(2, KeyIdents);
- break;
- }
- }
- return (NSDictionarySelectors[MK] = Sel);
- }
-
- return NSDictionarySelectors[MK];
-}
-
-llvm::Optional<NSAPI::NSDictionaryMethodKind>
-NSAPI::getNSDictionaryMethodKind(Selector Sel) {
- for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
- NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
- if (Sel == getNSDictionarySelector(MK))
- return MK;
- }
-
- return llvm::Optional<NSDictionaryMethodKind>();
-}
-
-Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
- bool Instance) const {
- static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
- "numberWithChar",
- "numberWithUnsignedChar",
- "numberWithShort",
- "numberWithUnsignedShort",
- "numberWithInt",
- "numberWithUnsignedInt",
- "numberWithLong",
- "numberWithUnsignedLong",
- "numberWithLongLong",
- "numberWithUnsignedLongLong",
- "numberWithFloat",
- "numberWithDouble",
- "numberWithBool",
- "numberWithInteger",
- "numberWithUnsignedInteger"
- };
- static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
- "initWithChar",
- "initWithUnsignedChar",
- "initWithShort",
- "initWithUnsignedShort",
- "initWithInt",
- "initWithUnsignedInt",
- "initWithLong",
- "initWithUnsignedLong",
- "initWithLongLong",
- "initWithUnsignedLongLong",
- "initWithFloat",
- "initWithDouble",
- "initWithBool",
- "initWithInteger",
- "initWithUnsignedInteger"
- };
-
- Selector *Sels;
- const char **Names;
- if (Instance) {
- Sels = NSNumberInstanceSelectors;
- Names = InstanceSelectorName;
- } else {
- Sels = NSNumberClassSelectors;
- Names = ClassSelectorName;
- }
-
- if (Sels[MK].isNull())
- Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
- return Sels[MK];
-}
-
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
-NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
- for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
- NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
- if (isNSNumberLiteralSelector(MK, Sel))
- return MK;
- }
-
- return llvm::Optional<NSNumberLiteralMethodKind>();
-}
-
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
-NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
- const BuiltinType *BT = T->getAs<BuiltinType>();
- if (!BT)
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
-
- const TypedefType *TDT = T->getAs<TypedefType>();
- if (TDT) {
- QualType TDTTy = QualType(TDT, 0);
- if (isObjCBOOLType(TDTTy))
- return NSAPI::NSNumberWithBool;
- if (isObjCNSIntegerType(TDTTy))
- return NSAPI::NSNumberWithInteger;
- if (isObjCNSUIntegerType(TDTTy))
- return NSAPI::NSNumberWithUnsignedInteger;
- }
-
- switch (BT->getKind()) {
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- return NSAPI::NSNumberWithChar;
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- return NSAPI::NSNumberWithUnsignedChar;
- case BuiltinType::Short:
- return NSAPI::NSNumberWithShort;
- case BuiltinType::UShort:
- return NSAPI::NSNumberWithUnsignedShort;
- case BuiltinType::Int:
- return NSAPI::NSNumberWithInt;
- case BuiltinType::UInt:
- return NSAPI::NSNumberWithUnsignedInt;
- case BuiltinType::Long:
- return NSAPI::NSNumberWithLong;
- case BuiltinType::ULong:
- return NSAPI::NSNumberWithUnsignedLong;
- case BuiltinType::LongLong:
- return NSAPI::NSNumberWithLongLong;
- case BuiltinType::ULongLong:
- return NSAPI::NSNumberWithUnsignedLongLong;
- case BuiltinType::Float:
- return NSAPI::NSNumberWithFloat;
- case BuiltinType::Double:
- return NSAPI::NSNumberWithDouble;
- case BuiltinType::Bool:
- return NSAPI::NSNumberWithBool;
-
- case BuiltinType::Void:
- case BuiltinType::WChar_U:
- case BuiltinType::WChar_S:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Int128:
- case BuiltinType::LongDouble:
- case BuiltinType::UInt128:
- case BuiltinType::NullPtr:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCSel:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::BoundMember:
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::UnknownAny:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::Half:
- case BuiltinType::PseudoObject:
- case BuiltinType::BuiltinFn:
- break;
- }
-
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
-}
-
-/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
-bool NSAPI::isObjCBOOLType(QualType T) const {
- return isObjCTypedef(T, "BOOL", BOOLId);
-}
-/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
-bool NSAPI::isObjCNSIntegerType(QualType T) const {
- return isObjCTypedef(T, "NSInteger", NSIntegerId);
-}
-/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
-bool NSAPI::isObjCNSUIntegerType(QualType T) const {
- return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
-}
-
-bool NSAPI::isObjCTypedef(QualType T,
- StringRef name, IdentifierInfo *&II) const {
- if (!Ctx.getLangOpts().ObjC1)
- return false;
- if (T.isNull())
- return false;
-
- if (!II)
- II = &Ctx.Idents.get(name);
-
- while (const TypedefType *TDT = T->getAs<TypedefType>()) {
- if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
- return true;
- T = TDT->desugar();
- }
-
- return false;
-}
-
-bool NSAPI::isObjCEnumerator(const Expr *E,
- StringRef name, IdentifierInfo *&II) const {
- if (!Ctx.getLangOpts().ObjC1)
- return false;
- if (!E)
- return false;
-
- if (!II)
- II = &Ctx.Idents.get(name);
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
- if (const EnumConstantDecl *
- EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
- return EnumD->getIdentifier() == II;
-
- return false;
-}
-
-Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
- Selector &Sel) const {
- if (Sel.isNull()) {
- SmallVector<IdentifierInfo *, 4> Idents;
- for (ArrayRef<StringRef>::const_iterator
- I = Ids.begin(), E = Ids.end(); I != E; ++I)
- Idents.push_back(&Ctx.Idents.get(*I));
- Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
- }
- return Sel;
-}
+//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/NSAPI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +NSAPI::NSAPI(ASTContext &ctx) + : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0), + NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) { +} + +IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { + static const char *ClassName[NumClassIds] = { + "NSObject", + "NSString", + "NSArray", + "NSMutableArray", + "NSDictionary", + "NSMutableDictionary", + "NSNumber" + }; + + if (!ClassIds[K]) + return (ClassIds[K] = &Ctx.Idents.get(ClassName[K])); + + return ClassIds[K]; +} + +Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { + if (NSStringSelectors[MK].isNull()) { + Selector Sel; + switch (MK) { + case NSStr_stringWithString: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString")); + break; + case NSStr_stringWithUTF8String: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("stringWithUTF8String")); + break; + case NSStr_stringWithCStringEncoding: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("stringWithCString"), + &Ctx.Idents.get("encoding") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSStr_stringWithCString: + Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString")); + break; + case NSStr_initWithString: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString")); + break; + } + return (NSStringSelectors[MK] = Sel); + } + + return NSStringSelectors[MK]; +} + +llvm::Optional<NSAPI::NSStringMethodKind> +NSAPI::getNSStringMethodKind(Selector Sel) const { + for (unsigned i = 0; i != NumNSStringMethods; ++i) { + NSStringMethodKind MK = NSStringMethodKind(i); + if (Sel == getNSStringSelector(MK)) + return MK; + } + + return llvm::Optional<NSStringMethodKind>(); +} + +Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { + if (NSArraySelectors[MK].isNull()) { + Selector Sel; + switch (MK) { + case NSArr_array: + Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array")); + break; + case NSArr_arrayWithArray: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray")); + break; + case NSArr_arrayWithObject: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject")); + break; + case NSArr_arrayWithObjects: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); + break; + case NSArr_arrayWithObjectsCount: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("arrayWithObjects"), + &Ctx.Idents.get("count") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSArr_initWithArray: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray")); + break; + case NSArr_initWithObjects: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects")); + break; + case NSArr_objectAtIndex: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); + break; + case NSMutableArr_replaceObjectAtIndex: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + } + return (NSArraySelectors[MK] = Sel); + } + + return NSArraySelectors[MK]; +} + +llvm::Optional<NSAPI::NSArrayMethodKind> +NSAPI::getNSArrayMethodKind(Selector Sel) { + for (unsigned i = 0; i != NumNSArrayMethods; ++i) { + NSArrayMethodKind MK = NSArrayMethodKind(i); + if (Sel == getNSArraySelector(MK)) + return MK; + } + + return llvm::Optional<NSArrayMethodKind>(); +} + +Selector NSAPI::getNSDictionarySelector( + NSDictionaryMethodKind MK) const { + if (NSDictionarySelectors[MK].isNull()) { + Selector Sel; + switch (MK) { + case NSDict_dictionary: + Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary")); + break; + case NSDict_dictionaryWithDictionary: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("dictionaryWithDictionary")); + break; + case NSDict_dictionaryWithObjectForKey: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObject"), + &Ctx.Idents.get("forKey") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSDict_dictionaryWithObjectsForKeys: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), + &Ctx.Idents.get("forKeys") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSDict_dictionaryWithObjectsForKeysCount: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), + &Ctx.Idents.get("forKeys"), + &Ctx.Idents.get("count") + }; + Sel = Ctx.Selectors.getSelector(3, KeyIdents); + break; + } + case NSDict_dictionaryWithObjectsAndKeys: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("dictionaryWithObjectsAndKeys")); + break; + case NSDict_initWithDictionary: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("initWithDictionary")); + break; + case NSDict_initWithObjectsAndKeys: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("initWithObjectsAndKeys")); + break; + case NSDict_objectForKey: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); + break; + case NSMutableDict_setObjectForKey: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), + &Ctx.Idents.get("forKey") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + } + return (NSDictionarySelectors[MK] = Sel); + } + + return NSDictionarySelectors[MK]; +} + +llvm::Optional<NSAPI::NSDictionaryMethodKind> +NSAPI::getNSDictionaryMethodKind(Selector Sel) { + for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) { + NSDictionaryMethodKind MK = NSDictionaryMethodKind(i); + if (Sel == getNSDictionarySelector(MK)) + return MK; + } + + return llvm::Optional<NSDictionaryMethodKind>(); +} + +Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, + bool Instance) const { + static const char *ClassSelectorName[NumNSNumberLiteralMethods] = { + "numberWithChar", + "numberWithUnsignedChar", + "numberWithShort", + "numberWithUnsignedShort", + "numberWithInt", + "numberWithUnsignedInt", + "numberWithLong", + "numberWithUnsignedLong", + "numberWithLongLong", + "numberWithUnsignedLongLong", + "numberWithFloat", + "numberWithDouble", + "numberWithBool", + "numberWithInteger", + "numberWithUnsignedInteger" + }; + static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = { + "initWithChar", + "initWithUnsignedChar", + "initWithShort", + "initWithUnsignedShort", + "initWithInt", + "initWithUnsignedInt", + "initWithLong", + "initWithUnsignedLong", + "initWithLongLong", + "initWithUnsignedLongLong", + "initWithFloat", + "initWithDouble", + "initWithBool", + "initWithInteger", + "initWithUnsignedInteger" + }; + + Selector *Sels; + const char **Names; + if (Instance) { + Sels = NSNumberInstanceSelectors; + Names = InstanceSelectorName; + } else { + Sels = NSNumberClassSelectors; + Names = ClassSelectorName; + } + + if (Sels[MK].isNull()) + Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK])); + return Sels[MK]; +} + +llvm::Optional<NSAPI::NSNumberLiteralMethodKind> +NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const { + for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) { + NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i); + if (isNSNumberLiteralSelector(MK, Sel)) + return MK; + } + + return llvm::Optional<NSNumberLiteralMethodKind>(); +} + +llvm::Optional<NSAPI::NSNumberLiteralMethodKind> +NSAPI::getNSNumberFactoryMethodKind(QualType T) const { + const BuiltinType *BT = T->getAs<BuiltinType>(); + if (!BT) + return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); + + const TypedefType *TDT = T->getAs<TypedefType>(); + if (TDT) { + QualType TDTTy = QualType(TDT, 0); + if (isObjCBOOLType(TDTTy)) + return NSAPI::NSNumberWithBool; + if (isObjCNSIntegerType(TDTTy)) + return NSAPI::NSNumberWithInteger; + if (isObjCNSUIntegerType(TDTTy)) + return NSAPI::NSNumberWithUnsignedInteger; + } + + switch (BT->getKind()) { + case BuiltinType::Char_S: + case BuiltinType::SChar: + return NSAPI::NSNumberWithChar; + case BuiltinType::Char_U: + case BuiltinType::UChar: + return NSAPI::NSNumberWithUnsignedChar; + case BuiltinType::Short: + return NSAPI::NSNumberWithShort; + case BuiltinType::UShort: + return NSAPI::NSNumberWithUnsignedShort; + case BuiltinType::Int: + return NSAPI::NSNumberWithInt; + case BuiltinType::UInt: + return NSAPI::NSNumberWithUnsignedInt; + case BuiltinType::Long: + return NSAPI::NSNumberWithLong; + case BuiltinType::ULong: + return NSAPI::NSNumberWithUnsignedLong; + case BuiltinType::LongLong: + return NSAPI::NSNumberWithLongLong; + case BuiltinType::ULongLong: + return NSAPI::NSNumberWithUnsignedLongLong; + case BuiltinType::Float: + return NSAPI::NSNumberWithFloat; + case BuiltinType::Double: + return NSAPI::NSNumberWithDouble; + case BuiltinType::Bool: + return NSAPI::NSNumberWithBool; + + case BuiltinType::Void: + case BuiltinType::WChar_U: + case BuiltinType::WChar_S: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Int128: + case BuiltinType::LongDouble: + case BuiltinType::UInt128: + case BuiltinType::NullPtr: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCId: + case BuiltinType::ObjCSel: + case BuiltinType::BoundMember: + case BuiltinType::Dependent: + case BuiltinType::Overload: + case BuiltinType::UnknownAny: + case BuiltinType::ARCUnbridgedCast: + case BuiltinType::Half: + case BuiltinType::PseudoObject: + case BuiltinType::BuiltinFn: + break; + } + + return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); +} + +/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. +bool NSAPI::isObjCBOOLType(QualType T) const { + return isObjCTypedef(T, "BOOL", BOOLId); +} +/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. +bool NSAPI::isObjCNSIntegerType(QualType T) const { + return isObjCTypedef(T, "NSInteger", NSIntegerId); +} +/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. +bool NSAPI::isObjCNSUIntegerType(QualType T) const { + return isObjCTypedef(T, "NSUInteger", NSUIntegerId); +} + +bool NSAPI::isObjCTypedef(QualType T, + StringRef name, IdentifierInfo *&II) const { + if (!Ctx.getLangOpts().ObjC1) + return false; + if (T.isNull()) + return false; + + if (!II) + II = &Ctx.Idents.get(name); + + while (const TypedefType *TDT = T->getAs<TypedefType>()) { + if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) + return true; + T = TDT->desugar(); + } + + return false; +} + +bool NSAPI::isObjCEnumerator(const Expr *E, + StringRef name, IdentifierInfo *&II) const { + if (!Ctx.getLangOpts().ObjC1) + return false; + if (!E) + return false; + + if (!II) + II = &Ctx.Idents.get(name); + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + if (const EnumConstantDecl * + EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl())) + return EnumD->getIdentifier() == II; + + return false; +} + +Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids, + Selector &Sel) const { + if (Sel.isNull()) { + SmallVector<IdentifierInfo *, 4> Idents; + for (ArrayRef<StringRef>::const_iterator + I = Ids.begin(), E = Ids.end(); I != E; ++I) + Idents.push_back(&Ctx.Idents.get(*I)); + Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data()); + } + return Sel; +} diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 26eee2d74a1..97448eee81e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1512,12 +1512,6 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; - case OCLImage1d: return "image1d_t"; - case OCLImage1dArray: return "image1d_array_t"; - case OCLImage1dBuffer: return "image1d_buffer_t"; - case OCLImage2d: return "image2d_t"; - case OCLImage2dArray: return "image2d_array_t"; - case OCLImage3d: return "image3d_t"; } llvm_unreachable("Invalid builtin type."); diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index b86d2260a0c..c021cf886b3 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -1,367 +1,361 @@ -//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- 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 TypeLoc subclasses implementations.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/TypeLocVisitor.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// TypeLoc Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
- class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> {
- public:
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getLocalSourceRange(); \
- }
-#include "clang/AST/TypeLocNodes.def"
- };
-}
-
-SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
- if (TL.isNull()) return SourceRange();
- return TypeLocRanger().Visit(TL);
-}
-
-namespace {
- class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
- public:
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getFullDataSize(); \
- }
-#include "clang/AST/TypeLocNodes.def"
- };
-}
-
-/// \brief Returns the size of the type source info data block.
-unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
- if (Ty.isNull()) return 0;
- return TypeSizer().Visit(TypeLoc(Ty, 0));
-}
-
-namespace {
- class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> {
- public:
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getNextTypeLoc(); \
- }
-#include "clang/AST/TypeLocNodes.def"
- };
-}
-
-/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the
-/// TypeLoc is a PointerLoc and next TypeLoc is for "int".
-TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) {
- return NextLoc().Visit(TL);
-}
-
-/// \brief Initializes a type location, and all of its children
-/// recursively, as if the entire tree had been written in the
-/// given location.
-void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
- SourceLocation Loc) {
- while (true) {
- switch (TL.getTypeLocClass()) {
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- case CLASS: { \
- CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
- TLCasted.initializeLocal(Context, Loc); \
- TL = TLCasted.getNextTypeLoc(); \
- if (!TL) return; \
- continue; \
- }
-#include "clang/AST/TypeLocNodes.def"
- }
- }
-}
-
-SourceLocation TypeLoc::getBeginLoc() const {
- TypeLoc Cur = *this;
- TypeLoc LeftMost = Cur;
- while (true) {
- switch (Cur.getTypeLocClass()) {
- case Elaborated:
- LeftMost = Cur;
- break;
- case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
- LeftMost = Cur;
- break;
- }
- /* Fall through */
- case FunctionNoProto:
- case ConstantArray:
- case DependentSizedArray:
- case IncompleteArray:
- case VariableArray:
- // FIXME: Currently QualifiedTypeLoc does not have a source range
- case Qualified:
- Cur = Cur.getNextTypeLoc();
- continue;
- default:
- if (!Cur.getLocalSourceRange().getBegin().isInvalid())
- LeftMost = Cur;
- Cur = Cur.getNextTypeLoc();
- if (Cur.isNull())
- break;
- continue;
- } // switch
- break;
- } // while
- return LeftMost.getLocalSourceRange().getBegin();
-}
-
-SourceLocation TypeLoc::getEndLoc() const {
- TypeLoc Cur = *this;
- TypeLoc Last;
- while (true) {
- switch (Cur.getTypeLocClass()) {
- default:
- if (!Last)
- Last = Cur;
- return Last.getLocalSourceRange().getEnd();
- case Paren:
- case ConstantArray:
- case DependentSizedArray:
- case IncompleteArray:
- case VariableArray:
- case FunctionNoProto:
- Last = Cur;
- break;
- case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
- Last = TypeLoc();
- else
- Last = Cur;
- break;
- case Pointer:
- case BlockPointer:
- case MemberPointer:
- case LValueReference:
- case RValueReference:
- case PackExpansion:
- if (!Last)
- Last = Cur;
- break;
- case Qualified:
- case Elaborated:
- break;
- }
- Cur = Cur.getNextTypeLoc();
- }
-}
-
-
-namespace {
- struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> {
- // Overload resolution does the real work for us.
- static bool isTypeSpec(TypeSpecTypeLoc _) { return true; }
- static bool isTypeSpec(TypeLoc _) { return false; }
-
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return isTypeSpec(TyLoc); \
- }
-#include "clang/AST/TypeLocNodes.def"
- };
-}
-
-
-/// \brief Determines if the given type loc corresponds to a
-/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in
-/// the type hierarchy, this is made somewhat complicated.
-///
-/// There are a lot of types that currently use TypeSpecTypeLoc
-/// because it's a convenient base class. Ideally we would not accept
-/// those here, but ideally we would have better implementations for
-/// them.
-bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
- if (TL->getType().hasLocalQualifiers()) return false;
- return TSTChecker().Visit(*TL);
-}
-
-// Reimplemented to account for GNU/C++ extension
-// typeof unary-expression
-// where there are no parentheses.
-SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const {
- if (getRParenLoc().isValid())
- return SourceRange(getTypeofLoc(), getRParenLoc());
- else
- return SourceRange(getTypeofLoc(),
- getUnderlyingExpr()->getSourceRange().getEnd());
-}
-
-
-TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
- if (needsExtraLocalData())
- return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type);
- switch (getTypePtr()->getKind()) {
- case BuiltinType::Void:
- return TST_void;
- case BuiltinType::Bool:
- return TST_bool;
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- return TST_char;
- case BuiltinType::Char16:
- return TST_char16;
- case BuiltinType::Char32:
- return TST_char32;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- return TST_wchar;
- case BuiltinType::UChar:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- llvm_unreachable("Builtin type needs extra local data!");
- // Fall through, if the impossible happens.
-
- case BuiltinType::NullPtr:
- case BuiltinType::Overload:
- case BuiltinType::Dependent:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::PseudoObject:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::BuiltinFn:
- return TST_unspecified;
- }
-
- llvm_unreachable("Invalid BuiltinType Kind!");
-}
-
-TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
- while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
- TL = PTL->getInnerLoc();
- return TL;
-}
-
-void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
- SourceLocation Loc) {
- setElaboratedKeywordLoc(Loc);
- NestedNameSpecifierLocBuilder Builder;
- Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
- setQualifierLoc(Builder.getWithLocInContext(Context));
-}
-
-void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
- SourceLocation Loc) {
- setElaboratedKeywordLoc(Loc);
- NestedNameSpecifierLocBuilder Builder;
- Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
- setQualifierLoc(Builder.getWithLocInContext(Context));
- setNameLoc(Loc);
-}
-
-void
-DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
- SourceLocation Loc) {
- setElaboratedKeywordLoc(Loc);
- if (getTypePtr()->getQualifier()) {
- NestedNameSpecifierLocBuilder Builder;
- Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
- setQualifierLoc(Builder.getWithLocInContext(Context));
- } else {
- setQualifierLoc(NestedNameSpecifierLoc());
- }
- setTemplateKeywordLoc(Loc);
- setTemplateNameLoc(Loc);
- setLAngleLoc(Loc);
- setRAngleLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
-}
-
-void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
- unsigned NumArgs,
- const TemplateArgument *Args,
- TemplateArgumentLocInfo *ArgInfos,
- SourceLocation Loc) {
- for (unsigned i = 0, e = NumArgs; i != e; ++i) {
- switch (Args[i].getKind()) {
- case TemplateArgument::Null:
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::NullPtr:
- llvm_unreachable("Impossible TemplateArgument");
-
- case TemplateArgument::Expression:
- ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
- break;
-
- case TemplateArgument::Type:
- ArgInfos[i] = TemplateArgumentLocInfo(
- Context.getTrivialTypeSourceInfo(Args[i].getAsType(),
- Loc));
- break;
-
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion: {
- NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Args[i].getAsTemplate();
- if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
- Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
- else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
-
- ArgInfos[i] = TemplateArgumentLocInfo(
- Builder.getWithLocInContext(Context),
- Loc,
- Args[i].getKind() == TemplateArgument::Template
- ? SourceLocation()
- : Loc);
- break;
- }
-
- case TemplateArgument::Pack:
- ArgInfos[i] = TemplateArgumentLocInfo();
- break;
- }
- }
-}
+//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- 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 TypeLoc subclasses implementations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TypeLoc.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeLocVisitor.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// TypeLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalSourceRange(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { + if (TL.isNull()) return SourceRange(); + return TypeLocRanger().Visit(TL); +} + +namespace { + class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getFullDataSize(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +/// \brief Returns the size of the type source info data block. +unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { + if (Ty.isNull()) return 0; + return TypeSizer().Visit(TypeLoc(Ty, 0)); +} + +namespace { + class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getNextTypeLoc(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { + return NextLoc().Visit(TL); +} + +/// \brief Initializes a type location, and all of its children +/// recursively, as if the entire tree had been written in the +/// given location. +void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc) { + while (true) { + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case CLASS: { \ + CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \ + TLCasted.initializeLocal(Context, Loc); \ + TL = TLCasted.getNextTypeLoc(); \ + if (!TL) return; \ + continue; \ + } +#include "clang/AST/TypeLocNodes.def" + } + } +} + +SourceLocation TypeLoc::getBeginLoc() const { + TypeLoc Cur = *this; + TypeLoc LeftMost = Cur; + while (true) { + switch (Cur.getTypeLocClass()) { + case Elaborated: + LeftMost = Cur; + break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) { + LeftMost = Cur; + break; + } + /* Fall through */ + case FunctionNoProto: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + // FIXME: Currently QualifiedTypeLoc does not have a source range + case Qualified: + Cur = Cur.getNextTypeLoc(); + continue; + default: + if (!Cur.getLocalSourceRange().getBegin().isInvalid()) + LeftMost = Cur; + Cur = Cur.getNextTypeLoc(); + if (Cur.isNull()) + break; + continue; + } // switch + break; + } // while + return LeftMost.getLocalSourceRange().getBegin(); +} + +SourceLocation TypeLoc::getEndLoc() const { + TypeLoc Cur = *this; + TypeLoc Last; + while (true) { + switch (Cur.getTypeLocClass()) { + default: + if (!Last) + Last = Cur; + return Last.getLocalSourceRange().getEnd(); + case Paren: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + case FunctionNoProto: + Last = Cur; + break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) + Last = TypeLoc(); + else + Last = Cur; + break; + case Pointer: + case BlockPointer: + case MemberPointer: + case LValueReference: + case RValueReference: + case PackExpansion: + if (!Last) + Last = Cur; + break; + case Qualified: + case Elaborated: + break; + } + Cur = Cur.getNextTypeLoc(); + } +} + + +namespace { + struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +/// \brief Determines if the given type loc corresponds to a +/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in +/// the type hierarchy, this is made somewhat complicated. +/// +/// There are a lot of types that currently use TypeSpecTypeLoc +/// because it's a convenient base class. Ideally we would not accept +/// those here, but ideally we would have better implementations for +/// them. +bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { + if (TL->getType().hasLocalQualifiers()) return false; + return TSTChecker().Visit(*TL); +} + +// Reimplemented to account for GNU/C++ extension +// typeof unary-expression +// where there are no parentheses. +SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const { + if (getRParenLoc().isValid()) + return SourceRange(getTypeofLoc(), getRParenLoc()); + else + return SourceRange(getTypeofLoc(), + getUnderlyingExpr()->getSourceRange().getEnd()); +} + + +TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type); + switch (getTypePtr()->getKind()) { + case BuiltinType::Void: + return TST_void; + case BuiltinType::Bool: + return TST_bool; + case BuiltinType::Char_U: + case BuiltinType::Char_S: + return TST_char; + case BuiltinType::Char16: + return TST_char16; + case BuiltinType::Char32: + return TST_char32; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + return TST_wchar; + case BuiltinType::UChar: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + llvm_unreachable("Builtin type needs extra local data!"); + // Fall through, if the impossible happens. + + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + case BuiltinType::ARCUnbridgedCast: + case BuiltinType::PseudoObject: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + case BuiltinType::BuiltinFn: + return TST_unspecified; + } + + llvm_unreachable("Invalid BuiltinType Kind!"); +} + +TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { + while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL)) + TL = PTL->getInnerLoc(); + return TL; +} + +void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setElaboratedKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); +} + +void DependentNameTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setElaboratedKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + setNameLoc(Loc); +} + +void +DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setElaboratedKeywordLoc(Loc); + if (getTypePtr()->getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + } else { + setQualifierLoc(NestedNameSpecifierLoc()); + } + setTemplateKeywordLoc(Loc); + setTemplateNameLoc(Loc); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), + getTypePtr()->getArgs(), + getArgInfos(), Loc); +} + +void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, + unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc) { + for (unsigned i = 0, e = NumArgs; i != e; ++i) { + switch (Args[i].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + llvm_unreachable("Impossible TemplateArgument"); + + case TemplateArgument::Expression: + ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); + break; + + case TemplateArgument::Type: + ArgInfos[i] = TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(Args[i].getAsType(), + Loc)); + break; + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLocBuilder Builder; + TemplateName Template = Args[i].getAsTemplate(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); + + ArgInfos[i] = TemplateArgumentLocInfo( + Builder.getWithLocInContext(Context), + Loc, + Args[i].getKind() == TemplateArgument::Template + ? SourceLocation() + : Loc); + break; + } + + case TemplateArgument::Pack: + ArgInfos[i] = TemplateArgumentLocInfo(); + break; + } + } +} diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index c16081fb985..844514be27c 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1,2834 +1,2802 @@ -//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This coordinates the debug information generation while generating code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGDebugInfo.h"
-#include "CGBlocks.h"
-#include "CGObjCRuntime.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclFriend.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Constants.h"
-#include "llvm/DataLayout.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Instructions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/Support/Dwarf.h"
-#include "llvm/Support/FileSystem.h"
-using namespace clang;
-using namespace clang::CodeGen;
-
-CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
- : CGM(CGM), DBuilder(CGM.getModule()),
- BlockLiteralGenericSet(false) {
- CreateCompileUnit();
-}
-
-CGDebugInfo::~CGDebugInfo() {
- assert(LexicalBlockStack.empty() &&
- "Region stack mismatch, stack not empty!");
-}
-
-void CGDebugInfo::setLocation(SourceLocation Loc) {
- // If the new location isn't valid return.
- if (!Loc.isValid()) return;
-
- CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
-
- // If we've changed files in the middle of a lexical scope go ahead
- // and create a new lexical scope with file node if it's different
- // from the one in the scope.
- if (LexicalBlockStack.empty()) return;
-
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
- PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc);
-
- if (PCLoc.isInvalid() || PPLoc.isInvalid() ||
- !strcmp(PPLoc.getFilename(), PCLoc.getFilename()))
- return;
-
- llvm::MDNode *LB = LexicalBlockStack.back();
- llvm::DIScope Scope = llvm::DIScope(LB);
- if (Scope.isLexicalBlockFile()) {
- llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB);
- llvm::DIDescriptor D
- = DBuilder.createLexicalBlockFile(LBF.getScope(),
- getOrCreateFile(CurLoc));
- llvm::MDNode *N = D;
- LexicalBlockStack.pop_back();
- LexicalBlockStack.push_back(N);
- } else if (Scope.isLexicalBlock()) {
- llvm::DIDescriptor D
- = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
- llvm::MDNode *N = D;
- LexicalBlockStack.pop_back();
- LexicalBlockStack.push_back(N);
- }
-}
-
-/// getContextDescriptor - Get context info for the decl.
-llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) {
- if (!Context)
- return TheCU;
-
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
- I = RegionMap.find(Context);
- if (I != RegionMap.end()) {
- llvm::Value *V = I->second;
- return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
- }
-
- // Check namespace.
- if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
-
- if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) {
- if (!RDecl->isDependentType()) {
- llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
- getOrCreateMainFile());
- return llvm::DIDescriptor(Ty);
- }
- }
- return TheCU;
-}
-
-/// getFunctionName - Get function name for the given FunctionDecl. If the
-/// name is constructred on demand (e.g. C++ destructor) then the name
-/// is stored on the side.
-StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
- assert (FD && "Invalid FunctionDecl!");
- IdentifierInfo *FII = FD->getIdentifier();
- FunctionTemplateSpecializationInfo *Info
- = FD->getTemplateSpecializationInfo();
- if (!Info && FII)
- return FII->getName();
-
- // Otherwise construct human readable name for debug info.
- std::string NS = FD->getNameAsString();
-
- // Add any template specialization args.
- if (Info) {
- const TemplateArgumentList *TArgs = Info->TemplateArguments;
- const TemplateArgument *Args = TArgs->data();
- unsigned NumArgs = TArgs->size();
- PrintingPolicy Policy(CGM.getLangOpts());
- NS += TemplateSpecializationType::PrintTemplateArgumentList(Args,
- NumArgs,
- Policy);
- }
-
- // Copy this name on the side and use its reference.
- char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
- memcpy(StrPtr, NS.data(), NS.length());
- return StringRef(StrPtr, NS.length());
-}
-
-StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
- SmallString<256> MethodName;
- llvm::raw_svector_ostream OS(MethodName);
- OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
- const DeclContext *DC = OMD->getDeclContext();
- if (const ObjCImplementationDecl *OID =
- dyn_cast<const ObjCImplementationDecl>(DC)) {
- OS << OID->getName();
- } else if (const ObjCInterfaceDecl *OID =
- dyn_cast<const ObjCInterfaceDecl>(DC)) {
- OS << OID->getName();
- } else if (const ObjCCategoryImplDecl *OCD =
- dyn_cast<const ObjCCategoryImplDecl>(DC)){
- OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
- OCD->getIdentifier()->getNameStart() << ')';
- }
- OS << ' ' << OMD->getSelector().getAsString() << ']';
-
- char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
- memcpy(StrPtr, MethodName.begin(), OS.tell());
- return StringRef(StrPtr, OS.tell());
-}
-
-/// getSelectorName - Return selector name. This is used for debugging
-/// info.
-StringRef CGDebugInfo::getSelectorName(Selector S) {
- const std::string &SName = S.getAsString();
- char *StrPtr = DebugInfoNames.Allocate<char>(SName.size());
- memcpy(StrPtr, SName.data(), SName.size());
- return StringRef(StrPtr, SName.size());
-}
-
-/// getClassName - Get class name including template argument list.
-StringRef
-CGDebugInfo::getClassName(const RecordDecl *RD) {
- const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(RD);
- if (!Spec)
- return RD->getName();
-
- const TemplateArgument *Args;
- unsigned NumArgs;
- if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
- const TemplateSpecializationType *TST =
- cast<TemplateSpecializationType>(TAW->getType());
- Args = TST->getArgs();
- NumArgs = TST->getNumArgs();
- } else {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Args = TemplateArgs.data();
- NumArgs = TemplateArgs.size();
- }
- StringRef Name = RD->getIdentifier()->getName();
- PrintingPolicy Policy(CGM.getLangOpts());
- std::string TemplateArgList =
- TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy);
-
- // Copy this name on the side and use its reference.
- size_t Length = Name.size() + TemplateArgList.size();
- char *StrPtr = DebugInfoNames.Allocate<char>(Length);
- memcpy(StrPtr, Name.data(), Name.size());
- memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size());
- return StringRef(StrPtr, Length);
-}
-
-/// getOrCreateFile - Get the file debug info descriptor for the input location.
-llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
- if (!Loc.isValid())
- // If Location is not valid then use main input file.
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
-
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-
- if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty())
- // If the location is not valid then use main input file.
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
-
- // Cache the results.
- const char *fname = PLoc.getFilename();
- llvm::DenseMap<const char *, llvm::WeakVH>::iterator it =
- DIFileCache.find(fname);
-
- if (it != DIFileCache.end()) {
- // Verify that the information still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIFile(cast<llvm::MDNode>(V));
- }
-
- llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname());
-
- DIFileCache[fname] = F;
- return F;
-}
-
-/// getOrCreateMainFile - Get the file info for main compile unit.
-llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
-}
-
-/// getLineNumber - Get line number for the location. If location is invalid
-/// then use current location.
-unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
- if (Loc.isInvalid() && CurLoc.isInvalid())
- return 0;
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid()? PLoc.getLine() : 0;
-}
-
-/// getColumnNumber - Get column number for the location.
-unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
- // We may not want column information at all.
- if (!CGM.getCodeGenOpts().DebugColumnInfo)
- return 0;
-
- // If the location is invalid then use the current column.
- if (Loc.isInvalid() && CurLoc.isInvalid())
- return 0;
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
- return PLoc.isValid()? PLoc.getColumn() : 0;
-}
-
-StringRef CGDebugInfo::getCurrentDirname() {
- if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
- return CGM.getCodeGenOpts().DebugCompilationDir;
-
- if (!CWDName.empty())
- return CWDName;
- SmallString<256> CWD;
- llvm::sys::fs::current_path(CWD);
- char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
- memcpy(CompDirnamePtr, CWD.data(), CWD.size());
- return CWDName = StringRef(CompDirnamePtr, CWD.size());
-}
-
-/// CreateCompileUnit - Create new compile unit.
-void CGDebugInfo::CreateCompileUnit() {
-
- // Get absolute path name.
- SourceManager &SM = CGM.getContext().getSourceManager();
- std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
- if (MainFileName.empty())
- MainFileName = "<unknown>";
-
- // The main file name provided via the "-main-file-name" option contains just
- // the file name itself with no path information. This file name may have had
- // a relative path, so we look into the actual file entry for the main
- // file to determine the real absolute path for the file.
- std::string MainFileDir;
- if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- MainFileDir = MainFile->getDir()->getName();
- if (MainFileDir != ".")
- MainFileName = MainFileDir + "/" + MainFileName;
- }
-
- // Save filename string.
- char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
- memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
- StringRef Filename(FilenamePtr, MainFileName.length());
-
- unsigned LangTag;
- const LangOptions &LO = CGM.getLangOpts();
- if (LO.CPlusPlus) {
- if (LO.ObjC1)
- LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
- else
- LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
- } else if (LO.ObjC1) {
- LangTag = llvm::dwarf::DW_LANG_ObjC;
- } else if (LO.C99) {
- LangTag = llvm::dwarf::DW_LANG_C99;
- } else {
- LangTag = llvm::dwarf::DW_LANG_C89;
- }
-
- std::string Producer = getClangFullVersion();
-
- // Figure out which version of the ObjC runtime we have.
- unsigned RuntimeVers = 0;
- if (LO.ObjC1)
- RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
-
- // Create new compile unit.
- DBuilder.createCompileUnit(
- LangTag, Filename, getCurrentDirname(),
- Producer,
- LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
- // FIXME - Eliminate TheCU.
- TheCU = llvm::DICompileUnit(DBuilder.getCU());
-}
-
-/// CreateType - Get the Basic type from the cache or create a new
-/// one if necessary.
-llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
- unsigned Encoding = 0;
- StringRef BTName;
- switch (BT->getKind()) {
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
- llvm_unreachable("Unexpected builtin type");
- case BuiltinType::NullPtr:
- return DBuilder.
- createNullPtrType(BT->getName(CGM.getLangOpts()));
- case BuiltinType::Void:
- return llvm::DIType();
- case BuiltinType::ObjCClass:
- if (ClassTy.Verify())
- return ClassTy;
- ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU,
- getOrCreateMainFile(), 0);
- return ClassTy;
- case BuiltinType::ObjCId: {
- // typedef struct objc_class *Class;
- // typedef struct objc_object {
- // Class isa;
- // } *id;
-
- if (ObjTy.Verify())
- return ObjTy;
-
- if (!ClassTy.Verify())
- ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU,
- getOrCreateMainFile(), 0);
-
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
-
- llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
-
- llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
- getOrCreateMainFile(),
- 0, 0, 0, 0,
- llvm::DIArray());
-
- llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
- SmallVector<llvm::Value *, 1> EltTys;
- llvm::DIType FieldTy =
- DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
- getOrCreateMainFile(), 0, Size,
- 0, 0, 0, ISATy);
- EltTys.push_back(FieldTy);
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
- ObjNode->replaceOperandWith(10, Elements);
- ObjTy = llvm::DIType(ObjNode);
- return ObjTy;
- }
- case BuiltinType::ObjCSel: {
- if (SelTy.Verify())
- return SelTy;
- SelTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_selector", TheCU, getOrCreateMainFile(),
- 0);
- return SelTy;
- }
-
- case BuiltinType::OCLImage1d:
- return getOrCreateStructPtrType("opencl_image1d_t",
- OCLImage1dDITy);
- case BuiltinType::OCLImage1dArray:
- return getOrCreateStructPtrType("opencl_image1d_array_t",
- OCLImage1dArrayDITy);
- case BuiltinType::OCLImage1dBuffer:
- return getOrCreateStructPtrType("opencl_image1d_buffer_t",
- OCLImage1dBufferDITy);
- case BuiltinType::OCLImage2d:
- return getOrCreateStructPtrType("opencl_image2d_t",
- OCLImage2dDITy);
- case BuiltinType::OCLImage2dArray:
- return getOrCreateStructPtrType("opencl_image2d_array_t",
- OCLImage2dArrayDITy);
- case BuiltinType::OCLImage3d:
- return getOrCreateStructPtrType("opencl_image3d_t",
- OCLImage3dDITy);
-
- case BuiltinType::UChar:
- case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
- case BuiltinType::Char16:
- case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break;
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::UInt128:
- case BuiltinType::ULong:
- case BuiltinType::WChar_U:
- case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Int128:
- case BuiltinType::Long:
- case BuiltinType::WChar_S:
- case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
- case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::LongDouble:
- case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
- }
-
- switch (BT->getKind()) {
- case BuiltinType::Long: BTName = "long int"; break;
- case BuiltinType::LongLong: BTName = "long long int"; break;
- case BuiltinType::ULong: BTName = "long unsigned int"; break;
- case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
- default:
- BTName = BT->getName(CGM.getLangOpts());
- break;
- }
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(BT);
- uint64_t Align = CGM.getContext().getTypeAlign(BT);
- llvm::DIType DbgTy =
- DBuilder.createBasicType(BTName, Size, Align, Encoding);
- return DbgTy;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
- // Bit size, align and offset of the type.
- unsigned Encoding = llvm::dwarf::DW_ATE_complex_float;
- if (Ty->isComplexIntegerType())
- Encoding = llvm::dwarf::DW_ATE_lo_user;
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- llvm::DIType DbgTy =
- DBuilder.createBasicType("complex", Size, Align, Encoding);
-
- return DbgTy;
-}
-
-/// CreateCVRType - Get the qualified type from the cache or create
-/// a new one if necessary.
-llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
- QualifierCollector Qc;
- const Type *T = Qc.strip(Ty);
-
- // Ignore these qualifiers for now.
- Qc.removeObjCGCAttr();
- Qc.removeAddressSpace();
- Qc.removeObjCLifetime();
-
- // We will create one Derived type for one qualifier and recurse to handle any
- // additional ones.
- unsigned Tag;
- if (Qc.hasConst()) {
- Tag = llvm::dwarf::DW_TAG_const_type;
- Qc.removeConst();
- } else if (Qc.hasVolatile()) {
- Tag = llvm::dwarf::DW_TAG_volatile_type;
- Qc.removeVolatile();
- } else if (Qc.hasRestrict()) {
- Tag = llvm::dwarf::DW_TAG_restrict_type;
- Qc.removeRestrict();
- } else {
- assert(Qc.empty() && "Unknown type qualifier for debug info");
- return getOrCreateType(QualType(T, 0), Unit);
- }
-
- llvm::DIType FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit);
-
- // No need to fill in the Name, Line, Size, Alignment, Offset in case of
- // CVR derived types.
- llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy);
-
- return DbgTy;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
- llvm::DIFile Unit) {
- llvm::DIType DbgTy =
- CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
- Ty->getPointeeType(), Unit);
- return DbgTy;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
- llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
- Ty->getPointeeType(), Unit);
-}
-
-// Creates a forward declaration for a RecordDecl in the given context.
-llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
- llvm::DIDescriptor Ctx) {
- llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = getClassName(RD);
-
- unsigned Tag = 0;
- if (RD->isStruct() || RD->isInterface())
- Tag = llvm::dwarf::DW_TAG_structure_type;
- else if (RD->isUnion())
- Tag = llvm::dwarf::DW_TAG_union_type;
- else {
- assert(RD->isClass());
- Tag = llvm::dwarf::DW_TAG_class_type;
- }
-
- // Create the type.
- return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line);
-}
-
-// Walk up the context chain and create forward decls for record decls,
-// and normal descriptors for namespaces.
-llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
- if (!Context)
- return TheCU;
-
- // See if we already have the parent.
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
- I = RegionMap.find(Context);
- if (I != RegionMap.end()) {
- llvm::Value *V = I->second;
- return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
- }
-
- // Check namespace.
- if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
-
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
- if (!RD->isDependentType()) {
- llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
- getOrCreateMainFile());
- return llvm::DIDescriptor(Ty);
- }
- }
- return TheCU;
-}
-
-/// CreatePointeeType - Create Pointee type. If Pointee is a record
-/// then emit record's fwd if debug info size reduction is enabled.
-llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
- llvm::DIFile Unit) {
- if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo)
- return getOrCreateType(PointeeTy, Unit);
-
- // Limit debug info for the pointee type.
-
- // If we have an existing type, use that, it's still smaller than creating
- // a new type.
- llvm::DIType Ty = getTypeOrNull(PointeeTy);
- if (Ty.Verify()) return Ty;
-
- // Handle qualifiers.
- if (PointeeTy.hasLocalQualifiers())
- return CreateQualifiedType(PointeeTy, Unit);
-
- if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) {
- RecordDecl *RD = RTy->getDecl();
- llvm::DIDescriptor FDContext =
- getContextDescriptor(cast<Decl>(RD->getDeclContext()));
- llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
- TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy;
- return RetTy;
- }
- return getOrCreateType(PointeeTy, Unit);
-
-}
-
-llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
- const Type *Ty,
- QualType PointeeTy,
- llvm::DIFile Unit) {
- if (Tag == llvm::dwarf::DW_TAG_reference_type ||
- Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
- return DBuilder.createReferenceType(Tag,
- CreatePointeeType(PointeeTy, Unit));
-
- // Bit size, align and offset of the type.
- // Size is always the size of a pointer. We can't use getTypeSize here
- // because that does not return the correct value for references.
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
-
- return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit),
- Size, Align);
-}
-
-llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache) {
- if (Cache.Verify())
- return Cache;
- Cache =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- Name, TheCU, getOrCreateMainFile(),
- 0);
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- Cache = DBuilder.createPointerType(Cache, Size);
- return Cache;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
- llvm::DIFile Unit) {
- if (BlockLiteralGenericSet)
- return BlockLiteralGeneric;
-
- SmallVector<llvm::Value *, 8> EltTys;
- llvm::DIType FieldTy;
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
- llvm::DIArray Elements;
- llvm::DIType EltTy, DescTy;
-
- FieldOffset = 0;
- FType = CGM.getContext().UnsignedLongTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
-
- Elements = DBuilder.getOrCreateArray(EltTys);
- EltTys.clear();
-
- unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
- unsigned LineNo = getLineNumber(CurLoc);
-
- EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
- Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
-
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
-
- DescTy = DBuilder.createPointerType(EltTy, Size);
-
- FieldOffset = 0;
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
- FType = CGM.getContext().IntTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = DescTy;
- FieldSize = CGM.getContext().getTypeSize(Ty);
- FieldAlign = CGM.getContext().getTypeAlign(Ty);
- FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit,
- LineNo, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
- Elements = DBuilder.getOrCreateArray(EltTys);
-
- EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
- Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
-
- BlockLiteralGenericSet = true;
- BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
- return BlockLiteralGeneric;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
- // Typedefs are derived from some other type. If we have a typedef of a
- // typedef, make sure to emit the whole chain.
- llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
- if (!Src.Verify())
- return llvm::DIType();
- // We don't set size information, but do specify where the typedef was
- // declared.
- unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
- const TypedefNameDecl *TyDecl = Ty->getDecl();
-
- llvm::DIDescriptor TypedefContext =
- getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
-
- return
- DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
- llvm::DIFile Unit) {
- SmallVector<llvm::Value *, 16> EltTys;
-
- // Add the result type at least.
- EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit));
-
- // Set up remainder of arguments if there is a prototype.
- // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'!
- if (isa<FunctionNoProtoType>(Ty))
- EltTys.push_back(DBuilder.createUnspecifiedParameter());
- else if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) {
- for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
- EltTys.push_back(getOrCreateType(FPT->getArgType(i), Unit));
- }
-
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
- return DBuilder.createSubroutineType(Unit, EltTypeArray);
-}
-
-
-void CGDebugInfo::
-CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
-
- for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
- I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
- if (V->getInit()) {
- const APValue *Value = V->evaluateValue();
- if (Value && Value->isInt()) {
- llvm::ConstantInt *CI
- = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
-
- // Create the descriptor for static variable.
- llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
- StringRef VName = V->getName();
- llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
- // Do not use DIGlobalVariable for enums.
- if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
- DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
- getLineNumber(V->getLocation()),
- VTy, true, CI);
- }
- }
- }
- }
-}
-
-llvm::DIType CGDebugInfo::createFieldType(StringRef name,
- QualType type,
- uint64_t sizeInBitsOverride,
- SourceLocation loc,
- AccessSpecifier AS,
- uint64_t offsetInBits,
- llvm::DIFile tunit,
- llvm::DIDescriptor scope) {
- llvm::DIType debugType = getOrCreateType(type, tunit);
-
- // Get the location for the field.
- llvm::DIFile file = getOrCreateFile(loc);
- unsigned line = getLineNumber(loc);
-
- uint64_t sizeInBits = 0;
- unsigned alignInBits = 0;
- if (!type->isIncompleteArrayType()) {
- llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
-
- if (sizeInBitsOverride)
- sizeInBits = sizeInBitsOverride;
- }
-
- unsigned flags = 0;
- if (AS == clang::AS_private)
- flags |= llvm::DIDescriptor::FlagPrivate;
- else if (AS == clang::AS_protected)
- flags |= llvm::DIDescriptor::FlagProtected;
-
- return DBuilder.createMemberType(scope, name, file, line, sizeInBits,
- alignInBits, offsetInBits, flags, debugType);
-}
-
-/// CollectRecordFields - A helper function to collect debug info for
-/// record fields. This is used while creating debug info entry for a Record.
-void CGDebugInfo::
-CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
- SmallVectorImpl<llvm::Value *> &elements,
- llvm::DIType RecordTy) {
- unsigned fieldNo = 0;
- const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
-
- // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
- // has the name and the location of the variable so we should iterate over
- // both concurrently.
- if (CXXDecl && CXXDecl->isLambda()) {
- RecordDecl::field_iterator Field = CXXDecl->field_begin();
- unsigned fieldno = 0;
- for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
- E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
- const LambdaExpr::Capture C = *I;
- if (C.capturesVariable()) {
- VarDecl *V = C.getCapturedVar();
- llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
- StringRef VName = V->getName();
- uint64_t SizeInBitsOverride = 0;
- if (Field->isBitField()) {
- SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
- }
- llvm::DIType fieldType
- = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
- Field->getAccess(), layout.getFieldOffset(fieldno),
- VUnit, RecordTy);
- elements.push_back(fieldType);
- } else {
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this' or
- // by using AT_object_pointer for the function and having that be
- // used as 'this' for semantic references.
- assert(C.capturesThis() && "Field that isn't captured and isn't this?");
- FieldDecl *f = *Field;
- llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
- QualType type = f->getType();
- llvm::DIType fieldType
- = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
- layout.getFieldOffset(fieldNo), VUnit, RecordTy);
-
- elements.push_back(fieldType);
- }
- }
- } else {
- bool IsMsStruct = record->isMsStruct(CGM.getContext());
- const FieldDecl *LastFD = 0;
- for (RecordDecl::field_iterator I = record->field_begin(),
- E = record->field_end();
- I != E; ++I, ++fieldNo) {
- FieldDecl *field = *I;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
- --fieldNo;
- continue;
- }
- LastFD = field;
- }
-
- StringRef name = field->getName();
- QualType type = field->getType();
-
- // Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType()) {
- LastFD = field;
- continue;
- }
-
- uint64_t SizeInBitsOverride = 0;
- if (field->isBitField()) {
- SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
- }
-
- llvm::DIType fieldType
- = createFieldType(name, type, SizeInBitsOverride,
- field->getLocation(), field->getAccess(),
- layout.getFieldOffset(fieldNo), tunit, RecordTy);
-
- elements.push_back(fieldType);
- }
- }
-}
-
-/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
-/// function type is not updated to include implicit "this" pointer. Use this
-/// routine to get a method type which includes "this" pointer.
-llvm::DIType
-CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile Unit) {
- llvm::DIType FnTy
- = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(),
- 0),
- Unit);
-
- // Add "this" pointer.
- llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
- assert (Args.getNumElements() && "Invalid number of arguments!");
-
- SmallVector<llvm::Value *, 16> Elts;
-
- // First element is always return type. For 'void' functions it is NULL.
- Elts.push_back(Args.getElement(0));
-
- if (!Method->isStatic()) {
- // "this" pointer is always first argument.
- QualType ThisPtr = Method->getThisType(CGM.getContext());
-
- const CXXRecordDecl *RD = Method->getParent();
- if (isa<ClassTemplateSpecializationDecl>(RD)) {
- // Create pointer type directly in this case.
- const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
- QualType PointeeTy = ThisPtrTy->getPointeeType();
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
- uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
- llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
- llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- // TODO: This and the artificial type below are misleading, the
- // types aren't artificial the argument is, but the current
- // metadata doesn't represent that.
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- } else {
- llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- }
- }
-
- // Copy rest of the arguments.
- for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
- Elts.push_back(Args.getElement(i));
-
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
-
- return DBuilder.createSubroutineType(Unit, EltTypeArray);
-}
-
-/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
-/// inside a function.
-static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
- if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
- return isFunctionLocalClass(NRD);
- if (isa<FunctionDecl>(RD->getDeclContext()))
- return true;
- return false;
-}
-
-/// CreateCXXMemberFunction - A helper function to create a DISubprogram for
-/// a single member function GlobalDecl.
-llvm::DISubprogram
-CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
- llvm::DIFile Unit,
- llvm::DIType RecordTy) {
- bool IsCtorOrDtor =
- isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
-
- StringRef MethodName = getFunctionName(Method);
- llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
-
- // Since a single ctor/dtor corresponds to multiple functions, it doesn't
- // make sense to give a single ctor/dtor a linkage name.
- StringRef MethodLinkageName;
- if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
- MethodLinkageName = CGM.getMangledName(Method);
-
- // Get the location for the method.
- llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation());
- unsigned MethodLine = getLineNumber(Method->getLocation());
-
- // Collect virtual method info.
- llvm::DIType ContainingType;
- unsigned Virtuality = 0;
- unsigned VIndex = 0;
-
- if (Method->isVirtual()) {
- if (Method->isPure())
- Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual;
- else
- Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual;
-
- // It doesn't make sense to give a virtual destructor a vtable index,
- // since a single destructor has two entries in the vtable.
- if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getVTableContext().getMethodVTableIndex(Method);
- ContainingType = RecordTy;
- }
-
- unsigned Flags = 0;
- if (Method->isImplicit())
- Flags |= llvm::DIDescriptor::FlagArtificial;
- AccessSpecifier Access = Method->getAccess();
- if (Access == clang::AS_private)
- Flags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- Flags |= llvm::DIDescriptor::FlagProtected;
- if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
- if (CXXC->isExplicit())
- Flags |= llvm::DIDescriptor::FlagExplicit;
- } else if (const CXXConversionDecl *CXXC =
- dyn_cast<CXXConversionDecl>(Method)) {
- if (CXXC->isExplicit())
- Flags |= llvm::DIDescriptor::FlagExplicit;
- }
- if (Method->hasPrototype())
- Flags |= llvm::DIDescriptor::FlagPrototyped;
-
- llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
- llvm::DISubprogram SP =
- DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
- MethodDefUnit, MethodLine,
- MethodTy, /*isLocalToUnit=*/false,
- /* isDefinition=*/ false,
- Virtuality, VIndex, ContainingType,
- Flags, CGM.getLangOpts().Optimize, NULL,
- TParamsArray);
-
- SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
-
- return SP;
-}
-
-/// CollectCXXMemberFunctions - A helper function to collect debug info for
-/// C++ member functions. This is used while creating debug info entry for
-/// a Record.
-void CGDebugInfo::
-CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
-
- // Since we want more than just the individual member decls if we
- // have templated functions iterate over every declaration to gather
- // the functions.
- for(DeclContext::decl_iterator I = RD->decls_begin(),
- E = RD->decls_end(); I != E; ++I) {
- Decl *D = *I;
- if (D->isImplicit() && !D->isUsed())
- continue;
-
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
- else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
- for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
- SE = FTD->spec_end(); SI != SE; ++SI)
- EltTys.push_back(CreateCXXMemberFunction(cast<CXXMethodDecl>(*SI), Unit,
- RecordTy));
- }
-}
-
-/// CollectCXXFriends - A helper function to collect debug info for
-/// C++ base classes. This is used while creating debug info entry for
-/// a Record.
-void CGDebugInfo::
-CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
- for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
- BE = RD->friend_end(); BI != BE; ++BI) {
- if ((*BI)->isUnsupportedFriend())
- continue;
- if (TypeSourceInfo *TInfo = (*BI)->getFriendType())
- EltTys.push_back(DBuilder.createFriend(RecordTy,
- getOrCreateType(TInfo->getType(),
- Unit)));
- }
-}
-
-/// CollectCXXBases - A helper function to collect debug info for
-/// C++ base classes. This is used while creating debug info entry for
-/// a Record.
-void CGDebugInfo::
-CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy) {
-
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
- BE = RD->bases_end(); BI != BE; ++BI) {
- unsigned BFlags = 0;
- uint64_t BaseOffset;
-
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
-
- if (BI->isVirtual()) {
- // virtual base offset offset is -ve. The code generator emits dwarf
- // expression where it expects +ve number.
- BaseOffset =
- 0 - CGM.getVTableContext()
- .getVirtualBaseOffsetOffset(RD, Base).getQuantity();
- BFlags = llvm::DIDescriptor::FlagVirtual;
- } else
- BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
- // FIXME: Inconsistent units for BaseOffset. It is in bytes when
- // BI->isVirtual() and bits when not.
-
- AccessSpecifier Access = BI->getAccessSpecifier();
- if (Access == clang::AS_private)
- BFlags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- BFlags |= llvm::DIDescriptor::FlagProtected;
-
- llvm::DIType DTy =
- DBuilder.createInheritance(RecordTy,
- getOrCreateType(BI->getType(), Unit),
- BaseOffset, BFlags);
- EltTys.push_back(DTy);
- }
-}
-
-/// CollectTemplateParams - A helper function to collect template parameters.
-llvm::DIArray CGDebugInfo::
-CollectTemplateParams(const TemplateParameterList *TPList,
- const TemplateArgumentList &TAList,
- llvm::DIFile Unit) {
- SmallVector<llvm::Value *, 16> TemplateParams;
- for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
- const TemplateArgument &TA = TAList[i];
- const NamedDecl *ND = TPList->getParam(i);
- if (TA.getKind() == TemplateArgument::Type) {
- llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
- llvm::DITemplateTypeParameter TTP =
- DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy);
- TemplateParams.push_back(TTP);
- } else if (TA.getKind() == TemplateArgument::Integral) {
- llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
- llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
- TA.getAsIntegral().getZExtValue());
- TemplateParams.push_back(TVP);
- }
- }
- return DBuilder.getOrCreateArray(TemplateParams);
-}
-
-/// CollectFunctionTemplateParams - A helper function to collect debug
-/// info for function template parameters.
-llvm::DIArray CGDebugInfo::
-CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
- if (FD->getTemplatedKind() ==
- FunctionDecl::TK_FunctionTemplateSpecialization) {
- const TemplateParameterList *TList =
- FD->getTemplateSpecializationInfo()->getTemplate()
- ->getTemplateParameters();
- return
- CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit);
- }
- return llvm::DIArray();
-}
-
-/// CollectCXXTemplateParams - A helper function to collect debug info for
-/// template parameters.
-llvm::DIArray CGDebugInfo::
-CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
- llvm::DIFile Unit) {
- llvm::PointerUnion<ClassTemplateDecl *,
- ClassTemplatePartialSpecializationDecl *>
- PU = TSpecial->getSpecializedTemplateOrPartial();
-
- TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
- PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
- PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
- const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
- return CollectTemplateParams(TPList, TAList, Unit);
-}
-
-/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
-llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
- if (VTablePtrType.isValid())
- return VTablePtrType;
-
- ASTContext &Context = CGM.getContext();
-
- /* Function type */
- llvm::Value *STy = getOrCreateType(Context.IntTy, Unit);
- llvm::DIArray SElements = DBuilder.getOrCreateArray(STy);
- llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements);
- unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
- llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0,
- "__vtbl_ptr_type");
- VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
- return VTablePtrType;
-}
-
-/// getVTableName - Get vtable name for the given Class.
-StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
- // Construct gdb compatible name name.
- std::string Name = "_vptr$" + RD->getNameAsString();
-
- // Copy this name on the side and use its reference.
- char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
- memcpy(StrPtr, Name.data(), Name.length());
- return StringRef(StrPtr, Name.length());
-}
-
-
-/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
-/// debug info entry in EltTys vector.
-void CGDebugInfo::
-CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
- SmallVectorImpl<llvm::Value *> &EltTys) {
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
-
- // If there is a primary base then it will hold vtable info.
- if (RL.getPrimaryBase())
- return;
-
- // If this class is not dynamic then there is not any vtable info to collect.
- if (!RD->isDynamicClass())
- return;
-
- unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- llvm::DIType VPTR
- = DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
- 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial,
- getOrCreateVTablePtrType(Unit));
- EltTys.push_back(VPTR);
-}
-
-/// getOrCreateRecordType - Emit record type's standalone debug info.
-llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
- SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
- return T;
-}
-
-/// getOrCreateInterfaceType - Emit an objective c interface type standalone
-/// debug info.
-llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
- SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
- DBuilder.retainType(T);
- return T;
-}
-
-/// CreateType - get structure or union type.
-llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
- RecordDecl *RD = Ty->getDecl();
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
-
- // Records and classes and unions can all be recursive. To handle them, we
- // first generate a debug descriptor for the struct as a forward declaration.
- // Then (if it is a definition) we go through and get debug info for all of
- // its members. Finally, we create a descriptor for the complete type (which
- // may refer to the forward decl if the struct is recursive) and replace all
- // uses of the forward declaration with the final definition.
-
- llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
-
- if (FwdDecl.isForwardDecl())
- return FwdDecl;
-
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl);
-
- // Push the struct on region stack.
- LexicalBlockStack.push_back(FwdDeclNode);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
-
- // Add this to the completed types cache since we're completing it.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
-
- // Convert all the elements.
- SmallVector<llvm::Value *, 16> EltTys;
-
- // Note: The split of CXXDecl information here is intentional, the
- // gdb tests will depend on a certain ordering at printout. The debug
- // information offsets are still correct if we merge them all together
- // though.
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- if (CXXDecl) {
- CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
- CollectVTableInfo(CXXDecl, DefUnit, EltTys);
- }
-
- // Collect static variables with initializers and other fields.
- CollectRecordStaticVars(RD, FwdDecl);
- CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
- llvm::DIArray TParamsArray;
- if (CXXDecl) {
- CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
- CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl);
- if (const ClassTemplateSpecializationDecl *TSpecial
- = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit);
- }
-
- LexicalBlockStack.pop_back();
- RegionMap.erase(Ty->getDecl());
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- // FIXME: Magic numbers ahoy! These should be changed when we
- // get some enums in llvm/Analysis/DebugInfo.h to refer to
- // them.
- if (RD->isUnion())
- FwdDeclNode->replaceOperandWith(10, Elements);
- else if (CXXDecl) {
- FwdDeclNode->replaceOperandWith(10, Elements);
- FwdDeclNode->replaceOperandWith(13, TParamsArray);
- } else
- FwdDeclNode->replaceOperandWith(10, Elements);
-
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode);
- return llvm::DIType(FwdDeclNode);
-}
-
-/// CreateType - get objective-c object type.
-llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty,
- llvm::DIFile Unit) {
- // Ignore protocols.
- return getOrCreateType(Ty->getBaseType(), Unit);
-}
-
-/// CreateType - get objective-c interface type.
-llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
- llvm::DIFile Unit) {
- ObjCInterfaceDecl *ID = Ty->getDecl();
- if (!ID)
- return llvm::DIType();
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
- unsigned Line = getLineNumber(ID->getLocation());
- unsigned RuntimeLang = TheCU.getLanguage();
-
- // If this is just a forward declaration return a special forward-declaration
- // debug type since we won't be able to lay out the entire type.
- ObjCInterfaceDecl *Def = ID->getDefinition();
- if (!Def) {
- llvm::DIType FwdDecl =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- ID->getName(), TheCU, DefUnit, Line,
- RuntimeLang);
- return FwdDecl;
- }
-
- ID = Def;
-
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
-
- unsigned Flags = 0;
- if (ID->getImplementation())
- Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
-
- llvm::DIType RealDecl =
- DBuilder.createStructType(Unit, ID->getName(), DefUnit,
- Line, Size, Align, Flags,
- llvm::DIArray(), RuntimeLang);
-
- // Otherwise, insert it into the CompletedTypeCache so that recursive uses
- // will find it and we're emitting the complete type.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
- // Push the struct on region stack.
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
-
- LexicalBlockStack.push_back(FwdDeclNode);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
-
- // Convert all the elements.
- SmallVector<llvm::Value *, 16> EltTys;
-
- ObjCInterfaceDecl *SClass = ID->getSuperClass();
- if (SClass) {
- llvm::DIType SClassTy =
- getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
- if (!SClassTy.isValid())
- return llvm::DIType();
-
- llvm::DIType InhTag =
- DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
- EltTys.push_back(InhTag);
- }
-
- for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(),
- E = ID->prop_end(); I != E; ++I) {
- const ObjCPropertyDecl *PD = *I;
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- llvm::MDNode *PropertyNode =
- DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
- (Getter && Getter->isImplicit()) ? "" :
- getSelectorName(PD->getGetterName()),
- (Setter && Setter->isImplicit()) ? "" :
- getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
- EltTys.push_back(PropertyNode);
- }
-
- const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
- unsigned FieldNo = 0;
- for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
- Field = Field->getNextIvar(), ++FieldNo) {
- llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- if (!FieldTy.isValid())
- return llvm::DIType();
-
- StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields.
- if (FieldName.empty())
- continue;
-
- // Get the location for the field.
- llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation());
- unsigned FieldLine = getLineNumber(Field->getLocation());
- QualType FType = Field->getType();
- uint64_t FieldSize = 0;
- unsigned FieldAlign = 0;
-
- if (!FType->isIncompleteArrayType()) {
-
- // Bit size, align and offset of the type.
- FieldSize = Field->isBitField()
- ? Field->getBitWidthValue(CGM.getContext())
- : CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- }
-
- uint64_t FieldOffset;
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- // We don't know the runtime offset of an ivar if we're using the
- // non-fragile ABI. For bitfields, use the bit offset into the first
- // byte of storage of the bitfield. For other fields, use zero.
- if (Field->isBitField()) {
- FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(
- CGM, ID, Field);
- FieldOffset %= CGM.getContext().getCharWidth();
- } else {
- FieldOffset = 0;
- }
- } else {
- FieldOffset = RL.getFieldOffset(FieldNo);
- }
-
- unsigned Flags = 0;
- if (Field->getAccessControl() == ObjCIvarDecl::Protected)
- Flags = llvm::DIDescriptor::FlagProtected;
- else if (Field->getAccessControl() == ObjCIvarDecl::Private)
- Flags = llvm::DIDescriptor::FlagPrivate;
-
- llvm::MDNode *PropertyNode = NULL;
- if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
- if (ObjCPropertyImplDecl *PImpD =
- ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
- if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
- PropertyNode =
- DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
- (Getter && Getter->isImplicit()) ? "" :
- getSelectorName(PD->getGetterName()),
- (Setter && Setter->isImplicit()) ? "" :
- getSelectorName(PD->getSetterName()),
- PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
- }
- }
- }
- FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
- FieldLine, FieldSize, FieldAlign,
- FieldOffset, Flags, FieldTy,
- PropertyNode);
- EltTys.push_back(FieldTy);
- }
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- FwdDeclNode->replaceOperandWith(10, Elements);
-
- LexicalBlockStack.pop_back();
- return llvm::DIType(FwdDeclNode);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
- llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
- int64_t Count = Ty->getNumElements();
- if (Count == 0)
- // If number of elements are not known then this is an unbounded array.
- // Use Count == -1 to express such arrays.
- Count = -1;
-
- llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count);
- llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
-
- return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
- llvm::DIFile Unit) {
- uint64_t Size;
- uint64_t Align;
-
- // FIXME: make getTypeAlign() aware of VLAs and incomplete array types
- if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) {
- Size = 0;
- Align =
- CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT));
- } else if (Ty->isIncompleteArrayType()) {
- Size = 0;
- if (Ty->getElementType()->isIncompleteType())
- Align = 0;
- else
- Align = CGM.getContext().getTypeAlign(Ty->getElementType());
- } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) {
- Size = 0;
- Align = 0;
- } else {
- // Size and align of the whole array, not the element type.
- Size = CGM.getContext().getTypeSize(Ty);
- Align = CGM.getContext().getTypeAlign(Ty);
- }
-
- // Add the dimensions of the array. FIXME: This loses CV qualifiers from
- // interior arrays, do we care? Why aren't nested arrays represented the
- // obvious/recursive way?
- SmallVector<llvm::Value *, 8> Subscripts;
- QualType EltTy(Ty, 0);
- while ((Ty = dyn_cast<ArrayType>(EltTy))) {
- // If the number of elements is known, then count is that number. Otherwise,
- // it's -1. This allows us to represent a subrange with an array of 0
- // elements, like this:
- //
- // struct foo {
- // int x[0];
- // };
- int64_t Count = -1; // Count == -1 is an unbounded array.
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
- Count = CAT->getSize().getZExtValue();
-
- // FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
- EltTy = Ty->getElementType();
- }
-
- llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
-
- llvm::DIType DbgTy =
- DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
- SubscriptArray);
- return DbgTy;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
- llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
- Ty, Ty->getPointeeType(), Unit);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
- llvm::DIFile Unit) {
- return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type,
- Ty, Ty->getPointeeType(), Unit);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
- llvm::DIFile U) {
- QualType PointerDiffTy = CGM.getContext().getPointerDiffType();
- llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U);
-
- if (!Ty->getPointeeType()->isFunctionType()) {
- // We have a data member pointer type.
- return PointerDiffDITy;
- }
-
- // We have a member function pointer type. Treat it as a struct with two
- // ptrdiff_t members.
- std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty);
-
- uint64_t FieldOffset = 0;
- llvm::Value *ElementTypes[2];
-
- // FIXME: This should be a DW_TAG_pointer_to_member type.
- ElementTypes[0] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
- FieldOffset += Info.first;
-
- ElementTypes[1] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
-
- return DBuilder.createStructType(U, StringRef("test"),
- U, 0, FieldOffset,
- 0, 0, Elements);
-}
-
-llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
- llvm::DIFile U) {
- // Ignore the atomic wrapping
- // FIXME: What is the correct representation?
- return getOrCreateType(Ty->getValueType(), U);
-}
-
-/// CreateEnumType - get enumeration type.
-llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
- uint64_t Size = 0;
- uint64_t Align = 0;
- if (!ED->getTypeForDecl()->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
- Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
- }
-
- // If this is just a forward declaration, construct an appropriately
- // marked node and just return it.
- if (!ED->getDefinition()) {
- llvm::DIDescriptor EDContext;
- EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext()));
- llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
- unsigned Line = getLineNumber(ED->getLocation());
- StringRef EDName = ED->getName();
- return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
- EDName, EDContext, DefUnit, Line, 0,
- Size, Align);
- }
-
- // Create DIEnumerator elements for each enumerator.
- SmallVector<llvm::Value *, 16> Enumerators;
- ED = ED->getDefinition();
- for (EnumDecl::enumerator_iterator
- Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
- Enum != EnumEnd; ++Enum) {
- Enumerators.push_back(
- DBuilder.createEnumerator(Enum->getName(),
- Enum->getInitVal().getZExtValue()));
- }
-
- // Return a CompositeType for the enum itself.
- llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators);
-
- llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
- unsigned Line = getLineNumber(ED->getLocation());
- llvm::DIDescriptor EnumContext =
- getContextDescriptor(cast<Decl>(ED->getDeclContext()));
- llvm::DIType ClassTy = ED->isScopedUsingClassTag() ?
- getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
- llvm::DIType DbgTy =
- DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
- Size, Align, EltArray,
- ClassTy);
- return DbgTy;
-}
-
-static QualType UnwrapTypeForDebugInfo(QualType T) {
- do {
- QualType LastT = T;
- switch (T->getTypeClass()) {
- default:
- return T;
- case Type::TemplateSpecialization:
- T = cast<TemplateSpecializationType>(T)->desugar();
- break;
- case Type::TypeOfExpr:
- T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
- break;
- case Type::TypeOf:
- T = cast<TypeOfType>(T)->getUnderlyingType();
- break;
- case Type::Decltype:
- T = cast<DecltypeType>(T)->getUnderlyingType();
- break;
- case Type::UnaryTransform:
- T = cast<UnaryTransformType>(T)->getUnderlyingType();
- break;
- case Type::Attributed:
- T = cast<AttributedType>(T)->getEquivalentType();
- break;
- case Type::Elaborated:
- T = cast<ElaboratedType>(T)->getNamedType();
- break;
- case Type::Paren:
- T = cast<ParenType>(T)->getInnerType();
- break;
- case Type::SubstTemplateTypeParm: {
- // We need to keep the qualifiers handy since getReplacementType()
- // will strip them away.
- unsigned Quals = T.getLocalFastQualifiers();
- T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
- T.addFastQualifiers(Quals);
- }
- break;
- case Type::Auto:
- T = cast<AutoType>(T)->getDeducedType();
- break;
- }
-
- assert(T != LastT && "Type unwrapping failed to unwrap!");
- if (T == LastT)
- return T;
- } while (true);
-}
-
-/// getType - Get the type from the cache or return null type if it doesn't exist.
-llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
-
- // Check for existing entry.
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- TypeCache.find(Ty.getAsOpaquePtr());
- if (it != TypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
- }
-
- return llvm::DIType();
-}
-
-/// getCompletedTypeOrNull - Get the type from the cache or return null if it
-/// doesn't exist.
-llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
-
- // Check for existing entry.
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- CompletedTypeCache.find(Ty.getAsOpaquePtr());
- if (it != CompletedTypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
- }
-
- return llvm::DIType();
-}
-
-
-/// getOrCreateType - Get the type from the cache or create a new
-/// one if necessary.
-llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
- if (Ty.isNull())
- return llvm::DIType();
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
-
- llvm::DIType T = getCompletedTypeOrNull(Ty);
-
- if (T.Verify())
- return T;
-
- // Otherwise create the type.
- llvm::DIType Res = CreateTypeNode(Ty, Unit);
-
- llvm::DIType TC = getTypeOrNull(Ty);
- if (TC.Verify() && TC.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(TC)));
-
- // And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
-
- if (!Res.isForwardDecl())
- CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
-
- return Res;
-}
-
-/// CreateTypeNode - Create a new debug type node.
-llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
- // Handle qualifiers, which recursively handles what they refer to.
- if (Ty.hasLocalQualifiers())
- return CreateQualifiedType(Ty, Unit);
-
- const char *Diag = 0;
-
- // Work out details of type.
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Dependent types cannot show up in debug information");
-
- case Type::ExtVector:
- case Type::Vector:
- return CreateType(cast<VectorType>(Ty), Unit);
- case Type::ObjCObjectPointer:
- return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
- case Type::ObjCObject:
- return CreateType(cast<ObjCObjectType>(Ty), Unit);
- case Type::ObjCInterface:
- return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
- case Type::Builtin:
- return CreateType(cast<BuiltinType>(Ty));
- case Type::Complex:
- return CreateType(cast<ComplexType>(Ty));
- case Type::Pointer:
- return CreateType(cast<PointerType>(Ty), Unit);
- case Type::BlockPointer:
- return CreateType(cast<BlockPointerType>(Ty), Unit);
- case Type::Typedef:
- return CreateType(cast<TypedefType>(Ty), Unit);
- case Type::Record:
- return CreateType(cast<RecordType>(Ty));
- case Type::Enum:
- return CreateEnumType(cast<EnumType>(Ty)->getDecl());
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- return CreateType(cast<FunctionType>(Ty), Unit);
- case Type::ConstantArray:
- case Type::VariableArray:
- case Type::IncompleteArray:
- return CreateType(cast<ArrayType>(Ty), Unit);
-
- case Type::LValueReference:
- return CreateType(cast<LValueReferenceType>(Ty), Unit);
- case Type::RValueReference:
- return CreateType(cast<RValueReferenceType>(Ty), Unit);
-
- case Type::MemberPointer:
- return CreateType(cast<MemberPointerType>(Ty), Unit);
-
- case Type::Atomic:
- return CreateType(cast<AtomicType>(Ty), Unit);
-
- case Type::Attributed:
- case Type::TemplateSpecialization:
- case Type::Elaborated:
- case Type::Paren:
- case Type::SubstTemplateTypeParm:
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::UnaryTransform:
- case Type::Auto:
- llvm_unreachable("type should have been unwrapped!");
- }
-
- assert(Diag && "Fall through without a diagnostic?");
- unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "debug information for %0 is not yet supported");
- CGM.getDiags().Report(DiagID)
- << Diag;
- return llvm::DIType();
-}
-
-/// getOrCreateLimitedType - Get the type from the cache or create a new
-/// limited type if necessary.
-llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
- llvm::DIFile Unit) {
- if (Ty.isNull())
- return llvm::DIType();
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
-
- llvm::DIType T = getTypeOrNull(Ty);
-
- // We may have cached a forward decl when we could have created
- // a non-forward decl. Go ahead and create a non-forward decl
- // now.
- if (T.Verify() && !T.isForwardDecl()) return T;
-
- // Otherwise create the type.
- llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
-
- if (T.Verify() && T.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(T)));
-
- // And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
- return Res;
-}
-
-// TODO: Currently used for context chains when limiting debug info.
-llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
- RecordDecl *RD = Ty->getDecl();
-
- // Get overall information about the record type for the debug info.
- llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = getClassName(RD);
-
- llvm::DIDescriptor RDContext;
- if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo)
- RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
- else
- RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
-
- // If this is just a forward declaration, construct an appropriately
- // marked node and just return it.
- if (!RD->getDefinition())
- return createRecordFwdDecl(RD, RDContext);
-
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- llvm::TrackingVH<llvm::MDNode> RealDecl;
-
- if (RD->isUnion())
- RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
- else if (RD->isClass()) {
- // FIXME: This could be a struct type giving a default visibility different
- // than C++ class type, but needs llvm metadata changes first.
- RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, 0, llvm::DIType(),
- llvm::DIArray(), llvm::DIType(),
- llvm::DIArray());
- } else
- RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
-
- RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
-
- if (CXXDecl) {
- // A class's primary base or the class itself contains the vtable.
- llvm::MDNode *ContainingType = NULL;
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
- // Seek non virtual primary base root.
- while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
- }
- ContainingType =
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
- }
- else if (CXXDecl->isDynamicClass())
- ContainingType = RealDecl;
-
- RealDecl->replaceOperandWith(12, ContainingType);
- }
- return llvm::DIType(RealDecl);
-}
-
-/// CreateLimitedTypeNode - Create a new debug type node, but only forward
-/// declare composite types that haven't been processed yet.
-llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
-
- // Work out details of type.
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
- #include "clang/AST/TypeNodes.def"
- llvm_unreachable("Dependent types cannot show up in debug information");
-
- case Type::Record:
- return CreateLimitedType(cast<RecordType>(Ty));
- default:
- return CreateTypeNode(Ty, Unit);
- }
-}
-
-/// CreateMemberType - Create new member and increase Offset by FType's size.
-llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
- StringRef Name,
- uint64_t *Offset) {
- llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
- unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
- llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0,
- FieldSize, FieldAlign,
- *Offset, 0, FieldTy);
- *Offset += FieldSize;
- return Ty;
-}
-
-/// getFunctionDeclaration - Return debug info descriptor to describe method
-/// declaration for the given method definition.
-llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) return llvm::DISubprogram();
-
- // Setup context.
- getContextDescriptor(cast<Decl>(D->getDeclContext()));
-
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(FD->getCanonicalDecl());
- if (MI != SPCache.end()) {
- llvm::Value *V = MI->second;
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
- if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
- return SP;
- }
-
- for (FunctionDecl::redecl_iterator I = FD->redecls_begin(),
- E = FD->redecls_end(); I != E; ++I) {
- const FunctionDecl *NextFD = *I;
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(NextFD->getCanonicalDecl());
- if (MI != SPCache.end()) {
- llvm::Value *V = MI->second;
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
- if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
- return SP;
- }
- }
- return llvm::DISubprogram();
-}
-
-// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
-// implicit parameter "this".
-llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
- QualType FnType,
- llvm::DIFile F) {
-
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- return getOrCreateMethodType(Method, F);
- if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
- // Add "self" and "_cmd"
- SmallVector<llvm::Value *, 16> Elts;
-
- // First element is always return type. For 'void' functions it is NULL.
- Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
- // "self" pointer is always first argument.
- llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
- Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
- // "_cmd" pointer is always second argument.
- llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
- Elts.push_back(DBuilder.createArtificialType(CmdTy));
- // Get rest of the arguments.
- for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
- PE = OMethod->param_end(); PI != PE; ++PI)
- Elts.push_back(getOrCreateType((*PI)->getType(), F));
-
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
- return DBuilder.createSubroutineType(F, EltTypeArray);
- }
- return getOrCreateType(FnType, F);
-}
-
-/// EmitFunctionStart - Constructs the debug code for entering a function.
-void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
- llvm::Function *Fn,
- CGBuilderTy &Builder) {
-
- StringRef Name;
- StringRef LinkageName;
-
- FnBeginRegionCount.push_back(LexicalBlockStack.size());
-
- const Decl *D = GD.getDecl();
- // Function may lack declaration in source code if it is created by Clang
- // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
- bool HasDecl = (D != 0);
- // Use the location of the declaration.
- SourceLocation Loc;
- if (HasDecl)
- Loc = D->getLocation();
-
- unsigned Flags = 0;
- llvm::DIFile Unit = getOrCreateFile(Loc);
- llvm::DIDescriptor FDContext(Unit);
- llvm::DIArray TParamsArray;
- if (!HasDecl) {
- // Use llvm function name.
- Name = Fn->getName();
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If there is a DISubprogram for this function available then use it.
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- FI = SPCache.find(FD->getCanonicalDecl());
- if (FI != SPCache.end()) {
- llvm::Value *V = FI->second;
- llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V));
- if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
- llvm::MDNode *SPN = SP;
- LexicalBlockStack.push_back(SPN);
- RegionMap[D] = llvm::WeakVH(SP);
- return;
- }
- }
- Name = getFunctionName(FD);
- // Use mangled name as linkage name for c/c++ functions.
- if (FD->hasPrototype()) {
- LinkageName = CGM.getMangledName(GD);
- Flags |= llvm::DIDescriptor::FlagPrototyped;
- }
- if (LinkageName == Name ||
- CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
- LinkageName = StringRef();
-
- if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
- if (const NamespaceDecl *NSDecl =
- dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
- FDContext = getOrCreateNameSpace(NSDecl);
- else if (const RecordDecl *RDecl =
- dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
- FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext()));
-
- // Collect template parameters.
- TParamsArray = CollectFunctionTemplateParams(FD, Unit);
- }
- } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
- Name = getObjCMethodName(OMD);
- Flags |= llvm::DIDescriptor::FlagPrototyped;
- } else {
- // Use llvm function name.
- Name = Fn->getName();
- Flags |= llvm::DIDescriptor::FlagPrototyped;
- }
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
-
- unsigned LineNo = getLineNumber(Loc);
- if (!HasDecl || D->isImplicit())
- Flags |= llvm::DIDescriptor::FlagArtificial;
-
- llvm::DIType DIFnType;
- llvm::DISubprogram SPDecl;
- if (HasDecl &&
- CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
- DIFnType = getOrCreateFunctionType(D, FnType, Unit);
- SPDecl = getFunctionDeclaration(D);
- } else {
- // Create fake but valid subroutine type. Otherwise
- // llvm::DISubprogram::Verify() would return false, and
- // subprogram DIE will miss DW_AT_decl_file and
- // DW_AT_decl_line fields.
- SmallVector<llvm::Value*, 16> Elts;
- llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
- DIFnType = DBuilder.createSubroutineType(Unit, EltTypeArray);
- }
- llvm::DISubprogram SP;
- SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
- LineNo, DIFnType,
- Fn->hasInternalLinkage(), true/*definition*/,
- getLineNumber(CurLoc), Flags,
- CGM.getLangOpts().Optimize,
- Fn, TParamsArray, SPDecl);
-
- // Push function on region stack.
- llvm::MDNode *SPN = SP;
- LexicalBlockStack.push_back(SPN);
- if (HasDecl)
- RegionMap[D] = llvm::WeakVH(SP);
-}
-
-/// EmitLocation - Emit metadata to indicate a change in line/column
-/// information in the source file.
-void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
-
- // Update our current location
- setLocation(Loc);
-
- if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
-
- // Don't bother if things are the same as last time.
- SourceManager &SM = CGM.getContext().getSourceManager();
- if (CurLoc == PrevLoc ||
- SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
- // New Builder may not be in sync with CGDebugInfo.
- if (!Builder.getCurrentDebugLocation().isUnknown())
- return;
-
- // Update last state.
- PrevLoc = CurLoc;
-
- llvm::MDNode *Scope = LexicalBlockStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
- getColumnNumber(CurLoc),
- Scope));
-}
-
-/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
-/// the stack.
-void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
- llvm::DIDescriptor D =
- DBuilder.createLexicalBlock(LexicalBlockStack.empty() ?
- llvm::DIDescriptor() :
- llvm::DIDescriptor(LexicalBlockStack.back()),
- getOrCreateFile(CurLoc),
- getLineNumber(CurLoc),
- getColumnNumber(CurLoc));
- llvm::MDNode *DN = D;
- LexicalBlockStack.push_back(DN);
-}
-
-/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
-/// region - beginning of a DW_TAG_lexical_block.
-void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) {
- // Set our current location.
- setLocation(Loc);
-
- // Create a new lexical block and push it on the stack.
- CreateLexicalBlock(Loc);
-
- // Emit a line table change for the current location inside the new scope.
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc),
- getColumnNumber(Loc),
- LexicalBlockStack.back()));
-}
-
-/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
-/// region - end of a DW_TAG_lexical_block.
-void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) {
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
- // Provide an entry in the line table for the end of the block.
- EmitLocation(Builder, Loc);
-
- LexicalBlockStack.pop_back();
-}
-
-/// EmitFunctionEnd - Constructs the debug code for exiting a function.
-void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- unsigned RCount = FnBeginRegionCount.back();
- assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
-
- // Pop all regions for this function.
- while (LexicalBlockStack.size() != RCount)
- EmitLexicalBlockEnd(Builder, CurLoc);
- FnBeginRegionCount.pop_back();
-}
-
-// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
-// See BuildByRefType.
-llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
- uint64_t *XOffset) {
-
- SmallVector<llvm::Value *, 5> EltTys;
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
-
- llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- QualType Type = VD->getType();
-
- FieldOffset = 0;
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
- FType = CGM.getContext().IntTy;
- EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
-
- bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
- &FieldOffset));
- EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
- &FieldOffset));
- }
- bool HasByrefExtendedLayout;
- Qualifiers::ObjCLifetime Lifetime;
- if (CGM.getContext().getByrefLifetime(Type,
- Lifetime, HasByrefExtendedLayout)
- && HasByrefExtendedLayout)
- EltTys.push_back(CreateMemberType(Unit, FType,
- "__byref_variable_layout",
- &FieldOffset));
-
- CharUnits Align = CGM.getContext().getDeclAlign(VD);
- if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerAlign(0))) {
- CharUnits FieldOffsetInBytes
- = CGM.getContext().toCharUnitsFromBits(FieldOffset);
- CharUnits AlignedOffsetInBytes
- = FieldOffsetInBytes.RoundUpToAlignment(Align);
- CharUnits NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffsetInBytes;
-
- if (NumPaddingBytes.isPositive()) {
- llvm::APInt pad(32, NumPaddingBytes.getQuantity());
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
- }
- }
-
- FType = Type;
- llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().toBits(Align);
-
- *XOffset = FieldOffset;
- FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
- unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
-
- return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
- Elements);
-}
-
-/// EmitDeclare - Emit local variable declaration debug info.
-void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
- llvm::Value *Storage,
- unsigned ArgNo, CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
- llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- llvm::DIType Ty;
- uint64_t XOffset = 0;
- if (VD->hasAttr<BlocksAttr>())
- Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
- else
- Ty = getOrCreateType(VD->getType(), Unit);
-
- // If there is no debug info for this type then do not emit debug info
- // for this variable.
- if (!Ty)
- return;
-
- if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage)) {
- // If Storage is an aggregate returned as 'sret' then let debugger know
- // about this.
- if (Arg->hasStructRetAttr())
- Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
- else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) {
- // If an aggregate variable has non trivial destructor or non trivial copy
- // constructor than it is pass indirectly. Let debug info know about this
- // by using reference of the aggregate type as a argument type.
- if (Record->hasNonTrivialCopyConstructor() ||
- !Record->hasTrivialDestructor())
- Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
- }
- }
-
- // Get location information.
- unsigned Line = getLineNumber(VD->getLocation());
- unsigned Column = getColumnNumber(VD->getLocation());
- unsigned Flags = 0;
- if (VD->isImplicit())
- Flags |= llvm::DIDescriptor::FlagArtificial;
- // If this is the first argument and it is implicit then
- // give it an object pointer flag.
- // FIXME: There has to be a better way to do this, but for static
- // functions there won't be an implicit param at arg1 and
- // otherwise it is 'self' or 'this'.
- if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
- Flags |= llvm::DIDescriptor::FlagObjectPointer;
-
- llvm::MDNode *Scope = LexicalBlockStack.back();
-
- StringRef Name = VD->getName();
- if (!Name.empty()) {
- if (VD->hasAttr<BlocksAttr>()) {
- CharUnits offset = CharUnits::fromQuantity(32);
- SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = CGM.Int64Ty;
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- // offset of __forwarding field
- offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerWidth(0));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- // offset of x field
- offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
-
- // Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag,
- llvm::DIDescriptor(Scope),
- VD->getName(), Unit, Line, Ty,
- addr, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- } else if (isa<VariableArrayType>(VD->getType())) {
- // These are "complex" variables in that they need an op_deref.
- // Create the descriptor for the variable.
- llvm::Value *Addr = llvm::ConstantInt::get(CGM.Int64Ty,
- llvm::DIBuilder::OpDeref);
- llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag,
- llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- Addr, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- }
-
- // Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- }
-
- // If VD is an anonymous union then Storage represents value for
- // all union fields.
- if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
- const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- if (RD->isUnion()) {
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end();
- I != E; ++I) {
- FieldDecl *Field = *I;
- llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields. Do not ignore unnamed records.
- if (FieldName.empty() && !isa<RecordType>(Field->getType()))
- continue;
-
- // Use VarDecl's Tag, Scope and Line number.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- FieldName, Unit, Line, FieldTy,
- CGM.getLangOpts().Optimize, Flags,
- ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- }
- }
- }
-}
-
-void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
- llvm::Value *Storage,
- CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
-}
-
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
- llvm::Value *Storage,
- CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
-
- if (Builder.GetInsertBlock() == 0)
- return;
-
- bool isByRef = VD->hasAttr<BlocksAttr>();
-
- uint64_t XOffset = 0;
- llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- llvm::DIType Ty;
- if (isByRef)
- Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
- else
- Ty = getOrCreateType(VD->getType(), Unit);
-
- // Self is passed along as an implicit non-arg variable in a
- // block. Mark it as the object pointer.
- if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
- Ty = DBuilder.createObjectPointerType(Ty);
-
- // Get location information.
- unsigned Line = getLineNumber(VD->getLocation());
- unsigned Column = getColumnNumber(VD->getLocation());
-
- const llvm::DataLayout &target = CGM.getDataLayout();
-
- CharUnits offset = CharUnits::fromQuantity(
- target.getStructLayout(blockInfo.StructureType)
- ->getElementOffset(blockInfo.getCapture(VD).getIndex()));
-
- SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = CGM.Int64Ty;
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- if (isByRef) {
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- // offset of __forwarding field
- offset = CGM.getContext()
- .toCharUnitsFromBits(target.getPointerSizeInBits(0));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
- // offset of x field
- offset = CGM.getContext().toCharUnitsFromBits(XOffset);
- addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
- }
-
- // Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
- llvm::DIDescriptor(LexicalBlockStack.back()),
- VD->getName(), Unit, Line, Ty, addr);
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column,
- LexicalBlockStack.back()));
-}
-
-/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
-/// variable declaration.
-void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
- unsigned ArgNo,
- CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
-}
-
-namespace {
- struct BlockLayoutChunk {
- uint64_t OffsetInBits;
- const BlockDecl::Capture *Capture;
- };
- bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
- return l.OffsetInBits < r.OffsetInBits;
- }
-}
-
-void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
- CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- ASTContext &C = CGM.getContext();
- const BlockDecl *blockDecl = block.getBlockDecl();
-
- // Collect some general information about the block's location.
- SourceLocation loc = blockDecl->getCaretLocation();
- llvm::DIFile tunit = getOrCreateFile(loc);
- unsigned line = getLineNumber(loc);
- unsigned column = getColumnNumber(loc);
-
- // Build the debug-info type for the block literal.
- getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
-
- const llvm::StructLayout *blockLayout =
- CGM.getDataLayout().getStructLayout(block.StructureType);
-
- SmallVector<llvm::Value*, 16> fields;
- fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(0),
- tunit, tunit));
- fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(1),
- tunit, tunit));
- fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(2),
- tunit, tunit));
- fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(3),
- tunit, tunit));
- fields.push_back(createFieldType("__descriptor",
- C.getPointerType(block.NeedsCopyDispose ?
- C.getBlockDescriptorExtendedType() :
- C.getBlockDescriptorType()),
- 0, loc, AS_public,
- blockLayout->getElementOffsetInBits(4),
- tunit, tunit));
-
- // We want to sort the captures by offset, not because DWARF
- // requires this, but because we're paranoid about debuggers.
- SmallVector<BlockLayoutChunk, 8> chunks;
-
- // 'this' capture.
- if (blockDecl->capturesCXXThis()) {
- BlockLayoutChunk chunk;
- chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(block.CXXThisIndex);
- chunk.Capture = 0;
- chunks.push_back(chunk);
- }
-
- // Variable captures.
- for (BlockDecl::capture_const_iterator
- i = blockDecl->capture_begin(), e = blockDecl->capture_end();
- i != e; ++i) {
- const BlockDecl::Capture &capture = *i;
- const VarDecl *variable = capture.getVariable();
- const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
-
- // Ignore constant captures.
- if (captureInfo.isConstant())
- continue;
-
- BlockLayoutChunk chunk;
- chunk.OffsetInBits =
- blockLayout->getElementOffsetInBits(captureInfo.getIndex());
- chunk.Capture = &capture;
- chunks.push_back(chunk);
- }
-
- // Sort by offset.
- llvm::array_pod_sort(chunks.begin(), chunks.end());
-
- for (SmallVectorImpl<BlockLayoutChunk>::iterator
- i = chunks.begin(), e = chunks.end(); i != e; ++i) {
- uint64_t offsetInBits = i->OffsetInBits;
- const BlockDecl::Capture *capture = i->Capture;
-
- // If we have a null capture, this must be the C++ 'this' capture.
- if (!capture) {
- const CXXMethodDecl *method =
- cast<CXXMethodDecl>(blockDecl->getNonClosureContext());
- QualType type = method->getThisType(C);
-
- fields.push_back(createFieldType("this", type, 0, loc, AS_public,
- offsetInBits, tunit, tunit));
- continue;
- }
-
- const VarDecl *variable = capture->getVariable();
- StringRef name = variable->getName();
-
- llvm::DIType fieldType;
- if (capture->isByRef()) {
- std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy);
-
- // FIXME: this creates a second copy of this type!
- uint64_t xoffset;
- fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset);
- fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first);
- fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
- ptrInfo.first, ptrInfo.second,
- offsetInBits, 0, fieldType);
- } else {
- fieldType = createFieldType(name, variable->getType(), 0,
- loc, AS_public, offsetInBits, tunit, tunit);
- }
- fields.push_back(fieldType);
- }
-
- SmallString<36> typeName;
- llvm::raw_svector_ostream(typeName)
- << "__block_literal_" << CGM.getUniqueBlockCount();
-
- llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields);
-
- llvm::DIType type =
- DBuilder.createStructType(tunit, typeName.str(), tunit, line,
- CGM.getContext().toBits(block.BlockSize),
- CGM.getContext().toBits(block.BlockAlign),
- 0, fieldsArray);
- type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
-
- // Get overall information about the block.
- unsigned flags = llvm::DIDescriptor::FlagArtificial;
- llvm::MDNode *scope = LexicalBlockStack.back();
- StringRef name = ".block_descriptor";
-
- // Create the descriptor for the parameter.
- llvm::DIVariable debugVar =
- DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
- llvm::DIDescriptor(scope),
- name, tunit, line, type,
- CGM.getLangOpts().Optimize, flags,
- cast<llvm::Argument>(addr)->getArgNo() + 1);
-
- // Insert an llvm.dbg.value into the current block.
- llvm::Instruction *declare =
- DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar,
- Builder.GetInsertBlock());
- declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
-}
-
-/// EmitGlobalVariable - Emit information about a global variable.
-void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- const VarDecl *D) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- // Create global variable debug descriptor.
- llvm::DIFile Unit = getOrCreateFile(D->getLocation());
- unsigned LineNo = getLineNumber(D->getLocation());
-
- setLocation(D->getLocation());
-
- QualType T = D->getType();
- if (T->isIncompleteArrayType()) {
-
- // CodeGen turns int[] into int[1] so we'll do the same here.
- llvm::APInt ConstVal(32, 1);
- QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
-
- T = CGM.getContext().getConstantArrayType(ET, ConstVal,
- ArrayType::Normal, 0);
- }
- StringRef DeclName = D->getName();
- StringRef LinkageName;
- if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())
- && !isa<ObjCMethodDecl>(D->getDeclContext()))
- LinkageName = Var->getName();
- if (LinkageName == DeclName)
- LinkageName = StringRef();
- llvm::DIDescriptor DContext =
- getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
- DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
- Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var);
-}
-
-/// EmitGlobalVariable - Emit information about an objective-c interface.
-void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- ObjCInterfaceDecl *ID) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- // Create global variable debug descriptor.
- llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
- unsigned LineNo = getLineNumber(ID->getLocation());
-
- StringRef Name = ID->getName();
-
- QualType T = CGM.getContext().getObjCInterfaceType(ID);
- if (T->isIncompleteArrayType()) {
-
- // CodeGen turns int[] into int[1] so we'll do the same here.
- llvm::APInt ConstVal(32, 1);
- QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
-
- T = CGM.getContext().getConstantArrayType(ET, ConstVal,
- ArrayType::Normal, 0);
- }
-
- DBuilder.createGlobalVariable(Name, Unit, LineNo,
- getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var);
-}
-
-/// EmitGlobalVariable - Emit global variable's debug info.
-void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
- llvm::Constant *Init) {
- assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
- // Create the descriptor for the variable.
- llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
- StringRef Name = VD->getName();
- llvm::DIType Ty = getOrCreateType(VD->getType(), Unit);
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) {
- const EnumDecl *ED = cast<EnumDecl>(ECD->getDeclContext());
- assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?");
- Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
- }
- // Do not use DIGlobalVariable for enums.
- if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
- return;
- DBuilder.createStaticVariable(Unit, Name, Name, Unit,
- getLineNumber(VD->getLocation()),
- Ty, true, Init);
-}
-
-/// getOrCreateNamesSpace - Return namespace descriptor for the given
-/// namespace decl.
-llvm::DINameSpace
-CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
- llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
- NameSpaceCache.find(NSDecl);
- if (I != NameSpaceCache.end())
- return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
-
- unsigned LineNo = getLineNumber(NSDecl->getLocation());
- llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation());
- llvm::DIDescriptor Context =
- getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
- llvm::DINameSpace NS =
- DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
- NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
- return NS;
-}
-
-void CGDebugInfo::finalize() {
- for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI
- = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) {
- llvm::DIType Ty, RepTy;
- // Verify that the debug info still exists.
- if (llvm::Value *V = VI->second)
- Ty = llvm::DIType(cast<llvm::MDNode>(V));
-
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- TypeCache.find(VI->first);
- if (it != TypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- RepTy = llvm::DIType(cast<llvm::MDNode>(V));
- }
-
- if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
- Ty.replaceAllUsesWith(RepTy);
- }
- }
- DBuilder.finalize();
-}
+//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This coordinates the debug information generation while generating code. +// +//===----------------------------------------------------------------------===// + +#include "CGDebugInfo.h" +#include "CGBlocks.h" +#include "CGObjCRuntime.h" +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Constants.h" +#include "llvm/DataLayout.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Module.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/FileSystem.h" +using namespace clang; +using namespace clang::CodeGen; + +CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) + : CGM(CGM), DBuilder(CGM.getModule()), + BlockLiteralGenericSet(false) { + CreateCompileUnit(); +} + +CGDebugInfo::~CGDebugInfo() { + assert(LexicalBlockStack.empty() && + "Region stack mismatch, stack not empty!"); +} + +void CGDebugInfo::setLocation(SourceLocation Loc) { + // If the new location isn't valid return. + if (!Loc.isValid()) return; + + CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); + + // If we've changed files in the middle of a lexical scope go ahead + // and create a new lexical scope with file node if it's different + // from the one in the scope. + if (LexicalBlockStack.empty()) return; + + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); + PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc); + + if (PCLoc.isInvalid() || PPLoc.isInvalid() || + !strcmp(PPLoc.getFilename(), PCLoc.getFilename())) + return; + + llvm::MDNode *LB = LexicalBlockStack.back(); + llvm::DIScope Scope = llvm::DIScope(LB); + if (Scope.isLexicalBlockFile()) { + llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB); + llvm::DIDescriptor D + = DBuilder.createLexicalBlockFile(LBF.getScope(), + getOrCreateFile(CurLoc)); + llvm::MDNode *N = D; + LexicalBlockStack.pop_back(); + LexicalBlockStack.push_back(N); + } else if (Scope.isLexicalBlock()) { + llvm::DIDescriptor D + = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc)); + llvm::MDNode *N = D; + LexicalBlockStack.pop_back(); + LexicalBlockStack.push_back(N); + } +} + +/// getContextDescriptor - Get context info for the decl. +llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { + if (!Context) + return TheCU; + + llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator + I = RegionMap.find(Context); + if (I != RegionMap.end()) { + llvm::Value *V = I->second; + return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + } + + // Check namespace. + if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) + return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); + + if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) { + if (!RDecl->isDependentType()) { + llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), + getOrCreateMainFile()); + return llvm::DIDescriptor(Ty); + } + } + return TheCU; +} + +/// getFunctionName - Get function name for the given FunctionDecl. If the +/// name is constructred on demand (e.g. C++ destructor) then the name +/// is stored on the side. +StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { + assert (FD && "Invalid FunctionDecl!"); + IdentifierInfo *FII = FD->getIdentifier(); + FunctionTemplateSpecializationInfo *Info + = FD->getTemplateSpecializationInfo(); + if (!Info && FII) + return FII->getName(); + + // Otherwise construct human readable name for debug info. + std::string NS = FD->getNameAsString(); + + // Add any template specialization args. + if (Info) { + const TemplateArgumentList *TArgs = Info->TemplateArguments; + const TemplateArgument *Args = TArgs->data(); + unsigned NumArgs = TArgs->size(); + PrintingPolicy Policy(CGM.getLangOpts()); + NS += TemplateSpecializationType::PrintTemplateArgumentList(Args, + NumArgs, + Policy); + } + + // Copy this name on the side and use its reference. + char *StrPtr = DebugInfoNames.Allocate<char>(NS.length()); + memcpy(StrPtr, NS.data(), NS.length()); + return StringRef(StrPtr, NS.length()); +} + +StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { + SmallString<256> MethodName; + llvm::raw_svector_ostream OS(MethodName); + OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; + const DeclContext *DC = OMD->getDeclContext(); + if (const ObjCImplementationDecl *OID = + dyn_cast<const ObjCImplementationDecl>(DC)) { + OS << OID->getName(); + } else if (const ObjCInterfaceDecl *OID = + dyn_cast<const ObjCInterfaceDecl>(DC)) { + OS << OID->getName(); + } else if (const ObjCCategoryImplDecl *OCD = + dyn_cast<const ObjCCategoryImplDecl>(DC)){ + OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' << + OCD->getIdentifier()->getNameStart() << ')'; + } + OS << ' ' << OMD->getSelector().getAsString() << ']'; + + char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell()); + memcpy(StrPtr, MethodName.begin(), OS.tell()); + return StringRef(StrPtr, OS.tell()); +} + +/// getSelectorName - Return selector name. This is used for debugging +/// info. +StringRef CGDebugInfo::getSelectorName(Selector S) { + const std::string &SName = S.getAsString(); + char *StrPtr = DebugInfoNames.Allocate<char>(SName.size()); + memcpy(StrPtr, SName.data(), SName.size()); + return StringRef(StrPtr, SName.size()); +} + +/// getClassName - Get class name including template argument list. +StringRef +CGDebugInfo::getClassName(const RecordDecl *RD) { + const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(RD); + if (!Spec) + return RD->getName(); + + const TemplateArgument *Args; + unsigned NumArgs; + if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { + const TemplateSpecializationType *TST = + cast<TemplateSpecializationType>(TAW->getType()); + Args = TST->getArgs(); + NumArgs = TST->getNumArgs(); + } else { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Args = TemplateArgs.data(); + NumArgs = TemplateArgs.size(); + } + StringRef Name = RD->getIdentifier()->getName(); + PrintingPolicy Policy(CGM.getLangOpts()); + std::string TemplateArgList = + TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy); + + // Copy this name on the side and use its reference. + size_t Length = Name.size() + TemplateArgList.size(); + char *StrPtr = DebugInfoNames.Allocate<char>(Length); + memcpy(StrPtr, Name.data(), Name.size()); + memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size()); + return StringRef(StrPtr, Length); +} + +/// getOrCreateFile - Get the file debug info descriptor for the input location. +llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { + if (!Loc.isValid()) + // If Location is not valid then use main input file. + return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); + + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty()) + // If the location is not valid then use main input file. + return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); + + // Cache the results. + const char *fname = PLoc.getFilename(); + llvm::DenseMap<const char *, llvm::WeakVH>::iterator it = + DIFileCache.find(fname); + + if (it != DIFileCache.end()) { + // Verify that the information still exists. + if (llvm::Value *V = it->second) + return llvm::DIFile(cast<llvm::MDNode>(V)); + } + + llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname()); + + DIFileCache[fname] = F; + return F; +} + +/// getOrCreateMainFile - Get the file info for main compile unit. +llvm::DIFile CGDebugInfo::getOrCreateMainFile() { + return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); +} + +/// getLineNumber - Get line number for the location. If location is invalid +/// then use current location. +unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { + if (Loc.isInvalid() && CurLoc.isInvalid()) + return 0; + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); + return PLoc.isValid()? PLoc.getLine() : 0; +} + +/// getColumnNumber - Get column number for the location. +unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { + // We may not want column information at all. + if (!CGM.getCodeGenOpts().DebugColumnInfo) + return 0; + + // If the location is invalid then use the current column. + if (Loc.isInvalid() && CurLoc.isInvalid()) + return 0; + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); + return PLoc.isValid()? PLoc.getColumn() : 0; +} + +StringRef CGDebugInfo::getCurrentDirname() { + if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) + return CGM.getCodeGenOpts().DebugCompilationDir; + + if (!CWDName.empty()) + return CWDName; + SmallString<256> CWD; + llvm::sys::fs::current_path(CWD); + char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size()); + memcpy(CompDirnamePtr, CWD.data(), CWD.size()); + return CWDName = StringRef(CompDirnamePtr, CWD.size()); +} + +/// CreateCompileUnit - Create new compile unit. +void CGDebugInfo::CreateCompileUnit() { + + // Get absolute path name. + SourceManager &SM = CGM.getContext().getSourceManager(); + std::string MainFileName = CGM.getCodeGenOpts().MainFileName; + if (MainFileName.empty()) + MainFileName = "<unknown>"; + + // The main file name provided via the "-main-file-name" option contains just + // the file name itself with no path information. This file name may have had + // a relative path, so we look into the actual file entry for the main + // file to determine the real absolute path for the file. + std::string MainFileDir; + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { + MainFileDir = MainFile->getDir()->getName(); + if (MainFileDir != ".") + MainFileName = MainFileDir + "/" + MainFileName; + } + + // Save filename string. + char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length()); + memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length()); + StringRef Filename(FilenamePtr, MainFileName.length()); + + unsigned LangTag; + const LangOptions &LO = CGM.getLangOpts(); + if (LO.CPlusPlus) { + if (LO.ObjC1) + LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; + else + LangTag = llvm::dwarf::DW_LANG_C_plus_plus; + } else if (LO.ObjC1) { + LangTag = llvm::dwarf::DW_LANG_ObjC; + } else if (LO.C99) { + LangTag = llvm::dwarf::DW_LANG_C99; + } else { + LangTag = llvm::dwarf::DW_LANG_C89; + } + + std::string Producer = getClangFullVersion(); + + // Figure out which version of the ObjC runtime we have. + unsigned RuntimeVers = 0; + if (LO.ObjC1) + RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; + + // Create new compile unit. + DBuilder.createCompileUnit( + LangTag, Filename, getCurrentDirname(), + Producer, + LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); + // FIXME - Eliminate TheCU. + TheCU = llvm::DICompileUnit(DBuilder.getCU()); +} + +/// CreateType - Get the Basic type from the cache or create a new +/// one if necessary. +llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { + unsigned Encoding = 0; + StringRef BTName; + switch (BT->getKind()) { +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: + llvm_unreachable("Unexpected builtin type"); + case BuiltinType::NullPtr: + return DBuilder. + createNullPtrType(BT->getName(CGM.getLangOpts())); + case BuiltinType::Void: + return llvm::DIType(); + case BuiltinType::ObjCClass: + if (ClassTy.Verify()) + return ClassTy; + ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + "objc_class", TheCU, + getOrCreateMainFile(), 0); + return ClassTy; + case BuiltinType::ObjCId: { + // typedef struct objc_class *Class; + // typedef struct objc_object { + // Class isa; + // } *id; + + if (ObjTy.Verify()) + return ObjTy; + + if (!ClassTy.Verify()) + ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + "objc_class", TheCU, + getOrCreateMainFile(), 0); + + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); + + llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size); + + llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object", + getOrCreateMainFile(), + 0, 0, 0, 0, + llvm::DIArray()); + + llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy); + SmallVector<llvm::Value *, 1> EltTys; + llvm::DIType FieldTy = + DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa", + getOrCreateMainFile(), 0, Size, + 0, 0, 0, ISATy); + EltTys.push_back(FieldTy); + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); + + ObjNode->replaceOperandWith(10, Elements); + ObjTy = llvm::DIType(ObjNode); + return ObjTy; + } + case BuiltinType::ObjCSel: { + if (SelTy.Verify()) + return SelTy; + SelTy = + DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + "objc_selector", TheCU, getOrCreateMainFile(), + 0); + return SelTy; + } + case BuiltinType::UChar: + case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break; + case BuiltinType::Char16: + case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break; + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::UInt128: + case BuiltinType::ULong: + case BuiltinType::WChar_U: + case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break; + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Int128: + case BuiltinType::Long: + case BuiltinType::WChar_S: + case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; + case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::LongDouble: + case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; + } + + switch (BT->getKind()) { + case BuiltinType::Long: BTName = "long int"; break; + case BuiltinType::LongLong: BTName = "long long int"; break; + case BuiltinType::ULong: BTName = "long unsigned int"; break; + case BuiltinType::ULongLong: BTName = "long long unsigned int"; break; + default: + BTName = BT->getName(CGM.getLangOpts()); + break; + } + // Bit size, align and offset of the type. + uint64_t Size = CGM.getContext().getTypeSize(BT); + uint64_t Align = CGM.getContext().getTypeAlign(BT); + llvm::DIType DbgTy = + DBuilder.createBasicType(BTName, Size, Align, Encoding); + return DbgTy; +} + +llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) { + // Bit size, align and offset of the type. + unsigned Encoding = llvm::dwarf::DW_ATE_complex_float; + if (Ty->isComplexIntegerType()) + Encoding = llvm::dwarf::DW_ATE_lo_user; + + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + llvm::DIType DbgTy = + DBuilder.createBasicType("complex", Size, Align, Encoding); + + return DbgTy; +} + +/// CreateCVRType - Get the qualified type from the cache or create +/// a new one if necessary. +llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) { + QualifierCollector Qc; + const Type *T = Qc.strip(Ty); + + // Ignore these qualifiers for now. + Qc.removeObjCGCAttr(); + Qc.removeAddressSpace(); + Qc.removeObjCLifetime(); + + // We will create one Derived type for one qualifier and recurse to handle any + // additional ones. + unsigned Tag; + if (Qc.hasConst()) { + Tag = llvm::dwarf::DW_TAG_const_type; + Qc.removeConst(); + } else if (Qc.hasVolatile()) { + Tag = llvm::dwarf::DW_TAG_volatile_type; + Qc.removeVolatile(); + } else if (Qc.hasRestrict()) { + Tag = llvm::dwarf::DW_TAG_restrict_type; + Qc.removeRestrict(); + } else { + assert(Qc.empty() && "Unknown type qualifier for debug info"); + return getOrCreateType(QualType(T, 0), Unit); + } + + llvm::DIType FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); + + // No need to fill in the Name, Line, Size, Alignment, Offset in case of + // CVR derived types. + llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy); + + return DbgTy; +} + +llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, + llvm::DIFile Unit) { + llvm::DIType DbgTy = + CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, + Ty->getPointeeType(), Unit); + return DbgTy; +} + +llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, + llvm::DIFile Unit) { + return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, + Ty->getPointeeType(), Unit); +} + +// Creates a forward declaration for a RecordDecl in the given context. +llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD, + llvm::DIDescriptor Ctx) { + llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); + unsigned Line = getLineNumber(RD->getLocation()); + StringRef RDName = getClassName(RD); + + unsigned Tag = 0; + if (RD->isStruct() || RD->isInterface()) + Tag = llvm::dwarf::DW_TAG_structure_type; + else if (RD->isUnion()) + Tag = llvm::dwarf::DW_TAG_union_type; + else { + assert(RD->isClass()); + Tag = llvm::dwarf::DW_TAG_class_type; + } + + // Create the type. + return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line); +} + +// Walk up the context chain and create forward decls for record decls, +// and normal descriptors for namespaces. +llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) { + if (!Context) + return TheCU; + + // See if we already have the parent. + llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator + I = RegionMap.find(Context); + if (I != RegionMap.end()) { + llvm::Value *V = I->second; + return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + } + + // Check namespace. + if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) + return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); + + if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) { + if (!RD->isDependentType()) { + llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD), + getOrCreateMainFile()); + return llvm::DIDescriptor(Ty); + } + } + return TheCU; +} + +/// CreatePointeeType - Create Pointee type. If Pointee is a record +/// then emit record's fwd if debug info size reduction is enabled. +llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy, + llvm::DIFile Unit) { + if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo) + return getOrCreateType(PointeeTy, Unit); + + // Limit debug info for the pointee type. + + // If we have an existing type, use that, it's still smaller than creating + // a new type. + llvm::DIType Ty = getTypeOrNull(PointeeTy); + if (Ty.Verify()) return Ty; + + // Handle qualifiers. + if (PointeeTy.hasLocalQualifiers()) + return CreateQualifiedType(PointeeTy, Unit); + + if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) { + RecordDecl *RD = RTy->getDecl(); + llvm::DIDescriptor FDContext = + getContextDescriptor(cast<Decl>(RD->getDeclContext())); + llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext); + TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy; + return RetTy; + } + return getOrCreateType(PointeeTy, Unit); + +} + +llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, + const Type *Ty, + QualType PointeeTy, + llvm::DIFile Unit) { + if (Tag == llvm::dwarf::DW_TAG_reference_type || + Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) + return DBuilder.createReferenceType(Tag, + CreatePointeeType(PointeeTy, Unit)); + + // Bit size, align and offset of the type. + // Size is always the size of a pointer. We can't use getTypeSize here + // because that does not return the correct value for references. + unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); + uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + + return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), + Size, Align); +} + +llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, + llvm::DIFile Unit) { + if (BlockLiteralGenericSet) + return BlockLiteralGeneric; + + SmallVector<llvm::Value *, 8> EltTys; + llvm::DIType FieldTy; + QualType FType; + uint64_t FieldSize, FieldOffset; + unsigned FieldAlign; + llvm::DIArray Elements; + llvm::DIType EltTy, DescTy; + + FieldOffset = 0; + FType = CGM.getContext().UnsignedLongTy; + EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); + + Elements = DBuilder.getOrCreateArray(EltTys); + EltTys.clear(); + + unsigned Flags = llvm::DIDescriptor::FlagAppleBlock; + unsigned LineNo = getLineNumber(CurLoc); + + EltTy = DBuilder.createStructType(Unit, "__block_descriptor", + Unit, LineNo, FieldOffset, 0, + Flags, Elements); + + // Bit size, align and offset of the type. + uint64_t Size = CGM.getContext().getTypeSize(Ty); + + DescTy = DBuilder.createPointerType(EltTy, Size); + + FieldOffset = 0; + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); + FType = CGM.getContext().IntTy; + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); + + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + FieldTy = DescTy; + FieldSize = CGM.getContext().getTypeSize(Ty); + FieldAlign = CGM.getContext().getTypeAlign(Ty); + FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit, + LineNo, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + + FieldOffset += FieldSize; + Elements = DBuilder.getOrCreateArray(EltTys); + + EltTy = DBuilder.createStructType(Unit, "__block_literal_generic", + Unit, LineNo, FieldOffset, 0, + Flags, Elements); + + BlockLiteralGenericSet = true; + BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size); + return BlockLiteralGeneric; +} + +llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) { + // Typedefs are derived from some other type. If we have a typedef of a + // typedef, make sure to emit the whole chain. + llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit); + if (!Src.Verify()) + return llvm::DIType(); + // We don't set size information, but do specify where the typedef was + // declared. + unsigned Line = getLineNumber(Ty->getDecl()->getLocation()); + const TypedefNameDecl *TyDecl = Ty->getDecl(); + + llvm::DIDescriptor TypedefContext = + getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext())); + + return + DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext); +} + +llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, + llvm::DIFile Unit) { + SmallVector<llvm::Value *, 16> EltTys; + + // Add the result type at least. + EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit)); + + // Set up remainder of arguments if there is a prototype. + // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'! + if (isa<FunctionNoProtoType>(Ty)) + EltTys.push_back(DBuilder.createUnspecifiedParameter()); + else if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) { + for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) + EltTys.push_back(getOrCreateType(FPT->getArgType(i), Unit)); + } + + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys); + return DBuilder.createSubroutineType(Unit, EltTypeArray); +} + + +void CGDebugInfo:: +CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) { + + for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); + I != E; ++I) + if (const VarDecl *V = dyn_cast<VarDecl>(*I)) { + if (V->getInit()) { + const APValue *Value = V->evaluateValue(); + if (Value && Value->isInt()) { + llvm::ConstantInt *CI + = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); + + // Create the descriptor for static variable. + llvm::DIFile VUnit = getOrCreateFile(V->getLocation()); + StringRef VName = V->getName(); + llvm::DIType VTy = getOrCreateType(V->getType(), VUnit); + // Do not use DIGlobalVariable for enums. + if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) { + DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit, + getLineNumber(V->getLocation()), + VTy, true, CI); + } + } + } + } +} + +llvm::DIType CGDebugInfo::createFieldType(StringRef name, + QualType type, + uint64_t sizeInBitsOverride, + SourceLocation loc, + AccessSpecifier AS, + uint64_t offsetInBits, + llvm::DIFile tunit, + llvm::DIDescriptor scope) { + llvm::DIType debugType = getOrCreateType(type, tunit); + + // Get the location for the field. + llvm::DIFile file = getOrCreateFile(loc); + unsigned line = getLineNumber(loc); + + uint64_t sizeInBits = 0; + unsigned alignInBits = 0; + if (!type->isIncompleteArrayType()) { + llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type); + + if (sizeInBitsOverride) + sizeInBits = sizeInBitsOverride; + } + + unsigned flags = 0; + if (AS == clang::AS_private) + flags |= llvm::DIDescriptor::FlagPrivate; + else if (AS == clang::AS_protected) + flags |= llvm::DIDescriptor::FlagProtected; + + return DBuilder.createMemberType(scope, name, file, line, sizeInBits, + alignInBits, offsetInBits, flags, debugType); +} + +/// CollectRecordFields - A helper function to collect debug info for +/// record fields. This is used while creating debug info entry for a Record. +void CGDebugInfo:: +CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, + SmallVectorImpl<llvm::Value *> &elements, + llvm::DIType RecordTy) { + unsigned fieldNo = 0; + const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); + const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record); + + // For C++11 Lambdas a Field will be the same as a Capture, but the Capture + // has the name and the location of the variable so we should iterate over + // both concurrently. + if (CXXDecl && CXXDecl->isLambda()) { + RecordDecl::field_iterator Field = CXXDecl->field_begin(); + unsigned fieldno = 0; + for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(), + E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) { + const LambdaExpr::Capture C = *I; + if (C.capturesVariable()) { + VarDecl *V = C.getCapturedVar(); + llvm::DIFile VUnit = getOrCreateFile(C.getLocation()); + StringRef VName = V->getName(); + uint64_t SizeInBitsOverride = 0; + if (Field->isBitField()) { + SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext()); + assert(SizeInBitsOverride && "found named 0-width bitfield"); + } + llvm::DIType fieldType + = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(), + Field->getAccess(), layout.getFieldOffset(fieldno), + VUnit, RecordTy); + elements.push_back(fieldType); + } else { + // TODO: Need to handle 'this' in some way by probably renaming the + // this of the lambda class and having a field member of 'this' or + // by using AT_object_pointer for the function and having that be + // used as 'this' for semantic references. + assert(C.capturesThis() && "Field that isn't captured and isn't this?"); + FieldDecl *f = *Field; + llvm::DIFile VUnit = getOrCreateFile(f->getLocation()); + QualType type = f->getType(); + llvm::DIType fieldType + = createFieldType("this", type, 0, f->getLocation(), f->getAccess(), + layout.getFieldOffset(fieldNo), VUnit, RecordTy); + + elements.push_back(fieldType); + } + } + } else { + bool IsMsStruct = record->isMsStruct(CGM.getContext()); + const FieldDecl *LastFD = 0; + for (RecordDecl::field_iterator I = record->field_begin(), + E = record->field_end(); + I != E; ++I, ++fieldNo) { + FieldDecl *field = *I; + + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) { + --fieldNo; + continue; + } + LastFD = field; + } + + StringRef name = field->getName(); + QualType type = field->getType(); + + // Ignore unnamed fields unless they're anonymous structs/unions. + if (name.empty() && !type->isRecordType()) { + LastFD = field; + continue; + } + + uint64_t SizeInBitsOverride = 0; + if (field->isBitField()) { + SizeInBitsOverride = field->getBitWidthValue(CGM.getContext()); + assert(SizeInBitsOverride && "found named 0-width bitfield"); + } + + llvm::DIType fieldType + = createFieldType(name, type, SizeInBitsOverride, + field->getLocation(), field->getAccess(), + layout.getFieldOffset(fieldNo), tunit, RecordTy); + + elements.push_back(fieldType); + } + } +} + +/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This +/// function type is not updated to include implicit "this" pointer. Use this +/// routine to get a method type which includes "this" pointer. +llvm::DIType +CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, + llvm::DIFile Unit) { + llvm::DIType FnTy + = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(), + 0), + Unit); + + // Add "this" pointer. + llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray(); + assert (Args.getNumElements() && "Invalid number of arguments!"); + + SmallVector<llvm::Value *, 16> Elts; + + // First element is always return type. For 'void' functions it is NULL. + Elts.push_back(Args.getElement(0)); + + if (!Method->isStatic()) { + // "this" pointer is always first argument. + QualType ThisPtr = Method->getThisType(CGM.getContext()); + + const CXXRecordDecl *RD = Method->getParent(); + if (isa<ClassTemplateSpecializationDecl>(RD)) { + // Create pointer type directly in this case. + const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); + QualType PointeeTy = ThisPtrTy->getPointeeType(); + unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); + uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy); + llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit); + llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; + // TODO: This and the artificial type below are misleading, the + // types aren't artificial the argument is, but the current + // metadata doesn't represent that. + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + Elts.push_back(ThisPtrType); + } else { + llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit); + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + Elts.push_back(ThisPtrType); + } + } + + // Copy rest of the arguments. + for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) + Elts.push_back(Args.getElement(i)); + + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); + + return DBuilder.createSubroutineType(Unit, EltTypeArray); +} + +/// isFunctionLocalClass - Return true if CXXRecordDecl is defined +/// inside a function. +static bool isFunctionLocalClass(const CXXRecordDecl *RD) { + if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext())) + return isFunctionLocalClass(NRD); + if (isa<FunctionDecl>(RD->getDeclContext())) + return true; + return false; +} + +/// CreateCXXMemberFunction - A helper function to create a DISubprogram for +/// a single member function GlobalDecl. +llvm::DISubprogram +CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, + llvm::DIFile Unit, + llvm::DIType RecordTy) { + bool IsCtorOrDtor = + isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); + + StringRef MethodName = getFunctionName(Method); + llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit); + + // Since a single ctor/dtor corresponds to multiple functions, it doesn't + // make sense to give a single ctor/dtor a linkage name. + StringRef MethodLinkageName; + if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) + MethodLinkageName = CGM.getMangledName(Method); + + // Get the location for the method. + llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation()); + unsigned MethodLine = getLineNumber(Method->getLocation()); + + // Collect virtual method info. + llvm::DIType ContainingType; + unsigned Virtuality = 0; + unsigned VIndex = 0; + + if (Method->isVirtual()) { + if (Method->isPure()) + Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual; + else + Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual; + + // It doesn't make sense to give a virtual destructor a vtable index, + // since a single destructor has two entries in the vtable. + if (!isa<CXXDestructorDecl>(Method)) + VIndex = CGM.getVTableContext().getMethodVTableIndex(Method); + ContainingType = RecordTy; + } + + unsigned Flags = 0; + if (Method->isImplicit()) + Flags |= llvm::DIDescriptor::FlagArtificial; + AccessSpecifier Access = Method->getAccess(); + if (Access == clang::AS_private) + Flags |= llvm::DIDescriptor::FlagPrivate; + else if (Access == clang::AS_protected) + Flags |= llvm::DIDescriptor::FlagProtected; + if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) { + if (CXXC->isExplicit()) + Flags |= llvm::DIDescriptor::FlagExplicit; + } else if (const CXXConversionDecl *CXXC = + dyn_cast<CXXConversionDecl>(Method)) { + if (CXXC->isExplicit()) + Flags |= llvm::DIDescriptor::FlagExplicit; + } + if (Method->hasPrototype()) + Flags |= llvm::DIDescriptor::FlagPrototyped; + + llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); + llvm::DISubprogram SP = + DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName, + MethodDefUnit, MethodLine, + MethodTy, /*isLocalToUnit=*/false, + /* isDefinition=*/ false, + Virtuality, VIndex, ContainingType, + Flags, CGM.getLangOpts().Optimize, NULL, + TParamsArray); + + SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP); + + return SP; +} + +/// CollectCXXMemberFunctions - A helper function to collect debug info for +/// C++ member functions. This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, + SmallVectorImpl<llvm::Value *> &EltTys, + llvm::DIType RecordTy) { + + // Since we want more than just the individual member decls if we + // have templated functions iterate over every declaration to gather + // the functions. + for(DeclContext::decl_iterator I = RD->decls_begin(), + E = RD->decls_end(); I != E; ++I) { + Decl *D = *I; + if (D->isImplicit() && !D->isUsed()) + continue; + + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy)); + else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) + for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(), + SE = FTD->spec_end(); SI != SE; ++SI) + EltTys.push_back(CreateCXXMemberFunction(cast<CXXMethodDecl>(*SI), Unit, + RecordTy)); + } +} + +/// CollectCXXFriends - A helper function to collect debug info for +/// C++ base classes. This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit, + SmallVectorImpl<llvm::Value *> &EltTys, + llvm::DIType RecordTy) { + for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(), + BE = RD->friend_end(); BI != BE; ++BI) { + if ((*BI)->isUnsupportedFriend()) + continue; + if (TypeSourceInfo *TInfo = (*BI)->getFriendType()) + EltTys.push_back(DBuilder.createFriend(RecordTy, + getOrCreateType(TInfo->getType(), + Unit))); + } +} + +/// CollectCXXBases - A helper function to collect debug info for +/// C++ base classes. This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, + SmallVectorImpl<llvm::Value *> &EltTys, + llvm::DIType RecordTy) { + + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); BI != BE; ++BI) { + unsigned BFlags = 0; + uint64_t BaseOffset; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl()); + + if (BI->isVirtual()) { + // virtual base offset offset is -ve. The code generator emits dwarf + // expression where it expects +ve number. + BaseOffset = + 0 - CGM.getVTableContext() + .getVirtualBaseOffsetOffset(RD, Base).getQuantity(); + BFlags = llvm::DIDescriptor::FlagVirtual; + } else + BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base)); + // FIXME: Inconsistent units for BaseOffset. It is in bytes when + // BI->isVirtual() and bits when not. + + AccessSpecifier Access = BI->getAccessSpecifier(); + if (Access == clang::AS_private) + BFlags |= llvm::DIDescriptor::FlagPrivate; + else if (Access == clang::AS_protected) + BFlags |= llvm::DIDescriptor::FlagProtected; + + llvm::DIType DTy = + DBuilder.createInheritance(RecordTy, + getOrCreateType(BI->getType(), Unit), + BaseOffset, BFlags); + EltTys.push_back(DTy); + } +} + +/// CollectTemplateParams - A helper function to collect template parameters. +llvm::DIArray CGDebugInfo:: +CollectTemplateParams(const TemplateParameterList *TPList, + const TemplateArgumentList &TAList, + llvm::DIFile Unit) { + SmallVector<llvm::Value *, 16> TemplateParams; + for (unsigned i = 0, e = TAList.size(); i != e; ++i) { + const TemplateArgument &TA = TAList[i]; + const NamedDecl *ND = TPList->getParam(i); + if (TA.getKind() == TemplateArgument::Type) { + llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit); + llvm::DITemplateTypeParameter TTP = + DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy); + TemplateParams.push_back(TTP); + } else if (TA.getKind() == TemplateArgument::Integral) { + llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit); + llvm::DITemplateValueParameter TVP = + DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy, + TA.getAsIntegral().getZExtValue()); + TemplateParams.push_back(TVP); + } + } + return DBuilder.getOrCreateArray(TemplateParams); +} + +/// CollectFunctionTemplateParams - A helper function to collect debug +/// info for function template parameters. +llvm::DIArray CGDebugInfo:: +CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) { + if (FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { + const TemplateParameterList *TList = + FD->getTemplateSpecializationInfo()->getTemplate() + ->getTemplateParameters(); + return + CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit); + } + return llvm::DIArray(); +} + +/// CollectCXXTemplateParams - A helper function to collect debug info for +/// template parameters. +llvm::DIArray CGDebugInfo:: +CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial, + llvm::DIFile Unit) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + PU = TSpecial->getSpecializedTemplateOrPartial(); + + TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ? + PU.get<ClassTemplateDecl *>()->getTemplateParameters() : + PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters(); + const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs(); + return CollectTemplateParams(TPList, TAList, Unit); +} + +/// getOrCreateVTablePtrType - Return debug info descriptor for vtable. +llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { + if (VTablePtrType.isValid()) + return VTablePtrType; + + ASTContext &Context = CGM.getContext(); + + /* Function type */ + llvm::Value *STy = getOrCreateType(Context.IntTy, Unit); + llvm::DIArray SElements = DBuilder.getOrCreateArray(STy); + llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements); + unsigned Size = Context.getTypeSize(Context.VoidPtrTy); + llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0, + "__vtbl_ptr_type"); + VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size); + return VTablePtrType; +} + +/// getVTableName - Get vtable name for the given Class. +StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { + // Construct gdb compatible name name. + std::string Name = "_vptr$" + RD->getNameAsString(); + + // Copy this name on the side and use its reference. + char *StrPtr = DebugInfoNames.Allocate<char>(Name.length()); + memcpy(StrPtr, Name.data(), Name.length()); + return StringRef(StrPtr, Name.length()); +} + + +/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate +/// debug info entry in EltTys vector. +void CGDebugInfo:: +CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, + SmallVectorImpl<llvm::Value *> &EltTys) { + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + + // If there is a primary base then it will hold vtable info. + if (RL.getPrimaryBase()) + return; + + // If this class is not dynamic then there is not any vtable info to collect. + if (!RD->isDynamicClass()) + return; + + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); + llvm::DIType VPTR + = DBuilder.createMemberType(Unit, getVTableName(RD), Unit, + 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial, + getOrCreateVTablePtrType(Unit)); + EltTys.push_back(VPTR); +} + +/// getOrCreateRecordType - Emit record type's standalone debug info. +llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy, + SourceLocation Loc) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc)); + return T; +} + +/// getOrCreateInterfaceType - Emit an objective c interface type standalone +/// debug info. +llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D, + SourceLocation Loc) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc)); + DBuilder.retainType(T); + return T; +} + +/// CreateType - get structure or union type. +llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { + RecordDecl *RD = Ty->getDecl(); + + // Get overall information about the record type for the debug info. + llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); + + // Records and classes and unions can all be recursive. To handle them, we + // first generate a debug descriptor for the struct as a forward declaration. + // Then (if it is a definition) we go through and get debug info for all of + // its members. Finally, we create a descriptor for the complete type (which + // may refer to the forward decl if the struct is recursive) and replace all + // uses of the forward declaration with the final definition. + + llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit); + + if (FwdDecl.isForwardDecl()) + return FwdDecl; + + llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl); + + // Push the struct on region stack. + LexicalBlockStack.push_back(FwdDeclNode); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); + + // Add this to the completed types cache since we're completing it. + CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; + + // Convert all the elements. + SmallVector<llvm::Value *, 16> EltTys; + + // Note: The split of CXXDecl information here is intentional, the + // gdb tests will depend on a certain ordering at printout. The debug + // information offsets are still correct if we merge them all together + // though. + const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); + if (CXXDecl) { + CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl); + CollectVTableInfo(CXXDecl, DefUnit, EltTys); + } + + // Collect static variables with initializers and other fields. + CollectRecordStaticVars(RD, FwdDecl); + CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); + llvm::DIArray TParamsArray; + if (CXXDecl) { + CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); + CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl); + if (const ClassTemplateSpecializationDecl *TSpecial + = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit); + } + + LexicalBlockStack.pop_back(); + RegionMap.erase(Ty->getDecl()); + + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); + // FIXME: Magic numbers ahoy! These should be changed when we + // get some enums in llvm/Analysis/DebugInfo.h to refer to + // them. + if (RD->isUnion()) + FwdDeclNode->replaceOperandWith(10, Elements); + else if (CXXDecl) { + FwdDeclNode->replaceOperandWith(10, Elements); + FwdDeclNode->replaceOperandWith(13, TParamsArray); + } else + FwdDeclNode->replaceOperandWith(10, Elements); + + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode); + return llvm::DIType(FwdDeclNode); +} + +/// CreateType - get objective-c object type. +llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty, + llvm::DIFile Unit) { + // Ignore protocols. + return getOrCreateType(Ty->getBaseType(), Unit); +} + +/// CreateType - get objective-c interface type. +llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, + llvm::DIFile Unit) { + ObjCInterfaceDecl *ID = Ty->getDecl(); + if (!ID) + return llvm::DIType(); + + // Get overall information about the record type for the debug info. + llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation()); + unsigned Line = getLineNumber(ID->getLocation()); + unsigned RuntimeLang = TheCU.getLanguage(); + + // If this is just a forward declaration return a special forward-declaration + // debug type since we won't be able to lay out the entire type. + ObjCInterfaceDecl *Def = ID->getDefinition(); + if (!Def) { + llvm::DIType FwdDecl = + DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + ID->getName(), TheCU, DefUnit, Line, + RuntimeLang); + return FwdDecl; + } + + ID = Def; + + // Bit size, align and offset of the type. + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + + unsigned Flags = 0; + if (ID->getImplementation()) + Flags |= llvm::DIDescriptor::FlagObjcClassComplete; + + llvm::DIType RealDecl = + DBuilder.createStructType(Unit, ID->getName(), DefUnit, + Line, Size, Align, Flags, + llvm::DIArray(), RuntimeLang); + + // Otherwise, insert it into the CompletedTypeCache so that recursive uses + // will find it and we're emitting the complete type. + CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl; + // Push the struct on region stack. + llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl); + + LexicalBlockStack.push_back(FwdDeclNode); + RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); + + // Convert all the elements. + SmallVector<llvm::Value *, 16> EltTys; + + ObjCInterfaceDecl *SClass = ID->getSuperClass(); + if (SClass) { + llvm::DIType SClassTy = + getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); + if (!SClassTy.isValid()) + return llvm::DIType(); + + llvm::DIType InhTag = + DBuilder.createInheritance(RealDecl, SClassTy, 0, 0); + EltTys.push_back(InhTag); + } + + for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(), + E = ID->prop_end(); I != E; ++I) { + const ObjCPropertyDecl *PD = *I; + SourceLocation Loc = PD->getLocation(); + llvm::DIFile PUnit = getOrCreateFile(Loc); + unsigned PLine = getLineNumber(Loc); + ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); + ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); + llvm::MDNode *PropertyNode = + DBuilder.createObjCProperty(PD->getName(), + PUnit, PLine, + (Getter && Getter->isImplicit()) ? "" : + getSelectorName(PD->getGetterName()), + (Setter && Setter->isImplicit()) ? "" : + getSelectorName(PD->getSetterName()), + PD->getPropertyAttributes(), + getOrCreateType(PD->getType(), PUnit)); + EltTys.push_back(PropertyNode); + } + + const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID); + unsigned FieldNo = 0; + for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field; + Field = Field->getNextIvar(), ++FieldNo) { + llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); + if (!FieldTy.isValid()) + return llvm::DIType(); + + StringRef FieldName = Field->getName(); + + // Ignore unnamed fields. + if (FieldName.empty()) + continue; + + // Get the location for the field. + llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation()); + unsigned FieldLine = getLineNumber(Field->getLocation()); + QualType FType = Field->getType(); + uint64_t FieldSize = 0; + unsigned FieldAlign = 0; + + if (!FType->isIncompleteArrayType()) { + + // Bit size, align and offset of the type. + FieldSize = Field->isBitField() + ? Field->getBitWidthValue(CGM.getContext()) + : CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); + } + + uint64_t FieldOffset; + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + // We don't know the runtime offset of an ivar if we're using the + // non-fragile ABI. For bitfields, use the bit offset into the first + // byte of storage of the bitfield. For other fields, use zero. + if (Field->isBitField()) { + FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset( + CGM, ID, Field); + FieldOffset %= CGM.getContext().getCharWidth(); + } else { + FieldOffset = 0; + } + } else { + FieldOffset = RL.getFieldOffset(FieldNo); + } + + unsigned Flags = 0; + if (Field->getAccessControl() == ObjCIvarDecl::Protected) + Flags = llvm::DIDescriptor::FlagProtected; + else if (Field->getAccessControl() == ObjCIvarDecl::Private) + Flags = llvm::DIDescriptor::FlagPrivate; + + llvm::MDNode *PropertyNode = NULL; + if (ObjCImplementationDecl *ImpD = ID->getImplementation()) { + if (ObjCPropertyImplDecl *PImpD = + ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) { + if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) { + SourceLocation Loc = PD->getLocation(); + llvm::DIFile PUnit = getOrCreateFile(Loc); + unsigned PLine = getLineNumber(Loc); + ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); + ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); + PropertyNode = + DBuilder.createObjCProperty(PD->getName(), + PUnit, PLine, + (Getter && Getter->isImplicit()) ? "" : + getSelectorName(PD->getGetterName()), + (Setter && Setter->isImplicit()) ? "" : + getSelectorName(PD->getSetterName()), + PD->getPropertyAttributes(), + getOrCreateType(PD->getType(), PUnit)); + } + } + } + FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, + FieldLine, FieldSize, FieldAlign, + FieldOffset, Flags, FieldTy, + PropertyNode); + EltTys.push_back(FieldTy); + } + + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); + FwdDeclNode->replaceOperandWith(10, Elements); + + LexicalBlockStack.pop_back(); + return llvm::DIType(FwdDeclNode); +} + +llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) { + llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); + int64_t Count = Ty->getNumElements(); + if (Count == 0) + // If number of elements are not known then this is an unbounded array. + // Use Count == -1 to express such arrays. + Count = -1; + + llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count); + llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); + + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + + return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray); +} + +llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, + llvm::DIFile Unit) { + uint64_t Size; + uint64_t Align; + + // FIXME: make getTypeAlign() aware of VLAs and incomplete array types + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) { + Size = 0; + Align = + CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT)); + } else if (Ty->isIncompleteArrayType()) { + Size = 0; + if (Ty->getElementType()->isIncompleteType()) + Align = 0; + else + Align = CGM.getContext().getTypeAlign(Ty->getElementType()); + } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) { + Size = 0; + Align = 0; + } else { + // Size and align of the whole array, not the element type. + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); + } + + // Add the dimensions of the array. FIXME: This loses CV qualifiers from + // interior arrays, do we care? Why aren't nested arrays represented the + // obvious/recursive way? + SmallVector<llvm::Value *, 8> Subscripts; + QualType EltTy(Ty, 0); + while ((Ty = dyn_cast<ArrayType>(EltTy))) { + // If the number of elements is known, then count is that number. Otherwise, + // it's -1. This allows us to represent a subrange with an array of 0 + // elements, like this: + // + // struct foo { + // int x[0]; + // }; + int64_t Count = -1; // Count == -1 is an unbounded array. + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) + Count = CAT->getSize().getZExtValue(); + + // FIXME: Verify this is right for VLAs. + Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); + EltTy = Ty->getElementType(); + } + + llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); + + llvm::DIType DbgTy = + DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit), + SubscriptArray); + return DbgTy; +} + +llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, + llvm::DIFile Unit) { + return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, + Ty, Ty->getPointeeType(), Unit); +} + +llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty, + llvm::DIFile Unit) { + return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, + Ty, Ty->getPointeeType(), Unit); +} + +llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, + llvm::DIFile U) { + QualType PointerDiffTy = CGM.getContext().getPointerDiffType(); + llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U); + + if (!Ty->getPointeeType()->isFunctionType()) { + // We have a data member pointer type. + return PointerDiffDITy; + } + + // We have a member function pointer type. Treat it as a struct with two + // ptrdiff_t members. + std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty); + + uint64_t FieldOffset = 0; + llvm::Value *ElementTypes[2]; + + // FIXME: This should be a DW_TAG_pointer_to_member type. + ElementTypes[0] = + DBuilder.createMemberType(U, "ptr", U, 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + FieldOffset += Info.first; + + ElementTypes[1] = + DBuilder.createMemberType(U, "ptr", U, 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + + llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes); + + return DBuilder.createStructType(U, StringRef("test"), + U, 0, FieldOffset, + 0, 0, Elements); +} + +llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, + llvm::DIFile U) { + // Ignore the atomic wrapping + // FIXME: What is the correct representation? + return getOrCreateType(Ty->getValueType(), U); +} + +/// CreateEnumType - get enumeration type. +llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { + uint64_t Size = 0; + uint64_t Align = 0; + if (!ED->getTypeForDecl()->isIncompleteType()) { + Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); + Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl()); + } + + // If this is just a forward declaration, construct an appropriately + // marked node and just return it. + if (!ED->getDefinition()) { + llvm::DIDescriptor EDContext; + EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); + llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); + unsigned Line = getLineNumber(ED->getLocation()); + StringRef EDName = ED->getName(); + return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type, + EDName, EDContext, DefUnit, Line, 0, + Size, Align); + } + + // Create DIEnumerator elements for each enumerator. + SmallVector<llvm::Value *, 16> Enumerators; + ED = ED->getDefinition(); + for (EnumDecl::enumerator_iterator + Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); + Enum != EnumEnd; ++Enum) { + Enumerators.push_back( + DBuilder.createEnumerator(Enum->getName(), + Enum->getInitVal().getZExtValue())); + } + + // Return a CompositeType for the enum itself. + llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators); + + llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); + unsigned Line = getLineNumber(ED->getLocation()); + llvm::DIDescriptor EnumContext = + getContextDescriptor(cast<Decl>(ED->getDeclContext())); + llvm::DIType ClassTy = ED->isScopedUsingClassTag() ? + getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType(); + llvm::DIType DbgTy = + DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, + Size, Align, EltArray, + ClassTy); + return DbgTy; +} + +static QualType UnwrapTypeForDebugInfo(QualType T) { + do { + QualType LastT = T; + switch (T->getTypeClass()) { + default: + return T; + case Type::TemplateSpecialization: + T = cast<TemplateSpecializationType>(T)->desugar(); + break; + case Type::TypeOfExpr: + T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType(); + break; + case Type::TypeOf: + T = cast<TypeOfType>(T)->getUnderlyingType(); + break; + case Type::Decltype: + T = cast<DecltypeType>(T)->getUnderlyingType(); + break; + case Type::UnaryTransform: + T = cast<UnaryTransformType>(T)->getUnderlyingType(); + break; + case Type::Attributed: + T = cast<AttributedType>(T)->getEquivalentType(); + break; + case Type::Elaborated: + T = cast<ElaboratedType>(T)->getNamedType(); + break; + case Type::Paren: + T = cast<ParenType>(T)->getInnerType(); + break; + case Type::SubstTemplateTypeParm: { + // We need to keep the qualifiers handy since getReplacementType() + // will strip them away. + unsigned Quals = T.getLocalFastQualifiers(); + T = cast<SubstTemplateTypeParmType>(T)->getReplacementType(); + T.addFastQualifiers(Quals); + } + break; + case Type::Auto: + T = cast<AutoType>(T)->getDeducedType(); + break; + } + + assert(T != LastT && "Type unwrapping failed to unwrap!"); + if (T == LastT) + return T; + } while (true); +} + +/// getType - Get the type from the cache or return null type if it doesn't exist. +llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) { + + // Unwrap the type as needed for debug information. + Ty = UnwrapTypeForDebugInfo(Ty); + + // Check for existing entry. + llvm::DenseMap<void *, llvm::WeakVH>::iterator it = + TypeCache.find(Ty.getAsOpaquePtr()); + if (it != TypeCache.end()) { + // Verify that the debug info still exists. + if (llvm::Value *V = it->second) + return llvm::DIType(cast<llvm::MDNode>(V)); + } + + return llvm::DIType(); +} + +/// getCompletedTypeOrNull - Get the type from the cache or return null if it +/// doesn't exist. +llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { + + // Unwrap the type as needed for debug information. + Ty = UnwrapTypeForDebugInfo(Ty); + + // Check for existing entry. + llvm::DenseMap<void *, llvm::WeakVH>::iterator it = + CompletedTypeCache.find(Ty.getAsOpaquePtr()); + if (it != CompletedTypeCache.end()) { + // Verify that the debug info still exists. + if (llvm::Value *V = it->second) + return llvm::DIType(cast<llvm::MDNode>(V)); + } + + return llvm::DIType(); +} + + +/// getOrCreateType - Get the type from the cache or create a new +/// one if necessary. +llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { + if (Ty.isNull()) + return llvm::DIType(); + + // Unwrap the type as needed for debug information. + Ty = UnwrapTypeForDebugInfo(Ty); + + llvm::DIType T = getCompletedTypeOrNull(Ty); + + if (T.Verify()) + return T; + + // Otherwise create the type. + llvm::DIType Res = CreateTypeNode(Ty, Unit); + + llvm::DIType TC = getTypeOrNull(Ty); + if (TC.Verify() && TC.isForwardDecl()) + ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), + static_cast<llvm::Value*>(TC))); + + // And update the type cache. + TypeCache[Ty.getAsOpaquePtr()] = Res; + + if (!Res.isForwardDecl()) + CompletedTypeCache[Ty.getAsOpaquePtr()] = Res; + + return Res; +} + +/// CreateTypeNode - Create a new debug type node. +llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) { + // Handle qualifiers, which recursively handles what they refer to. + if (Ty.hasLocalQualifiers()) + return CreateQualifiedType(Ty, Unit); + + const char *Diag = 0; + + // Work out details of type. + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("Dependent types cannot show up in debug information"); + + case Type::ExtVector: + case Type::Vector: + return CreateType(cast<VectorType>(Ty), Unit); + case Type::ObjCObjectPointer: + return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); + case Type::ObjCObject: + return CreateType(cast<ObjCObjectType>(Ty), Unit); + case Type::ObjCInterface: + return CreateType(cast<ObjCInterfaceType>(Ty), Unit); + case Type::Builtin: + return CreateType(cast<BuiltinType>(Ty)); + case Type::Complex: + return CreateType(cast<ComplexType>(Ty)); + case Type::Pointer: + return CreateType(cast<PointerType>(Ty), Unit); + case Type::BlockPointer: + return CreateType(cast<BlockPointerType>(Ty), Unit); + case Type::Typedef: + return CreateType(cast<TypedefType>(Ty), Unit); + case Type::Record: + return CreateType(cast<RecordType>(Ty)); + case Type::Enum: + return CreateEnumType(cast<EnumType>(Ty)->getDecl()); + case Type::FunctionProto: + case Type::FunctionNoProto: + return CreateType(cast<FunctionType>(Ty), Unit); + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + return CreateType(cast<ArrayType>(Ty), Unit); + + case Type::LValueReference: + return CreateType(cast<LValueReferenceType>(Ty), Unit); + case Type::RValueReference: + return CreateType(cast<RValueReferenceType>(Ty), Unit); + + case Type::MemberPointer: + return CreateType(cast<MemberPointerType>(Ty), Unit); + + case Type::Atomic: + return CreateType(cast<AtomicType>(Ty), Unit); + + case Type::Attributed: + case Type::TemplateSpecialization: + case Type::Elaborated: + case Type::Paren: + case Type::SubstTemplateTypeParm: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::UnaryTransform: + case Type::Auto: + llvm_unreachable("type should have been unwrapped!"); + } + + assert(Diag && "Fall through without a diagnostic?"); + unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error, + "debug information for %0 is not yet supported"); + CGM.getDiags().Report(DiagID) + << Diag; + return llvm::DIType(); +} + +/// getOrCreateLimitedType - Get the type from the cache or create a new +/// limited type if necessary. +llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty, + llvm::DIFile Unit) { + if (Ty.isNull()) + return llvm::DIType(); + + // Unwrap the type as needed for debug information. + Ty = UnwrapTypeForDebugInfo(Ty); + + llvm::DIType T = getTypeOrNull(Ty); + + // We may have cached a forward decl when we could have created + // a non-forward decl. Go ahead and create a non-forward decl + // now. + if (T.Verify() && !T.isForwardDecl()) return T; + + // Otherwise create the type. + llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit); + + if (T.Verify() && T.isForwardDecl()) + ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), + static_cast<llvm::Value*>(T))); + + // And update the type cache. + TypeCache[Ty.getAsOpaquePtr()] = Res; + return Res; +} + +// TODO: Currently used for context chains when limiting debug info. +llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { + RecordDecl *RD = Ty->getDecl(); + + // Get overall information about the record type for the debug info. + llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); + unsigned Line = getLineNumber(RD->getLocation()); + StringRef RDName = getClassName(RD); + + llvm::DIDescriptor RDContext; + if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) + RDContext = createContextChain(cast<Decl>(RD->getDeclContext())); + else + RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext())); + + // If this is just a forward declaration, construct an appropriately + // marked node and just return it. + if (!RD->getDefinition()) + return createRecordFwdDecl(RD, RDContext); + + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); + llvm::TrackingVH<llvm::MDNode> RealDecl; + + if (RD->isUnion()) + RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, + Size, Align, 0, llvm::DIArray()); + else if (RD->isClass()) { + // FIXME: This could be a struct type giving a default visibility different + // than C++ class type, but needs llvm metadata changes first. + RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line, + Size, Align, 0, 0, llvm::DIType(), + llvm::DIArray(), llvm::DIType(), + llvm::DIArray()); + } else + RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, + Size, Align, 0, llvm::DIArray()); + + RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl); + + if (CXXDecl) { + // A class's primary base or the class itself contains the vtable. + llvm::MDNode *ContainingType = NULL; + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { + // Seek non virtual primary base root. + while (1) { + const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase); + const CXXRecordDecl *PBT = BRL.getPrimaryBase(); + if (PBT && !BRL.isPrimaryBaseVirtual()) + PBase = PBT; + else + break; + } + ContainingType = + getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit); + } + else if (CXXDecl->isDynamicClass()) + ContainingType = RealDecl; + + RealDecl->replaceOperandWith(12, ContainingType); + } + return llvm::DIType(RealDecl); +} + +/// CreateLimitedTypeNode - Create a new debug type node, but only forward +/// declare composite types that haven't been processed yet. +llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) { + + // Work out details of type. + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: + #include "clang/AST/TypeNodes.def" + llvm_unreachable("Dependent types cannot show up in debug information"); + + case Type::Record: + return CreateLimitedType(cast<RecordType>(Ty)); + default: + return CreateTypeNode(Ty, Unit); + } +} + +/// CreateMemberType - Create new member and increase Offset by FType's size. +llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, + StringRef Name, + uint64_t *Offset) { + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + uint64_t FieldSize = CGM.getContext().getTypeSize(FType); + unsigned FieldAlign = CGM.getContext().getTypeAlign(FType); + llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0, + FieldSize, FieldAlign, + *Offset, 0, FieldTy); + *Offset += FieldSize; + return Ty; +} + +/// getFunctionDeclaration - Return debug info descriptor to describe method +/// declaration for the given method definition. +llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) return llvm::DISubprogram(); + + // Setup context. + getContextDescriptor(cast<Decl>(D->getDeclContext())); + + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + MI = SPCache.find(FD->getCanonicalDecl()); + if (MI != SPCache.end()) { + llvm::Value *V = MI->second; + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); + if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) + return SP; + } + + for (FunctionDecl::redecl_iterator I = FD->redecls_begin(), + E = FD->redecls_end(); I != E; ++I) { + const FunctionDecl *NextFD = *I; + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + MI = SPCache.find(NextFD->getCanonicalDecl()); + if (MI != SPCache.end()) { + llvm::Value *V = MI->second; + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); + if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) + return SP; + } + } + return llvm::DISubprogram(); +} + +// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include +// implicit parameter "this". +llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D, + QualType FnType, + llvm::DIFile F) { + + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + return getOrCreateMethodType(Method, F); + if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) { + // Add "self" and "_cmd" + SmallVector<llvm::Value *, 16> Elts; + + // First element is always return type. For 'void' functions it is NULL. + Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); + // "self" pointer is always first argument. + llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F); + Elts.push_back(DBuilder.createObjectPointerType(SelfTy)); + // "_cmd" pointer is always second argument. + llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F); + Elts.push_back(DBuilder.createArtificialType(CmdTy)); + // Get rest of the arguments. + for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(), + PE = OMethod->param_end(); PI != PE; ++PI) + Elts.push_back(getOrCreateType((*PI)->getType(), F)); + + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); + return DBuilder.createSubroutineType(F, EltTypeArray); + } + return getOrCreateType(FnType, F); +} + +/// EmitFunctionStart - Constructs the debug code for entering a function. +void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, + llvm::Function *Fn, + CGBuilderTy &Builder) { + + StringRef Name; + StringRef LinkageName; + + FnBeginRegionCount.push_back(LexicalBlockStack.size()); + + const Decl *D = GD.getDecl(); + // Function may lack declaration in source code if it is created by Clang + // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk). + bool HasDecl = (D != 0); + // Use the location of the declaration. + SourceLocation Loc; + if (HasDecl) + Loc = D->getLocation(); + + unsigned Flags = 0; + llvm::DIFile Unit = getOrCreateFile(Loc); + llvm::DIDescriptor FDContext(Unit); + llvm::DIArray TParamsArray; + if (!HasDecl) { + // Use llvm function name. + Name = Fn->getName(); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If there is a DISubprogram for this function available then use it. + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + FI = SPCache.find(FD->getCanonicalDecl()); + if (FI != SPCache.end()) { + llvm::Value *V = FI->second; + llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V)); + if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) { + llvm::MDNode *SPN = SP; + LexicalBlockStack.push_back(SPN); + RegionMap[D] = llvm::WeakVH(SP); + return; + } + } + Name = getFunctionName(FD); + // Use mangled name as linkage name for c/c++ functions. + if (FD->hasPrototype()) { + LinkageName = CGM.getMangledName(GD); + Flags |= llvm::DIDescriptor::FlagPrototyped; + } + if (LinkageName == Name || + CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly) + LinkageName = StringRef(); + + if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { + if (const NamespaceDecl *NSDecl = + dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) + FDContext = getOrCreateNameSpace(NSDecl); + else if (const RecordDecl *RDecl = + dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) + FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext())); + + // Collect template parameters. + TParamsArray = CollectFunctionTemplateParams(FD, Unit); + } + } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { + Name = getObjCMethodName(OMD); + Flags |= llvm::DIDescriptor::FlagPrototyped; + } else { + // Use llvm function name. + Name = Fn->getName(); + Flags |= llvm::DIDescriptor::FlagPrototyped; + } + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); + + unsigned LineNo = getLineNumber(Loc); + if (!HasDecl || D->isImplicit()) + Flags |= llvm::DIDescriptor::FlagArtificial; + + llvm::DIType DIFnType; + llvm::DISubprogram SPDecl; + if (HasDecl && + CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { + DIFnType = getOrCreateFunctionType(D, FnType, Unit); + SPDecl = getFunctionDeclaration(D); + } else { + // Create fake but valid subroutine type. Otherwise + // llvm::DISubprogram::Verify() would return false, and + // subprogram DIE will miss DW_AT_decl_file and + // DW_AT_decl_line fields. + SmallVector<llvm::Value*, 16> Elts; + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); + DIFnType = DBuilder.createSubroutineType(Unit, EltTypeArray); + } + llvm::DISubprogram SP; + SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit, + LineNo, DIFnType, + Fn->hasInternalLinkage(), true/*definition*/, + getLineNumber(CurLoc), Flags, + CGM.getLangOpts().Optimize, + Fn, TParamsArray, SPDecl); + + // Push function on region stack. + llvm::MDNode *SPN = SP; + LexicalBlockStack.push_back(SPN); + if (HasDecl) + RegionMap[D] = llvm::WeakVH(SP); +} + +/// EmitLocation - Emit metadata to indicate a change in line/column +/// information in the source file. +void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { + + // Update our current location + setLocation(Loc); + + if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; + + // Don't bother if things are the same as last time. + SourceManager &SM = CGM.getContext().getSourceManager(); + if (CurLoc == PrevLoc || + SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc)) + // New Builder may not be in sync with CGDebugInfo. + if (!Builder.getCurrentDebugLocation().isUnknown()) + return; + + // Update last state. + PrevLoc = CurLoc; + + llvm::MDNode *Scope = LexicalBlockStack.back(); + Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc), + getColumnNumber(CurLoc), + Scope)); +} + +/// CreateLexicalBlock - Creates a new lexical block node and pushes it on +/// the stack. +void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { + llvm::DIDescriptor D = + DBuilder.createLexicalBlock(LexicalBlockStack.empty() ? + llvm::DIDescriptor() : + llvm::DIDescriptor(LexicalBlockStack.back()), + getOrCreateFile(CurLoc), + getLineNumber(CurLoc), + getColumnNumber(CurLoc)); + llvm::MDNode *DN = D; + LexicalBlockStack.push_back(DN); +} + +/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative +/// region - beginning of a DW_TAG_lexical_block. +void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { + // Set our current location. + setLocation(Loc); + + // Create a new lexical block and push it on the stack. + CreateLexicalBlock(Loc); + + // Emit a line table change for the current location inside the new scope. + Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc), + getColumnNumber(Loc), + LexicalBlockStack.back())); +} + +/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative +/// region - end of a DW_TAG_lexical_block. +void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + + // Provide an entry in the line table for the end of the block. + EmitLocation(Builder, Loc); + + LexicalBlockStack.pop_back(); +} + +/// EmitFunctionEnd - Constructs the debug code for exiting a function. +void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + unsigned RCount = FnBeginRegionCount.back(); + assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch"); + + // Pop all regions for this function. + while (LexicalBlockStack.size() != RCount) + EmitLexicalBlockEnd(Builder, CurLoc); + FnBeginRegionCount.pop_back(); +} + +// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. +// See BuildByRefType. +llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, + uint64_t *XOffset) { + + SmallVector<llvm::Value *, 5> EltTys; + QualType FType; + uint64_t FieldSize, FieldOffset; + unsigned FieldAlign; + + llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); + QualType Type = VD->getType(); + + FieldOffset = 0; + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); + FType = CGM.getContext().IntTy; + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); + + bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD); + if (HasCopyAndDispose) { + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", + &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", + &FieldOffset)); + } + bool HasByrefExtendedLayout; + Qualifiers::ObjCLifetime Lifetime; + if (CGM.getContext().getByrefLifetime(Type, + Lifetime, HasByrefExtendedLayout) + && HasByrefExtendedLayout) + EltTys.push_back(CreateMemberType(Unit, FType, + "__byref_variable_layout", + &FieldOffset)); + + CharUnits Align = CGM.getContext().getDeclAlign(VD); + if (Align > CGM.getContext().toCharUnitsFromBits( + CGM.getContext().getTargetInfo().getPointerAlign(0))) { + CharUnits FieldOffsetInBytes + = CGM.getContext().toCharUnitsFromBits(FieldOffset); + CharUnits AlignedOffsetInBytes + = FieldOffsetInBytes.RoundUpToAlignment(Align); + CharUnits NumPaddingBytes + = AlignedOffsetInBytes - FieldOffsetInBytes; + + if (NumPaddingBytes.isPositive()) { + llvm::APInt pad(32, NumPaddingBytes.getQuantity()); + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, + pad, ArrayType::Normal, 0); + EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); + } + } + + FType = Type; + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().toBits(Align); + + *XOffset = FieldOffset; + FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit, + 0, FieldSize, FieldAlign, + FieldOffset, 0, FieldTy); + EltTys.push_back(FieldTy); + FieldOffset += FieldSize; + + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); + + unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct; + + return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags, + Elements); +} + +/// EmitDeclare - Emit local variable declaration debug info. +void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, + llvm::Value *Storage, + unsigned ArgNo, CGBuilderTy &Builder) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + + llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); + llvm::DIType Ty; + uint64_t XOffset = 0; + if (VD->hasAttr<BlocksAttr>()) + Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); + else + Ty = getOrCreateType(VD->getType(), Unit); + + // If there is no debug info for this type then do not emit debug info + // for this variable. + if (!Ty) + return; + + if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage)) { + // If Storage is an aggregate returned as 'sret' then let debugger know + // about this. + if (Arg->hasStructRetAttr()) + Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty); + else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) { + // If an aggregate variable has non trivial destructor or non trivial copy + // constructor than it is pass indirectly. Let debug info know about this + // by using reference of the aggregate type as a argument type. + if (Record->hasNonTrivialCopyConstructor() || + !Record->hasTrivialDestructor()) + Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty); + } + } + + // Get location information. + unsigned Line = getLineNumber(VD->getLocation()); + unsigned Column = getColumnNumber(VD->getLocation()); + unsigned Flags = 0; + if (VD->isImplicit()) + Flags |= llvm::DIDescriptor::FlagArtificial; + // If this is the first argument and it is implicit then + // give it an object pointer flag. + // FIXME: There has to be a better way to do this, but for static + // functions there won't be an implicit param at arg1 and + // otherwise it is 'self' or 'this'. + if (isa<ImplicitParamDecl>(VD) && ArgNo == 1) + Flags |= llvm::DIDescriptor::FlagObjectPointer; + + llvm::MDNode *Scope = LexicalBlockStack.back(); + + StringRef Name = VD->getName(); + if (!Name.empty()) { + if (VD->hasAttr<BlocksAttr>()) { + CharUnits offset = CharUnits::fromQuantity(32); + SmallVector<llvm::Value *, 9> addr; + llvm::Type *Int64Ty = CGM.Int64Ty; + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); + // offset of __forwarding field + offset = CGM.getContext().toCharUnitsFromBits( + CGM.getContext().getTargetInfo().getPointerWidth(0)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); + // offset of x field + offset = CGM.getContext().toCharUnitsFromBits(XOffset); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + + // Create the descriptor for the variable. + llvm::DIVariable D = + DBuilder.createComplexVariable(Tag, + llvm::DIDescriptor(Scope), + VD->getName(), Unit, Line, Ty, + addr, ArgNo); + + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *Call = + DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); + return; + } else if (isa<VariableArrayType>(VD->getType())) { + // These are "complex" variables in that they need an op_deref. + // Create the descriptor for the variable. + llvm::Value *Addr = llvm::ConstantInt::get(CGM.Int64Ty, + llvm::DIBuilder::OpDeref); + llvm::DIVariable D = + DBuilder.createComplexVariable(Tag, + llvm::DIDescriptor(Scope), + Name, Unit, Line, Ty, + Addr, ArgNo); + + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *Call = + DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); + return; + } + + // Create the descriptor for the variable. + llvm::DIVariable D = + DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), + Name, Unit, Line, Ty, + CGM.getLangOpts().Optimize, Flags, ArgNo); + + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *Call = + DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); + return; + } + + // If VD is an anonymous union then Storage represents value for + // all union fields. + if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) { + const RecordDecl *RD = cast<RecordDecl>(RT->getDecl()); + if (RD->isUnion()) { + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); + I != E; ++I) { + FieldDecl *Field = *I; + llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); + StringRef FieldName = Field->getName(); + + // Ignore unnamed fields. Do not ignore unnamed records. + if (FieldName.empty() && !isa<RecordType>(Field->getType())) + continue; + + // Use VarDecl's Tag, Scope and Line number. + llvm::DIVariable D = + DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), + FieldName, Unit, Line, FieldTy, + CGM.getLangOpts().Optimize, Flags, + ArgNo); + + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *Call = + DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); + } + } + } +} + +void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, + llvm::Value *Storage, + CGBuilderTy &Builder) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); +} + +void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, + llvm::Value *Storage, + CGBuilderTy &Builder, + const CGBlockInfo &blockInfo) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + + if (Builder.GetInsertBlock() == 0) + return; + + bool isByRef = VD->hasAttr<BlocksAttr>(); + + uint64_t XOffset = 0; + llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); + llvm::DIType Ty; + if (isByRef) + Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); + else + Ty = getOrCreateType(VD->getType(), Unit); + + // Self is passed along as an implicit non-arg variable in a + // block. Mark it as the object pointer. + if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self") + Ty = DBuilder.createObjectPointerType(Ty); + + // Get location information. + unsigned Line = getLineNumber(VD->getLocation()); + unsigned Column = getColumnNumber(VD->getLocation()); + + const llvm::DataLayout &target = CGM.getDataLayout(); + + CharUnits offset = CharUnits::fromQuantity( + target.getStructLayout(blockInfo.StructureType) + ->getElementOffset(blockInfo.getCapture(VD).getIndex())); + + SmallVector<llvm::Value *, 9> addr; + llvm::Type *Int64Ty = CGM.Int64Ty; + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + if (isByRef) { + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); + // offset of __forwarding field + offset = CGM.getContext() + .toCharUnitsFromBits(target.getPointerSizeInBits(0)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); + addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); + // offset of x field + offset = CGM.getContext().toCharUnitsFromBits(XOffset); + addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); + } + + // Create the descriptor for the variable. + llvm::DIVariable D = + DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable, + llvm::DIDescriptor(LexicalBlockStack.back()), + VD->getName(), Unit, Line, Ty, addr); + // Insert an llvm.dbg.declare into the current block. + llvm::Instruction *Call = + DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint()); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, + LexicalBlockStack.back())); +} + +/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument +/// variable declaration. +void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, + unsigned ArgNo, + CGBuilderTy &Builder) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder); +} + +namespace { + struct BlockLayoutChunk { + uint64_t OffsetInBits; + const BlockDecl::Capture *Capture; + }; + bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) { + return l.OffsetInBits < r.OffsetInBits; + } +} + +void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, + llvm::Value *addr, + CGBuilderTy &Builder) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + ASTContext &C = CGM.getContext(); + const BlockDecl *blockDecl = block.getBlockDecl(); + + // Collect some general information about the block's location. + SourceLocation loc = blockDecl->getCaretLocation(); + llvm::DIFile tunit = getOrCreateFile(loc); + unsigned line = getLineNumber(loc); + unsigned column = getColumnNumber(loc); + + // Build the debug-info type for the block literal. + getContextDescriptor(cast<Decl>(blockDecl->getDeclContext())); + + const llvm::StructLayout *blockLayout = + CGM.getDataLayout().getStructLayout(block.StructureType); + + SmallVector<llvm::Value*, 16> fields; + fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public, + blockLayout->getElementOffsetInBits(0), + tunit, tunit)); + fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public, + blockLayout->getElementOffsetInBits(1), + tunit, tunit)); + fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public, + blockLayout->getElementOffsetInBits(2), + tunit, tunit)); + fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public, + blockLayout->getElementOffsetInBits(3), + tunit, tunit)); + fields.push_back(createFieldType("__descriptor", + C.getPointerType(block.NeedsCopyDispose ? + C.getBlockDescriptorExtendedType() : + C.getBlockDescriptorType()), + 0, loc, AS_public, + blockLayout->getElementOffsetInBits(4), + tunit, tunit)); + + // We want to sort the captures by offset, not because DWARF + // requires this, but because we're paranoid about debuggers. + SmallVector<BlockLayoutChunk, 8> chunks; + + // 'this' capture. + if (blockDecl->capturesCXXThis()) { + BlockLayoutChunk chunk; + chunk.OffsetInBits = + blockLayout->getElementOffsetInBits(block.CXXThisIndex); + chunk.Capture = 0; + chunks.push_back(chunk); + } + + // Variable captures. + for (BlockDecl::capture_const_iterator + i = blockDecl->capture_begin(), e = blockDecl->capture_end(); + i != e; ++i) { + const BlockDecl::Capture &capture = *i; + const VarDecl *variable = capture.getVariable(); + const CGBlockInfo::Capture &captureInfo = block.getCapture(variable); + + // Ignore constant captures. + if (captureInfo.isConstant()) + continue; + + BlockLayoutChunk chunk; + chunk.OffsetInBits = + blockLayout->getElementOffsetInBits(captureInfo.getIndex()); + chunk.Capture = &capture; + chunks.push_back(chunk); + } + + // Sort by offset. + llvm::array_pod_sort(chunks.begin(), chunks.end()); + + for (SmallVectorImpl<BlockLayoutChunk>::iterator + i = chunks.begin(), e = chunks.end(); i != e; ++i) { + uint64_t offsetInBits = i->OffsetInBits; + const BlockDecl::Capture *capture = i->Capture; + + // If we have a null capture, this must be the C++ 'this' capture. + if (!capture) { + const CXXMethodDecl *method = + cast<CXXMethodDecl>(blockDecl->getNonClosureContext()); + QualType type = method->getThisType(C); + + fields.push_back(createFieldType("this", type, 0, loc, AS_public, + offsetInBits, tunit, tunit)); + continue; + } + + const VarDecl *variable = capture->getVariable(); + StringRef name = variable->getName(); + + llvm::DIType fieldType; + if (capture->isByRef()) { + std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy); + + // FIXME: this creates a second copy of this type! + uint64_t xoffset; + fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset); + fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first); + fieldType = DBuilder.createMemberType(tunit, name, tunit, line, + ptrInfo.first, ptrInfo.second, + offsetInBits, 0, fieldType); + } else { + fieldType = createFieldType(name, variable->getType(), 0, + loc, AS_public, offsetInBits, tunit, tunit); + } + fields.push_back(fieldType); + } + + SmallString<36> typeName; + llvm::raw_svector_ostream(typeName) + << "__block_literal_" << CGM.getUniqueBlockCount(); + + llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields); + + llvm::DIType type = + DBuilder.createStructType(tunit, typeName.str(), tunit, line, + CGM.getContext().toBits(block.BlockSize), + CGM.getContext().toBits(block.BlockAlign), + 0, fieldsArray); + type = DBuilder.createPointerType(type, CGM.PointerWidthInBits); + + // Get overall information about the block. + unsigned flags = llvm::DIDescriptor::FlagArtificial; + llvm::MDNode *scope = LexicalBlockStack.back(); + StringRef name = ".block_descriptor"; + + // Create the descriptor for the parameter. + llvm::DIVariable debugVar = + DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, + llvm::DIDescriptor(scope), + name, tunit, line, type, + CGM.getLangOpts().Optimize, flags, + cast<llvm::Argument>(addr)->getArgNo() + 1); + + // Insert an llvm.dbg.value into the current block. + llvm::Instruction *declare = + DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar, + Builder.GetInsertBlock()); + declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope)); +} + +/// EmitGlobalVariable - Emit information about a global variable. +void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, + const VarDecl *D) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + // Create global variable debug descriptor. + llvm::DIFile Unit = getOrCreateFile(D->getLocation()); + unsigned LineNo = getLineNumber(D->getLocation()); + + setLocation(D->getLocation()); + + QualType T = D->getType(); + if (T->isIncompleteArrayType()) { + + // CodeGen turns int[] into int[1] so we'll do the same here. + llvm::APInt ConstVal(32, 1); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); + + T = CGM.getContext().getConstantArrayType(ET, ConstVal, + ArrayType::Normal, 0); + } + StringRef DeclName = D->getName(); + StringRef LinkageName; + if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) + && !isa<ObjCMethodDecl>(D->getDeclContext())) + LinkageName = Var->getName(); + if (LinkageName == DeclName) + LinkageName = StringRef(); + llvm::DIDescriptor DContext = + getContextDescriptor(dyn_cast<Decl>(D->getDeclContext())); + DBuilder.createStaticVariable(DContext, DeclName, LinkageName, + Unit, LineNo, getOrCreateType(T, Unit), + Var->hasInternalLinkage(), Var); +} + +/// EmitGlobalVariable - Emit information about an objective-c interface. +void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, + ObjCInterfaceDecl *ID) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + // Create global variable debug descriptor. + llvm::DIFile Unit = getOrCreateFile(ID->getLocation()); + unsigned LineNo = getLineNumber(ID->getLocation()); + + StringRef Name = ID->getName(); + + QualType T = CGM.getContext().getObjCInterfaceType(ID); + if (T->isIncompleteArrayType()) { + + // CodeGen turns int[] into int[1] so we'll do the same here. + llvm::APInt ConstVal(32, 1); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); + + T = CGM.getContext().getConstantArrayType(ET, ConstVal, + ArrayType::Normal, 0); + } + + DBuilder.createGlobalVariable(Name, Unit, LineNo, + getOrCreateType(T, Unit), + Var->hasInternalLinkage(), Var); +} + +/// EmitGlobalVariable - Emit global variable's debug info. +void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, + llvm::Constant *Init) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); + // Create the descriptor for the variable. + llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); + StringRef Name = VD->getName(); + llvm::DIType Ty = getOrCreateType(VD->getType(), Unit); + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) { + const EnumDecl *ED = cast<EnumDecl>(ECD->getDeclContext()); + assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?"); + Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit); + } + // Do not use DIGlobalVariable for enums. + if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type) + return; + DBuilder.createStaticVariable(Unit, Name, Name, Unit, + getLineNumber(VD->getLocation()), + Ty, true, Init); +} + +/// getOrCreateNamesSpace - Return namespace descriptor for the given +/// namespace decl. +llvm::DINameSpace +CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { + llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I = + NameSpaceCache.find(NSDecl); + if (I != NameSpaceCache.end()) + return llvm::DINameSpace(cast<llvm::MDNode>(I->second)); + + unsigned LineNo = getLineNumber(NSDecl->getLocation()); + llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation()); + llvm::DIDescriptor Context = + getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext())); + llvm::DINameSpace NS = + DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo); + NameSpaceCache[NSDecl] = llvm::WeakVH(NS); + return NS; +} + +void CGDebugInfo::finalize() { + for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI + = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) { + llvm::DIType Ty, RepTy; + // Verify that the debug info still exists. + if (llvm::Value *V = VI->second) + Ty = llvm::DIType(cast<llvm::MDNode>(V)); + + llvm::DenseMap<void *, llvm::WeakVH>::iterator it = + TypeCache.find(VI->first); + if (it != TypeCache.end()) { + // Verify that the debug info still exists. + if (llvm::Value *V = it->second) + RepTy = llvm::DIType(cast<llvm::MDNode>(V)); + } + + if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) { + Ty.replaceAllUsesWith(RepTy); + } + } + DBuilder.finalize(); +} diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 5a3b1221058..cb9ce8beef5 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -1,330 +1,325 @@ -//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is the source level debug info generator for llvm translation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
-#define CLANG_CODEGEN_CGDEBUGINFO_H
-
-#include "CGBuilder.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/DIBuilder.h"
-#include "llvm/DebugInfo.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ValueHandle.h"
-
-namespace llvm {
- class MDNode;
-}
-
-namespace clang {
- class CXXMethodDecl;
- class VarDecl;
- class ObjCInterfaceDecl;
- class ClassTemplateSpecializationDecl;
- class GlobalDecl;
-
-namespace CodeGen {
- class CodeGenModule;
- class CodeGenFunction;
- class CGBlockInfo;
-
-/// CGDebugInfo - This class gathers all debug information during compilation
-/// and is responsible for emitting to llvm globals or pass directly to
-/// the backend.
-class CGDebugInfo {
- CodeGenModule &CGM;
- llvm::DIBuilder DBuilder;
- llvm::DICompileUnit TheCU;
- SourceLocation CurLoc, PrevLoc;
- llvm::DIType VTablePtrType;
- llvm::DIType ClassTy;
- llvm::DIType ObjTy;
- llvm::DIType SelTy;
- llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy;
- llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
- llvm::DIType OCLImage3dDITy;
-
- /// TypeCache - Cache of previously constructed Types.
- llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
-
- /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
- llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
-
- /// ReplaceMap - Cache of forward declared types to RAUW at the end of
- /// compilation.
- std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
-
- bool BlockLiteralGenericSet;
- llvm::DIType BlockLiteralGeneric;
-
- // LexicalBlockStack - Keep track of our current nested lexical block.
- std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
- llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
- // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the
- // beginning of a function. This is used to pop unbalanced regions at
- // the end of a function.
- std::vector<unsigned> FnBeginRegionCount;
-
- /// DebugInfoNames - This is a storage for names that are
- /// constructed on demand. For example, C++ destructors, C++ operators etc..
- llvm::BumpPtrAllocator DebugInfoNames;
- StringRef CWDName;
-
- llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
- llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
- llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
-
- /// Helper functions for getOrCreateType.
- llvm::DIType CreateType(const BuiltinType *Ty);
- llvm::DIType CreateType(const ComplexType *Ty);
- llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
- llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
- llvm::DIFile F);
- llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const RecordType *Ty);
- llvm::DIType CreateLimitedType(const RecordType *Ty);
- llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit);
- llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
- llvm::DIType CreateEnumType(const EnumDecl *ED);
- llvm::DIType getTypeOrNull(const QualType);
- llvm::DIType getCompletedTypeOrNull(const QualType);
- llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile F);
- llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
- llvm::DIFile F);
- llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
- llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
- llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F);
- llvm::DIType CreatePointerLikeType(unsigned Tag,
- const Type *Ty, QualType PointeeTy,
- llvm::DIFile F);
-
- llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache);
-
- llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
- llvm::DIFile F,
- llvm::DIType RecordTy);
-
- void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &E,
- llvm::DIType T);
-
- void CollectCXXFriends(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy);
-
- void CollectCXXBases(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys,
- llvm::DIType RecordTy);
-
- llvm::DIArray
- CollectTemplateParams(const TemplateParameterList *TPList,
- const TemplateArgumentList &TAList,
- llvm::DIFile Unit);
- llvm::DIArray
- CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit);
- llvm::DIArray
- CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
- llvm::DIFile F);
-
- llvm::DIType createFieldType(StringRef name, QualType type,
- uint64_t sizeInBitsOverride, SourceLocation loc,
- AccessSpecifier AS, uint64_t offsetInBits,
- llvm::DIFile tunit,
- llvm::DIDescriptor scope);
- void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
- void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &E,
- llvm::DIType RecordTy);
-
- void CollectVTableInfo(const CXXRecordDecl *Decl,
- llvm::DIFile F,
- SmallVectorImpl<llvm::Value *> &EltTys);
-
- // CreateLexicalBlock - Create a new lexical block node and push it on
- // the stack.
- void CreateLexicalBlock(SourceLocation Loc);
-
-public:
- CGDebugInfo(CodeGenModule &CGM);
- ~CGDebugInfo();
-
- void finalize();
-
- /// setLocation - Update the current source location. If \arg loc is
- /// invalid it is ignored.
- void setLocation(SourceLocation Loc);
-
- /// EmitLocation - Emit metadata to indicate a change in line/column
- /// information in the source file.
- void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
- /// start of a new function.
- void EmitFunctionStart(GlobalDecl GD, QualType FnType,
- llvm::Function *Fn, CGBuilderTy &Builder);
-
- /// EmitFunctionEnd - Constructs the debug code for exiting a function.
- void EmitFunctionEnd(CGBuilderTy &Builder);
-
- /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a
- /// new lexical block and push the block onto the stack.
- void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical
- /// block and pop the current block.
- void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc);
-
- /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic
- /// variable declaration.
- void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
- CGBuilderTy &Builder);
-
- /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an
- /// imported variable declaration in a block.
- void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable,
- llvm::Value *storage,
- CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo);
-
- /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
- /// variable declaration.
- void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
- unsigned ArgNo, CGBuilderTy &Builder);
-
- /// EmitDeclareOfBlockLiteralArgVariable - Emit call to
- /// llvm.dbg.declare for the block-literal argument to a block
- /// invocation function.
- void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
- CGBuilderTy &Builder);
-
- /// EmitGlobalVariable - Emit information about a global variable.
- void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
-
- /// EmitGlobalVariable - Emit information about an objective-c interface.
- void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl);
-
- /// EmitGlobalVariable - Emit global variable's debug info.
- void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init);
-
- /// getOrCreateRecordType - Emit record type's standalone debug info.
- llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L);
-
- /// getOrCreateInterfaceType - Emit an objective c interface type standalone
- /// debug info.
- llvm::DIType getOrCreateInterfaceType(QualType Ty,
- SourceLocation Loc);
-
-private:
- /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
- void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
- unsigned ArgNo, CGBuilderTy &Builder);
-
- // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
- // See BuildByRefType.
- llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
- uint64_t *OffSet);
-
- /// getContextDescriptor - Get context info for the decl.
- llvm::DIDescriptor getContextDescriptor(const Decl *Decl);
-
- /// createRecordFwdDecl - Create a forward decl for a RecordType in a given
- /// context.
- llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor);
-
- /// createContextChain - Create a set of decls for the context chain.
- llvm::DIDescriptor createContextChain(const Decl *Decl);
-
- /// getCurrentDirname - Return current directory name.
- StringRef getCurrentDirname();
-
- /// CreateCompileUnit - Create new compile unit.
- void CreateCompileUnit();
-
- /// getOrCreateFile - Get the file debug info descriptor for the input
- /// location.
- llvm::DIFile getOrCreateFile(SourceLocation Loc);
-
- /// getOrCreateMainFile - Get the file info for main compile unit.
- llvm::DIFile getOrCreateMainFile();
-
- /// getOrCreateType - Get the type from the cache or create a new type if
- /// necessary.
- llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
-
- /// getOrCreateLimitedType - Get the type from the cache or create a new
- /// partial type if necessary.
- llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
-
- /// CreateTypeNode - Create type metadata for a source language type.
- llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
-
- /// CreateLimitedTypeNode - Create type metadata for a source language
- /// type, but only partial types for records.
- llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
-
- /// CreateMemberType - Create new member and increase Offset by FType's size.
- llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
- StringRef Name, uint64_t *Offset);
-
- /// getFunctionDeclaration - Return debug info descriptor to describe method
- /// declaration for the given method definition.
- llvm::DISubprogram getFunctionDeclaration(const Decl *D);
-
- /// getFunctionName - Get function name for the given FunctionDecl. If the
- /// name is constructred on demand (e.g. C++ destructor) then the name
- /// is stored on the side.
- StringRef getFunctionName(const FunctionDecl *FD);
-
- /// getObjCMethodName - Returns the unmangled name of an Objective-C method.
- /// This is the display name for the debugging info.
- StringRef getObjCMethodName(const ObjCMethodDecl *FD);
-
- /// getSelectorName - Return selector name. This is used for debugging
- /// info.
- StringRef getSelectorName(Selector S);
-
- /// getClassName - Get class name including template argument list.
- StringRef getClassName(const RecordDecl *RD);
-
- /// getVTableName - Get vtable name for the given Class.
- StringRef getVTableName(const CXXRecordDecl *Decl);
-
- /// getLineNumber - Get line number for the location. If location is invalid
- /// then use current location.
- unsigned getLineNumber(SourceLocation Loc);
-
- /// getColumnNumber - Get column number for the location. If location is
- /// invalid then use current location.
- unsigned getColumnNumber(SourceLocation Loc);
-};
-} // namespace CodeGen
-} // namespace clang
-
-
-#endif
+//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the source level debug info generator for llvm translation. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGDEBUGINFO_H +#define CLANG_CODEGEN_CGDEBUGINFO_H + +#include "CGBuilder.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/DIBuilder.h" +#include "llvm/DebugInfo.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/ValueHandle.h" + +namespace llvm { + class MDNode; +} + +namespace clang { + class CXXMethodDecl; + class VarDecl; + class ObjCInterfaceDecl; + class ClassTemplateSpecializationDecl; + class GlobalDecl; + +namespace CodeGen { + class CodeGenModule; + class CodeGenFunction; + class CGBlockInfo; + +/// CGDebugInfo - This class gathers all debug information during compilation +/// and is responsible for emitting to llvm globals or pass directly to +/// the backend. +class CGDebugInfo { + CodeGenModule &CGM; + llvm::DIBuilder DBuilder; + llvm::DICompileUnit TheCU; + SourceLocation CurLoc, PrevLoc; + llvm::DIType VTablePtrType; + llvm::DIType ClassTy; + llvm::DIType ObjTy; + llvm::DIType SelTy; + + /// TypeCache - Cache of previously constructed Types. + llvm::DenseMap<void *, llvm::WeakVH> TypeCache; + + /// CompleteTypeCache - Cache of previously constructed complete RecordTypes. + llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache; + + /// ReplaceMap - Cache of forward declared types to RAUW at the end of + /// compilation. + std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap; + + bool BlockLiteralGenericSet; + llvm::DIType BlockLiteralGeneric; + + // LexicalBlockStack - Keep track of our current nested lexical block. + std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack; + llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap; + // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the + // beginning of a function. This is used to pop unbalanced regions at + // the end of a function. + std::vector<unsigned> FnBeginRegionCount; + + /// DebugInfoNames - This is a storage for names that are + /// constructed on demand. For example, C++ destructors, C++ operators etc.. + llvm::BumpPtrAllocator DebugInfoNames; + StringRef CWDName; + + llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; + + /// Helper functions for getOrCreateType. + llvm::DIType CreateType(const BuiltinType *Ty); + llvm::DIType CreateType(const ComplexType *Ty); + llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F); + llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const ObjCObjectPointerType *Ty, + llvm::DIFile F); + llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const RecordType *Ty); + llvm::DIType CreateLimitedType(const RecordType *Ty); + llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit); + llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); + llvm::DIType CreateEnumType(const EnumDecl *ED); + llvm::DIType getTypeOrNull(const QualType); + llvm::DIType getCompletedTypeOrNull(const QualType); + llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, + llvm::DIFile F); + llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType, + llvm::DIFile F); + llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F); + llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N); + llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F); + llvm::DIType CreatePointerLikeType(unsigned Tag, + const Type *Ty, QualType PointeeTy, + llvm::DIFile F); + + llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method, + llvm::DIFile F, + llvm::DIType RecordTy); + + void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, + llvm::DIFile F, + SmallVectorImpl<llvm::Value *> &E, + llvm::DIType T); + + void CollectCXXFriends(const CXXRecordDecl *Decl, + llvm::DIFile F, + SmallVectorImpl<llvm::Value *> &EltTys, + llvm::DIType RecordTy); + + void CollectCXXBases(const CXXRecordDecl *Decl, + llvm::DIFile F, + SmallVectorImpl<llvm::Value *> &EltTys, + llvm::DIType RecordTy); + + llvm::DIArray + CollectTemplateParams(const TemplateParameterList *TPList, + const TemplateArgumentList &TAList, + llvm::DIFile Unit); + llvm::DIArray + CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit); + llvm::DIArray + CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, + llvm::DIFile F); + + llvm::DIType createFieldType(StringRef name, QualType type, + uint64_t sizeInBitsOverride, SourceLocation loc, + AccessSpecifier AS, uint64_t offsetInBits, + llvm::DIFile tunit, + llvm::DIDescriptor scope); + void CollectRecordStaticVars(const RecordDecl *, llvm::DIType); + void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, + SmallVectorImpl<llvm::Value *> &E, + llvm::DIType RecordTy); + + void CollectVTableInfo(const CXXRecordDecl *Decl, + llvm::DIFile F, + SmallVectorImpl<llvm::Value *> &EltTys); + + // CreateLexicalBlock - Create a new lexical block node and push it on + // the stack. + void CreateLexicalBlock(SourceLocation Loc); + +public: + CGDebugInfo(CodeGenModule &CGM); + ~CGDebugInfo(); + + void finalize(); + + /// setLocation - Update the current source location. If \arg loc is + /// invalid it is ignored. + void setLocation(SourceLocation Loc); + + /// EmitLocation - Emit metadata to indicate a change in line/column + /// information in the source file. + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + + /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate + /// start of a new function. + void EmitFunctionStart(GlobalDecl GD, QualType FnType, + llvm::Function *Fn, CGBuilderTy &Builder); + + /// EmitFunctionEnd - Constructs the debug code for exiting a function. + void EmitFunctionEnd(CGBuilderTy &Builder); + + /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a + /// new lexical block and push the block onto the stack. + void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc); + + /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical + /// block and pop the current block. + void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc); + + /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic + /// variable declaration. + void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, + CGBuilderTy &Builder); + + /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an + /// imported variable declaration in a block. + void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable, + llvm::Value *storage, + CGBuilderTy &Builder, + const CGBlockInfo &blockInfo); + + /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument + /// variable declaration. + void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, + unsigned ArgNo, CGBuilderTy &Builder); + + /// EmitDeclareOfBlockLiteralArgVariable - Emit call to + /// llvm.dbg.declare for the block-literal argument to a block + /// invocation function. + void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, + llvm::Value *addr, + CGBuilderTy &Builder); + + /// EmitGlobalVariable - Emit information about a global variable. + void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); + + /// EmitGlobalVariable - Emit information about an objective-c interface. + void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl); + + /// EmitGlobalVariable - Emit global variable's debug info. + void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); + + /// getOrCreateRecordType - Emit record type's standalone debug info. + llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L); + + /// getOrCreateInterfaceType - Emit an objective c interface type standalone + /// debug info. + llvm::DIType getOrCreateInterfaceType(QualType Ty, + SourceLocation Loc); + +private: + /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. + void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, + unsigned ArgNo, CGBuilderTy &Builder); + + // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. + // See BuildByRefType. + llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD, + uint64_t *OffSet); + + /// getContextDescriptor - Get context info for the decl. + llvm::DIDescriptor getContextDescriptor(const Decl *Decl); + + /// createRecordFwdDecl - Create a forward decl for a RecordType in a given + /// context. + llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor); + + /// createContextChain - Create a set of decls for the context chain. + llvm::DIDescriptor createContextChain(const Decl *Decl); + + /// getCurrentDirname - Return current directory name. + StringRef getCurrentDirname(); + + /// CreateCompileUnit - Create new compile unit. + void CreateCompileUnit(); + + /// getOrCreateFile - Get the file debug info descriptor for the input + /// location. + llvm::DIFile getOrCreateFile(SourceLocation Loc); + + /// getOrCreateMainFile - Get the file info for main compile unit. + llvm::DIFile getOrCreateMainFile(); + + /// getOrCreateType - Get the type from the cache or create a new type if + /// necessary. + llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F); + + /// getOrCreateLimitedType - Get the type from the cache or create a new + /// partial type if necessary. + llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F); + + /// CreateTypeNode - Create type metadata for a source language type. + llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); + + /// CreateLimitedTypeNode - Create type metadata for a source language + /// type, but only partial types for records. + llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F); + + /// CreateMemberType - Create new member and increase Offset by FType's size. + llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, + StringRef Name, uint64_t *Offset); + + /// getFunctionDeclaration - Return debug info descriptor to describe method + /// declaration for the given method definition. + llvm::DISubprogram getFunctionDeclaration(const Decl *D); + + /// getFunctionName - Get function name for the given FunctionDecl. If the + /// name is constructred on demand (e.g. C++ destructor) then the name + /// is stored on the side. + StringRef getFunctionName(const FunctionDecl *FD); + + /// getObjCMethodName - Returns the unmangled name of an Objective-C method. + /// This is the display name for the debugging info. + StringRef getObjCMethodName(const ObjCMethodDecl *FD); + + /// getSelectorName - Return selector name. This is used for debugging + /// info. + StringRef getSelectorName(Selector S); + + /// getClassName - Get class name including template argument list. + StringRef getClassName(const RecordDecl *RD); + + /// getVTableName - Get vtable name for the given Class. + StringRef getVTableName(const CXXRecordDecl *Decl); + + /// getLineNumber - Get line number for the location. If location is invalid + /// then use current location. + unsigned getLineNumber(SourceLocation Loc); + + /// getColumnNumber - Get column number for the location. If location is + /// invalid then use current location. + unsigned getColumnNumber(SourceLocation Loc); +}; +} // namespace CodeGen +} // namespace clang + + +#endif diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp index 61d62860d18..3a0e116e5ab 100644 --- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -1,59 +1,28 @@ -//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for OpenCL code generation. Concrete
-// subclasses of this implement code generation for specific OpenCL
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CGOpenCLRuntime.h"
-#include "CodeGenFunction.h"
-#include "llvm/GlobalValue.h"
-#include "llvm/DerivedTypes.h"
-#include <assert.h>
-
-using namespace clang;
-using namespace CodeGen;
-
-CGOpenCLRuntime::~CGOpenCLRuntime() {}
-
-void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
- const VarDecl &D) {
- return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-}
-
-llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
- assert(T->isOpenCLSpecificType() &&
- "Not an OpenCL specific type!");
-
- switch (cast<BuiltinType>(T)->getKind()) {
- default:
- llvm_unreachable("Unexpected opencl builtin type!");
- return 0;
- case BuiltinType::OCLImage1d:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_t"), 0);
- case BuiltinType::OCLImage1dArray:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_array_t"), 0);
- case BuiltinType::OCLImage1dBuffer:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_buffer_t"), 0);
- case BuiltinType::OCLImage2d:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image2d_t"), 0);
- case BuiltinType::OCLImage2dArray:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image2d_array_t"), 0);
- case BuiltinType::OCLImage3d:
- return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image3d_t"), 0);
- }
-}
+//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for OpenCL code generation. Concrete +// subclasses of this implement code generation for specific OpenCL +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#include "CGOpenCLRuntime.h" +#include "CodeGenFunction.h" +#include "llvm/GlobalValue.h" + +using namespace clang; +using namespace CodeGen; + +CGOpenCLRuntime::~CGOpenCLRuntime() {} + +void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, + const VarDecl &D) { + return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); +} diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.h b/clang/lib/CodeGen/CGOpenCLRuntime.h index 7b33951c267..9a8430fb750 100644 --- a/clang/lib/CodeGen/CGOpenCLRuntime.h +++ b/clang/lib/CodeGen/CGOpenCLRuntime.h @@ -1,52 +1,46 @@ -//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This provides an abstract class for OpenCL code generation. Concrete
-// subclasses of this implement code generation for specific OpenCL
-// runtime libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
-#define CLANG_CODEGEN_OPENCLRUNTIME_H
-
-#include "clang/AST/Type.h"
-#include "llvm/Type.h"
-#include "llvm/Value.h"
-
-namespace clang {
-
-class VarDecl;
-
-namespace CodeGen {
-
-class CodeGenFunction;
-class CodeGenModule;
-
-class CGOpenCLRuntime {
-protected:
- CodeGenModule &CGM;
-
-public:
- CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
- virtual ~CGOpenCLRuntime();
-
- /// Emit the IR required for a work-group-local variable declaration, and add
- /// an entry to CGF's LocalDeclMap for D. The base class does this using
- /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
- virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
- const VarDecl &D);
-
- virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
-};
-
-}
-}
-
-#endif
+//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for OpenCL code generation. Concrete +// subclasses of this implement code generation for specific OpenCL +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H +#define CLANG_CODEGEN_OPENCLRUNTIME_H + +namespace clang { + +class VarDecl; + +namespace CodeGen { + +class CodeGenFunction; +class CodeGenModule; + +class CGOpenCLRuntime { +protected: + CodeGenModule &CGM; + +public: + CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {} + virtual ~CGOpenCLRuntime(); + + /// Emit the IR required for a work-group-local variable declaration, and add + /// an entry to CGF's LocalDeclMap for D. The base class does this using + /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D. + virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, + const VarDecl &D); +}; + +} +} + +#endif diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index 0a1fb4b02c6..53716a071f2 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -1,1017 +1,1011 @@ -//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of RTTI descriptors.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Type.h"
-#include "clang/Frontend/CodeGenOptions.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-class RTTIBuilder {
- CodeGenModule &CGM; // Per-module state.
- llvm::LLVMContext &VMContext;
-
- /// Fields - The fields of the RTTI descriptor currently being built.
- SmallVector<llvm::Constant *, 16> Fields;
-
- /// GetAddrOfTypeName - Returns the mangled type name of the given type.
- llvm::GlobalVariable *
- GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage);
-
- /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
- /// descriptor of the given type.
- llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
-
- /// BuildVTablePointer - Build the vtable pointer for the given type.
- void BuildVTablePointer(const Type *Ty);
-
- /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
- /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
- void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
- /// classes with bases that do not satisfy the abi::__si_class_type_info
- /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
- void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
- /// for pointer types.
- void BuildPointerTypeInfo(QualType PointeeTy);
-
- /// BuildObjCObjectTypeInfo - Build the appropriate kind of
- /// type_info for an object type.
- void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
-
- /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
- /// struct, used for member pointer types.
- void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
-
-public:
- RTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
- VMContext(CGM.getModule().getContext()) { }
-
- // Pointer type info flags.
- enum {
- /// PTI_Const - Type has const qualifier.
- PTI_Const = 0x1,
-
- /// PTI_Volatile - Type has volatile qualifier.
- PTI_Volatile = 0x2,
-
- /// PTI_Restrict - Type has restrict qualifier.
- PTI_Restrict = 0x4,
-
- /// PTI_Incomplete - Type is incomplete.
- PTI_Incomplete = 0x8,
-
- /// PTI_ContainingClassIncomplete - Containing class is incomplete.
- /// (in pointer to member).
- PTI_ContainingClassIncomplete = 0x10
- };
-
- // VMI type info flags.
- enum {
- /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
- VMI_NonDiamondRepeat = 0x1,
-
- /// VMI_DiamondShaped - Class is diamond shaped.
- VMI_DiamondShaped = 0x2
- };
-
- // Base class type info flags.
- enum {
- /// BCTI_Virtual - Base class is virtual.
- BCTI_Virtual = 0x1,
-
- /// BCTI_Public - Base class is public.
- BCTI_Public = 0x2
- };
-
- /// BuildTypeInfo - Build the RTTI type info struct for the given type.
- ///
- /// \param Force - true to force the creation of this RTTI value
- llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
-};
-}
-
-llvm::GlobalVariable *
-RTTIBuilder::GetAddrOfTypeName(QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage) {
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- // We know that the mangled name of the type starts at index 4 of the
- // mangled name of the typename, so we can just index into it in order to
- // get the mangled name of the type.
- llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
- Name.substr(4));
-
- llvm::GlobalVariable *GV =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage);
-
- GV->setInitializer(Init);
-
- return GV;
-}
-
-llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
- // Mangle the RTTI name.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- // Look for an existing global.
- llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
-
- if (!GV) {
- // Create a new global variable.
- GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
- /*Constant=*/true,
- llvm::GlobalValue::ExternalLinkage, 0, Name);
- }
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
-/// info for that type is defined in the standard library.
-static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
- // Itanium C++ ABI 2.9.2:
- // Basic type information (e.g. for "int", "bool", etc.) will be kept in
- // the run-time support library. Specifically, the run-time support
- // library should contain type_info objects for the types X, X* and
- // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
- // unsigned char, signed char, short, unsigned short, int, unsigned int,
- // long, unsigned long, long long, unsigned long long, float, double,
- // long double, char16_t, char32_t, and the IEEE 754r decimal and
- // half-precision floating point types.
- switch (Ty->getKind()) {
- case BuiltinType::Void:
- case BuiltinType::NullPtr:
- case BuiltinType::Bool:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- case BuiltinType::UChar:
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- case BuiltinType::Long:
- case BuiltinType::ULong:
- case BuiltinType::LongLong:
- case BuiltinType::ULongLong:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Int128:
- case BuiltinType::UInt128:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- return true;
-
- case BuiltinType::Dependent:
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- llvm_unreachable("asking for RRTI for a placeholder type!");
-
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- llvm_unreachable("FIXME: Objective-C types are unsupported!");
- }
-
- llvm_unreachable("Invalid BuiltinType Kind!");
-}
-
-static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
- QualType PointeeTy = PointerTy->getPointeeType();
- const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
- if (!BuiltinTy)
- return false;
-
- // Check the qualifiers.
- Qualifiers Quals = PointeeTy.getQualifiers();
- Quals.removeConst();
-
- if (!Quals.empty())
- return false;
-
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-}
-
-/// IsStandardLibraryRTTIDescriptor - Returns whether the type
-/// information for the given type exists in the standard library.
-static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
- // Type info for builtin types is defined in the standard library.
- if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-
- // Type info for some pointer types to builtin types is defined in the
- // standard library.
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return TypeInfoIsInStandardLibrary(PointerTy);
-
- return false;
-}
-
-/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the type
-/// information in this translation unit. Assumes that it is not a
-/// standard-library type.
-static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
- ASTContext &Context = CGM.getContext();
-
- // If RTTI is disabled, don't consider key functions.
- if (!Context.getLangOpts().RTTI) return false;
-
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!RD->hasDefinition())
- return false;
-
- if (!RD->isDynamicClass())
- return false;
-
- return !CGM.getVTables().ShouldEmitVTableInThisTU(RD);
- }
-
- return false;
-}
-
-/// IsIncompleteClassType - Returns whether the given record type is incomplete.
-static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getDecl()->isCompleteDefinition();
-}
-
-/// ContainsIncompleteClassType - Returns whether the given type contains an
-/// incomplete class type. This is true if
-///
-/// * The given type is an incomplete class type.
-/// * The given type is a pointer type whose pointee type contains an
-/// incomplete class type.
-/// * The given type is a member pointer type whose class is an incomplete
-/// class type.
-/// * The given type is a member pointer type whoise pointee type contains an
-/// incomplete class type.
-/// is an indirect or direct pointer to an incomplete class type.
-static bool ContainsIncompleteClassType(QualType Ty) {
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- if (IsIncompleteClassType(RecordTy))
- return true;
- }
-
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return ContainsIncompleteClassType(PointerTy->getPointeeType());
-
- if (const MemberPointerType *MemberPointerTy =
- dyn_cast<MemberPointerType>(Ty)) {
- // Check if the class type is incomplete.
- const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
- if (IsIncompleteClassType(ClassType))
- return true;
-
- return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
- }
-
- return false;
-}
-
-/// getTypeInfoLinkage - Return the linkage that the type info and type info
-/// name constants should have for the given type.
-static llvm::GlobalVariable::LinkageTypes
-getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
- // Itanium C++ ABI 2.9.5p7:
- // In addition, it and all of the intermediate abi::__pointer_type_info
- // structs in the chain down to the abi::__class_type_info for the
- // incomplete class type must be prevented from resolving to the
- // corresponding type_info structs for the complete class type, possibly
- // by making them local static objects. Finally, a dummy class RTTI is
- // generated for the incomplete type that will not resolve to the final
- // complete class RTTI (because the latter need not exist), possibly by
- // making it a local static object.
- if (ContainsIncompleteClassType(Ty))
- return llvm::GlobalValue::InternalLinkage;
-
- switch (Ty->getLinkage()) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
- return llvm::GlobalValue::InternalLinkage;
-
- case ExternalLinkage:
- if (!CGM.getLangOpts().RTTI) {
- // RTTI is not enabled, which means that this type info struct is going
- // to be used for exception handling. Give it linkonce_odr linkage.
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- if (RD->hasAttr<WeakAttr>())
- return llvm::GlobalValue::WeakODRLinkage;
- if (RD->isDynamicClass())
- return CGM.getVTableLinkage(RD);
- }
-
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- llvm_unreachable("Invalid linkage!");
-}
-
-// CanUseSingleInheritance - Return whether the given record decl has a "single,
-// public, non-virtual base at offset zero (i.e. the derived class is dynamic
-// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
-static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
- // Check the number of bases.
- if (RD->getNumBases() != 1)
- return false;
-
- // Get the base.
- CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
-
- // Check that the base is not virtual.
- if (Base->isVirtual())
- return false;
-
- // Check that the base is public.
- if (Base->getAccessSpecifier() != AS_public)
- return false;
-
- // Check that the class is dynamic iff the base is.
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseDecl->isEmpty() &&
- BaseDecl->isDynamicClass() != RD->isDynamicClass())
- return false;
-
- return true;
-}
-
-void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
- // abi::__class_type_info.
- static const char * const ClassTypeInfo =
- "_ZTVN10__cxxabiv117__class_type_infoE";
- // abi::__si_class_type_info.
- static const char * const SIClassTypeInfo =
- "_ZTVN10__cxxabiv120__si_class_type_infoE";
- // abi::__vmi_class_type_info.
- static const char * const VMIClassTypeInfo =
- "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
-
- const char *VTableName = 0;
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Builtin:
- // GCC treats vector and complex types as fundamental types.
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::Atomic:
- // FIXME: GCC treats block pointers as fundamental types?!
- case Type::BlockPointer:
- // abi::__fundamental_type_info.
- VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // abi::__array_type_info.
- VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // abi::__function_type_info.
- VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
- break;
-
- case Type::Enum:
- // abi::__enum_type_info.
- VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
-
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- VTableName = ClassTypeInfo;
- } else if (CanUseSingleInheritance(RD)) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = VMIClassTypeInfo;
- }
-
- break;
- }
-
- case Type::ObjCObject:
- // Ignore protocol qualifiers.
- Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
-
- // Handle id and Class.
- if (isa<BuiltinType>(Ty)) {
- VTableName = ClassTypeInfo;
- break;
- }
-
- assert(isa<ObjCInterfaceType>(Ty));
- // Fall through.
-
- case Type::ObjCInterface:
- if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = ClassTypeInfo;
- }
- break;
-
- case Type::ObjCObjectPointer:
- case Type::Pointer:
- // abi::__pointer_type_info.
- VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
- break;
-
- case Type::MemberPointer:
- // abi::__pointer_to_member_type_info.
- VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
- }
-
- llvm::Constant *VTable =
- CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
-
- llvm::Type *PtrDiffTy =
- CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
-
- // The vtable address point is 2.
- llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
- VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
-
- Fields.push_back(VTable);
-}
-
-// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures
-// from available_externally to the correct linkage if necessary. An example of
-// this is:
-//
-// struct A {
-// virtual void f();
-// };
-//
-// const std::type_info &g() {
-// return typeid(A);
-// }
-//
-// void A::f() { }
-//
-// When we're generating the typeid(A) expression, we do not yet know that
-// A's key function is defined in this translation unit, so we will give the
-// typeinfo and typename structures available_externally linkage. When A::f
-// forces the vtable to be generated, we need to change the linkage of the
-// typeinfo and typename structs, otherwise we'll end up with undefined
-// externals when linking.
-static void
-maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
- QualType Ty) {
- // We're only interested in globals with available_externally linkage.
- if (!GV->hasAvailableExternallyLinkage())
- return;
-
- // Get the real linkage for the type.
- llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty);
-
- // If variable is supposed to have available_externally linkage, we don't
- // need to do anything.
- if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
- return;
-
- // Update the typeinfo linkage.
- GV->setLinkage(Linkage);
-
- // Get the typename global.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name);
-
- assert(TypeNameGV->hasAvailableExternallyLinkage() &&
- "Type name has different linkage from type info!");
-
- // And update its linkage.
- TypeNameGV->setLinkage(Linkage);
-}
-
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
- // We want to operate on the canonical type.
- Ty = CGM.getContext().getCanonicalType(Ty);
-
- // Check if we've already emitted an RTTI descriptor for this type.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
- if (OldGV && !OldGV->isDeclaration()) {
- maybeUpdateRTTILinkage(CGM, OldGV, Ty);
-
- return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
- }
-
- // Check if there is already an external RTTI descriptor for this type.
- bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);
- if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty)))
- return GetAddrOfExternalRTTIDescriptor(Ty);
-
- // Emit the standard library with external linkage.
- llvm::GlobalVariable::LinkageTypes Linkage;
- if (IsStdLib)
- Linkage = llvm::GlobalValue::ExternalLinkage;
- else
- Linkage = getTypeInfoLinkage(CGM, Ty);
-
- // Add the vtable pointer.
- BuildVTablePointer(cast<Type>(Ty));
-
- // And the name.
- llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
-
- Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy));
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- // GCC treats vector types as fundamental types.
- case Type::Builtin:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::BlockPointer:
- // Itanium C++ ABI 2.9.5p4:
- // abi::__fundamental_type_info adds no data members to std::type_info.
- break;
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__array_type_info adds no data members to std::type_info.
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__function_type_info adds no data members to std::type_info.
- break;
-
- case Type::Enum:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__enum_type_info adds no data members to std::type_info.
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- // We don't need to emit any fields.
- break;
- }
-
- if (CanUseSingleInheritance(RD))
- BuildSIClassTypeInfo(RD);
- else
- BuildVMIClassTypeInfo(RD);
-
- break;
- }
-
- case Type::ObjCObject:
- case Type::ObjCInterface:
- BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
- break;
-
- case Type::ObjCObjectPointer:
- BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
- break;
-
- case Type::Pointer:
- BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
- break;
-
- case Type::MemberPointer:
- BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
- break;
-
- case Type::Atomic:
- // No fields, at least for the moment.
- break;
- }
-
- llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
- /*Constant=*/true, Linkage, Init, Name);
-
- // If there's already an old global variable, replace it with the new one.
- if (OldGV) {
- GV->takeName(OldGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtr);
- OldGV->eraseFromParent();
- }
-
- // GCC only relies on the uniqueness of the type names, not the
- // type_infos themselves, so we can emit these as hidden symbols.
- // But don't do this if we're worried about strict visibility
- // compatibility.
- if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI);
- CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName);
- } else {
- Visibility TypeInfoVisibility = DefaultVisibility;
- if (CGM.getCodeGenOpts().HiddenWeakVTables &&
- Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
- TypeInfoVisibility = HiddenVisibility;
-
- // The type name should have the same visibility as the type itself.
- Visibility ExplicitVisibility = Ty->getVisibility();
- TypeName->setVisibility(CodeGenModule::
- GetLLVMVisibility(ExplicitVisibility));
-
- TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility());
- GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility));
- }
-
- GV->setUnnamedAddr(true);
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// ComputeQualifierFlags - Compute the pointer type info flags from the
-/// given qualifier.
-static unsigned ComputeQualifierFlags(Qualifiers Quals) {
- unsigned Flags = 0;
-
- if (Quals.hasConst())
- Flags |= RTTIBuilder::PTI_Const;
- if (Quals.hasVolatile())
- Flags |= RTTIBuilder::PTI_Volatile;
- if (Quals.hasRestrict())
- Flags |= RTTIBuilder::PTI_Restrict;
-
- return Flags;
-}
-
-/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
-/// for the given Objective-C object type.
-void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
- // Drop qualifiers.
- const Type *T = OT->getBaseType().getTypePtr();
- assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
-
- // The builtin types are abi::__class_type_infos and don't require
- // extra fields.
- if (isa<BuiltinType>(T)) return;
-
- ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
- ObjCInterfaceDecl *Super = Class->getSuperClass();
-
- // Root classes are also __class_type_info.
- if (!Super) return;
-
- QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
-
- // Everything else is single inheritance.
- llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy);
- Fields.push_back(BaseTypeInfo);
-}
-
-/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
-/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
-void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
- // Itanium C++ ABI 2.9.5p6b:
- // It adds to abi::__class_type_info a single member pointing to the
- // type_info structure for the base type,
- llvm::Constant *BaseTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
- Fields.push_back(BaseTypeInfo);
-}
-
-namespace {
- /// SeenBases - Contains virtual and non-virtual bases seen when traversing
- /// a class hierarchy.
- struct SeenBases {
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
- };
-}
-
-/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
-/// abi::__vmi_class_type_info.
-///
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
- SeenBases &Bases) {
-
- unsigned Flags = 0;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual()) {
- // Mark the virtual base as seen.
- if (!Bases.VirtualBases.insert(BaseDecl)) {
- // If this virtual base has been seen before, then the class is diamond
- // shaped.
- Flags |= RTTIBuilder::VMI_DiamondShaped;
- } else {
- if (Bases.NonVirtualBases.count(BaseDecl))
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- }
- } else {
- // Mark the non-virtual base as seen.
- if (!Bases.NonVirtualBases.insert(BaseDecl)) {
- // If this non-virtual base has been seen before, then the class has non-
- // diamond shaped repeated inheritance.
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- } else {
- if (Bases.VirtualBases.count(BaseDecl))
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- }
- }
-
- // Walk all bases.
- for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(),
- E = BaseDecl->bases_end(); I != E; ++I)
- Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
-
- return Flags;
-}
-
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
- unsigned Flags = 0;
- SeenBases Bases;
-
- // Walk all bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I)
- Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
-
- return Flags;
-}
-
-/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
-/// classes with bases that do not satisfy the abi::__si_class_type_info
-/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
-void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
-
- // Itanium C++ ABI 2.9.5p6c:
- // __flags is a word with flags describing details about the class
- // structure, which may be referenced by using the __flags_masks
- // enumeration. These flags refer to both direct and indirect bases.
- unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_count is a word with the number of direct proper base class
- // descriptions that follow.
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
-
- if (!RD->getNumBases())
- return;
-
- llvm::Type *LongLTy =
- CGM.getTypes().ConvertType(CGM.getContext().LongTy);
-
- // Now add the base class descriptions.
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_info[] is an array of base class descriptions -- one for every
- // direct proper base. Each description is of the type:
- //
- // struct abi::__base_class_type_info {
- // public:
- // const __class_type_info *__base_type;
- // long __offset_flags;
- //
- // enum __offset_flags_masks {
- // __virtual_mask = 0x1,
- // __public_mask = 0x2,
- // __offset_shift = 8
- // };
- // };
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier *Base = I;
-
- // The __base_type member points to the RTTI for the base type.
- Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType()));
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- int64_t OffsetFlags = 0;
-
- // All but the lower 8 bits of __offset_flags are a signed offset.
- // For a non-virtual base, this is the offset in the object of the base
- // subobject. For a virtual base, this is the offset in the virtual table of
- // the virtual base offset for the virtual base referenced (negative).
- CharUnits Offset;
- if (Base->isVirtual())
- Offset =
- CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
- else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- Offset = Layout.getBaseClassOffset(BaseDecl);
- };
-
- OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
-
- // The low-order byte of __offset_flags contains flags, as given by the
- // masks from the enumeration __offset_flags_masks.
- if (Base->isVirtual())
- OffsetFlags |= BCTI_Virtual;
- if (Base->getAccessSpecifier() == AS_public)
- OffsetFlags |= BCTI_Public;
-
- Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
- }
-}
-
-/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
-/// used for pointer types.
-void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
- Qualifiers Quals;
- QualType UnqualifiedPointeeTy =
- CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to
- unsigned Flags = ComputeQualifierFlags(Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // When the abi::__pbase_type_info is for a direct or indirect pointer to an
- // incomplete class type, the incomplete target type flag is set.
- if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
- Flags |= PTI_Incomplete;
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
- Fields.push_back(PointeeTypeInfo);
-}
-
-/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
-/// struct, used for member pointer types.
-void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
- QualType PointeeTy = Ty->getPointeeType();
-
- Qualifiers Quals;
- QualType UnqualifiedPointeeTy =
- CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to.
- unsigned Flags = ComputeQualifierFlags(Quals);
-
- const RecordType *ClassType = cast<RecordType>(Ty->getClass());
-
- // Itanium C++ ABI 2.9.5p7:
- // When the abi::__pbase_type_info is for a direct or indirect pointer to an
- // incomplete class type, the incomplete target type flag is set.
- if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
- Flags |= PTI_Incomplete;
-
- if (IsIncompleteClassType(ClassType))
- Flags |= PTI_ContainingClassIncomplete;
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
- Fields.push_back(PointeeTypeInfo);
-
- // Itanium C++ ABI 2.9.5p9:
- // __context is a pointer to an abi::__class_type_info corresponding to the
- // class type containing the member pointed to
- // (e.g., the "A" in "int A::*").
- Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
-}
-
-llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
- bool ForEH) {
- // Return a bogus pointer if RTTI is disabled, unless it's for EH.
- // FIXME: should we even be calling this method if RTTI is disabled
- // and it's not for EH?
- if (!ForEH && !getLangOpts().RTTI)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
- if (ForEH && Ty->isObjCObjectPointerType() &&
- LangOpts.ObjCRuntime.isGNUFamily())
- return ObjCRuntime->GetEHType(Ty);
-
- return RTTIBuilder(*this).BuildTypeInfo(Ty);
-}
-
-void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
- QualType PointerType = Context.getPointerType(Type);
- QualType PointerTypeConst = Context.getPointerType(Type.withConst());
- RTTIBuilder(*this).BuildTypeInfo(Type, true);
- RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
- RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
-}
-
-void CodeGenModule::EmitFundamentalRTTIDescriptors() {
- QualType FundamentalTypes[] = { Context.VoidTy, Context.NullPtrTy,
- Context.BoolTy, Context.WCharTy,
- Context.CharTy, Context.UnsignedCharTy,
- Context.SignedCharTy, Context.ShortTy,
- Context.UnsignedShortTy, Context.IntTy,
- Context.UnsignedIntTy, Context.LongTy,
- Context.UnsignedLongTy, Context.LongLongTy,
- Context.UnsignedLongLongTy, Context.FloatTy,
- Context.DoubleTy, Context.LongDoubleTy,
- Context.Char16Ty, Context.Char32Ty };
- for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i)
- EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
-}
+//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of RTTI descriptors. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "CGCXXABI.h" +#include "CGObjCRuntime.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Frontend/CodeGenOptions.h" + +using namespace clang; +using namespace CodeGen; + +namespace { +class RTTIBuilder { + CodeGenModule &CGM; // Per-module state. + llvm::LLVMContext &VMContext; + + /// Fields - The fields of the RTTI descriptor currently being built. + SmallVector<llvm::Constant *, 16> Fields; + + /// GetAddrOfTypeName - Returns the mangled type name of the given type. + llvm::GlobalVariable * + GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage); + + /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI + /// descriptor of the given type. + llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); + + /// BuildVTablePointer - Build the vtable pointer for the given type. + void BuildVTablePointer(const Type *Ty); + + /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single + /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. + void BuildSIClassTypeInfo(const CXXRecordDecl *RD); + + /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for + /// classes with bases that do not satisfy the abi::__si_class_type_info + /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. + void BuildVMIClassTypeInfo(const CXXRecordDecl *RD); + + /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used + /// for pointer types. + void BuildPointerTypeInfo(QualType PointeeTy); + + /// BuildObjCObjectTypeInfo - Build the appropriate kind of + /// type_info for an object type. + void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty); + + /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info + /// struct, used for member pointer types. + void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty); + +public: + RTTIBuilder(CodeGenModule &CGM) : CGM(CGM), + VMContext(CGM.getModule().getContext()) { } + + // Pointer type info flags. + enum { + /// PTI_Const - Type has const qualifier. + PTI_Const = 0x1, + + /// PTI_Volatile - Type has volatile qualifier. + PTI_Volatile = 0x2, + + /// PTI_Restrict - Type has restrict qualifier. + PTI_Restrict = 0x4, + + /// PTI_Incomplete - Type is incomplete. + PTI_Incomplete = 0x8, + + /// PTI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + PTI_ContainingClassIncomplete = 0x10 + }; + + // VMI type info flags. + enum { + /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance. + VMI_NonDiamondRepeat = 0x1, + + /// VMI_DiamondShaped - Class is diamond shaped. + VMI_DiamondShaped = 0x2 + }; + + // Base class type info flags. + enum { + /// BCTI_Virtual - Base class is virtual. + BCTI_Virtual = 0x1, + + /// BCTI_Public - Base class is public. + BCTI_Public = 0x2 + }; + + /// BuildTypeInfo - Build the RTTI type info struct for the given type. + /// + /// \param Force - true to force the creation of this RTTI value + llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); +}; +} + +llvm::GlobalVariable * +RTTIBuilder::GetAddrOfTypeName(QualType Ty, + llvm::GlobalVariable::LinkageTypes Linkage) { + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); + Out.flush(); + StringRef Name = OutName.str(); + + // We know that the mangled name of the type starts at index 4 of the + // mangled name of the typename, so we can just index into it in order to + // get the mangled name of the type. + llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext, + Name.substr(4)); + + llvm::GlobalVariable *GV = + CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage); + + GV->setInitializer(Init); + + return GV; +} + +llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { + // Mangle the RTTI name. + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); + Out.flush(); + StringRef Name = OutName.str(); + + // Look for an existing global. + llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name); + + if (!GV) { + // Create a new global variable. + GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy, + /*Constant=*/true, + llvm::GlobalValue::ExternalLinkage, 0, Name); + } + + return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); +} + +/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type +/// info for that type is defined in the standard library. +static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { + // Itanium C++ ABI 2.9.2: + // Basic type information (e.g. for "int", "bool", etc.) will be kept in + // the run-time support library. Specifically, the run-time support + // library should contain type_info objects for the types X, X* and + // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char, + // unsigned char, signed char, short, unsigned short, int, unsigned int, + // long, unsigned long, long long, unsigned long long, float, double, + // long double, char16_t, char32_t, and the IEEE 754r decimal and + // half-precision floating point types. + switch (Ty->getKind()) { + case BuiltinType::Void: + case BuiltinType::NullPtr: + case BuiltinType::Bool: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char_U: + case BuiltinType::Char_S: + case BuiltinType::UChar: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Int128: + case BuiltinType::UInt128: + return true; + + case BuiltinType::Dependent: +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + llvm_unreachable("asking for RRTI for a placeholder type!"); + + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + llvm_unreachable("FIXME: Objective-C types are unsupported!"); + } + + llvm_unreachable("Invalid BuiltinType Kind!"); +} + +static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { + QualType PointeeTy = PointerTy->getPointeeType(); + const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy); + if (!BuiltinTy) + return false; + + // Check the qualifiers. + Qualifiers Quals = PointeeTy.getQualifiers(); + Quals.removeConst(); + + if (!Quals.empty()) + return false; + + return TypeInfoIsInStandardLibrary(BuiltinTy); +} + +/// IsStandardLibraryRTTIDescriptor - Returns whether the type +/// information for the given type exists in the standard library. +static bool IsStandardLibraryRTTIDescriptor(QualType Ty) { + // Type info for builtin types is defined in the standard library. + if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty)) + return TypeInfoIsInStandardLibrary(BuiltinTy); + + // Type info for some pointer types to builtin types is defined in the + // standard library. + if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) + return TypeInfoIsInStandardLibrary(PointerTy); + + return false; +} + +/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for +/// the given type exists somewhere else, and that we should not emit the type +/// information in this translation unit. Assumes that it is not a +/// standard-library type. +static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { + ASTContext &Context = CGM.getContext(); + + // If RTTI is disabled, don't consider key functions. + if (!Context.getLangOpts().RTTI) return false; + + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!RD->hasDefinition()) + return false; + + if (!RD->isDynamicClass()) + return false; + + return !CGM.getVTables().ShouldEmitVTableInThisTU(RD); + } + + return false; +} + +/// IsIncompleteClassType - Returns whether the given record type is incomplete. +static bool IsIncompleteClassType(const RecordType *RecordTy) { + return !RecordTy->getDecl()->isCompleteDefinition(); +} + +/// ContainsIncompleteClassType - Returns whether the given type contains an +/// incomplete class type. This is true if +/// +/// * The given type is an incomplete class type. +/// * The given type is a pointer type whose pointee type contains an +/// incomplete class type. +/// * The given type is a member pointer type whose class is an incomplete +/// class type. +/// * The given type is a member pointer type whoise pointee type contains an +/// incomplete class type. +/// is an indirect or direct pointer to an incomplete class type. +static bool ContainsIncompleteClassType(QualType Ty) { + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { + if (IsIncompleteClassType(RecordTy)) + return true; + } + + if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) + return ContainsIncompleteClassType(PointerTy->getPointeeType()); + + if (const MemberPointerType *MemberPointerTy = + dyn_cast<MemberPointerType>(Ty)) { + // Check if the class type is incomplete. + const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass()); + if (IsIncompleteClassType(ClassType)) + return true; + + return ContainsIncompleteClassType(MemberPointerTy->getPointeeType()); + } + + return false; +} + +/// getTypeInfoLinkage - Return the linkage that the type info and type info +/// name constants should have for the given type. +static llvm::GlobalVariable::LinkageTypes +getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) { + // Itanium C++ ABI 2.9.5p7: + // In addition, it and all of the intermediate abi::__pointer_type_info + // structs in the chain down to the abi::__class_type_info for the + // incomplete class type must be prevented from resolving to the + // corresponding type_info structs for the complete class type, possibly + // by making them local static objects. Finally, a dummy class RTTI is + // generated for the incomplete type that will not resolve to the final + // complete class RTTI (because the latter need not exist), possibly by + // making it a local static object. + if (ContainsIncompleteClassType(Ty)) + return llvm::GlobalValue::InternalLinkage; + + switch (Ty->getLinkage()) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return llvm::GlobalValue::InternalLinkage; + + case ExternalLinkage: + if (!CGM.getLangOpts().RTTI) { + // RTTI is not enabled, which means that this type info struct is going + // to be used for exception handling. Give it linkonce_odr linkage. + return llvm::GlobalValue::LinkOnceODRLinkage; + } + + if (const RecordType *Record = dyn_cast<RecordType>(Ty)) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (RD->hasAttr<WeakAttr>()) + return llvm::GlobalValue::WeakODRLinkage; + if (RD->isDynamicClass()) + return CGM.getVTableLinkage(RD); + } + + return llvm::GlobalValue::LinkOnceODRLinkage; + } + + llvm_unreachable("Invalid linkage!"); +} + +// CanUseSingleInheritance - Return whether the given record decl has a "single, +// public, non-virtual base at offset zero (i.e. the derived class is dynamic +// iff the base is)", according to Itanium C++ ABI, 2.95p6b. +static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { + // Check the number of bases. + if (RD->getNumBases() != 1) + return false; + + // Get the base. + CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(); + + // Check that the base is not virtual. + if (Base->isVirtual()) + return false; + + // Check that the base is public. + if (Base->getAccessSpecifier() != AS_public) + return false; + + // Check that the class is dynamic iff the base is. + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (!BaseDecl->isEmpty() && + BaseDecl->isDynamicClass() != RD->isDynamicClass()) + return false; + + return true; +} + +void RTTIBuilder::BuildVTablePointer(const Type *Ty) { + // abi::__class_type_info. + static const char * const ClassTypeInfo = + "_ZTVN10__cxxabiv117__class_type_infoE"; + // abi::__si_class_type_info. + static const char * const SIClassTypeInfo = + "_ZTVN10__cxxabiv120__si_class_type_infoE"; + // abi::__vmi_class_type_info. + static const char * const VMIClassTypeInfo = + "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + + const char *VTableName = 0; + + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("Non-canonical and dependent types shouldn't get here"); + + case Type::LValueReference: + case Type::RValueReference: + llvm_unreachable("References shouldn't get here"); + + case Type::Builtin: + // GCC treats vector and complex types as fundamental types. + case Type::Vector: + case Type::ExtVector: + case Type::Complex: + case Type::Atomic: + // FIXME: GCC treats block pointers as fundamental types?! + case Type::BlockPointer: + // abi::__fundamental_type_info. + VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + // abi::__array_type_info. + VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; + break; + + case Type::FunctionNoProto: + case Type::FunctionProto: + // abi::__function_type_info. + VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + break; + + case Type::Enum: + // abi::__enum_type_info. + VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; + break; + + case Type::Record: { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); + + if (!RD->hasDefinition() || !RD->getNumBases()) { + VTableName = ClassTypeInfo; + } else if (CanUseSingleInheritance(RD)) { + VTableName = SIClassTypeInfo; + } else { + VTableName = VMIClassTypeInfo; + } + + break; + } + + case Type::ObjCObject: + // Ignore protocol qualifiers. + Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr(); + + // Handle id and Class. + if (isa<BuiltinType>(Ty)) { + VTableName = ClassTypeInfo; + break; + } + + assert(isa<ObjCInterfaceType>(Ty)); + // Fall through. + + case Type::ObjCInterface: + if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) { + VTableName = SIClassTypeInfo; + } else { + VTableName = ClassTypeInfo; + } + break; + + case Type::ObjCObjectPointer: + case Type::Pointer: + // abi::__pointer_type_info. + VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; + break; + + case Type::MemberPointer: + // abi::__pointer_to_member_type_info. + VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; + break; + } + + llvm::Constant *VTable = + CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy); + + llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + // The vtable address point is 2. + llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two); + VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy); + + Fields.push_back(VTable); +} + +// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures +// from available_externally to the correct linkage if necessary. An example of +// this is: +// +// struct A { +// virtual void f(); +// }; +// +// const std::type_info &g() { +// return typeid(A); +// } +// +// void A::f() { } +// +// When we're generating the typeid(A) expression, we do not yet know that +// A's key function is defined in this translation unit, so we will give the +// typeinfo and typename structures available_externally linkage. When A::f +// forces the vtable to be generated, we need to change the linkage of the +// typeinfo and typename structs, otherwise we'll end up with undefined +// externals when linking. +static void +maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV, + QualType Ty) { + // We're only interested in globals with available_externally linkage. + if (!GV->hasAvailableExternallyLinkage()) + return; + + // Get the real linkage for the type. + llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty); + + // If variable is supposed to have available_externally linkage, we don't + // need to do anything. + if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) + return; + + // Update the typeinfo linkage. + GV->setLinkage(Linkage); + + // Get the typename global. + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); + Out.flush(); + StringRef Name = OutName.str(); + + llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name); + + assert(TypeNameGV->hasAvailableExternallyLinkage() && + "Type name has different linkage from type info!"); + + // And update its linkage. + TypeNameGV->setLinkage(Linkage); +} + +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { + // We want to operate on the canonical type. + Ty = CGM.getContext().getCanonicalType(Ty); + + // Check if we've already emitted an RTTI descriptor for this type. + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); + Out.flush(); + StringRef Name = OutName.str(); + + llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); + if (OldGV && !OldGV->isDeclaration()) { + maybeUpdateRTTILinkage(CGM, OldGV, Ty); + + return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy); + } + + // Check if there is already an external RTTI descriptor for this type. + bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty); + if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty))) + return GetAddrOfExternalRTTIDescriptor(Ty); + + // Emit the standard library with external linkage. + llvm::GlobalVariable::LinkageTypes Linkage; + if (IsStdLib) + Linkage = llvm::GlobalValue::ExternalLinkage; + else + Linkage = getTypeInfoLinkage(CGM, Ty); + + // Add the vtable pointer. + BuildVTablePointer(cast<Type>(Ty)); + + // And the name. + llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); + + Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy)); + + switch (Ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("Non-canonical and dependent types shouldn't get here"); + + // GCC treats vector types as fundamental types. + case Type::Builtin: + case Type::Vector: + case Type::ExtVector: + case Type::Complex: + case Type::BlockPointer: + // Itanium C++ ABI 2.9.5p4: + // abi::__fundamental_type_info adds no data members to std::type_info. + break; + + case Type::LValueReference: + case Type::RValueReference: + llvm_unreachable("References shouldn't get here"); + + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + // Itanium C++ ABI 2.9.5p5: + // abi::__array_type_info adds no data members to std::type_info. + break; + + case Type::FunctionNoProto: + case Type::FunctionProto: + // Itanium C++ ABI 2.9.5p5: + // abi::__function_type_info adds no data members to std::type_info. + break; + + case Type::Enum: + // Itanium C++ ABI 2.9.5p5: + // abi::__enum_type_info adds no data members to std::type_info. + break; + + case Type::Record: { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); + if (!RD->hasDefinition() || !RD->getNumBases()) { + // We don't need to emit any fields. + break; + } + + if (CanUseSingleInheritance(RD)) + BuildSIClassTypeInfo(RD); + else + BuildVMIClassTypeInfo(RD); + + break; + } + + case Type::ObjCObject: + case Type::ObjCInterface: + BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty)); + break; + + case Type::ObjCObjectPointer: + BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType()); + break; + + case Type::Pointer: + BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType()); + break; + + case Type::MemberPointer: + BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty)); + break; + + case Type::Atomic: + // No fields, at least for the moment. + break; + } + + llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields); + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*Constant=*/true, Linkage, Init, Name); + + // If there's already an old global variable, replace it with the new one. + if (OldGV) { + GV->takeName(OldGV); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtr); + OldGV->eraseFromParent(); + } + + // GCC only relies on the uniqueness of the type names, not the + // type_infos themselves, so we can emit these as hidden symbols. + // But don't do this if we're worried about strict visibility + // compatibility. + if (const RecordType *RT = dyn_cast<RecordType>(Ty)) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI); + CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName); + } else { + Visibility TypeInfoVisibility = DefaultVisibility; + if (CGM.getCodeGenOpts().HiddenWeakVTables && + Linkage == llvm::GlobalValue::LinkOnceODRLinkage) + TypeInfoVisibility = HiddenVisibility; + + // The type name should have the same visibility as the type itself. + Visibility ExplicitVisibility = Ty->getVisibility(); + TypeName->setVisibility(CodeGenModule:: + GetLLVMVisibility(ExplicitVisibility)); + + TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility()); + GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility)); + } + + GV->setUnnamedAddr(true); + + return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); +} + +/// ComputeQualifierFlags - Compute the pointer type info flags from the +/// given qualifier. +static unsigned ComputeQualifierFlags(Qualifiers Quals) { + unsigned Flags = 0; + + if (Quals.hasConst()) + Flags |= RTTIBuilder::PTI_Const; + if (Quals.hasVolatile()) + Flags |= RTTIBuilder::PTI_Volatile; + if (Quals.hasRestrict()) + Flags |= RTTIBuilder::PTI_Restrict; + + return Flags; +} + +/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info +/// for the given Objective-C object type. +void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) { + // Drop qualifiers. + const Type *T = OT->getBaseType().getTypePtr(); + assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T)); + + // The builtin types are abi::__class_type_infos and don't require + // extra fields. + if (isa<BuiltinType>(T)) return; + + ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl(); + ObjCInterfaceDecl *Super = Class->getSuperClass(); + + // Root classes are also __class_type_info. + if (!Super) return; + + QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super); + + // Everything else is single inheritance. + llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy); + Fields.push_back(BaseTypeInfo); +} + +/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single +/// inheritance, according to the Itanium C++ ABI, 2.95p6b. +void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) { + // Itanium C++ ABI 2.9.5p6b: + // It adds to abi::__class_type_info a single member pointing to the + // type_info structure for the base type, + llvm::Constant *BaseTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType()); + Fields.push_back(BaseTypeInfo); +} + +namespace { + /// SeenBases - Contains virtual and non-virtual bases seen when traversing + /// a class hierarchy. + struct SeenBases { + llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases; + llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases; + }; +} + +/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in +/// abi::__vmi_class_type_info. +/// +static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, + SeenBases &Bases) { + + unsigned Flags = 0; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isVirtual()) { + // Mark the virtual base as seen. + if (!Bases.VirtualBases.insert(BaseDecl)) { + // If this virtual base has been seen before, then the class is diamond + // shaped. + Flags |= RTTIBuilder::VMI_DiamondShaped; + } else { + if (Bases.NonVirtualBases.count(BaseDecl)) + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + } + } else { + // Mark the non-virtual base as seen. + if (!Bases.NonVirtualBases.insert(BaseDecl)) { + // If this non-virtual base has been seen before, then the class has non- + // diamond shaped repeated inheritance. + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + } else { + if (Bases.VirtualBases.count(BaseDecl)) + Flags |= RTTIBuilder::VMI_NonDiamondRepeat; + } + } + + // Walk all bases. + for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(), + E = BaseDecl->bases_end(); I != E; ++I) + Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); + + return Flags; +} + +static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) { + unsigned Flags = 0; + SeenBases Bases; + + // Walk all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) + Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); + + return Flags; +} + +/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for +/// classes with bases that do not satisfy the abi::__si_class_type_info +/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. +void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { + llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + + // Itanium C++ ABI 2.9.5p6c: + // __flags is a word with flags describing details about the class + // structure, which may be referenced by using the __flags_masks + // enumeration. These flags refer to both direct and indirect bases. + unsigned Flags = ComputeVMIClassTypeInfoFlags(RD); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); + + // Itanium C++ ABI 2.9.5p6c: + // __base_count is a word with the number of direct proper base class + // descriptions that follow. + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases())); + + if (!RD->getNumBases()) + return; + + llvm::Type *LongLTy = + CGM.getTypes().ConvertType(CGM.getContext().LongTy); + + // Now add the base class descriptions. + + // Itanium C++ ABI 2.9.5p6c: + // __base_info[] is an array of base class descriptions -- one for every + // direct proper base. Each description is of the type: + // + // struct abi::__base_class_type_info { + // public: + // const __class_type_info *__base_type; + // long __offset_flags; + // + // enum __offset_flags_masks { + // __virtual_mask = 0x1, + // __public_mask = 0x2, + // __offset_shift = 8 + // }; + // }; + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXBaseSpecifier *Base = I; + + // The __base_type member points to the RTTI for the base type. + Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType())); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + int64_t OffsetFlags = 0; + + // All but the lower 8 bits of __offset_flags are a signed offset. + // For a non-virtual base, this is the offset in the object of the base + // subobject. For a virtual base, this is the offset in the virtual table of + // the virtual base offset for the virtual base referenced (negative). + CharUnits Offset; + if (Base->isVirtual()) + Offset = + CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); + else { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + Offset = Layout.getBaseClassOffset(BaseDecl); + }; + + OffsetFlags = uint64_t(Offset.getQuantity()) << 8; + + // The low-order byte of __offset_flags contains flags, as given by the + // masks from the enumeration __offset_flags_masks. + if (Base->isVirtual()) + OffsetFlags |= BCTI_Virtual; + if (Base->getAccessSpecifier() == AS_public) + OffsetFlags |= BCTI_Public; + + Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags)); + } +} + +/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, +/// used for pointer types. +void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { + Qualifiers Quals; + QualType UnqualifiedPointeeTy = + CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals); + + // Itanium C++ ABI 2.9.5p7: + // __flags is a flag word describing the cv-qualification and other + // attributes of the type pointed to + unsigned Flags = ComputeQualifierFlags(Quals); + + // Itanium C++ ABI 2.9.5p7: + // When the abi::__pbase_type_info is for a direct or indirect pointer to an + // incomplete class type, the incomplete target type flag is set. + if (ContainsIncompleteClassType(UnqualifiedPointeeTy)) + Flags |= PTI_Incomplete; + + llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); + + // Itanium C++ ABI 2.9.5p7: + // __pointee is a pointer to the std::type_info derivation for the + // unqualified type being pointed to. + llvm::Constant *PointeeTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy); + Fields.push_back(PointeeTypeInfo); +} + +/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info +/// struct, used for member pointer types. +void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { + QualType PointeeTy = Ty->getPointeeType(); + + Qualifiers Quals; + QualType UnqualifiedPointeeTy = + CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals); + + // Itanium C++ ABI 2.9.5p7: + // __flags is a flag word describing the cv-qualification and other + // attributes of the type pointed to. + unsigned Flags = ComputeQualifierFlags(Quals); + + const RecordType *ClassType = cast<RecordType>(Ty->getClass()); + + // Itanium C++ ABI 2.9.5p7: + // When the abi::__pbase_type_info is for a direct or indirect pointer to an + // incomplete class type, the incomplete target type flag is set. + if (ContainsIncompleteClassType(UnqualifiedPointeeTy)) + Flags |= PTI_Incomplete; + + if (IsIncompleteClassType(ClassType)) + Flags |= PTI_ContainingClassIncomplete; + + llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); + + // Itanium C++ ABI 2.9.5p7: + // __pointee is a pointer to the std::type_info derivation for the + // unqualified type being pointed to. + llvm::Constant *PointeeTypeInfo = + RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy); + Fields.push_back(PointeeTypeInfo); + + // Itanium C++ ABI 2.9.5p9: + // __context is a pointer to an abi::__class_type_info corresponding to the + // class type containing the member pointed to + // (e.g., the "A" in "int A::*"). + Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, + bool ForEH) { + // Return a bogus pointer if RTTI is disabled, unless it's for EH. + // FIXME: should we even be calling this method if RTTI is disabled + // and it's not for EH? + if (!ForEH && !getLangOpts().RTTI) + return llvm::Constant::getNullValue(Int8PtrTy); + + if (ForEH && Ty->isObjCObjectPointerType() && + LangOpts.ObjCRuntime.isGNUFamily()) + return ObjCRuntime->GetEHType(Ty); + + return RTTIBuilder(*this).BuildTypeInfo(Ty); +} + +void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { + QualType PointerType = Context.getPointerType(Type); + QualType PointerTypeConst = Context.getPointerType(Type.withConst()); + RTTIBuilder(*this).BuildTypeInfo(Type, true); + RTTIBuilder(*this).BuildTypeInfo(PointerType, true); + RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true); +} + +void CodeGenModule::EmitFundamentalRTTIDescriptors() { + QualType FundamentalTypes[] = { Context.VoidTy, Context.NullPtrTy, + Context.BoolTy, Context.WCharTy, + Context.CharTy, Context.UnsignedCharTy, + Context.SignedCharTy, Context.ShortTy, + Context.UnsignedShortTy, Context.IntTy, + Context.UnsignedIntTy, Context.LongTy, + Context.UnsignedLongTy, Context.LongLongTy, + Context.UnsignedLongLongTy, Context.FloatTy, + Context.DoubleTy, Context.LongDoubleTy, + Context.Char16Ty, Context.Char32Ty }; + for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i) + EmitFundamentalRTTIDescriptor(FundamentalTypes[i]); +} diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 8cb6dd001cb..a0effa8c1f6 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -14,7 +14,6 @@ #include "CodeGenTypes.h" #include "CGCXXABI.h" #include "CGCall.h" -#include "CGOpenCLRuntime.h" #include "CGRecordLayout.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -367,15 +366,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { case BuiltinType::Int128: ResultType = llvm::IntegerType::get(getLLVMContext(), 128); break; - - case BuiltinType::OCLImage1d: - case BuiltinType::OCLImage1dArray: - case BuiltinType::OCLImage1dBuffer: - case BuiltinType::OCLImage2d: - case BuiltinType::OCLImage2dArray: - case BuiltinType::OCLImage3d: - ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty); - break; case BuiltinType::Dependent: #define BUILTIN_TYPE(Id, SingletonId) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 390fd34536e..518c8a07871 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2753,30 +2753,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); break; - case tok::kw_image1d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image1d_array_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_array_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image1d_buffer_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_buffer_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image2d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image2d_array_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_array_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image3d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image3d_t, Loc, - PrevSpec, DiagID); - break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID); @@ -3620,14 +3596,6 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -3700,14 +3668,6 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -3852,14 +3812,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index b7705f8c0d3..14980ee994f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1078,13 +1078,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: - case tok::kw___vector: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: { + case tok::kw___vector: { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index e411899ef4e..b26181f08ea 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1,1580 +1,1574 @@ -//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===//
-//
-// 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 tentative parsing portions of the Parser
-// interfaces, for ambiguity resolution.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Parse/Parser.h"
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Sema/ParsedTemplate.h"
-using namespace clang;
-
-/// isCXXDeclarationStatement - C++-specialized function that disambiguates
-/// between a declaration or an expression statement, when parsing function
-/// bodies. Returns true for declaration, false for expression.
-///
-/// declaration-statement:
-/// block-declaration
-///
-/// block-declaration:
-/// simple-declaration
-/// asm-definition
-/// namespace-alias-definition
-/// using-declaration
-/// using-directive
-/// [C++0x] static_assert-declaration
-///
-/// asm-definition:
-/// 'asm' '(' string-literal ')' ';'
-///
-/// namespace-alias-definition:
-/// 'namespace' identifier = qualified-namespace-specifier ';'
-///
-/// using-declaration:
-/// 'using' typename[opt] '::'[opt] nested-name-specifier
-/// unqualified-id ';'
-/// 'using' '::' unqualified-id ;
-///
-/// using-directive:
-/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
-/// namespace-name ';'
-///
-bool Parser::isCXXDeclarationStatement() {
- switch (Tok.getKind()) {
- // asm-definition
- case tok::kw_asm:
- // namespace-alias-definition
- case tok::kw_namespace:
- // using-declaration
- // using-directive
- case tok::kw_using:
- // static_assert-declaration
- case tok::kw_static_assert:
- case tok::kw__Static_assert:
- return true;
- // simple-declaration
- default:
- return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
- }
-}
-
-/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
-/// between a simple-declaration or an expression-statement.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
-/// Returns false if the statement is disambiguated as expression.
-///
-/// simple-declaration:
-/// decl-specifier-seq init-declarator-list[opt] ';'
-///
-/// (if AllowForRangeDecl specified)
-/// for ( for-range-declaration : for-range-initializer ) statement
-/// for-range-declaration:
-/// attribute-specifier-seqopt type-specifier-seq declarator
-bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
- // C++ 6.8p1:
- // There is an ambiguity in the grammar involving expression-statements and
- // declarations: An expression-statement with a function-style explicit type
- // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
- // from a declaration where the first declarator starts with a '('. In those
- // cases the statement is a declaration. [Note: To disambiguate, the whole
- // statement might have to be examined to determine if it is an
- // expression-statement or a declaration].
-
- // C++ 6.8p3:
- // The disambiguation is purely syntactic; that is, the meaning of the names
- // occurring in such a statement, beyond whether they are type-names or not,
- // is not generally used in or changed by the disambiguation. Class
- // templates are instantiated as necessary to determine if a qualified name
- // is a type-name. Disambiguation precedes parsing, and a statement
- // disambiguated as a declaration may be an ill-formed declaration.
-
- // We don't have to parse all of the decl-specifier-seq part. There's only
- // an ambiguity if the first decl-specifier is
- // simple-type-specifier/typename-specifier followed by a '(', which may
- // indicate a function-style cast expression.
- // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
- // a case.
-
- bool InvalidAsDeclaration = false;
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
- &InvalidAsDeclaration);
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
-
- // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
- // and so gets some cases wrong. We can't carry on if we've already seen
- // something which makes this statement invalid as a declaration in this case,
- // since it can cause us to misparse valid code. Revisit this once
- // TryParseInitDeclaratorList is fixed.
- if (InvalidAsDeclaration)
- return false;
-
- // FIXME: Add statistics about the number of ambiguous statements encountered
- // and how they were resolved (number of declarations+number of expressions).
-
- // Ok, we have a simple-type-specifier/typename-specifier followed by a '(',
- // or an identifier which doesn't resolve as anything. We need tentative
- // parsing...
-
- TentativeParsingAction PA(*this);
- TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
- PA.Revert();
-
- // In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
- return true;
-
- // Declarations take precedence over expressions.
- if (TPR == TPResult::Ambiguous())
- TPR = TPResult::True();
-
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
-}
-
-/// simple-declaration:
-/// decl-specifier-seq init-declarator-list[opt] ';'
-///
-/// (if AllowForRangeDecl specified)
-/// for ( for-range-declaration : for-range-initializer ) statement
-/// for-range-declaration:
-/// attribute-specifier-seqopt type-specifier-seq declarator
-///
-Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
-
- // Two decl-specifiers in a row conclusively disambiguate this as being a
- // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
- // overwhelmingly common case that the next token is a '('.
- if (Tok.isNot(tok::l_paren)) {
- TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR == TPResult::Ambiguous())
- return TPResult::True();
- if (TPR == TPResult::True() || TPR == TPResult::Error())
- return TPR;
- assert(TPR == TPResult::False());
- }
-
- TPResult TPR = TryParseInitDeclaratorList();
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon)))
- return TPResult::False();
-
- return TPResult::Ambiguous();
-}
-
-/// init-declarator-list:
-/// init-declarator
-/// init-declarator-list ',' init-declarator
-///
-/// init-declarator:
-/// declarator initializer[opt]
-/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
-///
-/// initializer:
-/// '=' initializer-clause
-/// '(' expression-list ')'
-///
-/// initializer-clause:
-/// assignment-expression
-/// '{' initializer-list ','[opt] '}'
-/// '{' '}'
-///
-Parser::TPResult Parser::TryParseInitDeclaratorList() {
- while (1) {
- // declarator
- TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- // [GNU] simple-asm-expr[opt] attributes[opt]
- if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
- return TPResult::True();
-
- // initializer[opt]
- if (Tok.is(tok::l_paren)) {
- // Parse through the parens.
- ConsumeParen();
- if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
- } else if (Tok.is(tok::equal) || isTokIdentifier_in()) {
- // MSVC and g++ won't examine the rest of declarators if '=' is
- // encountered; they just conclude that we have a declaration.
- // EDG parses the initializer completely, which is the proper behavior
- // for this case.
- //
- // At present, Clang follows MSVC and g++, since the parser does not have
- // the ability to parse an expression fully without recording the
- // results of that parse.
- // Also allow 'in' after on objective-c declaration as in:
- // for (int (^b)(void) in array). Ideally this should be done in the
- // context of parsing for-init-statement of a foreach statement only. But,
- // in any other context 'in' is invalid after a declaration and parser
- // issues the error regardless of outcome of this decision.
- // FIXME. Change if above assumption does not hold.
- return TPResult::True();
- }
-
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // the comma.
- }
-
- return TPResult::Ambiguous();
-}
-
-/// isCXXConditionDeclaration - Disambiguates between a declaration or an
-/// expression for a condition of a if/switch/while/for statement.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
-///
-/// condition:
-/// expression
-/// type-specifier-seq declarator '=' assignment-expression
-/// [C++11] type-specifier-seq declarator '=' initializer-clause
-/// [C++11] type-specifier-seq declarator braced-init-list
-/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
-/// '=' assignment-expression
-///
-bool Parser::isCXXConditionDeclaration() {
- TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
-
- // FIXME: Add statistics about the number of ambiguous statements encountered
- // and how they were resolved (number of declarations+number of expressions).
-
- // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
- // We need tentative parsing...
-
- TentativeParsingAction PA(*this);
-
- // type-specifier-seq
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
- assert(Tok.is(tok::l_paren) && "Expected '('");
-
- // declarator
- TPR = TryParseDeclarator(false/*mayBeAbstract*/);
-
- // In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
- TPR = TPResult::True();
-
- if (TPR == TPResult::Ambiguous()) {
- // '='
- // [GNU] simple-asm-expr[opt] attributes[opt]
- if (Tok.is(tok::equal) ||
- Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
- TPR = TPResult::True();
- else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))
- TPR = TPResult::True();
- else
- TPR = TPResult::False();
- }
-
- PA.Revert();
-
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
-}
-
- /// \brief Determine whether the next set of tokens contains a type-id.
- ///
- /// The context parameter states what context we're parsing right
- /// now, which affects how this routine copes with the token
- /// following the type-id. If the context is TypeIdInParens, we have
- /// already parsed the '(' and we will cease lookahead when we hit
- /// the corresponding ')'. If the context is
- /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
- /// before this template argument, and will cease lookahead when we
- /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
- /// and false for an expression. If during the disambiguation
- /// process a parsing error is encountered, the function returns
- /// true to let the declaration parsing code handle it.
- ///
- /// type-id:
- /// type-specifier-seq abstract-declarator[opt]
- ///
-bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
-
- isAmbiguous = false;
-
- // C++ 8.2p2:
- // The ambiguity arising from the similarity between a function-style cast and
- // a type-id can occur in different contexts. The ambiguity appears as a
- // choice between a function-style cast expression and a declaration of a
- // type. The resolution is that any construct that could possibly be a type-id
- // in its syntactic context shall be considered a type-id.
-
- TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
-
- // FIXME: Add statistics about the number of ambiguous statements encountered
- // and how they were resolved (number of declarations+number of expressions).
-
- // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
- // We need tentative parsing...
-
- TentativeParsingAction PA(*this);
-
- // type-specifier-seq
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
-
- assert(Tok.is(tok::l_paren) && "Expected '('");
-
- // declarator
- TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
-
- // In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
- TPR = TPResult::True();
-
- if (TPR == TPResult::Ambiguous()) {
- // We are supposed to be inside parens, so if after the abstract declarator
- // we encounter a ')' this is a type-id, otherwise it's an expression.
- if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
- TPR = TPResult::True();
- isAmbiguous = true;
-
- // We are supposed to be inside a template argument, so if after
- // the abstract declarator we encounter a '>', '>>' (in C++0x), or
- // ',', this is a type-id. Otherwise, it's an expression.
- } else if (Context == TypeIdAsTemplateArgument &&
- (Tok.is(tok::greater) || Tok.is(tok::comma) ||
- (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
- TPR = TPResult::True();
- isAmbiguous = true;
-
- } else
- TPR = TPResult::False();
- }
-
- PA.Revert();
-
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
-}
-
-/// \brief Returns true if this is a C++11 attribute-specifier. Per
-/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens
-/// always introduce an attribute. In Objective-C++11, this rule does not
-/// apply if either '[' begins a message-send.
-///
-/// If Disambiguate is true, we try harder to determine whether a '[[' starts
-/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not.
-///
-/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an
-/// Obj-C message send or the start of an attribute. Otherwise, we assume it
-/// is not an Obj-C message send.
-///
-/// C++11 [dcl.attr.grammar]:
-///
-/// attribute-specifier:
-/// '[' '[' attribute-list ']' ']'
-/// alignment-specifier
-///
-/// attribute-list:
-/// attribute[opt]
-/// attribute-list ',' attribute[opt]
-/// attribute '...'
-/// attribute-list ',' attribute '...'
-///
-/// attribute:
-/// attribute-token attribute-argument-clause[opt]
-///
-/// attribute-token:
-/// identifier
-/// identifier '::' identifier
-///
-/// attribute-argument-clause:
-/// '(' balanced-token-seq ')'
-Parser::CXX11AttributeKind
-Parser::isCXX11AttributeSpecifier(bool Disambiguate,
- bool OuterMightBeMessageSend) {
- if (Tok.is(tok::kw_alignas))
- return CAK_AttributeSpecifier;
-
- if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
- return CAK_NotAttributeSpecifier;
-
- // No tentative parsing if we don't need to look for ']]' or a lambda.
- if (!Disambiguate && !getLangOpts().ObjC1)
- return CAK_AttributeSpecifier;
-
- TentativeParsingAction PA(*this);
-
- // Opening brackets were checked for above.
- ConsumeBracket();
-
- // Outside Obj-C++11, treat anything with a matching ']]' as an attribute.
- if (!getLangOpts().ObjC1) {
- ConsumeBracket();
-
- bool IsAttribute = SkipUntil(tok::r_square, false);
- IsAttribute &= Tok.is(tok::r_square);
-
- PA.Revert();
-
- return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier;
- }
-
- // In Obj-C++11, we need to distinguish four situations:
- // 1a) int x[[attr]]; C++11 attribute.
- // 1b) [[attr]]; C++11 statement attribute.
- // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index.
- // 3a) int x[[obj get]]; Message send in array size/index.
- // 3b) [[Class alloc] init]; Message send in message send.
- // 4) [[obj]{ return self; }() doStuff]; Lambda in message send.
- // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted.
-
- // If we have a lambda-introducer, then this is definitely not a message send.
- // FIXME: If this disambiguation is too slow, fold the tentative lambda parse
- // into the tentative attribute parse below.
- LambdaIntroducer Intro;
- if (!TryParseLambdaIntroducer(Intro)) {
- // A lambda cannot end with ']]', and an attribute must.
- bool IsAttribute = Tok.is(tok::r_square);
-
- PA.Revert();
-
- if (IsAttribute)
- // Case 1: C++11 attribute.
- return CAK_AttributeSpecifier;
-
- if (OuterMightBeMessageSend)
- // Case 4: Lambda in message send.
- return CAK_NotAttributeSpecifier;
-
- // Case 2: Lambda in array size / index.
- return CAK_InvalidAttributeSpecifier;
- }
-
- ConsumeBracket();
-
- // If we don't have a lambda-introducer, then we have an attribute or a
- // message-send.
- bool IsAttribute = true;
- while (Tok.isNot(tok::r_square)) {
- if (Tok.is(tok::comma)) {
- // Case 1: Stray commas can only occur in attributes.
- PA.Revert();
- return CAK_AttributeSpecifier;
- }
-
- // Parse the attribute-token, if present.
- // C++11 [dcl.attr.grammar]:
- // If a keyword or an alternative token that satisfies the syntactic
- // requirements of an identifier is contained in an attribute-token,
- // it is considered an identifier.
- SourceLocation Loc;
- if (!TryParseCXX11AttributeIdentifier(Loc)) {
- IsAttribute = false;
- break;
- }
- if (Tok.is(tok::coloncolon)) {
- ConsumeToken();
- if (!TryParseCXX11AttributeIdentifier(Loc)) {
- IsAttribute = false;
- break;
- }
- }
-
- // Parse the attribute-argument-clause, if present.
- if (Tok.is(tok::l_paren)) {
- ConsumeParen();
- if (!SkipUntil(tok::r_paren, false)) {
- IsAttribute = false;
- break;
- }
- }
-
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
-
- if (Tok.isNot(tok::comma))
- break;
-
- ConsumeToken();
- }
-
- // An attribute must end ']]'.
- if (IsAttribute) {
- if (Tok.is(tok::r_square)) {
- ConsumeBracket();
- IsAttribute = Tok.is(tok::r_square);
- } else {
- IsAttribute = false;
- }
- }
-
- PA.Revert();
-
- if (IsAttribute)
- // Case 1: C++11 statement attribute.
- return CAK_AttributeSpecifier;
-
- // Case 3: Message send.
- return CAK_NotAttributeSpecifier;
-}
-
-/// declarator:
-/// direct-declarator
-/// ptr-operator declarator
-///
-/// direct-declarator:
-/// declarator-id
-/// direct-declarator '(' parameter-declaration-clause ')'
-/// cv-qualifier-seq[opt] exception-specification[opt]
-/// direct-declarator '[' constant-expression[opt] ']'
-/// '(' declarator ')'
-/// [GNU] '(' attributes declarator ')'
-///
-/// abstract-declarator:
-/// ptr-operator abstract-declarator[opt]
-/// direct-abstract-declarator
-/// ...
-///
-/// direct-abstract-declarator:
-/// direct-abstract-declarator[opt]
-/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
-/// exception-specification[opt]
-/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
-/// '(' abstract-declarator ')'
-///
-/// ptr-operator:
-/// '*' cv-qualifier-seq[opt]
-/// '&'
-/// [C++0x] '&&' [TODO]
-/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
-///
-/// cv-qualifier-seq:
-/// cv-qualifier cv-qualifier-seq[opt]
-///
-/// cv-qualifier:
-/// 'const'
-/// 'volatile'
-///
-/// declarator-id:
-/// '...'[opt] id-expression
-///
-/// id-expression:
-/// unqualified-id
-/// qualified-id [TODO]
-///
-/// unqualified-id:
-/// identifier
-/// operator-function-id [TODO]
-/// conversion-function-id [TODO]
-/// '~' class-name [TODO]
-/// template-id [TODO]
-///
-Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
- bool mayHaveIdentifier) {
- // declarator:
- // direct-declarator
- // ptr-operator declarator
-
- while (1) {
- if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
- if (TryAnnotateCXXScopeToken(true))
- return TPResult::Error();
-
- if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
- Tok.is(tok::ampamp) ||
- (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
- // ptr-operator
- ConsumeToken();
- while (Tok.is(tok::kw_const) ||
- Tok.is(tok::kw_volatile) ||
- Tok.is(tok::kw_restrict))
- ConsumeToken();
- } else {
- break;
- }
- }
-
- // direct-declarator:
- // direct-abstract-declarator:
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
-
- if ((Tok.is(tok::identifier) ||
- (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) &&
- mayHaveIdentifier) {
- // declarator-id
- if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
- else
- TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
- ConsumeToken();
- } else if (Tok.is(tok::l_paren)) {
- ConsumeParen();
- if (mayBeAbstract &&
- (Tok.is(tok::r_paren) || // 'int()' is a function.
- // 'int(...)' is a function.
- (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) ||
- isDeclarationSpecifier())) { // 'int(int)' is a function.
- // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
- // exception-specification[opt]
- TPResult TPR = TryParseFunctionDeclarator();
- if (TPR != TPResult::Ambiguous())
- return TPR;
- } else {
- // '(' declarator ')'
- // '(' attributes declarator ')'
- // '(' abstract-declarator ')'
- if (Tok.is(tok::kw___attribute) ||
- Tok.is(tok::kw___declspec) ||
- Tok.is(tok::kw___cdecl) ||
- Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___fastcall) ||
- Tok.is(tok::kw___thiscall) ||
- Tok.is(tok::kw___unaligned))
- return TPResult::True(); // attributes indicate declaration
- TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
- if (TPR != TPResult::Ambiguous())
- return TPR;
- if (Tok.isNot(tok::r_paren))
- return TPResult::False();
- ConsumeParen();
- }
- } else if (!mayBeAbstract) {
- return TPResult::False();
- }
-
- while (1) {
- TPResult TPR(TPResult::Ambiguous());
-
- // abstract-declarator: ...
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
-
- if (Tok.is(tok::l_paren)) {
- // Check whether we have a function declarator or a possible ctor-style
- // initializer that follows the declarator. Note that ctor-style
- // initializers are not possible in contexts where abstract declarators
- // are allowed.
- if (!mayBeAbstract && !isCXXFunctionDeclarator())
- break;
-
- // direct-declarator '(' parameter-declaration-clause ')'
- // cv-qualifier-seq[opt] exception-specification[opt]
- ConsumeParen();
- TPR = TryParseFunctionDeclarator();
- } else if (Tok.is(tok::l_square)) {
- // direct-declarator '[' constant-expression[opt] ']'
- // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
- TPR = TryParseBracketDeclarator();
- } else {
- break;
- }
-
- if (TPR != TPResult::Ambiguous())
- return TPR;
- }
-
- return TPResult::Ambiguous();
-}
-
-Parser::TPResult
-Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
- switch (Kind) {
- // Obviously starts an expression.
- case tok::numeric_constant:
- case tok::char_constant:
- case tok::wide_char_constant:
- case tok::utf16_char_constant:
- case tok::utf32_char_constant:
- case tok::string_literal:
- case tok::wide_string_literal:
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- case tok::l_square:
- case tok::l_paren:
- case tok::amp:
- case tok::ampamp:
- case tok::star:
- case tok::plus:
- case tok::plusplus:
- case tok::minus:
- case tok::minusminus:
- case tok::tilde:
- case tok::exclaim:
- case tok::kw_sizeof:
- case tok::kw___func__:
- case tok::kw_const_cast:
- case tok::kw_delete:
- case tok::kw_dynamic_cast:
- case tok::kw_false:
- case tok::kw_new:
- case tok::kw_operator:
- case tok::kw_reinterpret_cast:
- case tok::kw_static_cast:
- case tok::kw_this:
- case tok::kw_throw:
- case tok::kw_true:
- case tok::kw_typeid:
- case tok::kw_alignof:
- case tok::kw_noexcept:
- case tok::kw_nullptr:
- case tok::kw__Alignof:
- case tok::kw___null:
- case tok::kw___alignof:
- case tok::kw___builtin_choose_expr:
- case tok::kw___builtin_offsetof:
- case tok::kw___builtin_types_compatible_p:
- case tok::kw___builtin_va_arg:
- case tok::kw___imag:
- case tok::kw___real:
- case tok::kw___FUNCTION__:
- case tok::kw_L__FUNCTION__:
- case tok::kw___PRETTY_FUNCTION__:
- case tok::kw___has_nothrow_assign:
- case tok::kw___has_nothrow_copy:
- case tok::kw___has_nothrow_constructor:
- case tok::kw___has_trivial_assign:
- case tok::kw___has_trivial_copy:
- case tok::kw___has_trivial_constructor:
- case tok::kw___has_trivial_destructor:
- case tok::kw___has_virtual_destructor:
- case tok::kw___is_abstract:
- case tok::kw___is_base_of:
- case tok::kw___is_class:
- case tok::kw___is_convertible_to:
- case tok::kw___is_empty:
- case tok::kw___is_enum:
- case tok::kw___is_interface_class:
- case tok::kw___is_final:
- case tok::kw___is_literal:
- case tok::kw___is_literal_type:
- case tok::kw___is_pod:
- case tok::kw___is_polymorphic:
- case tok::kw___is_trivial:
- case tok::kw___is_trivially_assignable:
- case tok::kw___is_trivially_constructible:
- case tok::kw___is_trivially_copyable:
- case tok::kw___is_union:
- case tok::kw___uuidof:
- return TPResult::True();
-
- // Obviously starts a type-specifier-seq:
- case tok::kw_char:
- case tok::kw_const:
- case tok::kw_double:
- case tok::kw_enum:
- case tok::kw_half:
- case tok::kw_float:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_restrict:
- case tok::kw_short:
- case tok::kw_signed:
- case tok::kw_struct:
- case tok::kw_union:
- case tok::kw_unsigned:
- case tok::kw_void:
- case tok::kw_volatile:
- case tok::kw__Bool:
- case tok::kw__Complex:
- case tok::kw_class:
- case tok::kw_typename:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw___underlying_type:
- case tok::kw_thread_local:
- case tok::kw__Decimal32:
- case tok::kw__Decimal64:
- case tok::kw__Decimal128:
- case tok::kw___thread:
- case tok::kw_typeof:
- case tok::kw___cdecl:
- case tok::kw___stdcall:
- case tok::kw___fastcall:
- case tok::kw___thiscall:
- case tok::kw___unaligned:
- case tok::kw___vector:
- case tok::kw___pixel:
- case tok::kw__Atomic:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw___unknown_anytype:
- return TPResult::False();
-
- default:
- break;
- }
-
- return TPResult::Ambiguous();
-}
-
-bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
- return std::find(TentativelyDeclaredIdentifiers.begin(),
- TentativelyDeclaredIdentifiers.end(), II)
- != TentativelyDeclaredIdentifiers.end();
-}
-
-/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
-/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
-/// be either a decl-specifier or a function-style cast, and TPResult::Error()
-/// if a parsing error was found and reported.
-///
-/// If HasMissingTypename is provided, a name with a dependent scope specifier
-/// will be treated as ambiguous if the 'typename' keyword is missing. If this
-/// happens, *HasMissingTypename will be set to 'true'. This will also be used
-/// as an indicator that undeclared identifiers (which will trigger a later
-/// parse error) should be treated as types. Returns TPResult::Ambiguous() in
-/// such cases.
-///
-/// decl-specifier:
-/// storage-class-specifier
-/// type-specifier
-/// function-specifier
-/// 'friend'
-/// 'typedef'
-/// [C++0x] 'constexpr'
-/// [GNU] attributes declaration-specifiers[opt]
-///
-/// storage-class-specifier:
-/// 'register'
-/// 'static'
-/// 'extern'
-/// 'mutable'
-/// 'auto'
-/// [GNU] '__thread'
-///
-/// function-specifier:
-/// 'inline'
-/// 'virtual'
-/// 'explicit'
-///
-/// typedef-name:
-/// identifier
-///
-/// type-specifier:
-/// simple-type-specifier
-/// class-specifier
-/// enum-specifier
-/// elaborated-type-specifier
-/// typename-specifier
-/// cv-qualifier
-///
-/// simple-type-specifier:
-/// '::'[opt] nested-name-specifier[opt] type-name
-/// '::'[opt] nested-name-specifier 'template'
-/// simple-template-id [TODO]
-/// 'char'
-/// 'wchar_t'
-/// 'bool'
-/// 'short'
-/// 'int'
-/// 'long'
-/// 'signed'
-/// 'unsigned'
-/// 'float'
-/// 'double'
-/// 'void'
-/// [GNU] typeof-specifier
-/// [GNU] '_Complex'
-/// [C++0x] 'auto' [TODO]
-/// [C++0x] 'decltype' ( expression )
-///
-/// type-name:
-/// class-name
-/// enum-name
-/// typedef-name
-///
-/// elaborated-type-specifier:
-/// class-key '::'[opt] nested-name-specifier[opt] identifier
-/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
-/// simple-template-id
-/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
-///
-/// enum-name:
-/// identifier
-///
-/// enum-specifier:
-/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
-/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
-///
-/// class-specifier:
-/// class-head '{' member-specification[opt] '}'
-///
-/// class-head:
-/// class-key identifier[opt] base-clause[opt]
-/// class-key nested-name-specifier identifier base-clause[opt]
-/// class-key nested-name-specifier[opt] simple-template-id
-/// base-clause[opt]
-///
-/// class-key:
-/// 'class'
-/// 'struct'
-/// 'union'
-///
-/// cv-qualifier:
-/// 'const'
-/// 'volatile'
-/// [GNU] restrict
-///
-Parser::TPResult
-Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
- bool *HasMissingTypename) {
- switch (Tok.getKind()) {
- case tok::identifier: {
- // Check for need to substitute AltiVec __vector keyword
- // for "vector" identifier.
- if (TryAltiVecVectorToken())
- return TPResult::True();
-
- const Token &Next = NextToken();
- // In 'foo bar', 'foo' is always a type name outside of Objective-C.
- if (!getLangOpts().ObjC1 && Next.is(tok::identifier))
- return TPResult::True();
-
- if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
- // Determine whether this is a valid expression. If not, we will hit
- // a parse error one way or another. In that case, tell the caller that
- // this is ambiguous. Typo-correct to type and expression keywords and
- // to types and identifiers, in order to try to recover from errors.
- CorrectionCandidateCallback TypoCorrection;
- TypoCorrection.WantRemainingKeywords = false;
- switch (TryAnnotateName(false /* no nested name specifier */,
- &TypoCorrection)) {
- case ANK_Error:
- return TPResult::Error();
- case ANK_TentativeDecl:
- return TPResult::False();
- case ANK_TemplateName:
- // A bare type template-name which can't be a template template
- // argument is an error, and was probably intended to be a type.
- return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
- case ANK_Unresolved:
- return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False();
- case ANK_Success:
- break;
- }
- assert(Tok.isNot(tok::identifier) &&
- "TryAnnotateName succeeded without producing an annotation");
- } else {
- // This might possibly be a type with a dependent scope specifier and
- // a missing 'typename' keyword. Don't use TryAnnotateName in this case,
- // since it will annotate as a primary expression, and we want to use the
- // "missing 'typename'" logic.
- if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
- // If annotation failed, assume it's a non-type.
- // FIXME: If this happens due to an undeclared identifier, treat it as
- // ambiguous.
- if (Tok.is(tok::identifier))
- return TPResult::False();
- }
-
- // We annotated this token as something. Recurse to handle whatever we got.
- return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
- }
-
- case tok::kw_typename: // typename T::type
- // Annotate typenames and C++ scope specifiers. If we get one, just
- // recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
- return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
-
- case tok::coloncolon: { // ::foo::bar
- const Token &Next = NextToken();
- if (Next.is(tok::kw_new) || // ::new
- Next.is(tok::kw_delete)) // ::delete
- return TPResult::False();
- }
- // Fall through.
- case tok::kw_decltype:
- // Annotate typenames and C++ scope specifiers. If we get one, just
- // recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
- return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
-
- // decl-specifier:
- // storage-class-specifier
- // type-specifier
- // function-specifier
- // 'friend'
- // 'typedef'
- // 'constexpr'
- case tok::kw_friend:
- case tok::kw_typedef:
- case tok::kw_constexpr:
- // storage-class-specifier
- case tok::kw_register:
- case tok::kw_static:
- case tok::kw_extern:
- case tok::kw_mutable:
- case tok::kw_auto:
- case tok::kw___thread:
- // function-specifier
- case tok::kw_inline:
- case tok::kw_virtual:
- case tok::kw_explicit:
-
- // Modules
- case tok::kw___module_private__:
-
- // Debugger support
- case tok::kw___unknown_anytype:
-
- // type-specifier:
- // simple-type-specifier
- // class-specifier
- // enum-specifier
- // elaborated-type-specifier
- // typename-specifier
- // cv-qualifier
-
- // class-specifier
- // elaborated-type-specifier
- case tok::kw_class:
- case tok::kw_struct:
- case tok::kw_union:
- // enum-specifier
- case tok::kw_enum:
- // cv-qualifier
- case tok::kw_const:
- case tok::kw_volatile:
-
- // GNU
- case tok::kw_restrict:
- case tok::kw__Complex:
- case tok::kw___attribute:
- return TPResult::True();
-
- // Microsoft
- case tok::kw___declspec:
- case tok::kw___cdecl:
- case tok::kw___stdcall:
- case tok::kw___fastcall:
- case tok::kw___thiscall:
- case tok::kw___w64:
- case tok::kw___ptr64:
- case tok::kw___ptr32:
- case tok::kw___forceinline:
- case tok::kw___unaligned:
- return TPResult::True();
-
- // Borland
- case tok::kw___pascal:
- return TPResult::True();
-
- // AltiVec
- case tok::kw___vector:
- return TPResult::True();
-
- case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- if (TemplateId->Kind != TNK_Type_template)
- return TPResult::False();
- CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType();
- assert(Tok.is(tok::annot_typename));
- goto case_typename;
- }
-
- case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
- // We've already annotated a scope; try to annotate a type.
- if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
- if (!Tok.is(tok::annot_typename)) {
- // If the next token is an identifier or a type qualifier, then this
- // can't possibly be a valid expression either.
- if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
- CXXScopeSpec SS;
- Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
- Tok.getAnnotationRange(),
- SS);
- if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
- TentativeParsingAction PA(*this);
- ConsumeToken();
- ConsumeToken();
- bool isIdentifier = Tok.is(tok::identifier);
- TPResult TPR = TPResult::False();
- if (!isIdentifier)
- TPR = isCXXDeclarationSpecifier(BracedCastResult,
- HasMissingTypename);
- PA.Revert();
-
- if (isIdentifier ||
- TPR == TPResult::True() || TPR == TPResult::Error())
- return TPResult::Error();
-
- if (HasMissingTypename) {
- // We can't tell whether this is a missing 'typename' or a valid
- // expression.
- *HasMissingTypename = true;
- return TPResult::Ambiguous();
- }
- } else {
- // Try to resolve the name. If it doesn't exist, assume it was
- // intended to name a type and keep disambiguating.
- switch (TryAnnotateName(false /* SS is not dependent */)) {
- case ANK_Error:
- return TPResult::Error();
- case ANK_TentativeDecl:
- return TPResult::False();
- case ANK_TemplateName:
- // A bare type template-name which can't be a template template
- // argument is an error, and was probably intended to be a type.
- return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
- case ANK_Unresolved:
- return HasMissingTypename ? TPResult::Ambiguous()
- : TPResult::False();
- case ANK_Success:
- // Annotated it, check again.
- assert(Tok.isNot(tok::annot_cxxscope) ||
- NextToken().isNot(tok::identifier));
- return isCXXDeclarationSpecifier(BracedCastResult,
- HasMissingTypename);
- }
- }
- }
- return TPResult::False();
- }
- // If that succeeded, fallthrough into the generic simple-type-id case.
-
- // The ambiguity resides in a simple-type-specifier/typename-specifier
- // followed by a '('. The '(' could either be the start of:
- //
- // direct-declarator:
- // '(' declarator ')'
- //
- // direct-abstract-declarator:
- // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
- // exception-specification[opt]
- // '(' abstract-declarator ')'
- //
- // or part of a function-style cast expression:
- //
- // simple-type-specifier '(' expression-list[opt] ')'
- //
-
- // simple-type-specifier:
-
- case tok::annot_typename:
- case_typename:
- // In Objective-C, we might have a protocol-qualified type.
- if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
- // Tentatively parse the
- TentativeParsingAction PA(*this);
- ConsumeToken(); // The type token
-
- TPResult TPR = TryParseProtocolQualifiers();
- bool isFollowedByParen = Tok.is(tok::l_paren);
- bool isFollowedByBrace = Tok.is(tok::l_brace);
-
- PA.Revert();
-
- if (TPR == TPResult::Error())
- return TPResult::Error();
-
- if (isFollowedByParen)
- return TPResult::Ambiguous();
-
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
- return BracedCastResult;
-
- return TPResult::True();
- }
-
- case tok::kw_char:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_bool:
- case tok::kw_short:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_half:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_void:
- case tok::annot_decltype:
- if (NextToken().is(tok::l_paren))
- return TPResult::Ambiguous();
-
- // This is a function-style cast in all cases we disambiguate other than
- // one:
- // struct S {
- // enum E : int { a = 4 }; // enum
- // enum E : int { 4 }; // bit-field
- // };
- if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
- return BracedCastResult;
-
- if (isStartOfObjCClassMessageMissingOpenBracket())
- return TPResult::False();
-
- return TPResult::True();
-
- // GNU typeof support.
- case tok::kw_typeof: {
- if (NextToken().isNot(tok::l_paren))
- return TPResult::True();
-
- TentativeParsingAction PA(*this);
-
- TPResult TPR = TryParseTypeofSpecifier();
- bool isFollowedByParen = Tok.is(tok::l_paren);
- bool isFollowedByBrace = Tok.is(tok::l_brace);
-
- PA.Revert();
-
- if (TPR == TPResult::Error())
- return TPResult::Error();
-
- if (isFollowedByParen)
- return TPResult::Ambiguous();
-
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
- return BracedCastResult;
-
- return TPResult::True();
- }
-
- // C++0x type traits support
- case tok::kw___underlying_type:
- return TPResult::True();
-
- // C11 _Atomic
- case tok::kw__Atomic:
- return TPResult::True();
-
- default:
- return TPResult::False();
- }
-}
-
-/// [GNU] typeof-specifier:
-/// 'typeof' '(' expressions ')'
-/// 'typeof' '(' type-name ')'
-///
-Parser::TPResult Parser::TryParseTypeofSpecifier() {
- assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
- ConsumeToken();
-
- assert(Tok.is(tok::l_paren) && "Expected '('");
- // Parse through the parens after 'typeof'.
- ConsumeParen();
- if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
-
- return TPResult::Ambiguous();
-}
-
-/// [ObjC] protocol-qualifiers:
-//// '<' identifier-list '>'
-Parser::TPResult Parser::TryParseProtocolQualifiers() {
- assert(Tok.is(tok::less) && "Expected '<' for qualifier list");
- ConsumeToken();
- do {
- if (Tok.isNot(tok::identifier))
- return TPResult::Error();
- ConsumeToken();
-
- if (Tok.is(tok::comma)) {
- ConsumeToken();
- continue;
- }
-
- if (Tok.is(tok::greater)) {
- ConsumeToken();
- return TPResult::Ambiguous();
- }
- } while (false);
-
- return TPResult::Error();
-}
-
-Parser::TPResult
-Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) {
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
- HasMissingTypename);
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- if (Tok.is(tok::kw_typeof))
- TryParseTypeofSpecifier();
- else {
- if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
- ConsumeToken();
-
- if (getLangOpts().ObjC1 && Tok.is(tok::less))
- TryParseProtocolQualifiers();
- }
-
- return TPResult::Ambiguous();
-}
-
-/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
-/// a constructor-style initializer, when parsing declaration statements.
-/// Returns true for function declarator and false for constructor-style
-/// initializer.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
-///
-/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
-/// exception-specification[opt]
-///
-bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
-
- // C++ 8.2p1:
- // The ambiguity arising from the similarity between a function-style cast and
- // a declaration mentioned in 6.8 can also occur in the context of a
- // declaration. In that context, the choice is between a function declaration
- // with a redundant set of parentheses around a parameter name and an object
- // declaration with a function-style cast as the initializer. Just as for the
- // ambiguities mentioned in 6.8, the resolution is to consider any construct
- // that could possibly be a declaration a declaration.
-
- TentativeParsingAction PA(*this);
-
- ConsumeParen();
- bool InvalidAsDeclaration = false;
- TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
- if (TPR == TPResult::Ambiguous()) {
- if (Tok.isNot(tok::r_paren))
- TPR = TPResult::False();
- else {
- const Token &Next = NextToken();
- if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
- Next.is(tok::kw_const) || Next.is(tok::kw_volatile) ||
- Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) ||
- Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) ||
- Next.is(tok::l_brace) || Next.is(tok::kw_try) ||
- Next.is(tok::equal) || Next.is(tok::arrow))
- // The next token cannot appear after a constructor-style initializer,
- // and can appear next in a function definition. This must be a function
- // declarator.
- TPR = TPResult::True();
- else if (InvalidAsDeclaration)
- // Use the absence of 'typename' as a tie-breaker.
- TPR = TPResult::False();
- }
- }
-
- PA.Revert();
-
- if (IsAmbiguous && TPR == TPResult::Ambiguous())
- *IsAmbiguous = true;
-
- // In case of an error, let the declaration parsing code handle it.
- return TPR != TPResult::False();
-}
-
-/// parameter-declaration-clause:
-/// parameter-declaration-list[opt] '...'[opt]
-/// parameter-declaration-list ',' '...'
-///
-/// parameter-declaration-list:
-/// parameter-declaration
-/// parameter-declaration-list ',' parameter-declaration
-///
-/// parameter-declaration:
-/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
-/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
-/// '=' assignment-expression
-/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
-/// attributes[opt]
-/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
-/// attributes[opt] '=' assignment-expression
-///
-Parser::TPResult
-Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
-
- if (Tok.is(tok::r_paren))
- return TPResult::Ambiguous();
-
- // parameter-declaration-list[opt] '...'[opt]
- // parameter-declaration-list ',' '...'
- //
- // parameter-declaration-list:
- // parameter-declaration
- // parameter-declaration-list ',' parameter-declaration
- //
- while (1) {
- // '...'[opt]
- if (Tok.is(tok::ellipsis)) {
- ConsumeToken();
- if (Tok.is(tok::r_paren))
- return TPResult::True(); // '...)' is a sign of a function declarator.
- else
- return TPResult::False();
- }
-
- // An attribute-specifier-seq here is a sign of a function declarator.
- if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
- /*OuterMightBeMessageSend*/true))
- return TPResult::True();
-
- ParsedAttributes attrs(AttrFactory);
- MaybeParseMicrosoftAttributes(attrs);
-
- // decl-specifier-seq
- // A parameter-declaration's initializer must be preceded by an '=', so
- // decl-specifier-seq '{' is not a parameter in C++11.
- TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration);
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- // declarator
- // abstract-declarator[opt]
- TPR = TryParseDeclarator(true/*mayBeAbstract*/);
- if (TPR != TPResult::Ambiguous())
- return TPR;
-
- // [GNU] attributes[opt]
- if (Tok.is(tok::kw___attribute))
- return TPResult::True();
-
- if (Tok.is(tok::equal)) {
- // '=' assignment-expression
- // Parse through assignment-expression.
- if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/,
- true/*DontConsume*/))
- return TPResult::Error();
- }
-
- if (Tok.is(tok::ellipsis)) {
- ConsumeToken();
- if (Tok.is(tok::r_paren))
- return TPResult::True(); // '...)' is a sign of a function declarator.
- else
- return TPResult::False();
- }
-
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // the comma.
- }
-
- return TPResult::Ambiguous();
-}
-
-/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
-/// parsing as a function declarator.
-/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
-/// return TPResult::Ambiguous(), otherwise it will return either False() or
-/// Error().
-///
-/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
-/// exception-specification[opt]
-///
-/// exception-specification:
-/// 'throw' '(' type-id-list[opt] ')'
-///
-Parser::TPResult Parser::TryParseFunctionDeclarator() {
-
- // The '(' is already parsed.
-
- TPResult TPR = TryParseParameterDeclarationClause();
- if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
- TPR = TPResult::False();
-
- if (TPR == TPResult::False() || TPR == TPResult::Error())
- return TPR;
-
- // Parse through the parens.
- if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
-
- // cv-qualifier-seq
- while (Tok.is(tok::kw_const) ||
- Tok.is(tok::kw_volatile) ||
- Tok.is(tok::kw_restrict) )
- ConsumeToken();
-
- // ref-qualifier[opt]
- if (Tok.is(tok::amp) || Tok.is(tok::ampamp))
- ConsumeToken();
-
- // exception-specification
- if (Tok.is(tok::kw_throw)) {
- ConsumeToken();
- if (Tok.isNot(tok::l_paren))
- return TPResult::Error();
-
- // Parse through the parens after 'throw'.
- ConsumeParen();
- if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
- }
- if (Tok.is(tok::kw_noexcept)) {
- ConsumeToken();
- // Possibly an expression as well.
- if (Tok.is(tok::l_paren)) {
- // Find the matching rparen.
- ConsumeParen();
- if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
- }
- }
-
- return TPResult::Ambiguous();
-}
-
-/// '[' constant-expression[opt] ']'
-///
-Parser::TPResult Parser::TryParseBracketDeclarator() {
- ConsumeBracket();
- if (!SkipUntil(tok::r_square))
- return TPResult::Error();
-
- return TPResult::Ambiguous();
-}
+//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===// +// +// 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 tentative parsing portions of the Parser +// interfaces, for ambiguity resolution. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/ParsedTemplate.h" +using namespace clang; + +/// isCXXDeclarationStatement - C++-specialized function that disambiguates +/// between a declaration or an expression statement, when parsing function +/// bodies. Returns true for declaration, false for expression. +/// +/// declaration-statement: +/// block-declaration +/// +/// block-declaration: +/// simple-declaration +/// asm-definition +/// namespace-alias-definition +/// using-declaration +/// using-directive +/// [C++0x] static_assert-declaration +/// +/// asm-definition: +/// 'asm' '(' string-literal ')' ';' +/// +/// namespace-alias-definition: +/// 'namespace' identifier = qualified-namespace-specifier ';' +/// +/// using-declaration: +/// 'using' typename[opt] '::'[opt] nested-name-specifier +/// unqualified-id ';' +/// 'using' '::' unqualified-id ; +/// +/// using-directive: +/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] +/// namespace-name ';' +/// +bool Parser::isCXXDeclarationStatement() { + switch (Tok.getKind()) { + // asm-definition + case tok::kw_asm: + // namespace-alias-definition + case tok::kw_namespace: + // using-declaration + // using-directive + case tok::kw_using: + // static_assert-declaration + case tok::kw_static_assert: + case tok::kw__Static_assert: + return true; + // simple-declaration + default: + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); + } +} + +/// isCXXSimpleDeclaration - C++-specialized function that disambiguates +/// between a simple-declaration or an expression-statement. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// Returns false if the statement is disambiguated as expression. +/// +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' +/// +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { + // C++ 6.8p1: + // There is an ambiguity in the grammar involving expression-statements and + // declarations: An expression-statement with a function-style explicit type + // conversion (5.2.3) as its leftmost subexpression can be indistinguishable + // from a declaration where the first declarator starts with a '('. In those + // cases the statement is a declaration. [Note: To disambiguate, the whole + // statement might have to be examined to determine if it is an + // expression-statement or a declaration]. + + // C++ 6.8p3: + // The disambiguation is purely syntactic; that is, the meaning of the names + // occurring in such a statement, beyond whether they are type-names or not, + // is not generally used in or changed by the disambiguation. Class + // templates are instantiated as necessary to determine if a qualified name + // is a type-name. Disambiguation precedes parsing, and a statement + // disambiguated as a declaration may be an ill-formed declaration. + + // We don't have to parse all of the decl-specifier-seq part. There's only + // an ambiguity if the first decl-specifier is + // simple-type-specifier/typename-specifier followed by a '(', which may + // indicate a function-style cast expression. + // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such + // a case. + + bool InvalidAsDeclaration = false; + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + &InvalidAsDeclaration); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer, + // and so gets some cases wrong. We can't carry on if we've already seen + // something which makes this statement invalid as a declaration in this case, + // since it can cause us to misparse valid code. Revisit this once + // TryParseInitDeclaratorList is fixed. + if (InvalidAsDeclaration) + return false; + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', + // or an identifier which doesn't resolve as anything. We need tentative + // parsing... + + TentativeParsingAction PA(*this); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); + PA.Revert(); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + return true; + + // Declarations take precedence over expressions. + if (TPR == TPResult::Ambiguous()) + TPR = TPResult::True(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' +/// +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +/// +Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + // Two decl-specifiers in a row conclusively disambiguate this as being a + // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the + // overwhelmingly common case that the next token is a '('. + if (Tok.isNot(tok::l_paren)) { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR == TPResult::Ambiguous()) + return TPResult::True(); + if (TPR == TPResult::True() || TPR == TPResult::Error()) + return TPR; + assert(TPR == TPResult::False()); + } + + TPResult TPR = TryParseInitDeclaratorList(); + if (TPR != TPResult::Ambiguous()) + return TPR; + + if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) + return TPResult::False(); + + return TPResult::Ambiguous(); +} + +/// init-declarator-list: +/// init-declarator +/// init-declarator-list ',' init-declarator +/// +/// init-declarator: +/// declarator initializer[opt] +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] +/// +/// initializer: +/// '=' initializer-clause +/// '(' expression-list ')' +/// +/// initializer-clause: +/// assignment-expression +/// '{' initializer-list ','[opt] '}' +/// '{' '}' +/// +Parser::TPResult Parser::TryParseInitDeclaratorList() { + while (1) { + // declarator + TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // [GNU] simple-asm-expr[opt] attributes[opt] + if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + return TPResult::True(); + + // initializer[opt] + if (Tok.is(tok::l_paren)) { + // Parse through the parens. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { + // MSVC and g++ won't examine the rest of declarators if '=' is + // encountered; they just conclude that we have a declaration. + // EDG parses the initializer completely, which is the proper behavior + // for this case. + // + // At present, Clang follows MSVC and g++, since the parser does not have + // the ability to parse an expression fully without recording the + // results of that parse. + // Also allow 'in' after on objective-c declaration as in: + // for (int (^b)(void) in array). Ideally this should be done in the + // context of parsing for-init-statement of a foreach statement only. But, + // in any other context 'in' is invalid after a declaration and parser + // issues the error regardless of outcome of this decision. + // FIXME. Change if above assumption does not hold. + return TPResult::True(); + } + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // the comma. + } + + return TPResult::Ambiguous(); +} + +/// isCXXConditionDeclaration - Disambiguates between a declaration or an +/// expression for a condition of a if/switch/while/for statement. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// +/// condition: +/// expression +/// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list +/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] +/// '=' assignment-expression +/// +bool Parser::isCXXConditionDeclaration() { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + + // type-specifier-seq + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); + + // declarator + TPR = TryParseDeclarator(false/*mayBeAbstract*/); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + TPR = TPResult::True(); + + if (TPR == TPResult::Ambiguous()) { + // '=' + // [GNU] simple-asm-expr[opt] attributes[opt] + if (Tok.is(tok::equal) || + Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + TPR = TPResult::True(); + else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) + TPR = TPResult::True(); + else + TPR = TPResult::False(); + } + + PA.Revert(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + + /// \brief Determine whether the next set of tokens contains a type-id. + /// + /// The context parameter states what context we're parsing right + /// now, which affects how this routine copes with the token + /// following the type-id. If the context is TypeIdInParens, we have + /// already parsed the '(' and we will cease lookahead when we hit + /// the corresponding ')'. If the context is + /// TypeIdAsTemplateArgument, we've already parsed the '<' or ',' + /// before this template argument, and will cease lookahead when we + /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id + /// and false for an expression. If during the disambiguation + /// process a parsing error is encountered, the function returns + /// true to let the declaration parsing code handle it. + /// + /// type-id: + /// type-specifier-seq abstract-declarator[opt] + /// +bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { + + isAmbiguous = false; + + // C++ 8.2p2: + // The ambiguity arising from the similarity between a function-style cast and + // a type-id can occur in different contexts. The ambiguity appears as a + // choice between a function-style cast expression and a declaration of a + // type. The resolution is that any construct that could possibly be a type-id + // in its syntactic context shall be considered a type-id. + + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + + // type-specifier-seq + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + assert(Tok.is(tok::l_paren) && "Expected '('"); + + // declarator + TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + TPR = TPResult::True(); + + if (TPR == TPResult::Ambiguous()) { + // We are supposed to be inside parens, so if after the abstract declarator + // we encounter a ')' this is a type-id, otherwise it's an expression. + if (Context == TypeIdInParens && Tok.is(tok::r_paren)) { + TPR = TPResult::True(); + isAmbiguous = true; + + // We are supposed to be inside a template argument, so if after + // the abstract declarator we encounter a '>', '>>' (in C++0x), or + // ',', this is a type-id. Otherwise, it's an expression. + } else if (Context == TypeIdAsTemplateArgument && + (Tok.is(tok::greater) || Tok.is(tok::comma) || + (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { + TPR = TPResult::True(); + isAmbiguous = true; + + } else + TPR = TPResult::False(); + } + + PA.Revert(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + +/// \brief Returns true if this is a C++11 attribute-specifier. Per +/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens +/// always introduce an attribute. In Objective-C++11, this rule does not +/// apply if either '[' begins a message-send. +/// +/// If Disambiguate is true, we try harder to determine whether a '[[' starts +/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not. +/// +/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an +/// Obj-C message send or the start of an attribute. Otherwise, we assume it +/// is not an Obj-C message send. +/// +/// C++11 [dcl.attr.grammar]: +/// +/// attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// alignment-specifier +/// +/// attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' +/// +/// attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// attribute-token: +/// identifier +/// identifier '::' identifier +/// +/// attribute-argument-clause: +/// '(' balanced-token-seq ')' +Parser::CXX11AttributeKind +Parser::isCXX11AttributeSpecifier(bool Disambiguate, + bool OuterMightBeMessageSend) { + if (Tok.is(tok::kw_alignas)) + return CAK_AttributeSpecifier; + + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) + return CAK_NotAttributeSpecifier; + + // No tentative parsing if we don't need to look for ']]' or a lambda. + if (!Disambiguate && !getLangOpts().ObjC1) + return CAK_AttributeSpecifier; + + TentativeParsingAction PA(*this); + + // Opening brackets were checked for above. + ConsumeBracket(); + + // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. + if (!getLangOpts().ObjC1) { + ConsumeBracket(); + + bool IsAttribute = SkipUntil(tok::r_square, false); + IsAttribute &= Tok.is(tok::r_square); + + PA.Revert(); + + return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; + } + + // In Obj-C++11, we need to distinguish four situations: + // 1a) int x[[attr]]; C++11 attribute. + // 1b) [[attr]]; C++11 statement attribute. + // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index. + // 3a) int x[[obj get]]; Message send in array size/index. + // 3b) [[Class alloc] init]; Message send in message send. + // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. + // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. + + // If we have a lambda-introducer, then this is definitely not a message send. + // FIXME: If this disambiguation is too slow, fold the tentative lambda parse + // into the tentative attribute parse below. + LambdaIntroducer Intro; + if (!TryParseLambdaIntroducer(Intro)) { + // A lambda cannot end with ']]', and an attribute must. + bool IsAttribute = Tok.is(tok::r_square); + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 attribute. + return CAK_AttributeSpecifier; + + if (OuterMightBeMessageSend) + // Case 4: Lambda in message send. + return CAK_NotAttributeSpecifier; + + // Case 2: Lambda in array size / index. + return CAK_InvalidAttributeSpecifier; + } + + ConsumeBracket(); + + // If we don't have a lambda-introducer, then we have an attribute or a + // message-send. + bool IsAttribute = true; + while (Tok.isNot(tok::r_square)) { + if (Tok.is(tok::comma)) { + // Case 1: Stray commas can only occur in attributes. + PA.Revert(); + return CAK_AttributeSpecifier; + } + + // Parse the attribute-token, if present. + // C++11 [dcl.attr.grammar]: + // If a keyword or an alternative token that satisfies the syntactic + // requirements of an identifier is contained in an attribute-token, + // it is considered an identifier. + SourceLocation Loc; + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + } + + // Parse the attribute-argument-clause, if present. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (!SkipUntil(tok::r_paren, false)) { + IsAttribute = false; + break; + } + } + + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // An attribute must end ']]'. + if (IsAttribute) { + if (Tok.is(tok::r_square)) { + ConsumeBracket(); + IsAttribute = Tok.is(tok::r_square); + } else { + IsAttribute = false; + } + } + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 statement attribute. + return CAK_AttributeSpecifier; + + // Case 3: Message send. + return CAK_NotAttributeSpecifier; +} + +/// declarator: +/// direct-declarator +/// ptr-operator declarator +/// +/// direct-declarator: +/// declarator-id +/// direct-declarator '(' parameter-declaration-clause ')' +/// cv-qualifier-seq[opt] exception-specification[opt] +/// direct-declarator '[' constant-expression[opt] ']' +/// '(' declarator ')' +/// [GNU] '(' attributes declarator ')' +/// +/// abstract-declarator: +/// ptr-operator abstract-declarator[opt] +/// direct-abstract-declarator +/// ... +/// +/// direct-abstract-declarator: +/// direct-abstract-declarator[opt] +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' +/// '(' abstract-declarator ')' +/// +/// ptr-operator: +/// '*' cv-qualifier-seq[opt] +/// '&' +/// [C++0x] '&&' [TODO] +/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] +/// +/// cv-qualifier-seq: +/// cv-qualifier cv-qualifier-seq[opt] +/// +/// cv-qualifier: +/// 'const' +/// 'volatile' +/// +/// declarator-id: +/// '...'[opt] id-expression +/// +/// id-expression: +/// unqualified-id +/// qualified-id [TODO] +/// +/// unqualified-id: +/// identifier +/// operator-function-id [TODO] +/// conversion-function-id [TODO] +/// '~' class-name [TODO] +/// template-id [TODO] +/// +Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, + bool mayHaveIdentifier) { + // declarator: + // direct-declarator + // ptr-operator declarator + + while (1) { + if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) + if (TryAnnotateCXXScopeToken(true)) + return TPResult::Error(); + + if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || + Tok.is(tok::ampamp) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { + // ptr-operator + ConsumeToken(); + while (Tok.is(tok::kw_const) || + Tok.is(tok::kw_volatile) || + Tok.is(tok::kw_restrict)) + ConsumeToken(); + } else { + break; + } + } + + // direct-declarator: + // direct-abstract-declarator: + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if ((Tok.is(tok::identifier) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && + mayHaveIdentifier) { + // declarator-id + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + else + TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); + ConsumeToken(); + } else if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (mayBeAbstract && + (Tok.is(tok::r_paren) || // 'int()' is a function. + // 'int(...)' is a function. + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || + isDeclarationSpecifier())) { // 'int(int)' is a function. + // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] + // exception-specification[opt] + TPResult TPR = TryParseFunctionDeclarator(); + if (TPR != TPResult::Ambiguous()) + return TPR; + } else { + // '(' declarator ')' + // '(' attributes declarator ')' + // '(' abstract-declarator ')' + if (Tok.is(tok::kw___attribute) || + Tok.is(tok::kw___declspec) || + Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___thiscall) || + Tok.is(tok::kw___unaligned)) + return TPResult::True(); // attributes indicate declaration + TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); + if (TPR != TPResult::Ambiguous()) + return TPR; + if (Tok.isNot(tok::r_paren)) + return TPResult::False(); + ConsumeParen(); + } + } else if (!mayBeAbstract) { + return TPResult::False(); + } + + while (1) { + TPResult TPR(TPResult::Ambiguous()); + + // abstract-declarator: ... + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.is(tok::l_paren)) { + // Check whether we have a function declarator or a possible ctor-style + // initializer that follows the declarator. Note that ctor-style + // initializers are not possible in contexts where abstract declarators + // are allowed. + if (!mayBeAbstract && !isCXXFunctionDeclarator()) + break; + + // direct-declarator '(' parameter-declaration-clause ')' + // cv-qualifier-seq[opt] exception-specification[opt] + ConsumeParen(); + TPR = TryParseFunctionDeclarator(); + } else if (Tok.is(tok::l_square)) { + // direct-declarator '[' constant-expression[opt] ']' + // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' + TPR = TryParseBracketDeclarator(); + } else { + break; + } + + if (TPR != TPResult::Ambiguous()) + return TPR; + } + + return TPResult::Ambiguous(); +} + +Parser::TPResult +Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { + switch (Kind) { + // Obviously starts an expression. + case tok::numeric_constant: + case tok::char_constant: + case tok::wide_char_constant: + case tok::utf16_char_constant: + case tok::utf32_char_constant: + case tok::string_literal: + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + case tok::l_square: + case tok::l_paren: + case tok::amp: + case tok::ampamp: + case tok::star: + case tok::plus: + case tok::plusplus: + case tok::minus: + case tok::minusminus: + case tok::tilde: + case tok::exclaim: + case tok::kw_sizeof: + case tok::kw___func__: + case tok::kw_const_cast: + case tok::kw_delete: + case tok::kw_dynamic_cast: + case tok::kw_false: + case tok::kw_new: + case tok::kw_operator: + case tok::kw_reinterpret_cast: + case tok::kw_static_cast: + case tok::kw_this: + case tok::kw_throw: + case tok::kw_true: + case tok::kw_typeid: + case tok::kw_alignof: + case tok::kw_noexcept: + case tok::kw_nullptr: + case tok::kw__Alignof: + case tok::kw___null: + case tok::kw___alignof: + case tok::kw___builtin_choose_expr: + case tok::kw___builtin_offsetof: + case tok::kw___builtin_types_compatible_p: + case tok::kw___builtin_va_arg: + case tok::kw___imag: + case tok::kw___real: + case tok::kw___FUNCTION__: + case tok::kw_L__FUNCTION__: + case tok::kw___PRETTY_FUNCTION__: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: + case tok::kw___has_trivial_assign: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_destructor: + case tok::kw___has_virtual_destructor: + case tok::kw___is_abstract: + case tok::kw___is_base_of: + case tok::kw___is_class: + case tok::kw___is_convertible_to: + case tok::kw___is_empty: + case tok::kw___is_enum: + case tok::kw___is_interface_class: + case tok::kw___is_final: + case tok::kw___is_literal: + case tok::kw___is_literal_type: + case tok::kw___is_pod: + case tok::kw___is_polymorphic: + case tok::kw___is_trivial: + case tok::kw___is_trivially_assignable: + case tok::kw___is_trivially_constructible: + case tok::kw___is_trivially_copyable: + case tok::kw___is_union: + case tok::kw___uuidof: + return TPResult::True(); + + // Obviously starts a type-specifier-seq: + case tok::kw_char: + case tok::kw_const: + case tok::kw_double: + case tok::kw_enum: + case tok::kw_half: + case tok::kw_float: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_restrict: + case tok::kw_short: + case tok::kw_signed: + case tok::kw_struct: + case tok::kw_union: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_volatile: + case tok::kw__Bool: + case tok::kw__Complex: + case tok::kw_class: + case tok::kw_typename: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw___underlying_type: + case tok::kw_thread_local: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___thread: + case tok::kw_typeof: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___unaligned: + case tok::kw___vector: + case tok::kw___pixel: + case tok::kw__Atomic: + case tok::kw___unknown_anytype: + return TPResult::False(); + + default: + break; + } + + return TPResult::Ambiguous(); +} + +bool Parser::isTentativelyDeclared(IdentifierInfo *II) { + return std::find(TentativelyDeclaredIdentifiers.begin(), + TentativelyDeclaredIdentifiers.end(), II) + != TentativelyDeclaredIdentifiers.end(); +} + +/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration +/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could +/// be either a decl-specifier or a function-style cast, and TPResult::Error() +/// if a parsing error was found and reported. +/// +/// If HasMissingTypename is provided, a name with a dependent scope specifier +/// will be treated as ambiguous if the 'typename' keyword is missing. If this +/// happens, *HasMissingTypename will be set to 'true'. This will also be used +/// as an indicator that undeclared identifiers (which will trigger a later +/// parse error) should be treated as types. Returns TPResult::Ambiguous() in +/// such cases. +/// +/// decl-specifier: +/// storage-class-specifier +/// type-specifier +/// function-specifier +/// 'friend' +/// 'typedef' +/// [C++0x] 'constexpr' +/// [GNU] attributes declaration-specifiers[opt] +/// +/// storage-class-specifier: +/// 'register' +/// 'static' +/// 'extern' +/// 'mutable' +/// 'auto' +/// [GNU] '__thread' +/// +/// function-specifier: +/// 'inline' +/// 'virtual' +/// 'explicit' +/// +/// typedef-name: +/// identifier +/// +/// type-specifier: +/// simple-type-specifier +/// class-specifier +/// enum-specifier +/// elaborated-type-specifier +/// typename-specifier +/// cv-qualifier +/// +/// simple-type-specifier: +/// '::'[opt] nested-name-specifier[opt] type-name +/// '::'[opt] nested-name-specifier 'template' +/// simple-template-id [TODO] +/// 'char' +/// 'wchar_t' +/// 'bool' +/// 'short' +/// 'int' +/// 'long' +/// 'signed' +/// 'unsigned' +/// 'float' +/// 'double' +/// 'void' +/// [GNU] typeof-specifier +/// [GNU] '_Complex' +/// [C++0x] 'auto' [TODO] +/// [C++0x] 'decltype' ( expression ) +/// +/// type-name: +/// class-name +/// enum-name +/// typedef-name +/// +/// elaborated-type-specifier: +/// class-key '::'[opt] nested-name-specifier[opt] identifier +/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt] +/// simple-template-id +/// 'enum' '::'[opt] nested-name-specifier[opt] identifier +/// +/// enum-name: +/// identifier +/// +/// enum-specifier: +/// 'enum' identifier[opt] '{' enumerator-list[opt] '}' +/// 'enum' identifier[opt] '{' enumerator-list ',' '}' +/// +/// class-specifier: +/// class-head '{' member-specification[opt] '}' +/// +/// class-head: +/// class-key identifier[opt] base-clause[opt] +/// class-key nested-name-specifier identifier base-clause[opt] +/// class-key nested-name-specifier[opt] simple-template-id +/// base-clause[opt] +/// +/// class-key: +/// 'class' +/// 'struct' +/// 'union' +/// +/// cv-qualifier: +/// 'const' +/// 'volatile' +/// [GNU] restrict +/// +Parser::TPResult +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, + bool *HasMissingTypename) { + switch (Tok.getKind()) { + case tok::identifier: { + // Check for need to substitute AltiVec __vector keyword + // for "vector" identifier. + if (TryAltiVecVectorToken()) + return TPResult::True(); + + const Token &Next = NextToken(); + // In 'foo bar', 'foo' is always a type name outside of Objective-C. + if (!getLangOpts().ObjC1 && Next.is(tok::identifier)) + return TPResult::True(); + + if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { + // Determine whether this is a valid expression. If not, we will hit + // a parse error one way or another. In that case, tell the caller that + // this is ambiguous. Typo-correct to type and expression keywords and + // to types and identifiers, in order to try to recover from errors. + CorrectionCandidateCallback TypoCorrection; + TypoCorrection.WantRemainingKeywords = false; + switch (TryAnnotateName(false /* no nested name specifier */, + &TypoCorrection)) { + case ANK_Error: + return TPResult::Error(); + case ANK_TentativeDecl: + return TPResult::False(); + case ANK_TemplateName: + // A bare type template-name which can't be a template template + // argument is an error, and was probably intended to be a type. + return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); + case ANK_Unresolved: + return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False(); + case ANK_Success: + break; + } + assert(Tok.isNot(tok::identifier) && + "TryAnnotateName succeeded without producing an annotation"); + } else { + // This might possibly be a type with a dependent scope specifier and + // a missing 'typename' keyword. Don't use TryAnnotateName in this case, + // since it will annotate as a primary expression, and we want to use the + // "missing 'typename'" logic. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + // If annotation failed, assume it's a non-type. + // FIXME: If this happens due to an undeclared identifier, treat it as + // ambiguous. + if (Tok.is(tok::identifier)) + return TPResult::False(); + } + + // We annotated this token as something. Recurse to handle whatever we got. + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + } + + case tok::kw_typename: // typename T::type + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + + case tok::coloncolon: { // ::foo::bar + const Token &Next = NextToken(); + if (Next.is(tok::kw_new) || // ::new + Next.is(tok::kw_delete)) // ::delete + return TPResult::False(); + } + // Fall through. + case tok::kw_decltype: + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + + // decl-specifier: + // storage-class-specifier + // type-specifier + // function-specifier + // 'friend' + // 'typedef' + // 'constexpr' + case tok::kw_friend: + case tok::kw_typedef: + case tok::kw_constexpr: + // storage-class-specifier + case tok::kw_register: + case tok::kw_static: + case tok::kw_extern: + case tok::kw_mutable: + case tok::kw_auto: + case tok::kw___thread: + // function-specifier + case tok::kw_inline: + case tok::kw_virtual: + case tok::kw_explicit: + + // Modules + case tok::kw___module_private__: + + // Debugger support + case tok::kw___unknown_anytype: + + // type-specifier: + // simple-type-specifier + // class-specifier + // enum-specifier + // elaborated-type-specifier + // typename-specifier + // cv-qualifier + + // class-specifier + // elaborated-type-specifier + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + // cv-qualifier + case tok::kw_const: + case tok::kw_volatile: + + // GNU + case tok::kw_restrict: + case tok::kw__Complex: + case tok::kw___attribute: + return TPResult::True(); + + // Microsoft + case tok::kw___declspec: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___forceinline: + case tok::kw___unaligned: + return TPResult::True(); + + // Borland + case tok::kw___pascal: + return TPResult::True(); + + // AltiVec + case tok::kw___vector: + return TPResult::True(); + + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind != TNK_Type_template) + return TPResult::False(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(); + assert(Tok.is(tok::annot_typename)); + goto case_typename; + } + + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed + // We've already annotated a scope; try to annotate a type. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + if (!Tok.is(tok::annot_typename)) { + // If the next token is an identifier or a type qualifier, then this + // can't possibly be a valid expression either. + if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { + TentativeParsingAction PA(*this); + ConsumeToken(); + ConsumeToken(); + bool isIdentifier = Tok.is(tok::identifier); + TPResult TPR = TPResult::False(); + if (!isIdentifier) + TPR = isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); + PA.Revert(); + + if (isIdentifier || + TPR == TPResult::True() || TPR == TPResult::Error()) + return TPResult::Error(); + + if (HasMissingTypename) { + // We can't tell whether this is a missing 'typename' or a valid + // expression. + *HasMissingTypename = true; + return TPResult::Ambiguous(); + } + } else { + // Try to resolve the name. If it doesn't exist, assume it was + // intended to name a type and keep disambiguating. + switch (TryAnnotateName(false /* SS is not dependent */)) { + case ANK_Error: + return TPResult::Error(); + case ANK_TentativeDecl: + return TPResult::False(); + case ANK_TemplateName: + // A bare type template-name which can't be a template template + // argument is an error, and was probably intended to be a type. + return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); + case ANK_Unresolved: + return HasMissingTypename ? TPResult::Ambiguous() + : TPResult::False(); + case ANK_Success: + // Annotated it, check again. + assert(Tok.isNot(tok::annot_cxxscope) || + NextToken().isNot(tok::identifier)); + return isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); + } + } + } + return TPResult::False(); + } + // If that succeeded, fallthrough into the generic simple-type-id case. + + // The ambiguity resides in a simple-type-specifier/typename-specifier + // followed by a '('. The '(' could either be the start of: + // + // direct-declarator: + // '(' declarator ')' + // + // direct-abstract-declarator: + // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] + // exception-specification[opt] + // '(' abstract-declarator ')' + // + // or part of a function-style cast expression: + // + // simple-type-specifier '(' expression-list[opt] ')' + // + + // simple-type-specifier: + + case tok::annot_typename: + case_typename: + // In Objective-C, we might have a protocol-qualified type. + if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { + // Tentatively parse the + TentativeParsingAction PA(*this); + ConsumeToken(); // The type token + + TPResult TPR = TryParseProtocolQualifiers(); + bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; + + return TPResult::True(); + } + + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::annot_decltype: + if (NextToken().is(tok::l_paren)) + return TPResult::Ambiguous(); + + // This is a function-style cast in all cases we disambiguate other than + // one: + // struct S { + // enum E : int { a = 4 }; // enum + // enum E : int { 4 }; // bit-field + // }; + if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace)) + return BracedCastResult; + + if (isStartOfObjCClassMessageMissingOpenBracket()) + return TPResult::False(); + + return TPResult::True(); + + // GNU typeof support. + case tok::kw_typeof: { + if (NextToken().isNot(tok::l_paren)) + return TPResult::True(); + + TentativeParsingAction PA(*this); + + TPResult TPR = TryParseTypeofSpecifier(); + bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; + + return TPResult::True(); + } + + // C++0x type traits support + case tok::kw___underlying_type: + return TPResult::True(); + + // C11 _Atomic + case tok::kw__Atomic: + return TPResult::True(); + + default: + return TPResult::False(); + } +} + +/// [GNU] typeof-specifier: +/// 'typeof' '(' expressions ')' +/// 'typeof' '(' type-name ')' +/// +Parser::TPResult Parser::TryParseTypeofSpecifier() { + assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!"); + ConsumeToken(); + + assert(Tok.is(tok::l_paren) && "Expected '('"); + // Parse through the parens after 'typeof'. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + + return TPResult::Ambiguous(); +} + +/// [ObjC] protocol-qualifiers: +//// '<' identifier-list '>' +Parser::TPResult Parser::TryParseProtocolQualifiers() { + assert(Tok.is(tok::less) && "Expected '<' for qualifier list"); + ConsumeToken(); + do { + if (Tok.isNot(tok::identifier)) + return TPResult::Error(); + ConsumeToken(); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + if (Tok.is(tok::greater)) { + ConsumeToken(); + return TPResult::Ambiguous(); + } + } while (false); + + return TPResult::Error(); +} + +Parser::TPResult +Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) { + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + HasMissingTypename); + if (TPR != TPResult::Ambiguous()) + return TPR; + + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + return TPResult::Ambiguous(); +} + +/// isCXXFunctionDeclarator - Disambiguates between a function declarator or +/// a constructor-style initializer, when parsing declaration statements. +/// Returns true for function declarator and false for constructor-style +/// initializer. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// +bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { + + // C++ 8.2p1: + // The ambiguity arising from the similarity between a function-style cast and + // a declaration mentioned in 6.8 can also occur in the context of a + // declaration. In that context, the choice is between a function declaration + // with a redundant set of parentheses around a parameter name and an object + // declaration with a function-style cast as the initializer. Just as for the + // ambiguities mentioned in 6.8, the resolution is to consider any construct + // that could possibly be a declaration a declaration. + + TentativeParsingAction PA(*this); + + ConsumeParen(); + bool InvalidAsDeclaration = false; + TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration); + if (TPR == TPResult::Ambiguous()) { + if (Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + else { + const Token &Next = NextToken(); + if (Next.is(tok::amp) || Next.is(tok::ampamp) || + Next.is(tok::kw_const) || Next.is(tok::kw_volatile) || + Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) || + Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) || + Next.is(tok::l_brace) || Next.is(tok::kw_try) || + Next.is(tok::equal) || Next.is(tok::arrow)) + // The next token cannot appear after a constructor-style initializer, + // and can appear next in a function definition. This must be a function + // declarator. + TPR = TPResult::True(); + else if (InvalidAsDeclaration) + // Use the absence of 'typename' as a tie-breaker. + TPR = TPResult::False(); + } + } + + PA.Revert(); + + if (IsAmbiguous && TPR == TPResult::Ambiguous()) + *IsAmbiguous = true; + + // In case of an error, let the declaration parsing code handle it. + return TPR != TPResult::False(); +} + +/// parameter-declaration-clause: +/// parameter-declaration-list[opt] '...'[opt] +/// parameter-declaration-list ',' '...' +/// +/// parameter-declaration-list: +/// parameter-declaration +/// parameter-declaration-list ',' parameter-declaration +/// +/// parameter-declaration: +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// '=' assignment-expression +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] '=' assignment-expression +/// +Parser::TPResult +Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { + + if (Tok.is(tok::r_paren)) + return TPResult::Ambiguous(); + + // parameter-declaration-list[opt] '...'[opt] + // parameter-declaration-list ',' '...' + // + // parameter-declaration-list: + // parameter-declaration + // parameter-declaration-list ',' parameter-declaration + // + while (1) { + // '...'[opt] + if (Tok.is(tok::ellipsis)) { + ConsumeToken(); + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); + } + + // An attribute-specifier-seq here is a sign of a function declarator. + if (isCXX11AttributeSpecifier(/*Disambiguate*/false, + /*OuterMightBeMessageSend*/true)) + return TPResult::True(); + + ParsedAttributes attrs(AttrFactory); + MaybeParseMicrosoftAttributes(attrs); + + // decl-specifier-seq + // A parameter-declaration's initializer must be preceded by an '=', so + // decl-specifier-seq '{' is not a parameter in C++11. + TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // declarator + // abstract-declarator[opt] + TPR = TryParseDeclarator(true/*mayBeAbstract*/); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // [GNU] attributes[opt] + if (Tok.is(tok::kw___attribute)) + return TPResult::True(); + + if (Tok.is(tok::equal)) { + // '=' assignment-expression + // Parse through assignment-expression. + if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, + true/*DontConsume*/)) + return TPResult::Error(); + } + + if (Tok.is(tok::ellipsis)) { + ConsumeToken(); + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); + } + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // the comma. + } + + return TPResult::Ambiguous(); +} + +/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue +/// parsing as a function declarator. +/// If TryParseFunctionDeclarator fully parsed the function declarator, it will +/// return TPResult::Ambiguous(), otherwise it will return either False() or +/// Error(). +/// +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// +/// exception-specification: +/// 'throw' '(' type-id-list[opt] ')' +/// +Parser::TPResult Parser::TryParseFunctionDeclarator() { + + // The '(' is already parsed. + + TPResult TPR = TryParseParameterDeclarationClause(); + if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + + if (TPR == TPResult::False() || TPR == TPResult::Error()) + return TPR; + + // Parse through the parens. + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + + // cv-qualifier-seq + while (Tok.is(tok::kw_const) || + Tok.is(tok::kw_volatile) || + Tok.is(tok::kw_restrict) ) + ConsumeToken(); + + // ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) + ConsumeToken(); + + // exception-specification + if (Tok.is(tok::kw_throw)) { + ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return TPResult::Error(); + + // Parse through the parens after 'throw'. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + if (Tok.is(tok::kw_noexcept)) { + ConsumeToken(); + // Possibly an expression as well. + if (Tok.is(tok::l_paren)) { + // Find the matching rparen. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + } + + return TPResult::Ambiguous(); +} + +/// '[' constant-expression[opt] ']' +/// +Parser::TPResult Parser::TryParseBracketDeclarator() { + ConsumeBracket(); + if (!SkipUntil(tok::r_square)) + return TPResult::Error(); + + return TPResult::Ambiguous(); +} diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index b34b953a036..040e638b2e4 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -280,12 +280,6 @@ bool Declarator::isDeclarationOfFunction() const { case TST_unspecified: case TST_void: case TST_wchar: - case TST_image1d_t: - case TST_image1d_array_t: - case TST_image1d_buffer_t: - case TST_image2d_t: - case TST_image2d_array_t: - case TST_image3d_t: return false; case TST_decltype: @@ -420,12 +414,6 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; - case DeclSpec::TST_image1d_t: return "image1d_t"; - case DeclSpec::TST_image1d_array_t: return "image1d_array_t"; - case DeclSpec::TST_image1d_buffer_t: return "image1d_buffer_t"; - case DeclSpec::TST_image2d_t: return "image2d_t"; - case DeclSpec::TST_image2d_array_t: return "image2d_array_t"; - case DeclSpec::TST_image3d_t: return "image3d_t"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 6c7032089a0..f7978253af6 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -731,12 +731,6 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_class: case TST_auto: case TST_unknown_anytype: - case TST_image1d_t: - case TST_image1d_array_t: - case TST_image1d_buffer_t: - case TST_image2d_t: - case TST_image2d_array_t: - case TST_image3d_t: case TST_error: break; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1afc8c7f25b..2c7b7c18ece 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -903,30 +903,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; - case DeclSpec::TST_image1d_t: - Result = Context.OCLImage1dTy; - break; - - case DeclSpec::TST_image1d_array_t: - Result = Context.OCLImage1dArrayTy; - break; - - case DeclSpec::TST_image1d_buffer_t: - Result = Context.OCLImage1dBufferTy; - break; - - case DeclSpec::TST_image2d_t: - Result = Context.OCLImage2dTy; - break; - - case DeclSpec::TST_image2d_array_t: - Result = Context.OCLImage2dArrayTy; - break; - - case DeclSpec::TST_image3d_t: - Result = Context.OCLImage3dTy; - break; - case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 91eec732978..aec8a815654 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -1,86 +1,80 @@ -//===--- 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/Basic/IdentifierTable.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
-#include "llvm/ADT/StringExtras.h"
-
-using namespace clang;
-
-// Give ASTDeserializationListener's VTable a home.
-ASTDeserializationListener::~ASTDeserializationListener() { }
-
-serialization::TypeIdx
-serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
- unsigned ID = 0;
- switch (BT->getKind()) {
- case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break;
- case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break;
- case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break;
- case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break;
- case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break;
- case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break;
- case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break;
- case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break;
- case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break;
- case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break;
- case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break;
- case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break;
- case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break;
- case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break;
- case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break;
- case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break;
- case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break;
- case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break;
- case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break;
- case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break;
- case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break;
- case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break;
- case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
- case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
- case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
- case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
- case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
- case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
- case BuiltinType::ARCUnbridgedCast:
- ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break;
- case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
- case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
- case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
- case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break;
- case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break;
- case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break;
- case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break;
- case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break;
- case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break;
- case BuiltinType::BuiltinFn:
- ID = PREDEF_TYPE_BUILTIN_FN; break;
-
- }
-
- return TypeIdx(ID);
-}
-
-unsigned serialization::ComputeHash(Selector Sel) {
- unsigned N = Sel.getNumArgs();
- if (N == 0)
- ++N;
- unsigned R = 5381;
- for (unsigned I = 0; I != N; ++I)
- if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
- R = llvm::HashString(II->getName(), R);
- return R;
-}
+//===--- 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/Basic/IdentifierTable.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "llvm/ADT/StringExtras.h" + +using namespace clang; + +// Give ASTDeserializationListener's VTable a home. +ASTDeserializationListener::~ASTDeserializationListener() { } + +serialization::TypeIdx +serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { + unsigned ID = 0; + switch (BT->getKind()) { + case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break; + case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break; + case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break; + case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break; + case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break; + case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break; + case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break; + case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break; + case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break; + case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break; + case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break; + case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break; + case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break; + case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break; + case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break; + case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break; + case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break; + case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break; + case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break; + case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; + case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break; + case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break; + case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break; + case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; + case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break; + case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break; + case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break; + case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break; + case BuiltinType::ARCUnbridgedCast: + ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break; + case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; + case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; + case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; + case BuiltinType::BuiltinFn: + ID = PREDEF_TYPE_BUILTIN_FN; break; + + } + + return TypeIdx(ID); +} + +unsigned serialization::ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = llvm::HashString(II->getName(), R); + return R; +} diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 88b56141242..c0976ee1e65 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1,6998 +1,6992 @@ -//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the ASTReader class, which reads AST files.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Serialization/ASTReader.h"
-#include "ASTCommon.h"
-#include "ASTReaderInternals.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeLocVisitor.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemStatCache.h"
-#include "clang/Basic/OnDiskHashTable.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManagerInternals.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/Version.h"
-#include "clang/Basic/VersionTuple.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
-#include "clang/Serialization/ModuleManager.h"
-#include "clang/Serialization/SerializationDiagnostic.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/system_error.h"
-#include <algorithm>
-#include <cstdio>
-#include <iterator>
-
-using namespace clang;
-using namespace clang::serialization;
-using namespace clang::serialization::reader;
-
-//===----------------------------------------------------------------------===//
-// PCH validator implementation
-//===----------------------------------------------------------------------===//
-
-ASTReaderListener::~ASTReaderListener() {}
-
-/// \brief Compare the given set of language options against an existing set of
-/// language options.
-///
-/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
-///
-/// \returns true if the languagae options mis-match, false otherwise.
-static bool checkLanguageOptions(const LangOptions &LangOpts,
- const LangOptions &ExistingLangOpts,
- DiagnosticsEngine *Diags) {
-#define LANGOPT(Name, Bits, Default, Description) \
- if (ExistingLangOpts.Name != LangOpts.Name) { \
- if (Diags) \
- Diags->Report(diag::err_pch_langopt_mismatch) \
- << Description << LangOpts.Name << ExistingLangOpts.Name; \
- return true; \
- }
-
-#define VALUE_LANGOPT(Name, Bits, Default, Description) \
- if (ExistingLangOpts.Name != LangOpts.Name) { \
- if (Diags) \
- Diags->Report(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
- }
-
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
- if (Diags) \
- Diags->Report(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
- }
-
-#define BENIGN_LANGOPT(Name, Bits, Default, Description)
-#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
-#include "clang/Basic/LangOptions.def"
-
- if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
- if (Diags)
- Diags->Report(diag::err_pch_langopt_value_mismatch)
- << "target Objective-C runtime";
- return true;
- }
-
- return false;
-}
-
-/// \brief Compare the given set of target options against an existing set of
-/// target options.
-///
-/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
-///
-/// \returns true if the target options mis-match, false otherwise.
-static bool checkTargetOptions(const TargetOptions &TargetOpts,
- const TargetOptions &ExistingTargetOpts,
- DiagnosticsEngine *Diags) {
-#define CHECK_TARGET_OPT(Field, Name) \
- if (TargetOpts.Field != ExistingTargetOpts.Field) { \
- if (Diags) \
- Diags->Report(diag::err_pch_targetopt_mismatch) \
- << Name << TargetOpts.Field << ExistingTargetOpts.Field; \
- return true; \
- }
-
- CHECK_TARGET_OPT(Triple, "target");
- CHECK_TARGET_OPT(CPU, "target CPU");
- CHECK_TARGET_OPT(ABI, "target ABI");
- CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
- CHECK_TARGET_OPT(LinkerVersion, "target linker version");
-#undef CHECK_TARGET_OPT
-
- // Compare feature sets.
- SmallVector<StringRef, 4> ExistingFeatures(
- ExistingTargetOpts.FeaturesAsWritten.begin(),
- ExistingTargetOpts.FeaturesAsWritten.end());
- SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
- TargetOpts.FeaturesAsWritten.end());
- std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
- std::sort(ReadFeatures.begin(), ReadFeatures.end());
-
- unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
- unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
- while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
- if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
- ++ExistingIdx;
- ++ReadIdx;
- continue;
- }
-
- if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << false << ReadFeatures[ReadIdx];
- return true;
- }
-
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << true << ExistingFeatures[ExistingIdx];
- return true;
- }
-
- if (ExistingIdx < ExistingN) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << true << ExistingFeatures[ExistingIdx];
- return true;
- }
-
- if (ReadIdx < ReadN) {
- if (Diags)
- Diags->Report(diag::err_pch_targetopt_feature_mismatch)
- << false << ReadFeatures[ReadIdx];
- return true;
- }
-
- return false;
-}
-
-bool
-PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
- const LangOptions &ExistingLangOpts = PP.getLangOpts();
- return checkLanguageOptions(LangOpts, ExistingLangOpts,
- Complain? &Reader.Diags : 0);
-}
-
-bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
- const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
- return checkTargetOptions(TargetOpts, ExistingTargetOpts,
- Complain? &Reader.Diags : 0);
-}
-
-namespace {
- typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
- MacroDefinitionsMap;
-}
-
-/// \brief Collect the macro definitions provided by the given preprocessor
-/// options.
-static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
- MacroDefinitionsMap &Macros,
- SmallVectorImpl<StringRef> *MacroNames = 0){
- for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
- StringRef Macro = PPOpts.Macros[I].first;
- bool IsUndef = PPOpts.Macros[I].second;
-
- std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
- StringRef MacroName = MacroPair.first;
- StringRef MacroBody = MacroPair.second;
-
- // For an #undef'd macro, we only care about the name.
- if (IsUndef) {
- if (MacroNames && !Macros.count(MacroName))
- MacroNames->push_back(MacroName);
-
- Macros[MacroName] = std::make_pair("", true);
- continue;
- }
-
- // For a #define'd macro, figure out the actual definition.
- if (MacroName.size() == Macro.size())
- MacroBody = "1";
- else {
- // Note: GCC drops anything following an end-of-line character.
- StringRef::size_type End = MacroBody.find_first_of("\n\r");
- MacroBody = MacroBody.substr(0, End);
- }
-
- if (MacroNames && !Macros.count(MacroName))
- MacroNames->push_back(MacroName);
- Macros[MacroName] = std::make_pair(MacroBody, false);
- }
-}
-
-/// \brief Check the preprocessor options deserialized from the control block
-/// against the preprocessor options in an existing preprocessor.
-///
-/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
-static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
- const PreprocessorOptions &ExistingPPOpts,
- DiagnosticsEngine *Diags,
- FileManager &FileMgr,
- std::string &SuggestedPredefines) {
- // Check macro definitions.
- MacroDefinitionsMap ASTFileMacros;
- collectMacroDefinitions(PPOpts, ASTFileMacros);
- MacroDefinitionsMap ExistingMacros;
- SmallVector<StringRef, 4> ExistingMacroNames;
- collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
-
- for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
- // Dig out the macro definition in the existing preprocessor options.
- StringRef MacroName = ExistingMacroNames[I];
- std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
-
- // Check whether we know anything about this macro name or not.
- llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
- = ASTFileMacros.find(MacroName);
- if (Known == ASTFileMacros.end()) {
- // FIXME: Check whether this identifier was referenced anywhere in the
- // AST file. If so, we should reject the AST file. Unfortunately, this
- // information isn't in the control block. What shall we do about it?
-
- if (Existing.second) {
- SuggestedPredefines += "#undef ";
- SuggestedPredefines += MacroName.str();
- SuggestedPredefines += '\n';
- } else {
- SuggestedPredefines += "#define ";
- SuggestedPredefines += MacroName.str();
- SuggestedPredefines += ' ';
- SuggestedPredefines += Existing.first.str();
- SuggestedPredefines += '\n';
- }
- continue;
- }
-
- // If the macro was defined in one but undef'd in the other, we have a
- // conflict.
- if (Existing.second != Known->second.second) {
- if (Diags) {
- Diags->Report(diag::err_pch_macro_def_undef)
- << MacroName << Known->second.second;
- }
- return true;
- }
-
- // If the macro was #undef'd in both, or if the macro bodies are identical,
- // it's fine.
- if (Existing.second || Existing.first == Known->second.first)
- continue;
-
- // The macro bodies differ; complain.
- if (Diags) {
- Diags->Report(diag::err_pch_macro_def_conflict)
- << MacroName << Known->second.first << Existing.first;
- }
- return true;
- }
-
- // Check whether we're using predefines.
- if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
- if (Diags) {
- Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
- }
- return true;
- }
-
- // Compute the #include and #include_macros lines we need.
- for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
- StringRef File = ExistingPPOpts.Includes[I];
- if (File == ExistingPPOpts.ImplicitPCHInclude)
- continue;
-
- if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
- != PPOpts.Includes.end())
- continue;
-
- SuggestedPredefines += "#include \"";
- SuggestedPredefines +=
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
- SuggestedPredefines += "\"\n";
- }
-
- for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
- StringRef File = ExistingPPOpts.MacroIncludes[I];
- if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
- File)
- != PPOpts.MacroIncludes.end())
- continue;
-
- SuggestedPredefines += "#__include_macros \"";
- SuggestedPredefines +=
- HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
- SuggestedPredefines += "\"\n##\n";
- }
-
- return false;
-}
-
-bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
- bool Complain,
- std::string &SuggestedPredefines) {
- const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
-
- return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
- Complain? &Reader.Diags : 0,
- PP.getFileManager(),
- SuggestedPredefines);
-}
-
-void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
- unsigned ID) {
- PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
- ++NumHeaderInfos;
-}
-
-void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
- PP.setCounterValue(Value);
-}
-
-//===----------------------------------------------------------------------===//
-// AST reader implementation
-//===----------------------------------------------------------------------===//
-
-void
-ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
- DeserializationListener = Listener;
-}
-
-
-
-unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
- return serialization::ComputeHash(Sel);
-}
-
-
-std::pair<unsigned, unsigned>
-ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned KeyLen = ReadUnalignedLE16(d);
- unsigned DataLen = ReadUnalignedLE16(d);
- return std::make_pair(KeyLen, DataLen);
-}
-
-ASTSelectorLookupTrait::internal_key_type
-ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
- SelectorTable &SelTable = Reader.getContext().Selectors;
- unsigned N = ReadUnalignedLE16(d);
- IdentifierInfo *FirstII
- = Reader.getLocalIdentifier(F, ReadUnalignedLE32(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, ReadUnalignedLE32(d)));
-
- return SelTable.getSelector(N, Args.data());
-}
-
-ASTSelectorLookupTrait::data_type
-ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
- unsigned DataLen) {
- using namespace clang::io;
-
- data_type Result;
-
- Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d));
- unsigned NumInstanceMethods = ReadUnalignedLE16(d);
- unsigned NumFactoryMethods = ReadUnalignedLE16(d);
-
- // Load instance methods
- for (unsigned I = 0; I != NumInstanceMethods; ++I) {
- if (ObjCMethodDecl *Method
- = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
- Result.Instance.push_back(Method);
- }
-
- // Load factory methods
- for (unsigned I = 0; I != NumFactoryMethods; ++I) {
- if (ObjCMethodDecl *Method
- = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
- Result.Factory.push_back(Method);
- }
-
- return Result;
-}
-
-unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) {
- return llvm::HashString(StringRef(a.first, a.second));
-}
-
-std::pair<unsigned, unsigned>
-ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned DataLen = ReadUnalignedLE16(d);
- unsigned KeyLen = ReadUnalignedLE16(d);
- return std::make_pair(KeyLen, DataLen);
-}
-
-std::pair<const char*, unsigned>
-ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) {
- assert(n >= 2 && d[n-1] == '\0');
- return std::make_pair((const char*) d, n-1);
-}
-
-IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
- const unsigned char* d,
- unsigned DataLen) {
- using namespace clang::io;
- unsigned RawID = ReadUnalignedLE32(d);
- bool IsInteresting = RawID & 0x01;
-
- // Wipe out the "is interesting" bit.
- RawID = RawID >> 1;
-
- IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
- if (!IsInteresting) {
- // For uninteresting identifiers, just build the IdentifierInfo
- // and associate it with the persistent ID.
- IdentifierInfo *II = KnownII;
- if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
- KnownII = II;
- }
- Reader.SetIdentifierInfo(ID, II);
- II->setIsFromAST();
- Reader.markIdentifierUpToDate(II);
- return II;
- }
-
- unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
- unsigned Bits = ReadUnalignedLE16(d);
- bool CPlusPlusOperatorKeyword = Bits & 0x01;
- Bits >>= 1;
- bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
- Bits >>= 1;
- bool Poisoned = Bits & 0x01;
- Bits >>= 1;
- bool ExtensionToken = Bits & 0x01;
- Bits >>= 1;
- bool hadMacroDefinition = Bits & 0x01;
- Bits >>= 1;
-
- assert(Bits == 0 && "Extra bits in the identifier?");
- DataLen -= 8;
-
- // Build the IdentifierInfo itself and link the identifier ID with
- // the new IdentifierInfo.
- IdentifierInfo *II = KnownII;
- if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
- KnownII = II;
- }
- Reader.markIdentifierUpToDate(II);
- II->setIsFromAST();
-
- // Set or check the various bits in the IdentifierInfo structure.
- // Token IDs are read-only.
- if (HasRevertedTokenIDToIdentifier)
- II->RevertTokenIDToIdentifier();
- II->setObjCOrBuiltinID(ObjCOrBuiltinID);
- assert(II->isExtensionToken() == ExtensionToken &&
- "Incorrect extension token flag");
- (void)ExtensionToken;
- if (Poisoned)
- II->setIsPoisoned(true);
- assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
- "Incorrect C++ operator keyword flag");
- (void)CPlusPlusOperatorKeyword;
-
- // If this identifier is a macro, deserialize the macro
- // definition.
- if (hadMacroDefinition) {
- SmallVector<MacroID, 4> MacroIDs;
- while (uint32_t LocalID = ReadUnalignedLE32(d)) {
- MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
- DataLen -= 4;
- }
- DataLen -= 4;
- Reader.setIdentifierIsMacro(II, MacroIDs);
- }
-
- Reader.SetIdentifierInfo(ID, II);
-
- // Read all of the declarations visible at global scope with this
- // name.
- if (DataLen > 0) {
- SmallVector<uint32_t, 4> DeclIDs;
- for (; DataLen > 0; DataLen -= 4)
- DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d)));
- Reader.SetGloballyVisibleDecls(II, DeclIDs);
- }
-
- return II;
-}
-
-unsigned
-ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const {
- llvm::FoldingSetNodeID ID;
- ID.AddInteger(Key.Kind);
-
- switch (Key.Kind) {
- case DeclarationName::Identifier:
- case DeclarationName::CXXLiteralOperatorName:
- ID.AddString(((IdentifierInfo*)Key.Data)->getName());
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
- break;
- case DeclarationName::CXXOperatorName:
- ID.AddInteger((OverloadedOperatorKind)Key.Data);
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- case DeclarationName::CXXUsingDirective:
- break;
- }
-
- return ID.ComputeHash();
-}
-
-ASTDeclContextNameLookupTrait::internal_key_type
-ASTDeclContextNameLookupTrait::GetInternalKey(
- const external_key_type& Name) const {
- DeclNameKey Key;
- Key.Kind = Name.getNameKind();
- switch (Name.getNameKind()) {
- case DeclarationName::Identifier:
- Key.Data = (uint64_t)Name.getAsIdentifierInfo();
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
- break;
- case DeclarationName::CXXOperatorName:
- Key.Data = Name.getCXXOverloadedOperator();
- break;
- case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- case DeclarationName::CXXUsingDirective:
- Key.Data = 0;
- break;
- }
-
- return Key;
-}
-
-std::pair<unsigned, unsigned>
-ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned KeyLen = ReadUnalignedLE16(d);
- unsigned DataLen = ReadUnalignedLE16(d);
- return std::make_pair(KeyLen, DataLen);
-}
-
-ASTDeclContextNameLookupTrait::internal_key_type
-ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
-
- DeclNameKey Key;
- Key.Kind = (DeclarationName::NameKind)*d++;
- switch (Key.Kind) {
- case DeclarationName::Identifier:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
- break;
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- Key.Data =
- (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d))
- .getAsOpaquePtr();
- break;
- case DeclarationName::CXXOperatorName:
- Key.Data = *d++; // OverloadedOperatorKind
- break;
- case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
- break;
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- case DeclarationName::CXXUsingDirective:
- Key.Data = 0;
- break;
- }
-
- return Key;
-}
-
-ASTDeclContextNameLookupTrait::data_type
-ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
- const unsigned char* d,
- unsigned DataLen) {
- using namespace clang::io;
- unsigned NumDecls = ReadUnalignedLE16(d);
- LE32DeclID *Start = (LE32DeclID *)d;
- return std::make_pair(Start, Start + NumDecls);
-}
-
-bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
- llvm::BitstreamCursor &Cursor,
- const std::pair<uint64_t, uint64_t> &Offsets,
- DeclContextInfo &Info) {
- SavedStreamPosition SavedPosition(Cursor);
- // First the lexical decls.
- if (Offsets.first != 0) {
- Cursor.JumpToBit(Offsets.first);
-
- RecordData Record;
- const char *Blob;
- unsigned BlobLen;
- unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
- if (RecCode != DECL_CONTEXT_LEXICAL) {
- Error("Expected lexical block");
- return true;
- }
-
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
- Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
- }
-
- // Now the lookup table.
- if (Offsets.second != 0) {
- Cursor.JumpToBit(Offsets.second);
-
- RecordData Record;
- const char *Blob;
- unsigned BlobLen;
- unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
- if (RecCode != DECL_CONTEXT_VISIBLE) {
- Error("Expected visible lookup table block");
- return true;
- }
- Info.NameLookupTableData
- = ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob + Record[0],
- (const unsigned char *)Blob,
- ASTDeclContextNameLookupTrait(*this, M));
- }
-
- return false;
-}
-
-void ASTReader::Error(StringRef Msg) {
- Error(diag::err_fe_pch_malformed, Msg);
-}
-
-void ASTReader::Error(unsigned DiagID,
- StringRef Arg1, StringRef Arg2) {
- if (Diags.isDiagnosticInFlight())
- Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
- else
- Diag(DiagID) << Arg1 << Arg2;
-}
-
-//===----------------------------------------------------------------------===//
-// Source Manager Deserialization
-//===----------------------------------------------------------------------===//
-
-/// \brief Read the line table in the source manager block.
-/// \returns true if there was an error.
-bool ASTReader::ParseLineTable(ModuleFile &F,
- SmallVectorImpl<uint64_t> &Record) {
- unsigned Idx = 0;
- LineTableInfo &LineTable = SourceMgr.getLineTable();
-
- // Parse the file names
- std::map<int, int> FileIDs;
- for (int I = 0, N = Record[Idx++]; I != N; ++I) {
- // Extract the file name
- unsigned FilenameLen = Record[Idx++];
- std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
- Idx += FilenameLen;
- MaybeAddSystemRootToFilename(F, Filename);
- FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
- }
-
- // Parse the line entries
- std::vector<LineEntry> Entries;
- while (Idx < Record.size()) {
- int FID = Record[Idx++];
- assert(FID >= 0 && "Serialized line entries for non-local file.");
- // Remap FileID from 1-based old view.
- FID += F.SLocEntryBaseID - 1;
-
- // Extract the line entries
- unsigned NumEntries = Record[Idx++];
- assert(NumEntries && "Numentries is 00000");
- Entries.clear();
- Entries.reserve(NumEntries);
- for (unsigned I = 0; I != NumEntries; ++I) {
- unsigned FileOffset = Record[Idx++];
- unsigned LineNo = Record[Idx++];
- int FilenameID = FileIDs[Record[Idx++]];
- SrcMgr::CharacteristicKind FileKind
- = (SrcMgr::CharacteristicKind)Record[Idx++];
- unsigned IncludeOffset = Record[Idx++];
- Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
- FileKind, IncludeOffset));
- }
- LineTable.AddEntry(FileID::get(FID), Entries);
- }
-
- return false;
-}
-
-/// \brief Read a source manager block
-bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
- using namespace SrcMgr;
-
- llvm::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) {
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (SLocEntryCursor.ReadBlockEnd()) {
- Error("error at end of Source Manager block in AST file");
- return true;
- }
- return false;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- SLocEntryCursor.ReadSubBlockID();
- if (SLocEntryCursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- SLocEntryCursor.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- const char *BlobStart;
- unsigned BlobLen;
- Record.clear();
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case SM_SLOC_FILE_ENTRY:
- case SM_SLOC_BUFFER_ENTRY:
- case SM_SLOC_EXPANSION_ENTRY:
- // Once we hit one of the source location entries, we're done.
- return false;
- }
- }
-}
-
-/// \brief If a header file is not found at the path that we expect it to be
-/// and the PCH file was moved from its original location, try to resolve the
-/// file by assuming that header+PCH were moved together and the header is in
-/// the same place relative to the PCH.
-static std::string
-resolveFileRelativeToOriginalDir(const std::string &Filename,
- const std::string &OriginalDir,
- const std::string &CurrDir) {
- assert(OriginalDir != CurrDir &&
- "No point trying to resolve the file if the PCH dir didn't change");
- using namespace llvm::sys;
- SmallString<128> filePath(Filename);
- fs::make_absolute(filePath);
- assert(path::is_absolute(OriginalDir));
- SmallString<128> currPCHPath(CurrDir);
-
- path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
- fileDirE = path::end(path::parent_path(filePath));
- path::const_iterator origDirI = path::begin(OriginalDir),
- origDirE = path::end(OriginalDir);
- // Skip the common path components from filePath and OriginalDir.
- while (fileDirI != fileDirE && origDirI != origDirE &&
- *fileDirI == *origDirI) {
- ++fileDirI;
- ++origDirI;
- }
- for (; origDirI != origDirE; ++origDirI)
- path::append(currPCHPath, "..");
- path::append(currPCHPath, fileDirI, fileDirE);
- path::append(currPCHPath, path::filename(Filename));
- return currPCHPath.str();
-}
-
-bool ASTReader::ReadSLocEntry(int ID) {
- if (ID == 0)
- return false;
-
- if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
- Error("source location entry ID out-of-range for AST file");
- return true;
- }
-
- ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
- F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
- llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
- unsigned BaseOffset = F->SLocEntryBaseOffset;
-
- ++NumSLocEntriesRead;
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
- Error("incorrectly-formatted source location entry in AST file");
- return true;
- }
-
- RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- 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.getPointer();
- bool OverriddenBuffer = IF.getInt();
-
- if (!IF.getPointer())
- return true;
-
- SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
- if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
- // This is the module's main file.
- IncludeLoc = getImportLocation(F);
- }
- SrcMgr::CharacteristicKind
- FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
- FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
- ID, BaseOffset + Record[0]);
- SrcMgr::FileInfo &FileInfo =
- const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
- FileInfo.NumCreatedFIDs = Record[5];
- if (Record[3])
- FileInfo.setHasLineDirectives();
-
- const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
- unsigned NumFileDecls = Record[7];
- if (NumFileDecls) {
- assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
- FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
- NumFileDecls));
- }
-
- const SrcMgr::ContentCache *ContentCache
- = SourceMgr.getOrCreateContentCache(File,
- /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
- if (OverriddenBuffer && !ContentCache->BufferOverridden &&
- ContentCache->ContentsEntry == ContentCache->OrigEntry) {
- unsigned Code = SLocEntryCursor.ReadCode();
- Record.clear();
- unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
-
- if (RecCode != SM_SLOC_BUFFER_BLOB) {
- Error("AST record has invalid code");
- return true;
- }
-
- llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- File->getName());
- SourceMgr.overrideFileContents(File, Buffer);
- }
-
- break;
- }
-
- case SM_SLOC_BUFFER_ENTRY: {
- const char *Name = BlobStart;
- unsigned Offset = Record[0];
- SrcMgr::CharacteristicKind
- FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
- SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
- if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
- IncludeLoc = getImportLocation(F);
- }
- unsigned Code = SLocEntryCursor.ReadCode();
- Record.clear();
- unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
-
- if (RecCode != SM_SLOC_BUFFER_BLOB) {
- Error("AST record has invalid code");
- return true;
- }
-
- llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Name);
- SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
- BaseOffset + Offset, IncludeLoc);
- break;
- }
-
- case SM_SLOC_EXPANSION_ENTRY: {
- SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
- SourceMgr.createExpansionLoc(SpellingLoc,
- ReadSourceLocation(*F, Record[2]),
- ReadSourceLocation(*F, Record[3]),
- Record[4],
- ID,
- BaseOffset + Record[0]);
- break;
- }
- }
-
- return false;
-}
-
-std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
- if (ID == 0)
- return std::make_pair(SourceLocation(), "");
-
- if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
- Error("source location entry ID out-of-range for AST file");
- return std::make_pair(SourceLocation(), "");
- }
-
- // Find which module file this entry lands in.
- ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
- if (M->Kind != MK_Module)
- return std::make_pair(SourceLocation(), "");
-
- // FIXME: Can we map this down to a particular submodule? That would be
- // ideal.
- return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
-}
-
-/// \brief Find the location where the module F is imported.
-SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
- if (F->ImportLoc.isValid())
- return F->ImportLoc;
-
- // Otherwise we have a PCH. It's considered to be "imported" at the first
- // location of its includer.
- if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
- // Main file is the importer. We assume that it is the first entry in the
- // entry table. We can't ask the manager, because at the time of PCH loading
- // the main file entry doesn't exist yet.
- // The very first entry is the invalid instantiation loc, which takes up
- // offsets 0 and 1.
- return SourceLocation::getFromRawEncoding(2U);
- }
- //return F->Loaders[0]->FirstLoc;
- return F->ImportedBy[0]->FirstLoc;
-}
-
-/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
-/// specified cursor. Read the abbreviations that are at the top of the block
-/// and then leave the cursor pointing into the block.
-bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
- unsigned BlockID) {
- if (Cursor.EnterSubBlock(BlockID)) {
- Error("malformed block record in AST file");
- return Failure;
- }
-
- while (true) {
- uint64_t Offset = Cursor.GetCurrentBitNo();
- unsigned Code = Cursor.ReadCode();
-
- // We expect all abbrevs to be at the start of the block.
- if (Code != llvm::bitc::DEFINE_ABBREV) {
- Cursor.JumpToBit(Offset);
- return false;
- }
- Cursor.ReadAbbrevRecord();
- }
-}
-
-void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
- MacroInfo *Hint) {
- llvm::BitstreamCursor &Stream = F.MacroCursor;
-
- // Keep track of where we are in the stream, then jump back there
- // after reading this macro.
- SavedStreamPosition SavedPosition(Stream);
-
- Stream.JumpToBit(Offset);
- RecordData Record;
- SmallVector<IdentifierInfo*, 16> MacroArgs;
- MacroInfo *Macro = 0;
-
- // RAII object to add the loaded macro information once we're done
- // adding tokens.
- struct AddLoadedMacroInfoRAII {
- Preprocessor &PP;
- MacroInfo *Hint;
- MacroInfo *MI;
- IdentifierInfo *II;
-
- AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint)
- : PP(PP), Hint(Hint), MI(), II() { }
- ~AddLoadedMacroInfoRAII( ) {
- if (MI) {
- // Finally, install the macro.
- PP.addLoadedMacroInfo(II, MI, Hint);
- }
- }
- } AddLoadedMacroInfo(PP, Hint);
-
- while (true) {
- unsigned Code = Stream.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- // No known subblocks, always skip them.
- Stream.ReadSubBlockID();
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
-
- case llvm::bitc::DEFINE_ABBREV:
- Stream.ReadAbbrevRecord();
- continue;
- default: break;
- }
-
- // Read a record.
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- Record.clear();
- PreprocessorRecordTypes RecType =
- (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart,
- BlobLen);
- switch (RecType) {
- 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;
-
- IdentifierInfo *II = getLocalIdentifier(F, Record[0]);
- if (II == 0) {
- Error("macro must have a name in AST file");
- return;
- }
-
- unsigned GlobalID = getGlobalMacroID(F, Record[1]);
-
- // If this macro has already been loaded, don't do so again.
- if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS])
- return;
-
- SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]);
- unsigned NextIndex = 3;
- SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
- MacroInfo *MI = PP.AllocateMacroInfo(Loc);
-
- // Record this macro.
- MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
-
- SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
- if (UndefLoc.isValid())
- MI->setUndefLoc(UndefLoc);
-
- MI->setIsUsed(Record[NextIndex++]);
- MI->setIsFromAST();
-
- bool IsPublic = Record[NextIndex++];
- MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex));
-
- if (RecType == PP_MACRO_FUNCTION_LIKE) {
- // Decode function-like macro info.
- bool isC99VarArgs = Record[NextIndex++];
- bool isGNUVarArgs = Record[NextIndex++];
- bool hasCommaPasting = Record[NextIndex++];
- MacroArgs.clear();
- unsigned NumArgs = Record[NextIndex++];
- for (unsigned i = 0; i != NumArgs; ++i)
- MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
-
- // Install function-like macro info.
- MI->setIsFunctionLike();
- if (isC99VarArgs) MI->setIsC99Varargs();
- if (isGNUVarArgs) MI->setIsGNUVarargs();
- if (hasCommaPasting) MI->setHasCommaPasting();
- MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
- PP.getPreprocessorAllocator());
- }
-
- if (DeserializationListener)
- DeserializationListener->MacroRead(GlobalID, MI);
-
- // If an update record marked this as undefined, do so now.
- // FIXME: Only if the submodule this update came from is visible?
- MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID);
- if (Update != MacroUpdates.end()) {
- if (MI->getUndefLoc().isInvalid()) {
- for (unsigned I = 0, N = Update->second.size(); I != N; ++I) {
- bool Hidden = false;
- if (unsigned SubmoduleID = Update->second[I].first) {
- if (Module *Owner = getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility == Module::Hidden) {
- // Note that this #undef is hidden.
- Hidden = true;
-
- // Record this hiding for later.
- HiddenNamesMap[Owner].push_back(
- HiddenName(II, MI, Update->second[I].second.UndefLoc));
- }
- }
- }
-
- if (!Hidden) {
- MI->setUndefLoc(Update->second[I].second.UndefLoc);
- if (PPMutationListener *Listener = PP.getPPMutationListener())
- Listener->UndefinedMacro(MI);
- break;
- }
- }
- }
- MacroUpdates.erase(Update);
- }
-
- // Determine whether this macro definition is visible.
- bool Hidden = !MI->isPublic();
- if (!Hidden && GlobalSubmoduleID) {
- if (Module *Owner = getSubmodule(GlobalSubmoduleID)) {
- if (Owner->NameVisibility == Module::Hidden) {
- // The owning module is not visible, and this macro definition
- // should not be, either.
- Hidden = true;
-
- // Note that this macro definition was hidden because its owning
- // module is not yet visible.
- HiddenNamesMap[Owner].push_back(HiddenName(II, MI));
- }
- }
- }
- MI->setHidden(Hidden);
-
- // Make sure we install the macro once we're done.
- AddLoadedMacroInfo.MI = MI;
- AddLoadedMacroInfo.II = II;
-
- // 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();
- PPRec.RegisterMacroDefinition(Macro,
- PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true));
- }
-
- ++NumMacrosRead;
- break;
- }
-
- case PP_TOKEN: {
- // If we see a TOKEN before a PP_MACRO_*, then the file is
- // erroneous, just pretend we didn't see this.
- if (Macro == 0) break;
-
- Token Tok;
- Tok.startToken();
- Tok.setLocation(ReadSourceLocation(F, Record[0]));
- Tok.setLength(Record[1]);
- if (IdentifierInfo *II = getLocalIdentifier(F, Record[2]))
- Tok.setIdentifierInfo(II);
- Tok.setKind((tok::TokenKind)Record[3]);
- Tok.setFlag((Token::TokenFlags)Record[4]);
- Macro->AddTokenToBody(Tok);
- break;
- }
- }
- }
-}
-
-PreprocessedEntityID
-ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
- ContinuousRangeMap<uint32_t, int, 2>::const_iterator
- I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
- assert(I != M.PreprocessedEntityRemap.end()
- && "Invalid index into preprocessed entity index remap");
-
- return LocalID + I->second;
-}
-
-unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
- return llvm::HashString(llvm::sys::path::filename(path));
-}
-
-HeaderFileInfoTrait::internal_key_type
-HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
-
-bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
- if (strcmp(a, b) == 0)
- return true;
-
- if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
- return false;
-
- // Determine whether the actual files are equivalent.
- bool Result = false;
- if (llvm::sys::fs::equivalent(a, b, Result))
- return false;
-
- return Result;
-}
-
-std::pair<unsigned, unsigned>
-HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
- unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
- unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
-}
-
-HeaderFileInfoTrait::data_type
-HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
- unsigned DataLen) {
- const unsigned char *End = d + DataLen;
- using namespace clang::io;
- HeaderFileInfo HFI;
- unsigned Flags = *d++;
- HFI.isImport = (Flags >> 5) & 0x01;
- HFI.isPragmaOnce = (Flags >> 4) & 0x01;
- HFI.DirInfo = (Flags >> 2) & 0x03;
- HFI.Resolved = (Flags >> 1) & 0x01;
- HFI.IndexHeaderMapHeader = Flags & 0x01;
- HFI.NumIncludes = ReadUnalignedLE16(d);
- HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M,
- ReadUnalignedLE32(d));
- if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) {
- // The framework offset is 1 greater than the actual offset,
- // since 0 is used as an indicator for "no framework name".
- StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
- HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
- }
-
- assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
- (void)End;
-
- // This HeaderFileInfo was externally loaded.
- HFI.External = true;
- return HFI;
-}
-
-void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
- II->setHadMacroDefinition(true);
- assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
- PendingMacroIDs[II].append(IDs.begin(), IDs.end());
-}
-
-void ASTReader::ReadDefinedMacros() {
- // Note that we are loading defined macros.
- Deserializing Macros(this);
-
- for (ModuleReverseIterator I = ModuleMgr.rbegin(),
- E = ModuleMgr.rend(); I != E; ++I) {
- llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
-
- // If there was no preprocessor block, skip this file.
- if (!MacroCursor.getBitStreamReader())
- continue;
-
- llvm::BitstreamCursor Cursor = MacroCursor;
- Cursor.JumpToBit((*I)->MacroStartOffset);
-
- RecordData Record;
- while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
- break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- const char *BlobStart;
- unsigned BlobLen;
- Record.clear();
- switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case PP_MACRO_OBJECT_LIKE:
- case PP_MACRO_FUNCTION_LIKE:
- getLocalIdentifier(**I, Record[0]);
- break;
-
- case PP_TOKEN:
- // Ignore tokens.
- break;
- }
- }
- }
-}
-
-namespace {
- /// \brief Visitor class used to look up identifirs in an AST file.
- class IdentifierLookupVisitor {
- StringRef Name;
- unsigned PriorGeneration;
- IdentifierInfo *Found;
- public:
- IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
- : Name(Name), PriorGeneration(PriorGeneration), Found() { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- IdentifierLookupVisitor *This
- = static_cast<IdentifierLookupVisitor *>(UserData);
-
- // If we've already searched this module file, skip it now.
- if (M.Generation <= This->PriorGeneration)
- return true;
-
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
- if (!IdTable)
- return false;
-
- ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
- M, This->Found);
-
- std::pair<const char*, unsigned> Key(This->Name.begin(),
- This->Name.size());
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait);
- if (Pos == IdTable->end())
- return false;
-
- // Dereferencing the iterator has the effect of building the
- // IdentifierInfo node and populating it with the various
- // declarations it needs.
- This->Found = *Pos;
- return true;
- }
-
- // \brief Retrieve the identifier info found within the module
- // files.
- IdentifierInfo *getIdentifierInfo() const { return Found; }
- };
-}
-
-void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
- // Note that we are loading an identifier.
- Deserializing AnIdentifier(this);
-
- unsigned PriorGeneration = 0;
- if (getContext().getLangOpts().Modules)
- PriorGeneration = IdentifierGeneration[&II];
-
- IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
- markIdentifierUpToDate(&II);
-}
-
-void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
- if (!II)
- return;
-
- II->setOutOfDate(false);
-
- // Update the generation for this identifier.
- if (getContext().getLangOpts().Modules)
- IdentifierGeneration[II] = CurrentGeneration;
-}
-
-llvm::PointerIntPair<const FileEntry *, 1, bool>
-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].getPointer())
- return F.InputFilesLoaded[ID-1];
-
- // Go find this input file.
- llvm::BitstreamCursor &Cursor = F.InputFilesCursor;
- SavedStreamPosition SavedPosition(Cursor);
- Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
-
- unsigned Code = Cursor.ReadCode();
- RecordData Record;
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
- case INPUT_FILE: {
- unsigned StoredID = Record[0];
- assert(ID == StoredID && "Bogus stored ID or offset");
- (void)StoredID;
- off_t StoredSize = (off_t)Record[1];
- time_t StoredTime = (time_t)Record[2];
- bool Overridden = (bool)Record[3];
-
- // Get the file entry for this input file.
- StringRef OrigFilename(BlobStart, BlobLen);
- std::string Filename = OrigFilename;
- MaybeAddSystemRootToFilename(F, Filename);
- const FileEntry *File
- = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
-
- // If we didn't find the file, resolve it relative to the
- // original directory from which this AST file was created.
- if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
- F.OriginalDir != CurrentDir) {
- std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
- F.OriginalDir,
- CurrentDir);
- if (!Resolved.empty())
- File = FileMgr.getFile(Resolved);
- }
-
- // For an overridden file, create a virtual file with the stored
- // size/timestamp.
- if (Overridden && File == 0) {
- File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
- }
-
- if (File == 0) {
- if (Complain) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- }
- return InputFile();
- }
-
- // Note that we've loaded this input file.
- F.InputFilesLoaded[ID-1] = InputFile(File, Overridden);
-
- // Check if there was a request to override the contents of the file
- // that was part of the precompiled header. Overridding such a file
- // can lead to problems when lexing using the source locations from the
- // PCH.
- SourceManager &SM = getSourceManager();
- if (!Overridden && SM.isFileOverridden(File)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
- }
-
- // For an overridden file, there is nothing to validate.
- if (Overridden)
- return InputFile(File, Overridden);
-
- if ((StoredSize != File->getSize()
-#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || StoredTime != File->getModificationTime()
-#endif
- )) {
- if (Complain)
- Error(diag::err_fe_pch_file_modified, Filename);
-
- return InputFile();
- }
-
- return InputFile(File, Overridden);
- }
- }
-
- return InputFile();
-}
-
-const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
- ModuleFile &M = ModuleMgr.getPrimaryModule();
- std::string Filename = filenameStrRef;
- MaybeAddSystemRootToFilename(M, Filename);
- const FileEntry *File = FileMgr.getFile(Filename);
- if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
- M.OriginalDir != CurrentDir) {
- std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- M.OriginalDir,
- CurrentDir);
- if (!resolved.empty())
- File = FileMgr.getFile(resolved);
- }
-
- return File;
-}
-
-/// \brief If we are loading a relocatable PCH file, and the filename is
-/// not an absolute path, add the system root to the beginning of the file
-/// name.
-void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
- std::string &Filename) {
- // If this is not a relocatable PCH file, there's nothing to do.
- if (!M.RelocatablePCH)
- return;
-
- if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
- return;
-
- if (isysroot.empty()) {
- // If no system root was given, default to '/'
- Filename.insert(Filename.begin(), '/');
- return;
- }
-
- unsigned Length = isysroot.size();
- if (isysroot[Length - 1] != '/')
- Filename.insert(Filename.begin(), '/');
-
- Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
-}
-
-ASTReader::ASTReadResult
-ASTReader::ReadControlBlock(ModuleFile &F,
- llvm::SmallVectorImpl<ImportedModule> &Loaded,
- unsigned ClientLoadCapabilities) {
- llvm::BitstreamCursor &Stream = F.Stream;
-
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- Error("malformed block record in AST file");
- return Failure;
- }
-
- // Read all of the records and blocks in the control block.
- RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Error("error at end of control block in AST file");
- return Failure;
- }
-
- // Validate all of the input files.
- if (!DisableValidation) {
- bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- for (unsigned I = 0, N = Record[0]; I < N; ++I)
- if (!getInputFile(F, I+1, Complain).getPointer())
- return OutOfDate;
- }
-
- return Success;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
- case INPUT_FILES_BLOCK_ID:
- F.InputFilesCursor = Stream;
- if (Stream.SkipBlock() || // Skip with the main cursor
- // Read the abbreviations
- ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
- Error("malformed block record in AST file");
- return Failure;
- }
- continue;
-
- default:
- if (!Stream.SkipBlock())
- continue;
- break;
- }
-
- Error("malformed block record in AST file");
- return Failure;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
- }
-
- // Read and process a record.
- Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
- case METADATA: {
- if (Record[0] != VERSION_MAJOR && !DisableValidation) {
- if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
- Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
- return VersionMismatch;
- }
-
- bool hasErrors = Record[5];
- if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
- Diag(diag::err_pch_with_compiler_errors);
- return HadErrors;
- }
-
- F.RelocatablePCH = Record[4];
-
- const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
- if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
- if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
- Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
- return VersionMismatch;
- }
- break;
- }
-
- case IMPORTS: {
- // Load each of the imported PCH files.
- unsigned Idx = 0, N = Record.size();
- while (Idx < N) {
- // Read information about the AST file.
- ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
- // The import location will be the local one for now; we will adjust
- // all import locations of module imports after the global source
- // location info are setup.
- SourceLocation ImportLoc =
- SourceLocation::getFromRawEncoding(Record[Idx++]);
- unsigned Length = Record[Idx++];
- SmallString<128> ImportedFile(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- Idx += Length;
-
- // Load the AST file.
- switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
- ClientLoadCapabilities)) {
- case Failure: return Failure;
- // If we have to ignore the dependency, we'll have to ignore this too.
- case OutOfDate: return OutOfDate;
- case VersionMismatch: return VersionMismatch;
- case ConfigurationMismatch: return ConfigurationMismatch;
- case HadErrors: return HadErrors;
- case Success: break;
- }
- }
- break;
- }
-
- case LANGUAGE_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseLanguageOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case TARGET_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseTargetOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case DIAGNOSTIC_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseDiagnosticOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case FILE_SYSTEM_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseFileSystemOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case HEADER_SEARCH_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseHeaderSearchOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case PREPROCESSOR_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParsePreprocessorOptions(Record, Complain, *Listener,
- SuggestedPredefines) &&
- !DisableValidation)
- return ConfigurationMismatch;
- break;
- }
-
- case ORIGINAL_FILE:
- F.OriginalSourceFileID = FileID::get(Record[0]);
- F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
- F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
- MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
- break;
-
- case ORIGINAL_FILE_ID:
- F.OriginalSourceFileID = FileID::get(Record[0]);
- break;
-
- case ORIGINAL_PCH_DIR:
- F.OriginalDir.assign(BlobStart, BlobLen);
- break;
-
- case INPUT_FILE_OFFSETS:
- F.InputFileOffsets = (const uint32_t *)BlobStart;
- F.InputFilesLoaded.resize(Record[0]);
- break;
- }
- }
-
- Error("premature end of bitstream in AST file");
- return Failure;
-}
-
-bool ASTReader::ReadASTBlock(ModuleFile &F) {
- llvm::BitstreamCursor &Stream = F.Stream;
-
- if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
- Error("malformed block record in AST file");
- return true;
- }
-
- // Read all of the records and blocks for the AST file.
- RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Error("error at end of module block in AST file");
- return true;
- }
-
- DeclContext *DC = Context.getTranslationUnitDecl();
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
- DC->setMustBuildLookupTable();
-
- return false;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
- case DECLTYPES_BLOCK_ID:
- // We lazily load the decls block, but we want to set up the
- // DeclsCursor cursor to point into it. Clone our current bitcode
- // cursor to it, enter the block and read the abbrevs in that block.
- // With the main cursor, we just skip over it.
- F.DeclsCursor = Stream;
- if (Stream.SkipBlock() || // Skip with the main cursor.
- // Read the abbrevs.
- ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
- Error("malformed block record in AST file");
- return true;
- }
- break;
-
- case DECL_UPDATES_BLOCK_ID:
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- 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 true;
- }
- 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 true;
- }
- 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 true;
- break;
-
- case SUBMODULE_BLOCK_ID:
- if (ReadSubmoduleBlock(F))
- return true;
- break;
-
- case COMMENTS_BLOCK_ID: {
- llvm::BitstreamCursor C = Stream;
- if (Stream.SkipBlock() ||
- ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
- Error("malformed comments block in AST file");
- return true;
- }
- CommentsCursors.push_back(std::make_pair(C, &F));
- break;
- }
-
- default:
- if (!Stream.SkipBlock())
- break;
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
- }
-
- // Read and process a record.
- Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case TYPE_OFFSET: {
- if (F.LocalNumTypes != 0) {
- Error("duplicate TYPE_OFFSET record in AST file");
- return true;
- }
- F.TypeOffsets = (const uint32_t *)BlobStart;
- F.LocalNumTypes = Record[0];
- unsigned LocalBaseTypeIndex = Record[1];
- F.BaseTypeIndex = getTotalNumTypes();
-
- if (F.LocalNumTypes > 0) {
- // Introduce the global -> local mapping for types within this module.
- GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
-
- // Introduce the local -> global mapping for types within this module.
- F.TypeRemap.insertOrReplace(
- std::make_pair(LocalBaseTypeIndex,
- F.BaseTypeIndex - LocalBaseTypeIndex));
-
- TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
- }
- break;
- }
-
- case DECL_OFFSET: {
- if (F.LocalNumDecls != 0) {
- Error("duplicate DECL_OFFSET record in AST file");
- return true;
- }
- F.DeclOffsets = (const DeclOffset *)BlobStart;
- F.LocalNumDecls = Record[0];
- unsigned LocalBaseDeclID = Record[1];
- F.BaseDeclID = getTotalNumDecls();
-
- if (F.LocalNumDecls > 0) {
- // Introduce the global -> local mapping for declarations within this
- // module.
- GlobalDeclMap.insert(
- std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
-
- // Introduce the local -> global mapping for declarations within this
- // module.
- F.DeclRemap.insertOrReplace(
- std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
-
- // Introduce the global -> local mapping for declarations within this
- // module.
- F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
-
- DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
- }
- break;
- }
-
- case TU_UPDATE_LEXICAL: {
- DeclContext *TU = Context.getTranslationUnitDecl();
- DeclContextInfo &Info = F.DeclContextInfos[TU];
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart);
- Info.NumLexicalDecls
- = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair));
- TU->setHasExternalLexicalStorage(true);
- break;
- }
-
- case UPDATE_VISIBLE: {
- unsigned Idx = 0;
- serialization::DeclID ID = ReadDeclID(F, Record, Idx);
- ASTDeclContextNameLookupTable *Table =
- ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)BlobStart + Record[Idx++],
- (const unsigned char *)BlobStart,
- ASTDeclContextNameLookupTrait(*this, F));
- if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
- DeclContext *TU = Context.getTranslationUnitDecl();
- F.DeclContextInfos[TU].NameLookupTableData = Table;
- TU->setHasExternalVisibleStorage(true);
- } else
- PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
- break;
- }
-
- case IDENTIFIER_TABLE:
- F.IdentifierTableData = BlobStart;
- if (Record[0]) {
- F.IdentifierLookupTable
- = ASTIdentifierLookupTable::Create(
- (const unsigned char *)F.IdentifierTableData + Record[0],
- (const unsigned char *)F.IdentifierTableData,
- ASTIdentifierLookupTrait(*this, F));
-
- PP.getIdentifierTable().setExternalIdentifierLookup(this);
- }
- break;
-
- case IDENTIFIER_OFFSET: {
- if (F.LocalNumIdentifiers != 0) {
- Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return true;
- }
- F.IdentifierOffsets = (const uint32_t *)BlobStart;
- 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 EXTERNAL_DEFINITIONS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case SPECIAL_TYPES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
- break;
-
- case STATISTICS:
- TotalNumStatements += Record[0];
- TotalNumMacros += Record[1];
- TotalLexicalDeclContexts += Record[2];
- TotalVisibleDeclContexts += Record[3];
- break;
-
- case UNUSED_FILESCOPED_DECLS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case DELEGATING_CTORS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case WEAK_UNDECLARED_IDENTIFIERS:
- if (Record.size() % 4 != 0) {
- Error("invalid weak identifiers record");
- return true;
- }
-
- // FIXME: Ignore weak undeclared identifiers from non-original PCH
- // files. This isn't the way to do it :)
- WeakUndeclaredIdentifiers.clear();
-
- // Translate the weak, undeclared identifiers into global IDs.
- for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
- WeakUndeclaredIdentifiers.push_back(
- getGlobalIdentifierID(F, Record[I++]));
- WeakUndeclaredIdentifiers.push_back(
- getGlobalIdentifierID(F, Record[I++]));
- WeakUndeclaredIdentifiers.push_back(
- ReadSourceLocation(F, Record, I).getRawEncoding());
- WeakUndeclaredIdentifiers.push_back(Record[I++]);
- }
- break;
-
- case LOCALLY_SCOPED_EXTERNAL_DECLS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case SELECTOR_OFFSETS: {
- F.SelectorOffsets = (const uint32_t *)BlobStart;
- 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 *)BlobStart;
- if (Record[0])
- F.SelectorLookupTable
- = ASTSelectorLookupTable::Create(
- F.SelectorLookupTableData + Record[0],
- F.SelectorLookupTableData,
- ASTSelectorLookupTrait(*this, F));
- TotalNumMethodPoolEntries += Record[1];
- break;
-
- case REFERENCED_SELECTOR_POOL:
- if (!Record.empty()) {
- for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
- ReferencedSelectorsData.push_back(getGlobalSelectorID(F,
- Record[Idx++]));
- ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx).
- getRawEncoding());
- }
- }
- break;
-
- case PP_COUNTER_VALUE:
- if (!Record.empty() && Listener)
- Listener->ReadCounter(F, Record[0]);
- break;
-
- case FILE_SORTED_DECLS:
- F.FileSortedDecls = (const DeclID *)BlobStart;
- F.NumFileSortedDecls = Record[0];
- break;
-
- case SOURCE_LOCATION_OFFSETS: {
- F.SLocEntryOffsets = (const uint32_t *)BlobStart;
- F.LocalNumSLocEntries = Record[0];
- unsigned SLocSpaceSize = Record[1];
- llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
- SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
- SLocSpaceSize);
- // Make our entry in the range map. BaseID is negative and growing, so
- // we invert it. Because we invert it, though, we need the other end of
- // the range.
- unsigned RangeStart =
- unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
- GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
- F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
-
- // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
- assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0);
- GlobalSLocOffsetMap.insert(
- std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
- - SLocSpaceSize,&F));
-
- // Initialize the remapping table.
- // Invalid stays invalid.
- F.SLocRemap.insert(std::make_pair(0U, 0));
- // This module. Base was 2 when being compiled.
- F.SLocRemap.insert(std::make_pair(2U,
- static_cast<int>(F.SLocEntryBaseOffset - 2)));
-
- TotalNumSLocEntries += F.LocalNumSLocEntries;
- break;
- }
-
- case MODULE_OFFSET_MAP: {
- // Additional remapping information.
- const unsigned char *Data = (const unsigned char*)BlobStart;
- const unsigned char *DataEnd = Data + BlobLen;
-
- // Continuous range maps we may be updating in our module.
- ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- IdentifierRemap(F.IdentifierRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- MacroRemap(F.MacroRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- PreprocessedEntityRemap(F.PreprocessedEntityRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- SubmoduleRemap(F.SubmoduleRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
- SelectorRemap(F.SelectorRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
-
- while(Data < DataEnd) {
- uint16_t Len = io::ReadUnalignedLE16(Data);
- StringRef Name = StringRef((const char*)Data, Len);
- Data += Len;
- ModuleFile *OM = ModuleMgr.lookup(Name);
- if (!OM) {
- Error("SourceLocation remap refers to unknown module");
- return true;
- }
-
- uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
- uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
-
- // Source location offset is mapped to OM->SLocEntryBaseOffset.
- SLocRemap.insert(std::make_pair(SLocOffset,
- static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
- IdentifierRemap.insert(
- std::make_pair(IdentifierIDOffset,
- OM->BaseIdentifierID - IdentifierIDOffset));
- MacroRemap.insert(std::make_pair(MacroIDOffset,
- OM->BaseMacroID - MacroIDOffset));
- PreprocessedEntityRemap.insert(
- std::make_pair(PreprocessedEntityIDOffset,
- OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
- SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset,
- OM->BaseSubmoduleID - SubmoduleIDOffset));
- SelectorRemap.insert(std::make_pair(SelectorIDOffset,
- OM->BaseSelectorID - SelectorIDOffset));
- DeclRemap.insert(std::make_pair(DeclIDOffset,
- OM->BaseDeclID - DeclIDOffset));
-
- TypeRemap.insert(std::make_pair(TypeIndexOffset,
- OM->BaseTypeIndex - TypeIndexOffset));
-
- // Global -> local mappings.
- F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
- }
- break;
- }
-
- case SOURCE_MANAGER_LINE_TABLE:
- if (ParseLineTable(F, Record))
- return true;
- break;
-
- case SOURCE_LOCATION_PRELOADS: {
- // Need to transform from the local view (1-based IDs) to the global view,
- // which is based off F.SLocEntryBaseID.
- if (!F.PreloadSLocEntries.empty()) {
- Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return true;
- }
-
- F.PreloadSLocEntries.swap(Record);
- break;
- }
-
- case EXT_VECTOR_DECLS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case VTABLE_USES:
- if (Record.size() % 3 != 0) {
- Error("Invalid VTABLE_USES record");
- return true;
- }
-
- // Later tables overwrite earlier ones.
- // FIXME: Modules will have some trouble with this. This is clearly not
- // the right way to do this.
- VTableUses.clear();
-
- for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) {
- VTableUses.push_back(getGlobalDeclID(F, Record[Idx++]));
- VTableUses.push_back(
- ReadSourceLocation(F, Record, Idx).getRawEncoding());
- VTableUses.push_back(Record[Idx++]);
- }
- break;
-
- case DYNAMIC_CLASSES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- DynamicClasses.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case PENDING_IMPLICIT_INSTANTIATIONS:
- if (PendingInstantiations.size() % 2 != 0) {
- Error("Invalid existing PendingInstantiations");
- return true;
- }
-
- if (Record.size() % 2 != 0) {
- Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return true;
- }
-
- for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
- PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
- PendingInstantiations.push_back(
- ReadSourceLocation(F, Record, I).getRawEncoding());
- }
- break;
-
- case SEMA_DECL_REFS:
- // Later tables overwrite earlier ones.
- // FIXME: Modules will have some trouble with this.
- SemaDeclRefs.clear();
- 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 *)BlobStart;
- assert(BlobLen % sizeof(PPEntityOffset) == 0);
- F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset);
-
- unsigned LocalBasePreprocessedEntityID = Record[0];
-
- unsigned StartingID;
- if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord();
- if (!PP.getPreprocessingRecord()->getExternalSource())
- PP.getPreprocessingRecord()->SetExternalSource(*this);
- StartingID
- = PP.getPreprocessingRecord()
- ->allocateLoadedEntities(F.NumPreprocessedEntities);
- F.BasePreprocessedEntityID = StartingID;
-
- if (F.NumPreprocessedEntities > 0) {
- // Introduce the global -> local mapping for preprocessed entities in
- // this module.
- GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F));
-
- // Introduce the local -> global mapping for preprocessed entities in
- // this module.
- F.PreprocessedEntityRemap.insertOrReplace(
- std::make_pair(LocalBasePreprocessedEntityID,
- F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
- }
-
- break;
- }
-
- case DECL_UPDATE_OFFSETS: {
- if (Record.size() % 2 != 0) {
- Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return true;
- }
- for (unsigned I = 0, N = Record.size(); I != N; I += 2)
- DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
- .push_back(std::make_pair(&F, Record[I+1]));
- break;
- }
-
- case DECL_REPLACEMENTS: {
- if (Record.size() % 3 != 0) {
- Error("invalid DECL_REPLACEMENTS block in AST file");
- return true;
- }
- for (unsigned I = 0, N = Record.size(); I != N; I += 3)
- ReplacedDecls[getGlobalDeclID(F, Record[I])]
- = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]);
- break;
- }
-
- case OBJC_CATEGORIES_MAP: {
- if (F.LocalNumObjCCategoriesInMap != 0) {
- Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return true;
- }
-
- F.LocalNumObjCCategoriesInMap = Record[0];
- F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart;
- break;
- }
-
- case OBJC_CATEGORIES:
- F.ObjCCategories.swap(Record);
- break;
-
- case CXX_BASE_SPECIFIER_OFFSETS: {
- if (F.LocalNumCXXBaseSpecifiers != 0) {
- Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
- return true;
- }
-
- F.LocalNumCXXBaseSpecifiers = Record[0];
- F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart;
- NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
- break;
- }
-
- case DIAG_PRAGMA_MAPPINGS:
- if (F.PragmaDiagMappings.empty())
- F.PragmaDiagMappings.swap(Record);
- else
- F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
- Record.begin(), Record.end());
- break;
-
- case CUDA_SPECIAL_DECL_REFS:
- // Later tables overwrite earlier ones.
- // FIXME: Modules will have trouble with this.
- CUDASpecialDeclRefs.clear();
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case HEADER_SEARCH_TABLE: {
- F.HeaderFileInfoTableData = BlobStart;
- F.LocalNumHeaderFileInfos = Record[1];
- F.HeaderFileFrameworkStrings = BlobStart + Record[2];
- if (Record[0]) {
- F.HeaderFileInfoTable
- = HeaderFileInfoLookupTable::Create(
- (const unsigned char *)F.HeaderFileInfoTableData + Record[0],
- (const unsigned char *)F.HeaderFileInfoTableData,
- HeaderFileInfoTrait(*this, F,
- &PP.getHeaderSearchInfo(),
- BlobStart + Record[2]));
-
- PP.getHeaderSearchInfo().SetExternalSource(this);
- if (!PP.getHeaderSearchInfo().getExternalLookup())
- PP.getHeaderSearchInfo().SetExternalLookup(this);
- }
- break;
- }
-
- case FP_PRAGMA_OPTIONS:
- // Later tables overwrite earlier ones.
- FPPragmaOptions.swap(Record);
- break;
-
- case OPENCL_EXTENSIONS:
- // Later tables overwrite earlier ones.
- OpenCLExtensions.swap(Record);
- break;
-
- case TENTATIVE_DEFINITIONS:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case KNOWN_NAMESPACES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
- break;
-
- case IMPORTED_MODULES: {
- if (F.Kind != MK_Module) {
- // If we aren't loading a module (which has its own exports), make
- // all of the imported modules visible.
- // FIXME: Deal with macros-only imports.
- for (unsigned I = 0, N = Record.size(); I != N; ++I) {
- if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I]))
- ImportedModules.push_back(GlobalID);
- }
- }
- break;
- }
-
- case LOCAL_REDECLARATIONS: {
- F.RedeclarationChains.swap(Record);
- break;
- }
-
- case LOCAL_REDECLARATIONS_MAP: {
- if (F.LocalNumRedeclarationsInMap != 0) {
- Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return true;
- }
-
- F.LocalNumRedeclarationsInMap = Record[0];
- F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
- break;
- }
-
- case MERGED_DECLARATIONS: {
- for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
- GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
- SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
- for (unsigned N = Record[Idx++]; N > 0; --N)
- Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
- }
- break;
- }
-
- case MACRO_OFFSET: {
- if (F.LocalNumMacros != 0) {
- Error("duplicate MACRO_OFFSET record in AST file");
- return true;
- }
- F.MacroOffsets = (const uint32_t *)BlobStart;
- 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 MACRO_UPDATES: {
- for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
- MacroID ID = getGlobalMacroID(F, Record[I++]);
- if (I == N)
- break;
-
- SourceLocation UndefLoc = ReadSourceLocation(F, Record, I);
- SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);;
- MacroUpdate Update;
- Update.UndefLoc = UndefLoc;
- MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update));
- }
- break;
- }
- }
- }
- Error("premature end of bitstream in AST file");
- return true;
-}
-
-void ASTReader::makeNamesVisible(const HiddenNames &Names) {
- for (unsigned I = 0, N = Names.size(); I != N; ++I) {
- switch (Names[I].getKind()) {
- case HiddenName::Declaration:
- Names[I].getDecl()->Hidden = false;
- break;
-
- case HiddenName::MacroVisibility: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- Macro.second->setHidden(!Macro.second->isPublic());
- if (Macro.second->isDefined()) {
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
- }
- break;
- }
-
- case HiddenName::MacroUndef: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- if (Macro.second->isDefined()) {
- Macro.second->setUndefLoc(Names[I].getMacroUndefLoc());
- if (PPMutationListener *Listener = PP.getPPMutationListener())
- Listener->UndefinedMacro(Macro.second);
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
- }
- break;
- }
- }
- }
-}
-
-void ASTReader::makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind NameVisibility) {
- llvm::SmallPtrSet<Module *, 4> Visited;
- llvm::SmallVector<Module *, 4> Stack;
- Stack.push_back(Mod);
- while (!Stack.empty()) {
- Mod = Stack.back();
- Stack.pop_back();
-
- 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()) {
- makeNamesVisible(Hidden->second);
- HiddenNamesMap.erase(Hidden);
- }
-
- // Push any non-explicit submodules onto the stack to be marked as
- // visible.
- for (Module::submodule_iterator Sub = Mod->submodule_begin(),
- SubEnd = Mod->submodule_end();
- Sub != SubEnd; ++Sub) {
- if (!(*Sub)->IsExplicit && Visited.insert(*Sub))
- Stack.push_back(*Sub);
- }
-
- // Push any exported modules onto the stack to be marked as visible.
- bool AnyWildcard = false;
- bool UnrestrictedWildcard = false;
- llvm::SmallVector<Module *, 4> WildcardRestrictions;
- for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
- Module *Exported = Mod->Exports[I].getPointer();
- if (!Mod->Exports[I].getInt()) {
- // Export a named module directly; no wildcards involved.
- if (Visited.insert(Exported))
- Stack.push_back(Exported);
-
- continue;
- }
-
- // Wildcard export: export all of the imported modules that match
- // the given pattern.
- AnyWildcard = true;
- if (UnrestrictedWildcard)
- continue;
-
- if (Module *Restriction = Mod->Exports[I].getPointer())
- WildcardRestrictions.push_back(Restriction);
- else {
- WildcardRestrictions.clear();
- UnrestrictedWildcard = true;
- }
- }
-
- // If there were any wildcards, push any imported modules that were
- // re-exported by the wildcard restriction.
- if (!AnyWildcard)
- continue;
-
- for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
- Module *Imported = Mod->Imports[I];
- if (!Visited.insert(Imported))
- continue;
-
- bool Acceptable = UnrestrictedWildcard;
- if (!Acceptable) {
- // Check whether this module meets one of the restrictions.
- for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
- Module *Restriction = WildcardRestrictions[R];
- if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
- Acceptable = true;
- break;
- }
- }
- }
-
- if (!Acceptable)
- continue;
-
- Stack.push_back(Imported);
- }
- }
-}
-
-ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
- ModuleKind Type,
- SourceLocation ImportLoc,
- unsigned ClientLoadCapabilities) {
- // Bump the generation number.
- unsigned PreviousGeneration = CurrentGeneration++;
-
- unsigned NumModules = ModuleMgr.size();
- llvm::SmallVector<ImportedModule, 4> Loaded;
- switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
- /*ImportedBy=*/0, Loaded,
- ClientLoadCapabilities)) {
- case Failure:
- case OutOfDate:
- case VersionMismatch:
- case ConfigurationMismatch:
- case HadErrors:
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
- 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 (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
- M != MEnd; ++M) {
- ModuleFile &F = *M->Mod;
-
- // Read the AST block.
- if (ReadASTBlock(F))
- return Failure;
-
- // Once read, set the ModuleFile bit base offset and update the size in
- // bits of all files we've seen.
- F.GlobalBitOffset = TotalModulesSizeInBits;
- TotalModulesSizeInBits += F.SizeInBits;
- GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
-
- // Preload SLocEntries.
- for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
- int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
- // Load it through the SourceManager and don't call ReadSLocEntry()
- // directly because the entry may have already been loaded in which case
- // calling ReadSLocEntry() directly would trigger an assertion in
- // SourceManager.
- SourceMgr.getLoadedSLocEntryByID(Index);
- }
- }
-
- // Setup the import locations.
- for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
- M != MEnd; ++M) {
- ModuleFile &F = *M->Mod;
- if (!M->ImportedBy)
- F.ImportLoc = M->ImportLoc;
- else
- F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
- M->ImportLoc.getRawEncoding());
- }
-
- // Mark all of the identifiers in the identifier table as being out of date,
- // so that various accessors know to check the loaded modules when the
- // identifier is used.
- for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
- IdEnd = PP.getIdentifierTable().end();
- Id != IdEnd; ++Id)
- Id->second->setOutOfDate(true);
-
- // Resolve any unresolved module exports.
- for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
- UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
- SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
- Module *ResolvedMod = getSubmodule(GlobalID);
-
- if (Unresolved.IsImport) {
- if (ResolvedMod)
- Unresolved.Mod->Imports.push_back(ResolvedMod);
- continue;
- }
-
- if (ResolvedMod || Unresolved.IsWildcard)
- Unresolved.Mod->Exports.push_back(
- Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
- }
- UnresolvedModuleImportExports.clear();
-
- InitializeContext();
-
- if (DeserializationListener)
- DeserializationListener->ReaderInitialized(this);
-
- ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
- if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
- PrimaryModule.OriginalSourceFileID
- = FileID::get(PrimaryModule.SLocEntryBaseID
- + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
-
- // If this AST file is a precompiled preamble, then set the
- // preamble file ID of the source manager to the file source file
- // from which the preamble was built.
- if (Type == MK_Preamble) {
- SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
- } else if (Type == MK_MainFile) {
- SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
- }
- }
-
- // For any Objective-C class definitions we have already loaded, make sure
- // that we load any additional categories.
- for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
- loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
- ObjCClassesLoaded[I],
- PreviousGeneration);
- }
-
- return Success;
-}
-
-ASTReader::ASTReadResult
-ASTReader::ReadASTCore(StringRef FileName,
- ModuleKind Type,
- SourceLocation ImportLoc,
- ModuleFile *ImportedBy,
- llvm::SmallVectorImpl<ImportedModule> &Loaded,
- unsigned ClientLoadCapabilities) {
- ModuleFile *M;
- bool NewModule;
- std::string ErrorStr;
- llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc,
- ImportedBy, CurrentGeneration,
- ErrorStr);
-
- if (!M) {
- // We couldn't load the module.
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- return Failure;
- }
-
- if (!NewModule) {
- // We've already loaded this module.
- return Success;
- }
-
- // FIXME: This seems rather a hack. Should CurrentDir be part of the
- // module?
- if (FileName != "-") {
- CurrentDir = llvm::sys::path::parent_path(FileName);
- if (CurrentDir.empty()) CurrentDir = ".";
- }
-
- ModuleFile &F = *M;
- llvm::BitstreamCursor &Stream = F.Stream;
- Stream.init(F.StreamFile);
- F.SizeInBits = F.Buffer->getBufferSize() * 8;
-
- // Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
- Diag(diag::err_not_a_pch_file) << FileName;
- return Failure;
- }
-
- // This is used for compatibility with older PCH formats.
- bool HaveReadControlBlock = false;
-
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code != llvm::bitc::ENTER_SUBBLOCK) {
- Error("invalid record at top-level of AST file");
- return Failure;
- }
-
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the control subblock ID.
- switch (BlockID) {
- case llvm::bitc::BLOCKINFO_BLOCK_ID:
- if (Stream.ReadBlockInfoBlock()) {
- Error("malformed BlockInfoBlock in AST file");
- return Failure;
- }
- break;
- case CONTROL_BLOCK_ID:
- HaveReadControlBlock = true;
- switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
- case Success:
- break;
-
- case Failure: return Failure;
- 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::warn_pch_version_too_old);
- return VersionMismatch;
- }
-
- // Record that we've loaded this module.
- Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
- return Success;
-
- default:
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return Failure;
- }
- break;
- }
- }
-
- return Success;
-}
-
-void ASTReader::InitializeContext() {
- // If there's a listener, notify them that we "read" the translation unit.
- if (DeserializationListener)
- DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
- Context.getTranslationUnitDecl());
-
- // Make sure we load the declaration update records for the translation unit,
- // if there are any.
- loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
- Context.getTranslationUnitDecl());
-
- // FIXME: Find a better way to deal with collisions between these
- // built-in types. Right now, we just ignore the problem.
-
- // Load the special types.
- if (SpecialTypes.size() >= NumSpecialTypeIDs) {
- if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
- if (!Context.CFConstantStringTypeDecl)
- Context.setCFConstantStringType(GetType(String));
- }
-
- if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
- QualType FileType = GetType(File);
- if (FileType.isNull()) {
- Error("FILE type is NULL");
- return;
- }
-
- if (!Context.FILEDecl) {
- if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
- Context.setFILEDecl(Typedef->getDecl());
- else {
- const TagType *Tag = FileType->getAs<TagType>();
- if (!Tag) {
- Error("Invalid FILE type in AST file");
- return;
- }
- Context.setFILEDecl(Tag->getDecl());
- }
- }
- }
-
- if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) {
- QualType Jmp_bufType = GetType(Jmp_buf);
- if (Jmp_bufType.isNull()) {
- Error("jmp_buf type is NULL");
- return;
- }
-
- if (!Context.jmp_bufDecl) {
- if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
- Context.setjmp_bufDecl(Typedef->getDecl());
- else {
- const TagType *Tag = Jmp_bufType->getAs<TagType>();
- if (!Tag) {
- Error("Invalid jmp_buf type in AST file");
- return;
- }
- Context.setjmp_bufDecl(Tag->getDecl());
- }
- }
- }
-
- if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) {
- QualType Sigjmp_bufType = GetType(Sigjmp_buf);
- if (Sigjmp_bufType.isNull()) {
- Error("sigjmp_buf type is NULL");
- return;
- }
-
- if (!Context.sigjmp_bufDecl) {
- if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
- Context.setsigjmp_bufDecl(Typedef->getDecl());
- else {
- const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
- assert(Tag && "Invalid sigjmp_buf type in AST file");
- Context.setsigjmp_bufDecl(Tag->getDecl());
- }
- }
- }
-
- if (unsigned ObjCIdRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) {
- if (Context.ObjCIdRedefinitionType.isNull())
- Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef);
- }
-
- if (unsigned ObjCClassRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) {
- if (Context.ObjCClassRedefinitionType.isNull())
- Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef);
- }
-
- if (unsigned ObjCSelRedef
- = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) {
- if (Context.ObjCSelRedefinitionType.isNull())
- Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
- }
-
- if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) {
- QualType Ucontext_tType = GetType(Ucontext_t);
- if (Ucontext_tType.isNull()) {
- Error("ucontext_t type is NULL");
- return;
- }
-
- if (!Context.ucontext_tDecl) {
- if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>())
- Context.setucontext_tDecl(Typedef->getDecl());
- else {
- const TagType *Tag = Ucontext_tType->getAs<TagType>();
- assert(Tag && "Invalid ucontext_t type in AST file");
- Context.setucontext_tDecl(Tag->getDecl());
- }
- }
- }
- }
-
- ReadPragmaDiagnosticMappings(Context.getDiagnostics());
-
- // If there were any CUDA special declarations, deserialize them.
- if (!CUDASpecialDeclRefs.empty()) {
- assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!");
- Context.setcudaConfigureCallDecl(
- cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
- }
-
- // Re-export any modules that were imported by a non-module AST file.
- for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
- if (Module *Imported = getSubmodule(ImportedModules[I]))
- makeModuleVisible(Imported, Module::AllVisible);
- }
- ImportedModules.clear();
-}
-
-void ASTReader::finalizeForWriting() {
- for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
- HiddenEnd = HiddenNamesMap.end();
- Hidden != HiddenEnd; ++Hidden) {
- makeNamesVisible(Hidden->second);
- }
- HiddenNamesMap.clear();
-}
-
-/// \brief Retrieve the name of the original source file name
-/// directly from the AST file, without actually loading the AST
-/// file.
-std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
- FileManager &FileMgr,
- DiagnosticsEngine &Diags) {
- // Open the AST file.
- std::string ErrStr;
- OwningPtr<llvm::MemoryBuffer> Buffer;
- Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
- if (!Buffer) {
- Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr;
- return std::string();
- }
-
- // Initialize the stream
- llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
- Stream.init(StreamFile);
-
- // Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
- Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
- return std::string();
- }
-
- RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the AST subblock ID.
- switch (BlockID) {
- case CONTROL_BLOCK_ID:
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
-
- default:
- if (Stream.SkipBlock()) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
- }
- continue;
- }
-
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName;
- return std::string();
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
- }
-
- Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
- return std::string(BlobStart, BlobLen);
- }
-
- return std::string();
-}
-
-namespace {
- class SimplePCHValidator : public ASTReaderListener {
- const LangOptions &ExistingLangOpts;
- const TargetOptions &ExistingTargetOpts;
- const PreprocessorOptions &ExistingPPOpts;
- FileManager &FileMgr;
-
- public:
- SimplePCHValidator(const LangOptions &ExistingLangOpts,
- const TargetOptions &ExistingTargetOpts,
- const PreprocessorOptions &ExistingPPOpts,
- FileManager &FileMgr)
- : ExistingLangOpts(ExistingLangOpts),
- ExistingTargetOpts(ExistingTargetOpts),
- ExistingPPOpts(ExistingPPOpts),
- FileMgr(FileMgr)
- {
- }
-
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
- return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
- }
- virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
- return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
- }
- virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
- bool Complain,
- std::string &SuggestedPredefines) {
- return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
- SuggestedPredefines);
- }
- };
-}
-
-bool ASTReader::readASTFileControlBlock(StringRef Filename,
- FileManager &FileMgr,
- ASTReaderListener &Listener) {
- // Open the AST file.
- std::string ErrStr;
- OwningPtr<llvm::MemoryBuffer> Buffer;
- Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
- if (!Buffer) {
- return true;
- }
-
- // Initialize the stream
- llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
- Stream.init(StreamFile);
-
- // Sniff for the signature.
- if (Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'P' ||
- Stream.Read(8) != 'C' ||
- Stream.Read(8) != 'H') {
- return true;
- }
-
- RecordData Record;
- bool InControlBlock = false;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the control subblock ID.
- switch (BlockID) {
- case CONTROL_BLOCK_ID:
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- return true;
- } else {
- InControlBlock = true;
- }
- break;
-
- default:
- if (Stream.SkipBlock())
- return true;
- break;
- }
- continue;
- }
-
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- return true;
- }
-
- InControlBlock = false;
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
- }
-
- Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
- if (InControlBlock) {
- switch ((ControlRecordTypes)RecCode) {
- case METADATA: {
- if (Record[0] != VERSION_MAJOR) {
- return true;
- }
-
- const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
- if (StringRef(CurBranch) != ASTBranch)
- return true;
-
- break;
- }
- case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record, false, Listener))
- return true;
- break;
-
- case TARGET_OPTIONS:
- if (ParseTargetOptions(Record, false, Listener))
- return true;
- break;
-
- case DIAGNOSTIC_OPTIONS:
- if (ParseDiagnosticOptions(Record, false, Listener))
- return true;
- break;
-
- case FILE_SYSTEM_OPTIONS:
- if (ParseFileSystemOptions(Record, false, Listener))
- return true;
- break;
-
- case HEADER_SEARCH_OPTIONS:
- if (ParseHeaderSearchOptions(Record, false, Listener))
- return true;
- break;
-
- case PREPROCESSOR_OPTIONS: {
- std::string IgnoredSuggestedPredefines;
- if (ParsePreprocessorOptions(Record, false, Listener,
- IgnoredSuggestedPredefines))
- return true;
- break;
- }
-
- default:
- // No other validation to perform.
- break;
- }
- }
- }
-
- return false;
-}
-
-
-bool ASTReader::isAcceptableASTFile(StringRef Filename,
- FileManager &FileMgr,
- const LangOptions &LangOpts,
- const TargetOptions &TargetOpts,
- const PreprocessorOptions &PPOpts) {
- SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr);
- return !readASTFileControlBlock(Filename, FileMgr, validator);
-}
-
-bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
- // Enter the submodule block.
- if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
- Error("malformed submodule block record in AST file");
- return true;
- }
-
- ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
- bool First = true;
- Module *CurrentModule = 0;
- RecordData Record;
- while (true) {
- unsigned Code = F.Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (F.Stream.ReadBlockEnd()) {
- Error("error at end of submodule block in AST file");
- return true;
- }
- return false;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- F.Stream.ReadSubBlockID();
- if (F.Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- F.Stream.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- const char *BlobStart;
- unsigned BlobLen;
- Record.clear();
- switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case SUBMODULE_DEFINITION: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (Record.size() < 7) {
- Error("malformed module definition");
- return true;
- }
-
- StringRef Name(BlobStart, BlobLen);
- SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
- SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
- bool IsFramework = Record[2];
- bool IsExplicit = Record[3];
- bool IsSystem = Record[4];
- bool InferSubmodules = Record[5];
- bool InferExplicitSubmodules = Record[6];
- bool InferExportWildcard = Record[7];
-
- Module *ParentModule = 0;
- if (Parent)
- ParentModule = getSubmodule(Parent);
-
- // Retrieve this (sub)module from the module map, creating it if
- // necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
- IsFramework,
- IsExplicit).first;
- SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
- if (GlobalIndex >= SubmodulesLoaded.size() ||
- SubmodulesLoaded[GlobalIndex]) {
- Error("too many submodules");
- return true;
- }
-
- CurrentModule->setASTFile(F.File);
- CurrentModule->IsFromModuleFile = true;
- CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
- CurrentModule->InferSubmodules = InferSubmodules;
- CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
- CurrentModule->InferExportWildcard = InferExportWildcard;
- if (DeserializationListener)
- DeserializationListener->ModuleRead(GlobalID, CurrentModule);
-
- SubmodulesLoaded[GlobalIndex] = CurrentModule;
- break;
- }
-
- case SUBMODULE_UMBRELLA_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
- if (!CurrentModule->getUmbrellaHeader())
- ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
- else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
- Error("mismatched umbrella headers in submodule");
- return true;
- }
- }
- break;
- }
-
- case SUBMODULE_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
- if (std::find(CurrentModule->Headers.begin(),
- CurrentModule->Headers.end(),
- File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File, false);
- }
- break;
- }
-
- case SUBMODULE_EXCLUDED_HEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
- if (std::find(CurrentModule->Headers.begin(),
- CurrentModule->Headers.end(),
- File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File, true);
- }
- break;
- }
-
- case SUBMODULE_TOPHEADER: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- // FIXME: Be more lazy about this!
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *File = PP.getFileManager().getFile(FileName))
- CurrentModule->TopHeaders.insert(File);
- break;
- }
-
- case SUBMODULE_UMBRELLA_DIR: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- StringRef DirName(BlobStart, BlobLen);
- if (const DirectoryEntry *Umbrella
- = PP.getFileManager().getDirectory(DirName)) {
- if (!CurrentModule->getUmbrellaDir())
- ModMap.setUmbrellaDir(CurrentModule, Umbrella);
- else if (CurrentModule->getUmbrellaDir() != Umbrella) {
- Error("mismatched umbrella directories in submodule");
- return true;
- }
- }
- break;
- }
-
- case SUBMODULE_METADATA: {
- if (!First) {
- Error("submodule metadata record not at beginning of block");
- return true;
- }
- First = false;
-
- F.BaseSubmoduleID = getTotalNumSubmodules();
- F.LocalNumSubmodules = Record[0];
- unsigned LocalBaseSubmoduleID = Record[1];
- if (F.LocalNumSubmodules > 0) {
- // Introduce the global -> local mapping for submodules within this
- // module.
- GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F));
-
- // Introduce the local -> global mapping for submodules within this
- // module.
- F.SubmoduleRemap.insertOrReplace(
- std::make_pair(LocalBaseSubmoduleID,
- F.BaseSubmoduleID - LocalBaseSubmoduleID));
-
- SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
- }
- break;
- }
-
- case SUBMODULE_IMPORTS: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
- UnresolvedModuleImportExport Unresolved;
- Unresolved.File = &F;
- Unresolved.Mod = CurrentModule;
- Unresolved.ID = Record[Idx];
- Unresolved.IsImport = true;
- Unresolved.IsWildcard = false;
- UnresolvedModuleImportExports.push_back(Unresolved);
- }
- break;
- }
-
- case SUBMODULE_EXPORTS: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
- UnresolvedModuleImportExport Unresolved;
- Unresolved.File = &F;
- Unresolved.Mod = CurrentModule;
- Unresolved.ID = Record[Idx];
- Unresolved.IsImport = false;
- Unresolved.IsWildcard = Record[Idx + 1];
- UnresolvedModuleImportExports.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: {
- if (First) {
- Error("missing submodule metadata record at beginning of block");
- return true;
- }
-
- if (!CurrentModule)
- break;
-
- CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
- Context.getLangOpts(),
- Context.getTargetInfo());
- break;
- }
- }
- }
-}
-
-/// \brief Parse the record that corresponds to a LangOptions data
-/// structure.
-///
-/// This routine parses the language options from the AST file and then gives
-/// them to the AST listener if one is set.
-///
-/// \returns true if the listener deems the file unacceptable, false otherwise.
-bool ASTReader::ParseLanguageOptions(const RecordData &Record,
- bool Complain,
- ASTReaderListener &Listener) {
- 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"
-
- ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
- VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
- LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
-
- unsigned Length = Record[Idx++];
- LangOpts.CurrentModule.assign(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- return Listener.ReadLanguageOptions(LangOpts, Complain);
-}
-
-bool ASTReader::ParseTargetOptions(const RecordData &Record,
- bool Complain,
- ASTReaderListener &Listener) {
- unsigned Idx = 0;
- TargetOptions TargetOpts;
- TargetOpts.Triple = ReadString(Record, Idx);
- TargetOpts.CPU = ReadString(Record, Idx);
- TargetOpts.ABI = ReadString(Record, Idx);
- TargetOpts.CXXABI = ReadString(Record, Idx);
- TargetOpts.LinkerVersion = ReadString(Record, Idx);
- for (unsigned N = Record[Idx++]; N; --N) {
- TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
- }
- for (unsigned N = Record[Idx++]; N; --N) {
- TargetOpts.Features.push_back(ReadString(Record, Idx));
- }
-
- return Listener.ReadTargetOptions(TargetOpts, Complain);
-}
-
-bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
- ASTReaderListener &Listener) {
- DiagnosticOptions DiagOpts;
- unsigned Idx = 0;
-#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
- DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
-#include "clang/Basic/DiagnosticOptions.def"
-
- for (unsigned N = Record[Idx++]; N; --N) {
- DiagOpts.Warnings.push_back(ReadString(Record, Idx));
- }
-
- return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
-}
-
-bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
- ASTReaderListener &Listener) {
- FileSystemOptions FSOpts;
- unsigned Idx = 0;
- FSOpts.WorkingDir = ReadString(Record, Idx);
- return Listener.ReadFileSystemOptions(FSOpts, Complain);
-}
-
-bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
- bool Complain,
- ASTReaderListener &Listener) {
- HeaderSearchOptions HSOpts;
- unsigned Idx = 0;
- HSOpts.Sysroot = ReadString(Record, Idx);
-
- // Include entries.
- for (unsigned N = Record[Idx++]; N; --N) {
- std::string Path = ReadString(Record, Idx);
- frontend::IncludeDirGroup Group
- = static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
- bool IsUserSupplied = Record[Idx++];
- bool IsFramework = Record[Idx++];
- bool IgnoreSysRoot = Record[Idx++];
- bool IsInternal = Record[Idx++];
- bool ImplicitExternC = Record[Idx++];
- HSOpts.UserEntries.push_back(
- HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework,
- IgnoreSysRoot, IsInternal, ImplicitExternC));
- }
-
- // System header prefixes.
- for (unsigned N = Record[Idx++]; N; --N) {
- std::string Prefix = ReadString(Record, Idx);
- bool IsSystemHeader = Record[Idx++];
- HSOpts.SystemHeaderPrefixes.push_back(
- HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader));
- }
-
- HSOpts.ResourceDir = ReadString(Record, Idx);
- HSOpts.ModuleCachePath = ReadString(Record, Idx);
- HSOpts.DisableModuleHash = Record[Idx++];
- HSOpts.UseBuiltinIncludes = Record[Idx++];
- HSOpts.UseStandardSystemIncludes = Record[Idx++];
- HSOpts.UseStandardCXXIncludes = Record[Idx++];
- HSOpts.UseLibcxx = Record[Idx++];
-
- return Listener.ReadHeaderSearchOptions(HSOpts, Complain);
-}
-
-bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
- bool Complain,
- ASTReaderListener &Listener,
- std::string &SuggestedPredefines) {
- PreprocessorOptions PPOpts;
- unsigned Idx = 0;
-
- // Macro definitions/undefs
- for (unsigned N = Record[Idx++]; N; --N) {
- std::string Macro = ReadString(Record, Idx);
- bool IsUndef = Record[Idx++];
- PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
- }
-
- // Includes
- for (unsigned N = Record[Idx++]; N; --N) {
- PPOpts.Includes.push_back(ReadString(Record, Idx));
- }
-
- // Macro Includes
- for (unsigned N = Record[Idx++]; N; --N) {
- PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
- }
-
- PPOpts.UsePredefines = Record[Idx++];
- PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
- PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
- PPOpts.ObjCXXARCStandardLibrary =
- static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
- SuggestedPredefines.clear();
- return Listener.ReadPreprocessorOptions(PPOpts, Complain,
- SuggestedPredefines);
-}
-
-std::pair<ModuleFile *, unsigned>
-ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
- GlobalPreprocessedEntityMapType::iterator
- I = GlobalPreprocessedEntityMap.find(GlobalIndex);
- assert(I != GlobalPreprocessedEntityMap.end() &&
- "Corrupted global preprocessed entity map");
- ModuleFile *M = I->second;
- unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID;
- return std::make_pair(M, LocalIndex);
-}
-
-std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
-ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
- if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
- return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
- Mod.NumPreprocessedEntities);
-
- return std::make_pair(PreprocessingRecord::iterator(),
- PreprocessingRecord::iterator());
-}
-
-std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator>
-ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
- return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
- ModuleDeclIterator(this, &Mod,
- Mod.FileSortedDecls + Mod.NumFileSortedDecls));
-}
-
-PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
- PreprocessedEntityID PPID = Index+1;
- std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
- ModuleFile &M = *PPInfo.first;
- unsigned LocalIndex = PPInfo.second;
- const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
-
- SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
- M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
-
- unsigned Code = M.PreprocessorDetailCursor.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return 0;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- Error("unexpected subblock record in preprocessor detail block");
- return 0;
-
- case llvm::bitc::DEFINE_ABBREV:
- Error("unexpected abbrevation record in preprocessor detail block");
- return 0;
-
- default:
- break;
- }
-
- if (!PP.getPreprocessingRecord()) {
- Error("no preprocessing record");
- return 0;
- }
-
- // Read the record.
- SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
- ReadSourceLocation(M, PPOffs.End));
- PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- RecordData Record;
- PreprocessorDetailRecordTypes RecType =
- (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord(
- Code, Record, BlobStart, BlobLen);
- switch (RecType) {
- case PPD_MACRO_EXPANSION: {
- bool isBuiltin = Record[0];
- IdentifierInfo *Name = 0;
- MacroDefinition *Def = 0;
- if (isBuiltin)
- Name = getLocalIdentifier(M, Record[1]);
- else {
- PreprocessedEntityID
- GlobalID = getGlobalPreprocessedEntityID(M, Record[1]);
- Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1));
- }
-
- MacroExpansion *ME;
- if (isBuiltin)
- ME = new (PPRec) MacroExpansion(Name, Range);
- else
- ME = new (PPRec) MacroExpansion(Def, Range);
-
- return ME;
- }
-
- case PPD_MACRO_DEFINITION: {
- // Decode the identifier info and then check again; if the macro is
- // still defined and associated with the identifier,
- IdentifierInfo *II = getLocalIdentifier(M, Record[0]);
- MacroDefinition *MD
- = new (PPRec) MacroDefinition(II, Range);
-
- if (DeserializationListener)
- DeserializationListener->MacroDefinitionRead(PPID, MD);
-
- return MD;
- }
-
- case PPD_INCLUSION_DIRECTIVE: {
- const char *FullFileNameStart = BlobStart + Record[0];
- StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]);
- const FileEntry *File = 0;
- if (!FullFileName.empty())
- File = PP.getFileManager().getFile(FullFileName);
-
- // FIXME: Stable encoding
- InclusionDirective::InclusionKind Kind
- = static_cast<InclusionDirective::InclusionKind>(Record[2]);
- InclusionDirective *ID
- = new (PPRec) InclusionDirective(PPRec, Kind,
- StringRef(BlobStart, Record[0]),
- Record[1], Record[3],
- File,
- Range);
- return ID;
- }
- }
-
- llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
-}
-
-/// \brief \arg SLocMapI points at a chunk of a module that contains no
-/// preprocessed entities or the entities it contains are not the ones we are
-/// looking for. Find the next module that contains entities and return the ID
-/// of the first entry.
-PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
- GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
- ++SLocMapI;
- for (GlobalSLocOffsetMapType::const_iterator
- EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
- ModuleFile &M = *SLocMapI->second;
- if (M.NumPreprocessedEntities)
- return M.BasePreprocessedEntityID;
- }
-
- return getTotalNumPreprocessedEntities();
-}
-
-namespace {
-
-template <unsigned PPEntityOffset::*PPLoc>
-struct PPEntityComp {
- const ASTReader &Reader;
- ModuleFile &M;
-
- PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { }
-
- bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
- SourceLocation LHS = getLoc(L);
- SourceLocation RHS = getLoc(R);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- bool operator()(const PPEntityOffset &L, SourceLocation RHS) const {
- SourceLocation LHS = getLoc(L);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- bool operator()(SourceLocation LHS, const PPEntityOffset &R) const {
- SourceLocation RHS = getLoc(R);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- SourceLocation getLoc(const PPEntityOffset &PPE) const {
- return Reader.ReadSourceLocation(M, PPE.*PPLoc);
- }
-};
-
-}
-
-/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
-PreprocessedEntityID
-ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
- if (SourceMgr.isLocalSourceLocation(BLoc))
- return getTotalNumPreprocessedEntities();
-
- GlobalSLocOffsetMapType::const_iterator
- SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- BLoc.getOffset());
- assert(SLocMapI != GlobalSLocOffsetMap.end() &&
- "Corrupted global sloc offset map");
-
- if (SLocMapI->second->NumPreprocessedEntities == 0)
- return findNextPreprocessedEntity(SLocMapI);
-
- ModuleFile &M = *SLocMapI->second;
- typedef const PPEntityOffset *pp_iterator;
- pp_iterator pp_begin = M.PreprocessedEntityOffsets;
- pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
-
- size_t Count = M.NumPreprocessedEntities;
- size_t Half;
- pp_iterator First = pp_begin;
- pp_iterator PPI;
-
- // Do a binary search manually instead of using std::lower_bound because
- // The end locations of entities may be unordered (when a macro expansion
- // is inside another macro argument), but for this case it is not important
- // whether we get the first macro expansion or its containing macro.
- while (Count > 0) {
- Half = Count/2;
- PPI = First;
- std::advance(PPI, Half);
- if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
- BLoc)){
- First = PPI;
- ++First;
- Count = Count - Half - 1;
- } else
- Count = Half;
- }
-
- if (PPI == pp_end)
- return findNextPreprocessedEntity(SLocMapI);
-
- return M.BasePreprocessedEntityID + (PPI - pp_begin);
-}
-
-/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
-PreprocessedEntityID
-ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
- if (SourceMgr.isLocalSourceLocation(ELoc))
- return getTotalNumPreprocessedEntities();
-
- GlobalSLocOffsetMapType::const_iterator
- SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- ELoc.getOffset());
- assert(SLocMapI != GlobalSLocOffsetMap.end() &&
- "Corrupted global sloc offset map");
-
- if (SLocMapI->second->NumPreprocessedEntities == 0)
- return findNextPreprocessedEntity(SLocMapI);
-
- ModuleFile &M = *SLocMapI->second;
- typedef const PPEntityOffset *pp_iterator;
- pp_iterator pp_begin = M.PreprocessedEntityOffsets;
- pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
- pp_iterator PPI =
- std::upper_bound(pp_begin, pp_end, ELoc,
- PPEntityComp<&PPEntityOffset::Begin>(*this, M));
-
- if (PPI == pp_end)
- return findNextPreprocessedEntity(SLocMapI);
-
- return M.BasePreprocessedEntityID + (PPI - pp_begin);
-}
-
-/// \brief Returns a pair of [Begin, End) indices of preallocated
-/// preprocessed entities that \arg Range encompasses.
-std::pair<unsigned, unsigned>
- ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) {
- if (Range.isInvalid())
- return std::make_pair(0,0);
- assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
-
- PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin());
- PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd());
- return std::make_pair(BeginID, EndID);
-}
-
-/// \brief Optionally returns true or false if the preallocated preprocessed
-/// entity with index \arg Index came from file \arg FID.
-llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
- FileID FID) {
- if (FID.isInvalid())
- return false;
-
- std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
- ModuleFile &M = *PPInfo.first;
- unsigned LocalIndex = PPInfo.second;
- const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
-
- SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin);
- if (Loc.isInvalid())
- return false;
-
- if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID))
- return true;
- else
- return false;
-}
-
-namespace {
- /// \brief Visitor used to search for information about a header file.
- class HeaderFileInfoVisitor {
- ASTReader &Reader;
- const FileEntry *FE;
-
- llvm::Optional<HeaderFileInfo> HFI;
-
- public:
- HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
- : Reader(Reader), FE(FE) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- HeaderFileInfoVisitor *This
- = static_cast<HeaderFileInfoVisitor *>(UserData);
-
- HeaderFileInfoTrait Trait(This->Reader, M,
- &This->Reader.getPreprocessor().getHeaderSearchInfo(),
- M.HeaderFileFrameworkStrings,
- This->FE->getName());
-
- HeaderFileInfoLookupTable *Table
- = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
- if (!Table)
- return false;
-
- // Look in the on-disk hash table for an entry for this file name.
- HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
- &Trait);
- if (Pos == Table->end())
- return false;
-
- This->HFI = *Pos;
- return true;
- }
-
- llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
- };
-}
-
-HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
- HeaderFileInfoVisitor Visitor(*this, FE);
- ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
- if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
- if (Listener)
- Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
- return *HFI;
- }
-
- return HeaderFileInfo();
-}
-
-void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
- llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
- for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
- ModuleFile &F = *(*I);
- unsigned Idx = 0;
- DiagStates.clear();
- assert(!Diag.DiagStates.empty());
- DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
- while (Idx < F.PragmaDiagMappings.size()) {
- SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
- unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
- if (DiagStateID != 0) {
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
- FullSourceLoc(Loc, SourceMgr)));
- continue;
- }
-
- assert(DiagStateID == 0);
- // A new DiagState was created here.
- Diag.DiagStates.push_back(*Diag.GetCurDiagState());
- DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
- DiagStates.push_back(NewState);
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(NewState,
- FullSourceLoc(Loc, SourceMgr)));
- while (1) {
- assert(Idx < F.PragmaDiagMappings.size() &&
- "Invalid data, didn't find '-1' marking end of diag/map pairs");
- if (Idx >= F.PragmaDiagMappings.size()) {
- break; // Something is messed up but at least avoid infinite loop in
- // release build.
- }
- unsigned DiagID = F.PragmaDiagMappings[Idx++];
- if (DiagID == (unsigned)-1) {
- break; // no more diag/map pairs for this location.
- }
- diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
- DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc);
- Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo);
- }
- }
- }
-}
-
-/// \brief Get the correct cursor and offset for loading a type.
-ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
- GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
- assert(I != GlobalTypeMap.end() && "Corrupted global type map");
- ModuleFile *M = I->second;
- return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
-}
-
-/// \brief Read and return the type with the given index..
-///
-/// The index is the type ID, shifted and minus the number of predefs. This
-/// routine actually reads the record corresponding to the type at the given
-/// location. It is a helper routine for GetType, which deals with reading type
-/// IDs.
-QualType ASTReader::readTypeRecord(unsigned Index) {
- RecordLocation Loc = TypeCursorForIndex(Index);
- llvm::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_BLOCK_POINTER: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of block pointer type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getBlockPointerType(PointeeType);
- }
-
- case TYPE_LVALUE_REFERENCE: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of lvalue reference type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getLValueReferenceType(PointeeType, Record[1]);
- }
-
- case TYPE_RVALUE_REFERENCE: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of rvalue reference type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- return Context.getRValueReferenceType(PointeeType);
- }
-
- case TYPE_MEMBER_POINTER: {
- if (Record.size() != 2) {
- Error("Incorrect encoding of member pointer type");
- return QualType();
- }
- QualType PointeeType = readType(*Loc.F, Record, Idx);
- QualType ClassType = readType(*Loc.F, Record, Idx);
- if (PointeeType.isNull() || ClassType.isNull())
- return QualType();
-
- return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
- }
-
- case TYPE_CONSTANT_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- unsigned Idx = 3;
- llvm::APInt Size = ReadAPInt(Record, Idx);
- return Context.getConstantArrayType(ElementType, Size,
- ASM, IndexTypeQuals);
- }
-
- case TYPE_INCOMPLETE_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
- }
-
- case TYPE_VARIABLE_ARRAY: {
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
- unsigned IndexTypeQuals = Record[2];
- SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
- SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
- return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
- ASM, IndexTypeQuals,
- SourceRange(LBLoc, RBLoc));
- }
-
- case TYPE_VECTOR: {
- if (Record.size() != 3) {
- Error("incorrect encoding of vector type in AST file");
- return QualType();
- }
-
- QualType ElementType = readType(*Loc.F, Record, Idx);
- unsigned NumElements = Record[1];
- unsigned VecKind = Record[2];
- return Context.getVectorType(ElementType, NumElements,
- (VectorType::VectorKind)VecKind);
- }
-
- case TYPE_EXT_VECTOR: {
- if (Record.size() != 3) {
- Error("incorrect encoding of extended vector type in AST file");
- return QualType();
- }
-
- QualType ElementType = readType(*Loc.F, Record, Idx);
- unsigned NumElements = Record[1];
- return Context.getExtVectorType(ElementType, NumElements);
- }
-
- case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 6) {
- Error("incorrect encoding of no-proto function type");
- return QualType();
- }
- QualType ResultType = readType(*Loc.F, Record, Idx);
- FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
- (CallingConv)Record[4], Record[5]);
- return Context.getFunctionNoProtoType(ResultType, Info);
- }
-
- case TYPE_FUNCTION_PROTO: {
- QualType ResultType = readType(*Loc.F, Record, Idx);
-
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
- /*hasregparm*/ Record[2],
- /*regparm*/ Record[3],
- static_cast<CallingConv>(Record[4]),
- /*produces*/ Record[5]);
-
- unsigned Idx = 6;
- unsigned NumParams = Record[Idx++];
- SmallVector<QualType, 16> ParamTypes;
- for (unsigned I = 0; I != NumParams; ++I)
- ParamTypes.push_back(readType(*Loc.F, Record, Idx));
-
- EPI.Variadic = Record[Idx++];
- EPI.HasTrailingReturn = Record[Idx++];
- EPI.TypeQuals = Record[Idx++];
- EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
- ExceptionSpecificationType EST =
- static_cast<ExceptionSpecificationType>(Record[Idx++]);
- EPI.ExceptionSpecType = EST;
- SmallVector<QualType, 2> Exceptions;
- if (EST == EST_Dynamic) {
- EPI.NumExceptions = Record[Idx++];
- for (unsigned I = 0; I != EPI.NumExceptions; ++I)
- Exceptions.push_back(readType(*Loc.F, Record, Idx));
- EPI.Exceptions = Exceptions.data();
- } else if (EST == EST_ComputedNoexcept) {
- EPI.NoexceptExpr = ReadExpr(*Loc.F);
- } else if (EST == EST_Uninstantiated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- } else if (EST == EST_Unevaluated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- }
- return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
- 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:
- return Context.getAutoType(readType(*Loc.F, Record, Idx));
-
- 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();
- llvm::Optional<unsigned> NumExpansions;
- if (Record[1])
- NumExpansions = Record[1] - 1;
- return Context.getPackExpansionType(Pattern, NumExpansions);
- }
-
- case TYPE_ELABORATED: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- QualType NamedType = readType(*Loc.F, Record, Idx);
- return Context.getElaboratedType(Keyword, NNS, NamedType);
- }
-
- case TYPE_OBJC_INTERFACE: {
- unsigned Idx = 0;
- ObjCInterfaceDecl *ItfD
- = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
- return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
- }
-
- case TYPE_OBJC_OBJECT: {
- unsigned Idx = 0;
- QualType Base = readType(*Loc.F, Record, Idx);
- unsigned NumProtos = Record[Idx++];
- SmallVector<ObjCProtocolDecl*, 4> Protos;
- for (unsigned I = 0; I != NumProtos; ++I)
- Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
- return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
- }
-
- case TYPE_OBJC_OBJECT_POINTER: {
- unsigned Idx = 0;
- QualType Pointee = readType(*Loc.F, Record, Idx);
- return Context.getObjCObjectPointerType(Pointee);
- }
-
- case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
- unsigned Idx = 0;
- QualType Parm = readType(*Loc.F, Record, Idx);
- QualType Replacement = readType(*Loc.F, Record, Idx);
- return
- Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
- 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.
- return
- QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
- }
-
- case TYPE_TEMPLATE_TYPE_PARM: {
- unsigned Idx = 0;
- unsigned Depth = Record[Idx++];
- unsigned Index = Record[Idx++];
- bool Pack = Record[Idx++];
- TemplateTypeParmDecl *D
- = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
- return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
- }
-
- case TYPE_DEPENDENT_NAME: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
- QualType Canon = readType(*Loc.F, Record, Idx);
- if (!Canon.isNull())
- Canon = Context.getCanonicalType(Canon);
- return Context.getDependentNameType(Keyword, NNS, Name, Canon);
- }
-
- case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
- unsigned Idx = 0;
- ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
- unsigned NumArgs = Record[Idx++];
- SmallVector<TemplateArgument, 8> Args;
- Args.reserve(NumArgs);
- while (NumArgs--)
- Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
- return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
- Args.size(), Args.data());
- }
-
- case TYPE_DEPENDENT_SIZED_ARRAY: {
- unsigned Idx = 0;
-
- // ArrayType
- QualType ElementType = readType(*Loc.F, Record, Idx);
- ArrayType::ArraySizeModifier ASM
- = (ArrayType::ArraySizeModifier)Record[Idx++];
- unsigned IndexTypeQuals = Record[Idx++];
-
- // DependentSizedArrayType
- Expr *NumElts = ReadExpr(*Loc.F);
- SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
-
- return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
- IndexTypeQuals, Brackets);
- }
-
- case TYPE_TEMPLATE_SPECIALIZATION: {
- unsigned Idx = 0;
- bool IsDependent = Record[Idx++];
- TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
- SmallVector<TemplateArgument, 8> Args;
- ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
- QualType Underlying = readType(*Loc.F, Record, Idx);
- QualType T;
- if (Underlying.isNull())
- T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(),
- Args.size());
- else
- T = Context.getTemplateSpecializationType(Name, Args.data(),
- Args.size(), Underlying);
- const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
- return T;
- }
-
- case TYPE_ATOMIC: {
- if (Record.size() != 1) {
- Error("Incorrect encoding of atomic type");
- return QualType();
- }
- QualType ValueType = readType(*Loc.F, Record, Idx);
- return Context.getAtomicType(ValueType);
- }
- }
- llvm_unreachable("Invalid TypeCode!");
-}
-
-class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
- ASTReader &Reader;
- ModuleFile &F;
- const ASTReader::RecordData &Record;
- unsigned &Idx;
-
- SourceLocation ReadSourceLocation(const ASTReader::RecordData &R,
- unsigned &I) {
- return Reader.ReadSourceLocation(F, R, I);
- }
-
- template<typename T>
- T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) {
- return Reader.ReadDeclAs<T>(F, Record, Idx);
- }
-
-public:
- TypeLocReader(ASTReader &Reader, ModuleFile &F,
- const ASTReader::RecordData &Record, unsigned &Idx)
- : Reader(Reader), F(F), Record(Record), Idx(Idx)
- { }
-
- // We want compile-time assurance that we've enumerated all of
- // these, so unfortunately we have to declare them first, then
- // define them out-of-line.
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
-#include "clang/AST/TypeLocNodes.def"
-
- void VisitFunctionTypeLoc(FunctionTypeLoc);
- void VisitArrayTypeLoc(ArrayTypeLoc);
-};
-
-void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
- // nothing to do
-}
-void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- TL.setBuiltinLoc(ReadSourceLocation(Record, Idx));
- if (TL.needsExtraLocalData()) {
- TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
- TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
- TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
- TL.setModeAttr(Record[Idx++]);
- }
-}
-void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
- TL.setCaretLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
- TL.setAmpLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
- TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation(Record, Idx));
- TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
-}
-void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
- TL.setLBracketLoc(ReadSourceLocation(Record, Idx));
- TL.setRBracketLoc(ReadSourceLocation(Record, Idx));
- if (Record[Idx++])
- TL.setSizeExpr(Reader.ReadExpr(F));
- else
- TL.setSizeExpr(0);
-}
-void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
- VisitArrayTypeLoc(TL);
-}
-void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
- VisitArrayTypeLoc(TL);
-}
-void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
- VisitArrayTypeLoc(TL);
-}
-void TypeLocReader::VisitDependentSizedArrayTypeLoc(
- DependentSizedArrayTypeLoc TL) {
- VisitArrayTypeLoc(TL);
-}
-void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
- DependentSizedExtVectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
- TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
- TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
- TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
- }
-}
-void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
- VisitFunctionTypeLoc(TL);
-}
-void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
- VisitFunctionTypeLoc(TL);
-}
-void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
- TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
-}
-void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
- TL.setKWLoc(ReadSourceLocation(Record, Idx));
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
- TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
-}
-void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
- TL.setAttrNameLoc(ReadSourceLocation(Record, Idx));
- if (TL.hasAttrOperand()) {
- SourceRange range;
- range.setBegin(ReadSourceLocation(Record, Idx));
- range.setEnd(ReadSourceLocation(Record, Idx));
- TL.setAttrOperandParensRange(range);
- }
- if (TL.hasAttrExprOperand()) {
- if (Record[Idx++])
- TL.setAttrExprOperand(Reader.ReadExpr(F));
- else
- TL.setAttrExprOperand(0);
- } else if (TL.hasAttrEnumOperand())
- TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
- SubstTemplateTypeParmTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
- SubstTemplateTypeParmPackTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitTemplateSpecializationTypeLoc(
- TemplateSpecializationTypeLoc TL) {
- TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
- TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
- TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i,
- Reader.GetTemplateArgumentLocInfo(F,
- TL.getTypePtr()->getArg(i).getKind(),
- Record, Idx));
-}
-void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
-}
-void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
- DependentTemplateSpecializationTypeLoc TL) {
- TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
- TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
- TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
- TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
- TL.setArgLocInfo(I,
- Reader.GetTemplateArgumentLocInfo(F,
- TL.getTypePtr()->getArg(I).getKind(),
- Record, Idx));
-}
-void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
- TL.setEllipsisLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
- TL.setHasBaseTypeAsWritten(Record[Idx++]);
- TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
- TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
- for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- TL.setStarLoc(ReadSourceLocation(Record, Idx));
-}
-void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
- TL.setKWLoc(ReadSourceLocation(Record, Idx));
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
-}
-
-TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
- const RecordData &Record,
- unsigned &Idx) {
- QualType InfoTy = readType(F, Record, Idx);
- if (InfoTy.isNull())
- return 0;
-
- TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
- TypeLocReader TLR(*this, F, Record, Idx);
- for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
- TLR.Visit(TL);
- return TInfo;
-}
-
-QualType ASTReader::GetType(TypeID ID) {
- unsigned FastQuals = ID & Qualifiers::FastMask;
- unsigned Index = ID >> Qualifiers::FastWidth;
-
- if (Index < NUM_PREDEF_TYPE_IDS) {
- QualType T;
- switch ((PredefinedTypeIDs)Index) {
- case PREDEF_TYPE_NULL_ID: return QualType();
- case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
- case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
-
- case PREDEF_TYPE_CHAR_U_ID:
- case PREDEF_TYPE_CHAR_S_ID:
- // FIXME: Check that the signedness of CharTy is correct!
- T = Context.CharTy;
- break;
-
- case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
- case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
- case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
- case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
- case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
- case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
- case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
- case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
- case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
- case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
- case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
- case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
- case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
- case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
- case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
- case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
- case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
- case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
- case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
- case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
- case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
- case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
- case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
- case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
- case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
- case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
- case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
- case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
- case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
- case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
- case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
- case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
- case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
- case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
- case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
-
- case PREDEF_TYPE_AUTO_RREF_DEDUCT:
- T = Context.getAutoRRefDeductType();
- break;
-
- case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
- T = Context.ARCUnbridgedCastTy;
- break;
-
- case PREDEF_TYPE_VA_LIST_TAG:
- T = Context.getVaListTagType();
- break;
-
- case PREDEF_TYPE_BUILTIN_FN:
- T = Context.BuiltinFnTy;
- break;
- }
-
- assert(!T.isNull() && "Unknown predefined type");
- return T.withFastQualifiers(FastQuals);
- }
-
- Index -= NUM_PREDEF_TYPE_IDS;
- assert(Index < TypesLoaded.size() && "Type index out-of-range");
- if (TypesLoaded[Index].isNull()) {
- TypesLoaded[Index] = readTypeRecord(Index);
- if (TypesLoaded[Index].isNull())
- return QualType();
-
- TypesLoaded[Index]->setFromAST();
- if (DeserializationListener)
- DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
- TypesLoaded[Index]);
- }
-
- return TypesLoaded[Index].withFastQualifiers(FastQuals);
-}
-
-QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) {
- return GetType(getGlobalTypeID(F, LocalID));
-}
-
-serialization::TypeID
-ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
- unsigned FastQuals = LocalID & Qualifiers::FastMask;
- unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
-
- if (LocalIndex < NUM_PREDEF_TYPE_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
- assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
-
- unsigned GlobalIndex = LocalIndex + I->second;
- return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
-}
-
-TemplateArgumentLocInfo
-ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
- TemplateArgument::ArgKind Kind,
- const RecordData &Record,
- unsigned &Index) {
- switch (Kind) {
- case TemplateArgument::Expression:
- return ReadExpr(F);
- case TemplateArgument::Type:
- return GetTypeSourceInfo(F, Record, Index);
- case TemplateArgument::Template: {
- NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
- Index);
- SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
- return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
- SourceLocation());
- }
- case TemplateArgument::TemplateExpansion: {
- NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
- Index);
- SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
- SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
- return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
- EllipsisLoc);
- }
- case TemplateArgument::Null:
- case TemplateArgument::Integral:
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Pack:
- // FIXME: Is this right?
- return TemplateArgumentLocInfo();
- }
- llvm_unreachable("unexpected template argument loc");
-}
-
-TemplateArgumentLoc
-ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
- const RecordData &Record, unsigned &Index) {
- TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
-
- if (Arg.getKind() == TemplateArgument::Expression) {
- if (Record[Index++]) // bool InfoHasSameExpr.
- return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
- }
- return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(),
- Record, Index));
-}
-
-Decl *ASTReader::GetExternalDecl(uint32_t ID) {
- return GetDecl(ID);
-}
-
-uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
- unsigned &Idx){
- if (Idx >= Record.size())
- return 0;
-
- unsigned LocalID = Record[Idx++];
- return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
-}
-
-CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
- RecordLocation Loc = getLocalBitOffset(Offset);
- llvm::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 0;
- }
-
- unsigned Idx = 0;
- unsigned NumBases = Record[Idx++];
- void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
- CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
- for (unsigned I = 0; I != NumBases; ++I)
- Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
- return Bases;
-}
-
-serialization::DeclID
-ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
- if (LocalID < NUM_PREDEF_DECL_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
- assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
-
- return LocalID + I->second;
-}
-
-bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
- ModuleFile &M) const {
- GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- return &M == I->second;
-}
-
-ModuleFile *ASTReader::getOwningModuleFile(Decl *D) {
- if (!D->isFromASTFile())
- return 0;
- GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- return I->second;
-}
-
-SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
- if (ID < NUM_PREDEF_DECL_IDS)
- return SourceLocation();
-
- unsigned Index = ID - NUM_PREDEF_DECL_IDS;
-
- if (Index > DeclsLoaded.size()) {
- Error("declaration ID out-of-range for AST file");
- return SourceLocation();
- }
-
- if (Decl *D = DeclsLoaded[Index])
- return D->getLocation();
-
- unsigned RawLocation = 0;
- RecordLocation Rec = DeclCursorForID(ID, RawLocation);
- return ReadSourceLocation(*Rec.F, RawLocation);
-}
-
-Decl *ASTReader::GetDecl(DeclID ID) {
- if (ID < NUM_PREDEF_DECL_IDS) {
- switch ((PredefinedDeclIDs)ID) {
- case PREDEF_DECL_NULL_ID:
- return 0;
-
- case PREDEF_DECL_TRANSLATION_UNIT_ID:
- return Context.getTranslationUnitDecl();
-
- case PREDEF_DECL_OBJC_ID_ID:
- return Context.getObjCIdDecl();
-
- case PREDEF_DECL_OBJC_SEL_ID:
- return Context.getObjCSelDecl();
-
- case PREDEF_DECL_OBJC_CLASS_ID:
- return Context.getObjCClassDecl();
-
- case PREDEF_DECL_OBJC_PROTOCOL_ID:
- return Context.getObjCProtocolDecl();
-
- case PREDEF_DECL_INT_128_ID:
- return Context.getInt128Decl();
-
- case PREDEF_DECL_UNSIGNED_INT_128_ID:
- return Context.getUInt128Decl();
-
- case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
- return Context.getObjCInstanceTypeDecl();
-
- case PREDEF_DECL_BUILTIN_VA_LIST_ID:
- return Context.getBuiltinVaListDecl();
- }
- }
-
- unsigned Index = ID - NUM_PREDEF_DECL_IDS;
-
- if (Index >= DeclsLoaded.size()) {
- assert(0 && "declaration ID out-of-range for AST file");
- Error("declaration ID out-of-range for AST file");
- return 0;
- }
-
- if (!DeclsLoaded[Index]) {
- ReadDeclRecord(ID);
- if (DeserializationListener)
- DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
- }
-
- return DeclsLoaded[Index];
-}
-
-DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
- DeclID GlobalID) {
- if (GlobalID < NUM_PREDEF_DECL_IDS)
- return GlobalID;
-
- GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- ModuleFile *Owner = I->second;
-
- llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
- = M.GlobalToLocalDeclIDs.find(Owner);
- if (Pos == M.GlobalToLocalDeclIDs.end())
- return 0;
-
- return GlobalID - Owner->BaseDeclID + Pos->second;
-}
-
-serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
- const RecordData &Record,
- unsigned &Idx) {
- if (Idx >= Record.size()) {
- Error("Corrupted AST file");
- return 0;
- }
-
- return getGlobalDeclID(F, Record[Idx++]);
-}
-
-/// \brief Resolve the offset of a statement into a statement.
-///
-/// This operation will read a new statement from the external
-/// source each time it is called, and is meant to be used via a
-/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
-Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
- // Switch case IDs are per Decl.
- ClearSwitchCaseIDs();
-
- // Offset here is a global offset across the entire chain.
- RecordLocation Loc = getLocalBitOffset(Offset);
- Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
- return ReadStmtFromStream(*Loc.F);
-}
-
-namespace {
- class FindExternalLexicalDeclsVisitor {
- ASTReader &Reader;
- const DeclContext *DC;
- bool (*isKindWeWant)(Decl::Kind);
-
- SmallVectorImpl<Decl*> &Decls;
- bool PredefsVisited[NUM_PREDEF_DECL_IDS];
-
- public:
- FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
- bool (*isKindWeWant)(Decl::Kind),
- SmallVectorImpl<Decl*> &Decls)
- : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
- {
- for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
- PredefsVisited[I] = false;
- }
-
- static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
- if (Preorder)
- return false;
-
- FindExternalLexicalDeclsVisitor *This
- = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
-
- ModuleFile::DeclContextInfosMap::iterator Info
- = M.DeclContextInfos.find(This->DC);
- if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
- return false;
-
- // Load all of the declaration IDs
- for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
- *IDE = ID + Info->second.NumLexicalDecls;
- ID != IDE; ++ID) {
- if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
- continue;
-
- // Don't add predefined declarations to the lexical context more
- // than once.
- if (ID->second < NUM_PREDEF_DECL_IDS) {
- if (This->PredefsVisited[ID->second])
- continue;
-
- This->PredefsVisited[ID->second] = true;
- }
-
- if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
- if (!This->DC->isDeclInLexicalTraversal(D))
- This->Decls.push_back(D);
- }
- }
-
- return false;
- }
- };
-}
-
-ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
- bool (*isKindWeWant)(Decl::Kind),
- SmallVectorImpl<Decl*> &Decls) {
- // There might be lexical decls in multiple modules, for the TU at
- // least. Walk all of the modules in the order they were loaded.
- FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
- ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
- ++NumLexicalDeclContextsRead;
- return ELR_Success;
-}
-
-namespace {
-
-class DeclIDComp {
- ASTReader &Reader;
- ModuleFile &Mod;
-
-public:
- DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
-
- bool operator()(LocalDeclID L, LocalDeclID R) const {
- SourceLocation LHS = getLocation(L);
- SourceLocation RHS = getLocation(R);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- bool operator()(SourceLocation LHS, LocalDeclID R) const {
- SourceLocation RHS = getLocation(R);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- bool operator()(LocalDeclID L, SourceLocation RHS) const {
- SourceLocation LHS = getLocation(L);
- return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
- }
-
- SourceLocation getLocation(LocalDeclID ID) const {
- return Reader.getSourceManager().getFileLoc(
- Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
- }
-};
-
-}
-
-void ASTReader::FindFileRegionDecls(FileID File,
- unsigned Offset, unsigned Length,
- SmallVectorImpl<Decl *> &Decls) {
- SourceManager &SM = getSourceManager();
-
- llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File);
- if (I == FileDeclIDs.end())
- return;
-
- FileDeclsInfo &DInfo = I->second;
- if (DInfo.Decls.empty())
- return;
-
- SourceLocation
- BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
- SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
-
- DeclIDComp DIDComp(*this, *DInfo.Mod);
- ArrayRef<serialization::LocalDeclID>::iterator
- BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
- BeginLoc, DIDComp);
- if (BeginIt != DInfo.Decls.begin())
- --BeginIt;
-
- // If we are pointing at a top-level decl inside an objc container, we need
- // to backtrack until we find it otherwise we will fail to report that the
- // region overlaps with an objc container.
- while (BeginIt != DInfo.Decls.begin() &&
- GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
- ->isTopLevelDeclInObjCContainer())
- --BeginIt;
-
- ArrayRef<serialization::LocalDeclID>::iterator
- EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
- EndLoc, DIDComp);
- if (EndIt != DInfo.Decls.end())
- ++EndIt;
-
- for (ArrayRef<serialization::LocalDeclID>::iterator
- DIt = BeginIt; DIt != EndIt; ++DIt)
- Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
-}
-
-namespace {
- /// \brief ModuleFile visitor used to perform name lookup into a
- /// declaration context.
- class DeclContextNameLookupVisitor {
- ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
- DeclarationName Name;
- SmallVectorImpl<NamedDecl *> &Decls;
-
- public:
- DeclContextNameLookupVisitor(ASTReader &Reader,
- SmallVectorImpl<const DeclContext *> &Contexts,
- DeclarationName Name,
- SmallVectorImpl<NamedDecl *> &Decls)
- : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- DeclContextNameLookupVisitor *This
- = static_cast<DeclContextNameLookupVisitor *>(UserData);
-
- // Check whether we have any visible declaration information for
- // this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info;
- bool FoundInfo = false;
- for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
- Info = M.DeclContextInfos.find(This->Contexts[I]);
- if (Info != M.DeclContextInfos.end() &&
- Info->second.NameLookupTableData) {
- FoundInfo = true;
- break;
- }
- }
-
- if (!FoundInfo)
- return false;
-
- // Look for this name within this module.
- ASTDeclContextNameLookupTable *LookupTable =
- Info->second.NameLookupTableData;
- ASTDeclContextNameLookupTable::iterator Pos
- = LookupTable->find(This->Name);
- if (Pos == LookupTable->end())
- return false;
-
- bool FoundAnything = false;
- ASTDeclContextNameLookupTrait::data_type Data = *Pos;
- for (; Data.first != Data.second; ++Data.first) {
- NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
- if (!ND)
- continue;
-
- if (ND->getDeclName() != This->Name) {
- // A name might be null because the decl's redeclarable part is
- // currently read before reading its name. The lookup is triggered by
- // building that decl (likely indirectly), and so it is later in the
- // sense of "already existing" and can be ignored here.
- continue;
- }
-
- // Record this declaration.
- FoundAnything = true;
- This->Decls.push_back(ND);
- }
-
- return FoundAnything;
- }
- };
-}
-
-DeclContext::lookup_result
-ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
- DeclarationName Name) {
- assert(DC->hasExternalVisibleStorage() &&
- "DeclContext has no visible decls in storage");
- if (!Name)
- return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
- DeclContext::lookup_iterator(0));
-
- SmallVector<NamedDecl *, 64> Decls;
-
- // Compute the declaration contexts we need to look into. Multiple such
- // declaration contexts occur when two declaration contexts from disjoint
- // modules get merged, e.g., when two namespaces with the same name are
- // independently defined in separate modules.
- SmallVector<const DeclContext *, 2> Contexts;
- Contexts.push_back(DC);
-
- if (DC->isNamespace()) {
- MergedDeclsMap::iterator Merged
- = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
- if (Merged != MergedDecls.end()) {
- for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
- Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
- }
- }
-
- DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
- ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
- ++NumVisibleDeclContextsRead;
- SetExternalVisibleDeclsForName(DC, Name, Decls);
- return const_cast<DeclContext*>(DC)->lookup(Name);
-}
-
-namespace {
- /// \brief ModuleFile visitor used to retrieve all visible names in a
- /// declaration context.
- class DeclContextAllNamesVisitor {
- ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
- llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls;
-
- public:
- DeclContextAllNamesVisitor(ASTReader &Reader,
- SmallVectorImpl<const DeclContext *> &Contexts,
- llvm::DenseMap<DeclarationName,
- SmallVector<NamedDecl *, 8> > &Decls)
- : Reader(Reader), Contexts(Contexts), Decls(Decls) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- DeclContextAllNamesVisitor *This
- = static_cast<DeclContextAllNamesVisitor *>(UserData);
-
- // Check whether we have any visible declaration information for
- // this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info;
- bool FoundInfo = false;
- for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
- Info = M.DeclContextInfos.find(This->Contexts[I]);
- if (Info != M.DeclContextInfos.end() &&
- Info->second.NameLookupTableData) {
- FoundInfo = true;
- break;
- }
- }
-
- if (!FoundInfo)
- return false;
-
- ASTDeclContextNameLookupTable *LookupTable =
- Info->second.NameLookupTableData;
- bool FoundAnything = false;
- for (ASTDeclContextNameLookupTable::data_iterator
- I = LookupTable->data_begin(), E = LookupTable->data_end();
- I != E; ++I) {
- ASTDeclContextNameLookupTrait::data_type Data = *I;
- for (; Data.first != Data.second; ++Data.first) {
- NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
- *Data.first);
- if (!ND)
- continue;
-
- // Record this declaration.
- FoundAnything = true;
- This->Decls[ND->getDeclName()].push_back(ND);
- }
- }
-
- return FoundAnything;
- }
- };
-}
-
-void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
- if (!DC->hasExternalVisibleStorage())
- return;
- llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls;
-
- // Compute the declaration contexts we need to look into. Multiple such
- // declaration contexts occur when two declaration contexts from disjoint
- // modules get merged, e.g., when two namespaces with the same name are
- // independently defined in separate modules.
- SmallVector<const DeclContext *, 2> Contexts;
- Contexts.push_back(DC);
-
- if (DC->isNamespace()) {
- MergedDeclsMap::iterator Merged
- = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
- if (Merged != MergedDecls.end()) {
- for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
- Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
- }
- }
-
- DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls);
- ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
- ++NumVisibleDeclContextsRead;
-
- for (llvm::DenseMap<DeclarationName,
- llvm::SmallVector<NamedDecl*, 8> >::iterator
- I = Decls.begin(), E = Decls.end(); I != E; ++I) {
- SetExternalVisibleDeclsForName(DC, I->first, I->second);
- }
- const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
-}
-
-/// \brief Under non-PCH compilation the consumer receives the objc methods
-/// before receiving the implementation, and codegen depends on this.
-/// We simulate this by deserializing and passing to consumer the methods of the
-/// implementation before passing the deserialized implementation decl.
-static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
- ASTConsumer *Consumer) {
- assert(ImplD && Consumer);
-
- for (ObjCImplDecl::method_iterator
- I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I)
- Consumer->HandleInterestingDecl(DeclGroupRef(*I));
-
- Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
-}
-
-void ASTReader::PassInterestingDeclsToConsumer() {
- assert(Consumer);
- while (!InterestingDecls.empty()) {
- Decl *D = InterestingDecls.front();
- InterestingDecls.pop_front();
-
- PassInterestingDeclToConsumer(D);
- }
-}
-
-void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
- PassObjCImplDeclToConsumer(ImplD, Consumer);
- else
- Consumer->HandleInterestingDecl(DeclGroupRef(D));
-}
-
-void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
- this->Consumer = Consumer;
-
- if (!Consumer)
- return;
-
- for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
- // Force deserialization of this decl, which will cause it to be queued for
- // passing to the consumer.
- GetDecl(ExternalDefinitions[I]);
- }
- ExternalDefinitions.clear();
-
- PassInterestingDeclsToConsumer();
-}
-
-void ASTReader::PrintStats() {
- std::fprintf(stderr, "*** AST File Statistics:\n");
-
- unsigned NumTypesLoaded
- = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
- QualType());
- unsigned NumDeclsLoaded
- = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
- (Decl *)0);
- unsigned NumIdentifiersLoaded
- = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
- IdentifiersLoaded.end(),
- (IdentifierInfo *)0);
- unsigned NumMacrosLoaded
- = MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
- MacrosLoaded.end(),
- (MacroInfo *)0);
- 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));
- std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
- }
- std::fprintf(stderr, "\n");
- dump();
- std::fprintf(stderr, "\n");
-}
-
-template<typename Key, typename ModuleFile, unsigned InitialCapacity>
-static void
-dumpModuleIDMap(StringRef Name,
- const ContinuousRangeMap<Key, ModuleFile *,
- InitialCapacity> &Map) {
- if (Map.begin() == Map.end())
- return;
-
- typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType;
- llvm::errs() << Name << ":\n";
- for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
- I != IEnd; ++I) {
- llvm::errs() << " " << I->first << " -> " << I->second->FileName
- << "\n";
- }
-}
-
-void ASTReader::dump() {
- llvm::errs() << "*** PCH/ModuleFile Remappings:\n";
- dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
- dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
- dumpModuleIDMap("Global type map", GlobalTypeMap);
- dumpModuleIDMap("Global declaration map", GlobalDeclMap);
- dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
- dumpModuleIDMap("Global macro map", GlobalMacroMap);
- dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
- dumpModuleIDMap("Global selector map", GlobalSelectorMap);
- dumpModuleIDMap("Global preprocessed entity map",
- GlobalPreprocessedEntityMap);
-
- llvm::errs() << "\n*** PCH/Modules Loaded:";
- for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
- MEnd = ModuleMgr.end();
- M != MEnd; ++M)
- (*M)->dump();
-}
-
-/// Return the amount of memory used by memory buffers, breaking down
-/// by heap-backed versus mmap'ed memory.
-void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
- for (ModuleConstIterator I = ModuleMgr.begin(),
- E = ModuleMgr.end(); I != E; ++I) {
- if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
- size_t bytes = buf->getBufferSize();
- switch (buf->getBufferKind()) {
- case llvm::MemoryBuffer::MemoryBuffer_Malloc:
- sizes.malloc_bytes += bytes;
- break;
- case llvm::MemoryBuffer::MemoryBuffer_MMap:
- sizes.mmap_bytes += bytes;
- break;
- }
- }
- }
-}
-
-void ASTReader::InitializeSema(Sema &S) {
- SemaObj = &S;
- S.addExternalSource(this);
-
- // Makes sure any declarations that were deserialized "too early"
- // still get added to the identifier's declaration chains.
- for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
- SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],
- PreloadedDecls[I]->getDeclName());
- }
- PreloadedDecls.clear();
-
- // Load the offsets of the declarations that Sema references.
- // They will be lazily deserialized when needed.
- if (!SemaDeclRefs.empty()) {
- assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!");
- if (!SemaObj->StdNamespace)
- SemaObj->StdNamespace = SemaDeclRefs[0];
- if (!SemaObj->StdBadAlloc)
- SemaObj->StdBadAlloc = SemaDeclRefs[1];
- }
-
- if (!FPPragmaOptions.empty()) {
- assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
- SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
- }
-
- if (!OpenCLExtensions.empty()) {
- unsigned I = 0;
-#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++];
-#include "clang/Basic/OpenCLExtensions.def"
-
- assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS");
- }
-}
-
-IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
- // Note that we are loading an identifier.
- Deserializing AnIdentifier(this);
-
- IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
- /*PriorGeneration=*/0);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
- IdentifierInfo *II = Visitor.getIdentifierInfo();
- markIdentifierUpToDate(II);
- return II;
-}
-
-namespace clang {
- /// \brief An identifier-lookup iterator that enumerates all of the
- /// identifiers stored within a set of AST files.
- class ASTIdentifierIterator : public IdentifierIterator {
- /// \brief The AST reader whose identifiers are being enumerated.
- const ASTReader &Reader;
-
- /// \brief The current index into the chain of AST files stored in
- /// the AST reader.
- unsigned Index;
-
- /// \brief The current position within the identifier lookup table
- /// of the current AST file.
- ASTIdentifierLookupTable::key_iterator Current;
-
- /// \brief The end position within the identifier lookup table of
- /// the current AST file.
- ASTIdentifierLookupTable::key_iterator End;
-
- public:
- explicit ASTIdentifierIterator(const ASTReader &Reader);
-
- virtual StringRef Next();
- };
-}
-
-ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader)
- : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) {
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable;
- Current = IdTable->key_begin();
- End = IdTable->key_end();
-}
-
-StringRef ASTIdentifierIterator::Next() {
- while (Current == End) {
- // If we have exhausted all of our AST files, we're done.
- if (Index == 0)
- return StringRef();
-
- --Index;
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].
- IdentifierLookupTable;
- Current = IdTable->key_begin();
- End = IdTable->key_end();
- }
-
- // We have any identifiers remaining in the current AST file; return
- // the next one.
- std::pair<const char*, unsigned> Key = *Current;
- ++Current;
- return StringRef(Key.first, Key.second);
-}
-
-IdentifierIterator *ASTReader::getIdentifiers() const {
- return new ASTIdentifierIterator(*this);
-}
-
-namespace clang { namespace serialization {
- class ReadMethodPoolVisitor {
- ASTReader &Reader;
- Selector Sel;
- unsigned PriorGeneration;
- llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
- llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
-
- public:
- ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
- unsigned PriorGeneration)
- : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- ReadMethodPoolVisitor *This
- = static_cast<ReadMethodPoolVisitor *>(UserData);
-
- if (!M.SelectorLookupTable)
- return false;
-
- // If we've already searched this module file, skip it now.
- if (M.Generation <= This->PriorGeneration)
- return true;
-
- ASTSelectorLookupTable *PoolTable
- = (ASTSelectorLookupTable*)M.SelectorLookupTable;
- ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
- if (Pos == PoolTable->end())
- return false;
-
- ++This->Reader.NumSelectorsRead;
- // FIXME: Not quite happy with the statistics here. We probably should
- // disable this tracking when called via LoadSelector.
- // Also, should entries without methods count as misses?
- ++This->Reader.NumMethodPoolEntriesRead;
- ASTSelectorLookupTrait::data_type Data = *Pos;
- if (This->Reader.DeserializationListener)
- This->Reader.DeserializationListener->SelectorRead(Data.ID,
- This->Sel);
-
- This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
- This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
- return true;
- }
-
- /// \brief Retrieve the instance methods found by this visitor.
- ArrayRef<ObjCMethodDecl *> getInstanceMethods() const {
- return InstanceMethods;
- }
-
- /// \brief Retrieve the instance methods found by this visitor.
- ArrayRef<ObjCMethodDecl *> getFactoryMethods() const {
- return FactoryMethods;
- }
- };
-} } // end namespace clang::serialization
-
-/// \brief Add the given set of methods to the method list.
-static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
- ObjCMethodList &List) {
- for (unsigned I = 0, N = Methods.size(); I != N; ++I) {
- S.addMethodToGlobalList(&List, Methods[I]);
- }
-}
-
-void ASTReader::ReadMethodPool(Selector Sel) {
- // Get the selector generation and update it to the current generation.
- unsigned &Generation = SelectorGeneration[Sel];
- unsigned PriorGeneration = Generation;
- Generation = CurrentGeneration;
-
- // Search for methods defined with this selector.
- ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
- ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
-
- if (Visitor.getInstanceMethods().empty() &&
- Visitor.getFactoryMethods().empty()) {
- ++NumMethodPoolMisses;
- return;
- }
-
- if (!getSema())
- return;
-
- Sema &S = *getSema();
- Sema::GlobalMethodPool::iterator Pos
- = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
-
- addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
- addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
-}
-
-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::ReadTentativeDefinitions(
- SmallVectorImpl<VarDecl *> &TentativeDefs) {
- for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
- VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I]));
- if (Var)
- TentativeDefs.push_back(Var);
- }
- TentativeDefinitions.clear();
-}
-
-void ASTReader::ReadUnusedFileScopedDecls(
- SmallVectorImpl<const DeclaratorDecl *> &Decls) {
- for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
- DeclaratorDecl *D
- = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
- if (D)
- Decls.push_back(D);
- }
- UnusedFileScopedDecls.clear();
-}
-
-void ASTReader::ReadDelegatingConstructors(
- SmallVectorImpl<CXXConstructorDecl *> &Decls) {
- for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
- CXXConstructorDecl *D
- = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
- if (D)
- Decls.push_back(D);
- }
- DelegatingCtorDecls.clear();
-}
-
-void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {
- for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) {
- TypedefNameDecl *D
- = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]));
- if (D)
- Decls.push_back(D);
- }
- ExtVectorDecls.clear();
-}
-
-void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
- for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
- CXXRecordDecl *D
- = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I]));
- if (D)
- Decls.push_back(D);
- }
- DynamicClasses.clear();
-}
-
-void
-ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) {
- for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
- NamedDecl *D
- = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
- if (D)
- Decls.push_back(D);
- }
- LocallyScopedExternalDecls.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::LoadSelector(Selector Sel) {
- // It would be complicated to avoid reading the methods anyway. So don't.
- ReadMethodPool(Sel);
-}
-
-void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
- assert(ID && "Non-zero identifier ID required");
- assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
- IdentifiersLoaded[ID - 1] = II;
- if (DeserializationListener)
- DeserializationListener->IdentifierRead(ID, II);
-}
-
-/// \brief Set the globally-visible declarations associated with the given
-/// identifier.
-///
-/// If the AST reader is currently in a state where the given declaration IDs
-/// cannot safely be resolved, they are queued until it is safe to resolve
-/// them.
-///
-/// \param II an IdentifierInfo that refers to one or more globally-visible
-/// declarations.
-///
-/// \param DeclIDs the set of declaration IDs with the name @p II that are
-/// visible at global scope.
-///
-/// \param Nonrecursive should be true to indicate that the caller knows that
-/// this call is non-recursive, and therefore the globally-visible declarations
-/// will not be placed onto the pending queue.
-void
-ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
- const SmallVectorImpl<uint32_t> &DeclIDs,
- bool Nonrecursive) {
- if (NumCurrentElementsDeserializing && !Nonrecursive) {
- PendingIdentifierInfos.push_back(PendingIdentifierInfo());
- PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
- PII.II = II;
- PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end());
- return;
- }
-
- for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
- NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
- if (SemaObj) {
- // Introduce this declaration into the translation-unit scope
- // and add it to the declaration chain for this identifier, so
- // that (unqualified) name lookup will find it.
- SemaObj->pushExternalDeclIntoScope(D, II);
- } else {
- // Queue this declaration so that it will be added to the
- // translation unit scope and identifier's declaration chain
- // once a Sema object is known.
- PreloadedDecls.push_back(D);
- }
- }
-}
-
-IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
- if (ID == 0)
- return 0;
-
- if (IdentifiersLoaded.empty()) {
- Error("no identifier table in AST file");
- return 0;
- }
-
- ID -= 1;
- if (!IdentifiersLoaded[ID]) {
- GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
- assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
- ModuleFile *M = I->second;
- unsigned Index = ID - M->BaseIdentifierID;
- const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
-
- // All of the strings in the AST file are preceded by a 16-bit length.
- // Extract that 16-bit length to avoid having to execute strlen().
- // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as
- // unsigned integers. This is important to avoid integer overflow when
- // we cast them to 'unsigned'.
- const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
- unsigned StrLen = (((unsigned) StrLenPtr[0])
- | (((unsigned) StrLenPtr[1]) << 8)) - 1;
- IdentifiersLoaded[ID]
- = &PP.getIdentifierTable().get(StringRef(Str, StrLen));
- if (DeserializationListener)
- DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
- }
-
- return IdentifiersLoaded[ID];
-}
-
-IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) {
- return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
-}
-
-IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
- if (LocalID < NUM_PREDEF_IDENT_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
- assert(I != M.IdentifierRemap.end()
- && "Invalid index into identifier index remap");
-
- return LocalID + I->second;
-}
-
-MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
- if (ID == 0)
- return 0;
-
- if (MacrosLoaded.empty()) {
- Error("no macro table in AST file");
- return 0;
- }
-
- ID -= NUM_PREDEF_MACRO_IDS;
- if (!MacrosLoaded[ID]) {
- GlobalMacroMapType::iterator I
- = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
- assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
- ModuleFile *M = I->second;
- unsigned Index = ID - M->BaseMacroID;
- ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
- }
-
- return MacrosLoaded[ID];
-}
-
-MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
- if (LocalID < NUM_PREDEF_MACRO_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
- assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
-
- return LocalID + I->second;
-}
-
-serialization::SubmoduleID
-ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
- if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
- assert(I != M.SubmoduleRemap.end()
- && "Invalid index into submodule index remap");
-
- return LocalID + I->second;
-}
-
-Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
- if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
- assert(GlobalID == 0 && "Unhandled global submodule ID");
- return 0;
- }
-
- if (GlobalID > SubmodulesLoaded.size()) {
- Error("submodule ID out of range in AST file");
- return 0;
- }
-
- return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
-}
-
-Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
- return DecodeSelector(getGlobalSelectorID(M, LocalID));
-}
-
-Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
- if (ID == 0)
- return Selector();
-
- if (ID > SelectorsLoaded.size()) {
- Error("selector ID out of range in AST file");
- return Selector();
- }
-
- if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) {
- // Load this selector from the selector table.
- GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
- assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
- ModuleFile &M = *I->second;
- ASTSelectorLookupTrait Trait(*this, M);
- unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
- SelectorsLoaded[ID - 1] =
- Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0);
- if (DeserializationListener)
- DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
- }
-
- return SelectorsLoaded[ID - 1];
-}
-
-Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) {
- return DecodeSelector(ID);
-}
-
-uint32_t ASTReader::GetNumExternalSelectors() {
- // ID 0 (the null selector) is considered an external selector.
- return getTotalNumSelectors() + 1;
-}
-
-serialization::SelectorID
-ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
- if (LocalID < NUM_PREDEF_SELECTOR_IDS)
- return LocalID;
-
- ContinuousRangeMap<uint32_t, int, 2>::iterator I
- = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
- assert(I != M.SelectorRemap.end()
- && "Invalid index into selector index remap");
-
- return LocalID + I->second;
-}
-
-DeclarationName
-ASTReader::ReadDeclarationName(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
- switch (Kind) {
- case DeclarationName::Identifier:
- return DeclarationName(GetIdentifierInfo(F, Record, Idx));
-
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- return DeclarationName(ReadSelector(F, Record, Idx));
-
- case DeclarationName::CXXConstructorName:
- return Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXDestructorName:
- return Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXConversionFunctionName:
- return Context.DeclarationNames.getCXXConversionFunctionName(
- Context.getCanonicalType(readType(F, Record, Idx)));
-
- case DeclarationName::CXXOperatorName:
- return Context.DeclarationNames.getCXXOperatorName(
- (OverloadedOperatorKind)Record[Idx++]);
-
- case DeclarationName::CXXLiteralOperatorName:
- return Context.DeclarationNames.getCXXLiteralOperatorName(
- GetIdentifierInfo(F, Record, Idx));
-
- case DeclarationName::CXXUsingDirective:
- return DeclarationName::getUsingDirectiveName();
- }
-
- llvm_unreachable("Invalid NameKind!");
-}
-
-void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
- DeclarationNameLoc &DNLoc,
- DeclarationName Name,
- const RecordData &Record, unsigned &Idx) {
- switch (Name.getNameKind()) {
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx);
- break;
-
- case DeclarationName::CXXOperatorName:
- DNLoc.CXXOperatorName.BeginOpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
- DNLoc.CXXOperatorName.EndOpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
- break;
-
- case DeclarationName::CXXLiteralOperatorName:
- DNLoc.CXXLiteralOperatorName.OpNameLoc
- = ReadSourceLocation(F, Record, Idx).getRawEncoding();
- break;
-
- case DeclarationName::Identifier:
- case DeclarationName::ObjCZeroArgSelector:
- case DeclarationName::ObjCOneArgSelector:
- case DeclarationName::ObjCMultiArgSelector:
- case DeclarationName::CXXUsingDirective:
- break;
- }
-}
-
-void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
- DeclarationNameInfo &NameInfo,
- const RecordData &Record, unsigned &Idx) {
- NameInfo.setName(ReadDeclarationName(F, Record, Idx));
- NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
- DeclarationNameLoc DNLoc;
- ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
- NameInfo.setInfo(DNLoc);
-}
-
-void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
- const RecordData &Record, unsigned &Idx) {
- Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
- unsigned NumTPLists = Record[Idx++];
- Info.NumTemplParamLists = NumTPLists;
- if (NumTPLists) {
- Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
- for (unsigned i=0; i != NumTPLists; ++i)
- Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
- }
-}
-
-TemplateName
-ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
- switch (Kind) {
- case TemplateName::Template:
- return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
-
- case TemplateName::OverloadedTemplate: {
- unsigned size = Record[Idx++];
- UnresolvedSet<8> Decls;
- while (size--)
- Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
-
- return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
- }
-
- case TemplateName::QualifiedTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
- bool hasTemplKeyword = Record[Idx++];
- TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
- return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
- }
-
- case TemplateName::DependentTemplate: {
- NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
- if (Record[Idx++]) // isIdentifier
- return Context.getDependentTemplateName(NNS,
- GetIdentifierInfo(F, Record,
- Idx));
- return Context.getDependentTemplateName(NNS,
- (OverloadedOperatorKind)Record[Idx++]);
- }
-
- case TemplateName::SubstTemplateTemplateParm: {
- TemplateTemplateParmDecl *param
- = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
- if (!param) return TemplateName();
- TemplateName replacement = ReadTemplateName(F, Record, Idx);
- return Context.getSubstTemplateTemplateParm(param, replacement);
- }
-
- case TemplateName::SubstTemplateTemplateParmPack: {
- TemplateTemplateParmDecl *Param
- = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
- if (!Param)
- return TemplateName();
-
- TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx);
- if (ArgPack.getKind() != TemplateArgument::Pack)
- return TemplateName();
-
- return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
- }
- }
-
- llvm_unreachable("Unhandled template name kind!");
-}
-
-TemplateArgument
-ASTReader::ReadTemplateArgument(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
- switch (Kind) {
- case TemplateArgument::Null:
- return TemplateArgument();
- case TemplateArgument::Type:
- return TemplateArgument(readType(F, Record, Idx));
- case TemplateArgument::Declaration: {
- ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
- bool ForReferenceParam = Record[Idx++];
- return TemplateArgument(D, ForReferenceParam);
- }
- case TemplateArgument::NullPtr:
- return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
- case TemplateArgument::Integral: {
- llvm::APSInt Value = ReadAPSInt(Record, Idx);
- QualType T = readType(F, Record, Idx);
- return TemplateArgument(Context, Value, T);
- }
- case TemplateArgument::Template:
- return TemplateArgument(ReadTemplateName(F, Record, Idx));
- case TemplateArgument::TemplateExpansion: {
- TemplateName Name = ReadTemplateName(F, Record, Idx);
- llvm::Optional<unsigned> NumTemplateExpansions;
- if (unsigned NumExpansions = Record[Idx++])
- NumTemplateExpansions = NumExpansions - 1;
- return TemplateArgument(Name, NumTemplateExpansions);
- }
- case TemplateArgument::Expression:
- return TemplateArgument(ReadExpr(F));
- case TemplateArgument::Pack: {
- unsigned NumArgs = Record[Idx++];
- TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
- for (unsigned I = 0; I != NumArgs; ++I)
- Args[I] = ReadTemplateArgument(F, Record, Idx);
- return TemplateArgument(Args, NumArgs);
- }
- }
-
- llvm_unreachable("Unhandled template argument kind!");
-}
-
-TemplateParameterList *
-ASTReader::ReadTemplateParameterList(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
-
- unsigned NumParams = Record[Idx++];
- SmallVector<NamedDecl *, 16> Params;
- Params.reserve(NumParams);
- while (NumParams--)
- Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
-
- TemplateParameterList* TemplateParams =
- TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- Params.data(), Params.size(), RAngleLoc);
- return TemplateParams;
-}
-
-void
-ASTReader::
-ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
- ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- unsigned NumTemplateArgs = Record[Idx++];
- TemplArgs.reserve(NumTemplateArgs);
- while (NumTemplateArgs--)
- TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx));
-}
-
-/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
- const RecordData &Record, unsigned &Idx) {
- unsigned NumDecls = Record[Idx++];
- Set.reserve(Context, NumDecls);
- while (NumDecls--) {
- NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
- AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addDecl(Context, D, 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;
-}
-
-std::pair<CXXCtorInitializer **, unsigned>
-ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- CXXCtorInitializer **CtorInitializers = 0;
- unsigned NumInitializers = Record[Idx++];
- if (NumInitializers) {
- CtorInitializers
- = new (Context) CXXCtorInitializer*[NumInitializers];
- for (unsigned i=0; i != NumInitializers; ++i) {
- TypeSourceInfo *TInfo = 0;
- bool IsBaseVirtual = false;
- FieldDecl *Member = 0;
- IndirectFieldDecl *IndirectMember = 0;
-
- CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
- switch (Type) {
- case CTOR_INITIALIZER_BASE:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
- IsBaseVirtual = Record[Idx++];
- break;
-
- case CTOR_INITIALIZER_DELEGATING:
- TInfo = GetTypeSourceInfo(F, Record, Idx);
- break;
-
- case CTOR_INITIALIZER_MEMBER:
- Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
- break;
-
- case CTOR_INITIALIZER_INDIRECT_MEMBER:
- IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
- break;
- }
-
- SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
- Expr *Init = ReadExpr(F);
- SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
- SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
- bool IsWritten = Record[Idx++];
- unsigned SourceOrderOrNumArrayIndices;
- SmallVector<VarDecl *, 8> Indices;
- if (IsWritten) {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- } else {
- SourceOrderOrNumArrayIndices = Record[Idx++];
- Indices.reserve(SourceOrderOrNumArrayIndices);
- for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
- Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
- }
-
- CXXCtorInitializer *BOMInit;
- if (Type == CTOR_INITIALIZER_BASE) {
- BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
- LParenLoc, Init, RParenLoc,
- MemberOrEllipsisLoc);
- } else if (Type == CTOR_INITIALIZER_DELEGATING) {
- BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
- Init, RParenLoc);
- } else if (IsWritten) {
- if (Member)
- BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc);
- else
- BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
- MemberOrEllipsisLoc, LParenLoc,
- Init, RParenLoc);
- } else {
- BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
- LParenLoc, Init, RParenLoc,
- Indices.data(), Indices.size());
- }
-
- if (IsWritten)
- BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
- CtorInitializers[i] = BOMInit;
- }
- }
-
- return std::make_pair(CtorInitializers, NumInitializers);
-}
-
-NestedNameSpecifier *
-ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
- unsigned N = Record[Idx++];
- NestedNameSpecifier *NNS = 0, *Prev = 0;
- for (unsigned I = 0; I != N; ++I) {
- NestedNameSpecifier::SpecifierKind Kind
- = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
- switch (Kind) {
- case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, II);
- break;
- }
-
- case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, NS);
- break;
- }
-
- case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
- NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
- break;
- }
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
- if (!T)
- return 0;
-
- bool Template = Record[Idx++];
- NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
- break;
- }
-
- case NestedNameSpecifier::Global: {
- NNS = NestedNameSpecifier::GlobalSpecifier(Context);
- // No associated value, and there can't be a prefix.
- break;
- }
- }
- Prev = NNS;
- }
- return NNS;
-}
-
-NestedNameSpecifierLoc
-ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- unsigned N = Record[Idx++];
- NestedNameSpecifierLocBuilder Builder;
- for (unsigned I = 0; I != N; ++I) {
- NestedNameSpecifier::SpecifierKind Kind
- = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
- switch (Kind) {
- case NestedNameSpecifier::Identifier: {
- IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
- break;
- }
-
- case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
- break;
- }
-
- case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
- SourceRange Range = ReadSourceRange(F, Record, Idx);
- Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
- break;
- }
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- bool Template = Record[Idx++];
- TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
- if (!T)
- return NestedNameSpecifierLoc();
- SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
-
- // FIXME: 'template' keyword location not saved anywhere, so we fake it.
- Builder.Extend(Context,
- Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
- T->getTypeLoc(), ColonColonLoc);
- break;
- }
-
- case NestedNameSpecifier::Global: {
- SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
- Builder.MakeGlobal(Context, ColonColonLoc);
- break;
- }
- }
- }
-
- return Builder.getWithLocInContext(Context);
-}
-
-SourceRange
-ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
- SourceLocation beg = ReadSourceLocation(F, Record, Idx);
- SourceLocation end = ReadSourceLocation(F, Record, Idx);
- return SourceRange(beg, end);
-}
-
-/// \brief Read an integral value
-llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
- unsigned BitWidth = Record[Idx++];
- unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
- llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
- Idx += NumWords;
- return Result;
-}
-
-/// \brief Read a signed integral value
-llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
- bool isUnsigned = Record[Idx++];
- return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
-}
-
-/// \brief Read a floating-point value
-llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
- return llvm::APFloat(ReadAPInt(Record, Idx));
-}
-
-// \brief Read a string
-std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
- unsigned Len = Record[Idx++];
- std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
- Idx += Len;
- return Result;
-}
-
-VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
- unsigned &Idx) {
- unsigned Major = Record[Idx++];
- unsigned Minor = Record[Idx++];
- unsigned Subminor = Record[Idx++];
- if (Minor == 0)
- return VersionTuple(Major);
- if (Subminor == 0)
- return VersionTuple(Major, Minor - 1);
- return VersionTuple(Major, Minor - 1, Subminor - 1);
-}
-
-CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
- const RecordData &Record,
- unsigned &Idx) {
- CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
- return CXXTemporary::Create(Context, Decl);
-}
-
-DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
- return Diag(SourceLocation(), DiagID);
-}
-
-DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
- return Diags.Report(Loc, DiagID);
-}
-
-/// \brief Retrieve the identifier table associated with the
-/// preprocessor.
-IdentifierTable &ASTReader::getIdentifierTable() {
- return PP.getIdentifierTable();
-}
-
-/// \brief Record that the given ID maps to the given switch-case
-/// statement.
-void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
- assert((*CurrSwitchCaseStmts)[ID] == 0 &&
- "Already have a SwitchCase with this ID");
- (*CurrSwitchCaseStmts)[ID] = SC;
-}
-
-/// \brief Retrieve the switch-case statement with the given ID.
-SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) {
- assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID");
- return (*CurrSwitchCaseStmts)[ID];
-}
-
-void ASTReader::ClearSwitchCaseIDs() {
- CurrSwitchCaseStmts->clear();
-}
-
-void ASTReader::ReadComments() {
- std::vector<RawComment *> Comments;
- for (SmallVectorImpl<std::pair<llvm::BitstreamCursor,
- serialization::ModuleFile *> >::iterator
- I = CommentsCursors.begin(),
- E = CommentsCursors.end();
- I != E; ++I) {
- llvm::BitstreamCursor &Cursor = I->first;
- serialization::ModuleFile &F = *I->second;
- SavedStreamPosition SavedPosition(Cursor);
-
- RecordData Record;
- while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
- break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- Record.clear();
- switch ((CommentRecordTypes) Cursor.ReadRecord(Code, 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;
- }
- }
- }
- }
- Context.Comments.addCommentsToFront(Comments);
-}
-
-void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
- !PendingMacroIDs.empty()) {
- // If any identifiers with corresponding top-level declarations have
- // been loaded, load those declarations now.
- while (!PendingIdentifierInfos.empty()) {
- SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
- PendingIdentifierInfos.front().DeclIDs, true);
- PendingIdentifierInfos.pop_front();
- }
-
- // Load pending declaration chains.
- for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
- loadPendingDeclChain(PendingDeclChains[I]);
- PendingDeclChainsKnown.erase(PendingDeclChains[I]);
- }
- PendingDeclChains.clear();
-
- // Load any pending macro definitions.
- for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
- // FIXME: std::move here
- SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second;
- MacroInfo *Hint = 0;
- for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
- ++IDIdx) {
- Hint = getMacro(GlobalIDs[IDIdx], Hint);
- }
- }
- PendingMacroIDs.clear();
- }
-
- // If we deserialized any C++ or Objective-C class definitions, any
- // Objective-C protocol definitions, or any redeclarable templates, make sure
- // that all redeclarations point to the definitions. Note that this can only
- // happen now, after the redeclaration chains have been fully wired.
- for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
- DEnd = PendingDefinitions.end();
- D != DEnd; ++D) {
- if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
- if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
- // Make sure that the TagType points at the definition.
- const_cast<TagType*>(TagT)->decl = TD;
- }
-
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) {
- for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(),
- REnd = RD->redecls_end();
- R != REnd; ++R)
- cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData;
-
- }
-
- continue;
- }
-
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
- // Make sure that the ObjCInterfaceType points at the definition.
- const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
- ->Decl = ID;
-
- for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(),
- REnd = ID->redecls_end();
- R != REnd; ++R)
- R->Data = ID->Data;
-
- continue;
- }
-
- if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) {
- for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(),
- REnd = PD->redecls_end();
- R != REnd; ++R)
- R->Data = PD->Data;
-
- continue;
- }
-
- RedeclarableTemplateDecl *RTD
- = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
- for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
- REnd = RTD->redecls_end();
- R != REnd; ++R)
- R->Common = RTD->Common;
- }
- PendingDefinitions.clear();
-
- // Load the bodies of any functions or methods we've encountered. We do
- // this now (delayed) so that we can be sure that the declaration chains
- // have been fully wired up.
- for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
- PBEnd = PendingBodies.end();
- PB != PBEnd; ++PB) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
- // FIXME: Check for =delete/=default?
- // FIXME: Complain about ODR violations here?
- if (!getContext().getLangOpts().Modules || !FD->hasBody())
- FD->setLazyBody(PB->second);
- continue;
- }
-
- ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
- if (!getContext().getLangOpts().Modules || !MD->hasBody())
- MD->setLazyBody(PB->second);
- }
- PendingBodies.clear();
-}
-
-void ASTReader::FinishedDeserializing() {
- assert(NumCurrentElementsDeserializing &&
- "FinishedDeserializing not paired with StartedDeserializing");
- if (NumCurrentElementsDeserializing == 1) {
- // We decrease NumCurrentElementsDeserializing only after pending actions
- // are finished, to avoid recursively re-calling finishPendingActions().
- finishPendingActions();
- }
- --NumCurrentElementsDeserializing;
-
- if (NumCurrentElementsDeserializing == 0 &&
- Consumer && !PassingDeclsToConsumer) {
- // Guard variable to avoid recursively redoing the process of passing
- // decls to consumer.
- SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
- true);
-
- while (!InterestingDecls.empty()) {
- // We are not in recursive loading, so it's safe to pass the "interesting"
- // decls to the consumer.
- Decl *D = InterestingDecls.front();
- InterestingDecls.pop_front();
- PassInterestingDeclToConsumer(D);
- }
- }
-}
-
-ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
- StringRef isysroot, bool DisableValidation,
- bool AllowASTWithCompilerErrors)
- : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
- SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
- Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
- Consumer(0), ModuleMgr(PP.getFileManager()),
- isysroot(isysroot), DisableValidation(DisableValidation),
- AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
- CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
- NumSLocEntriesRead(0), TotalNumSLocEntries(0),
- NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
- TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
- NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0),
- NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
- NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
- TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
- PassingDeclsToConsumer(false),
- NumCXXBaseSpecifiersLoaded(0)
-{
- SourceMgr.setExternalSLocEntrySource(this);
-}
-
-ASTReader::~ASTReader() {
- for (DeclContextVisibleUpdatesPending::iterator
- I = PendingVisibleUpdates.begin(),
- E = PendingVisibleUpdates.end();
- I != E; ++I) {
- for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
- F = I->second.end();
- J != F; ++J)
- delete J->first;
- }
-}
+//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTReader class, which reads AST files. +// +//===----------------------------------------------------------------------===// + +#include "clang/Serialization/ASTReader.h" +#include "ASTCommon.h" +#include "ASTReaderInternals.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemStatCache.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Sema.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ModuleManager.h" +#include "clang/Serialization/SerializationDiagnostic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/system_error.h" +#include <algorithm> +#include <cstdio> +#include <iterator> + +using namespace clang; +using namespace clang::serialization; +using namespace clang::serialization::reader; + +//===----------------------------------------------------------------------===// +// PCH validator implementation +//===----------------------------------------------------------------------===// + +ASTReaderListener::~ASTReaderListener() {} + +/// \brief Compare the given set of language options against an existing set of +/// language options. +/// +/// \param Diags If non-NULL, diagnostics will be emitted via this engine. +/// +/// \returns true if the languagae options mis-match, false otherwise. +static bool checkLanguageOptions(const LangOptions &LangOpts, + const LangOptions &ExistingLangOpts, + DiagnosticsEngine *Diags) { +#define LANGOPT(Name, Bits, Default, Description) \ + if (ExistingLangOpts.Name != LangOpts.Name) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_mismatch) \ + << Description << LangOpts.Name << ExistingLangOpts.Name; \ + return true; \ + } + +#define VALUE_LANGOPT(Name, Bits, Default, Description) \ + if (ExistingLangOpts.Name != LangOpts.Name) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_value_mismatch) \ + << Description; \ + return true; \ + } + +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_value_mismatch) \ + << Description; \ + return true; \ + } + +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + + if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { + if (Diags) + Diags->Report(diag::err_pch_langopt_value_mismatch) + << "target Objective-C runtime"; + return true; + } + + return false; +} + +/// \brief Compare the given set of target options against an existing set of +/// target options. +/// +/// \param Diags If non-NULL, diagnostics will be emitted via this engine. +/// +/// \returns true if the target options mis-match, false otherwise. +static bool checkTargetOptions(const TargetOptions &TargetOpts, + const TargetOptions &ExistingTargetOpts, + DiagnosticsEngine *Diags) { +#define CHECK_TARGET_OPT(Field, Name) \ + if (TargetOpts.Field != ExistingTargetOpts.Field) { \ + if (Diags) \ + Diags->Report(diag::err_pch_targetopt_mismatch) \ + << Name << TargetOpts.Field << ExistingTargetOpts.Field; \ + return true; \ + } + + CHECK_TARGET_OPT(Triple, "target"); + CHECK_TARGET_OPT(CPU, "target CPU"); + CHECK_TARGET_OPT(ABI, "target ABI"); + CHECK_TARGET_OPT(CXXABI, "target C++ ABI"); + CHECK_TARGET_OPT(LinkerVersion, "target linker version"); +#undef CHECK_TARGET_OPT + + // Compare feature sets. + SmallVector<StringRef, 4> ExistingFeatures( + ExistingTargetOpts.FeaturesAsWritten.begin(), + ExistingTargetOpts.FeaturesAsWritten.end()); + SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(), + TargetOpts.FeaturesAsWritten.end()); + std::sort(ExistingFeatures.begin(), ExistingFeatures.end()); + std::sort(ReadFeatures.begin(), ReadFeatures.end()); + + unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size(); + unsigned ReadIdx = 0, ReadN = ReadFeatures.size(); + while (ExistingIdx < ExistingN && ReadIdx < ReadN) { + if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) { + ++ExistingIdx; + ++ReadIdx; + continue; + } + + if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << false << ReadFeatures[ReadIdx]; + return true; + } + + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << true << ExistingFeatures[ExistingIdx]; + return true; + } + + if (ExistingIdx < ExistingN) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << true << ExistingFeatures[ExistingIdx]; + return true; + } + + if (ReadIdx < ReadN) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << false << ReadFeatures[ReadIdx]; + return true; + } + + return false; +} + +bool +PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + const LangOptions &ExistingLangOpts = PP.getLangOpts(); + return checkLanguageOptions(LangOpts, ExistingLangOpts, + Complain? &Reader.Diags : 0); +} + +bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts(); + return checkTargetOptions(TargetOpts, ExistingTargetOpts, + Complain? &Reader.Diags : 0); +} + +namespace { + typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> > + MacroDefinitionsMap; +} + +/// \brief Collect the macro definitions provided by the given preprocessor +/// options. +static void collectMacroDefinitions(const PreprocessorOptions &PPOpts, + MacroDefinitionsMap &Macros, + SmallVectorImpl<StringRef> *MacroNames = 0){ + for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { + StringRef Macro = PPOpts.Macros[I].first; + bool IsUndef = PPOpts.Macros[I].second; + + std::pair<StringRef, StringRef> MacroPair = Macro.split('='); + StringRef MacroName = MacroPair.first; + StringRef MacroBody = MacroPair.second; + + // For an #undef'd macro, we only care about the name. + if (IsUndef) { + if (MacroNames && !Macros.count(MacroName)) + MacroNames->push_back(MacroName); + + Macros[MacroName] = std::make_pair("", true); + continue; + } + + // For a #define'd macro, figure out the actual definition. + if (MacroName.size() == Macro.size()) + MacroBody = "1"; + else { + // Note: GCC drops anything following an end-of-line character. + StringRef::size_type End = MacroBody.find_first_of("\n\r"); + MacroBody = MacroBody.substr(0, End); + } + + if (MacroNames && !Macros.count(MacroName)) + MacroNames->push_back(MacroName); + Macros[MacroName] = std::make_pair(MacroBody, false); + } +} + +/// \brief Check the preprocessor options deserialized from the control block +/// against the preprocessor options in an existing preprocessor. +/// +/// \param Diags If non-null, produce diagnostics for any mismatches incurred. +static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, + const PreprocessorOptions &ExistingPPOpts, + DiagnosticsEngine *Diags, + FileManager &FileMgr, + std::string &SuggestedPredefines) { + // Check macro definitions. + MacroDefinitionsMap ASTFileMacros; + collectMacroDefinitions(PPOpts, ASTFileMacros); + MacroDefinitionsMap ExistingMacros; + SmallVector<StringRef, 4> ExistingMacroNames; + collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames); + + for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) { + // Dig out the macro definition in the existing preprocessor options. + StringRef MacroName = ExistingMacroNames[I]; + std::pair<StringRef, bool> Existing = ExistingMacros[MacroName]; + + // Check whether we know anything about this macro name or not. + llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known + = ASTFileMacros.find(MacroName); + if (Known == ASTFileMacros.end()) { + // FIXME: Check whether this identifier was referenced anywhere in the + // AST file. If so, we should reject the AST file. Unfortunately, this + // information isn't in the control block. What shall we do about it? + + if (Existing.second) { + SuggestedPredefines += "#undef "; + SuggestedPredefines += MacroName.str(); + SuggestedPredefines += '\n'; + } else { + SuggestedPredefines += "#define "; + SuggestedPredefines += MacroName.str(); + SuggestedPredefines += ' '; + SuggestedPredefines += Existing.first.str(); + SuggestedPredefines += '\n'; + } + continue; + } + + // If the macro was defined in one but undef'd in the other, we have a + // conflict. + if (Existing.second != Known->second.second) { + if (Diags) { + Diags->Report(diag::err_pch_macro_def_undef) + << MacroName << Known->second.second; + } + return true; + } + + // If the macro was #undef'd in both, or if the macro bodies are identical, + // it's fine. + if (Existing.second || Existing.first == Known->second.first) + continue; + + // The macro bodies differ; complain. + if (Diags) { + Diags->Report(diag::err_pch_macro_def_conflict) + << MacroName << Known->second.first << Existing.first; + } + return true; + } + + // Check whether we're using predefines. + if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) { + if (Diags) { + Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines; + } + return true; + } + + // Compute the #include and #include_macros lines we need. + for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { + StringRef File = ExistingPPOpts.Includes[I]; + if (File == ExistingPPOpts.ImplicitPCHInclude) + continue; + + if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File) + != PPOpts.Includes.end()) + continue; + + SuggestedPredefines += "#include \""; + SuggestedPredefines += + HeaderSearch::NormalizeDashIncludePath(File, FileMgr); + SuggestedPredefines += "\"\n"; + } + + for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { + StringRef File = ExistingPPOpts.MacroIncludes[I]; + if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(), + File) + != PPOpts.MacroIncludes.end()) + continue; + + SuggestedPredefines += "#__include_macros \""; + SuggestedPredefines += + HeaderSearch::NormalizeDashIncludePath(File, FileMgr); + SuggestedPredefines += "\"\n##\n"; + } + + return false; +} + +bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts(); + + return checkPreprocessorOptions(PPOpts, ExistingPPOpts, + Complain? &Reader.Diags : 0, + PP.getFileManager(), + SuggestedPredefines); +} + +void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, + unsigned ID) { + PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); + ++NumHeaderInfos; +} + +void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { + PP.setCounterValue(Value); +} + +//===----------------------------------------------------------------------===// +// AST reader implementation +//===----------------------------------------------------------------------===// + +void +ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { + DeserializationListener = Listener; +} + + + +unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { + return serialization::ComputeHash(Sel); +} + + +std::pair<unsigned, unsigned> +ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} + +ASTSelectorLookupTrait::internal_key_type +ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext().Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.getLocalIdentifier(F, ReadUnalignedLE32(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, ReadUnalignedLE32(d))); + + return SelTable.getSelector(N, Args.data()); +} + +ASTSelectorLookupTrait::data_type +ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + + data_type Result; + + Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); + + // Load instance methods + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) + Result.Instance.push_back(Method); + } + + // Load factory methods + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) + Result.Factory.push_back(Method); + } + + return Result; +} + +unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { + return llvm::HashString(StringRef(a.first, a.second)); +} + +std::pair<unsigned, unsigned> +ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned DataLen = ReadUnalignedLE16(d); + unsigned KeyLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} + +std::pair<const char*, unsigned> +ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { + assert(n >= 2 && d[n-1] == '\0'); + return std::make_pair((const char*) d, n-1); +} + +IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned RawID = ReadUnalignedLE32(d); + bool IsInteresting = RawID & 0x01; + + // Wipe out the "is interesting" bit. + RawID = RawID >> 1; + + IdentID ID = Reader.getGlobalIdentifierID(F, RawID); + if (!IsInteresting) { + // For uninteresting identifiers, just build the IdentifierInfo + // and associate it with the persistent ID. + IdentifierInfo *II = KnownII; + if (!II) { + II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + KnownII = II; + } + Reader.SetIdentifierInfo(ID, II); + II->setIsFromAST(); + Reader.markIdentifierUpToDate(II); + return II; + } + + unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d); + unsigned Bits = ReadUnalignedLE16(d); + bool CPlusPlusOperatorKeyword = Bits & 0x01; + Bits >>= 1; + bool HasRevertedTokenIDToIdentifier = Bits & 0x01; + Bits >>= 1; + bool Poisoned = Bits & 0x01; + Bits >>= 1; + bool ExtensionToken = Bits & 0x01; + Bits >>= 1; + bool hadMacroDefinition = Bits & 0x01; + Bits >>= 1; + + assert(Bits == 0 && "Extra bits in the identifier?"); + DataLen -= 8; + + // Build the IdentifierInfo itself and link the identifier ID with + // the new IdentifierInfo. + IdentifierInfo *II = KnownII; + if (!II) { + II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + KnownII = II; + } + Reader.markIdentifierUpToDate(II); + II->setIsFromAST(); + + // Set or check the various bits in the IdentifierInfo structure. + // Token IDs are read-only. + if (HasRevertedTokenIDToIdentifier) + II->RevertTokenIDToIdentifier(); + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + assert(II->isExtensionToken() == ExtensionToken && + "Incorrect extension token flag"); + (void)ExtensionToken; + if (Poisoned) + II->setIsPoisoned(true); + assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && + "Incorrect C++ operator keyword flag"); + (void)CPlusPlusOperatorKeyword; + + // If this identifier is a macro, deserialize the macro + // definition. + if (hadMacroDefinition) { + SmallVector<MacroID, 4> MacroIDs; + while (uint32_t LocalID = ReadUnalignedLE32(d)) { + MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID)); + DataLen -= 4; + } + DataLen -= 4; + Reader.setIdentifierIsMacro(II, MacroIDs); + } + + Reader.SetIdentifierInfo(ID, II); + + // Read all of the declarations visible at global scope with this + // name. + if (DataLen > 0) { + SmallVector<uint32_t, 4> DeclIDs; + for (; DataLen > 0; DataLen -= 4) + DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d))); + Reader.SetGloballyVisibleDecls(II, DeclIDs); + } + + return II; +} + +unsigned +ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(Key.Kind); + + switch (Key.Kind) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + ID.AddString(((IdentifierInfo*)Key.Data)->getName()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); + break; + case DeclarationName::CXXOperatorName: + ID.AddInteger((OverloadedOperatorKind)Key.Data); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + break; + } + + return ID.ComputeHash(); +} + +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::GetInternalKey( + const external_key_type& Name) const { + DeclNameKey Key; + Key.Kind = Name.getNameKind(); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Name.getAsIdentifierInfo(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = Name.getCXXOverloadedOperator(); + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; + } + + return Key; +} + +std::pair<unsigned, unsigned> +ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} + +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; + + DeclNameKey Key; + Key.Kind = (DeclarationName::NameKind)*d++; + switch (Key.Kind) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = + (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) + .getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = *d++; // OverloadedOperatorKind + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; + } + + return Key; +} + +ASTDeclContextNameLookupTrait::data_type +ASTDeclContextNameLookupTrait::ReadData(internal_key_type, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned NumDecls = ReadUnalignedLE16(d); + LE32DeclID *Start = (LE32DeclID *)d; + return std::make_pair(Start, Start + NumDecls); +} + +bool ASTReader::ReadDeclContextStorage(ModuleFile &M, + llvm::BitstreamCursor &Cursor, + const std::pair<uint64_t, uint64_t> &Offsets, + DeclContextInfo &Info) { + SavedStreamPosition SavedPosition(Cursor); + // First the lexical decls. + if (Offsets.first != 0) { + Cursor.JumpToBit(Offsets.first); + + RecordData Record; + const char *Blob; + unsigned BlobLen; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); + if (RecCode != DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; + } + + Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob); + Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair); + } + + // Now the lookup table. + if (Offsets.second != 0) { + Cursor.JumpToBit(Offsets.second); + + RecordData Record; + const char *Blob; + unsigned BlobLen; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); + if (RecCode != DECL_CONTEXT_VISIBLE) { + Error("Expected visible lookup table block"); + return true; + } + Info.NameLookupTableData + = ASTDeclContextNameLookupTable::Create( + (const unsigned char *)Blob + Record[0], + (const unsigned char *)Blob, + ASTDeclContextNameLookupTrait(*this, M)); + } + + return false; +} + +void ASTReader::Error(StringRef Msg) { + Error(diag::err_fe_pch_malformed, Msg); +} + +void ASTReader::Error(unsigned DiagID, + StringRef Arg1, StringRef Arg2) { + if (Diags.isDiagnosticInFlight()) + Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); + else + Diag(DiagID) << Arg1 << Arg2; +} + +//===----------------------------------------------------------------------===// +// Source Manager Deserialization +//===----------------------------------------------------------------------===// + +/// \brief Read the line table in the source manager block. +/// \returns true if there was an error. +bool ASTReader::ParseLineTable(ModuleFile &F, + SmallVectorImpl<uint64_t> &Record) { + unsigned Idx = 0; + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + // Parse the file names + std::map<int, int> FileIDs; + for (int I = 0, N = Record[Idx++]; I != N; ++I) { + // Extract the file name + unsigned FilenameLen = Record[Idx++]; + std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); + Idx += FilenameLen; + MaybeAddSystemRootToFilename(F, Filename); + FileIDs[I] = LineTable.getLineTableFilenameID(Filename); + } + + // Parse the line entries + std::vector<LineEntry> Entries; + while (Idx < Record.size()) { + int FID = Record[Idx++]; + assert(FID >= 0 && "Serialized line entries for non-local file."); + // Remap FileID from 1-based old view. + FID += F.SLocEntryBaseID - 1; + + // Extract the line entries + unsigned NumEntries = Record[Idx++]; + assert(NumEntries && "Numentries is 00000"); + Entries.clear(); + Entries.reserve(NumEntries); + for (unsigned I = 0; I != NumEntries; ++I) { + unsigned FileOffset = Record[Idx++]; + unsigned LineNo = Record[Idx++]; + int FilenameID = FileIDs[Record[Idx++]]; + SrcMgr::CharacteristicKind FileKind + = (SrcMgr::CharacteristicKind)Record[Idx++]; + unsigned IncludeOffset = Record[Idx++]; + Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, + FileKind, IncludeOffset)); + } + LineTable.AddEntry(FileID::get(FID), Entries); + } + + return false; +} + +/// \brief Read a source manager block +bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { + using namespace SrcMgr; + + llvm::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) { + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (SLocEntryCursor.ReadBlockEnd()) { + Error("error at end of Source Manager block in AST file"); + return true; + } + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + SLocEntryCursor.ReadSubBlockID(); + if (SLocEntryCursor.SkipBlock()) { + Error("malformed block record in AST file"); + return true; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + SLocEntryCursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case SM_SLOC_FILE_ENTRY: + case SM_SLOC_BUFFER_ENTRY: + case SM_SLOC_EXPANSION_ENTRY: + // Once we hit one of the source location entries, we're done. + return false; + } + } +} + +/// \brief If a header file is not found at the path that we expect it to be +/// and the PCH file was moved from its original location, try to resolve the +/// file by assuming that header+PCH were moved together and the header is in +/// the same place relative to the PCH. +static std::string +resolveFileRelativeToOriginalDir(const std::string &Filename, + const std::string &OriginalDir, + const std::string &CurrDir) { + assert(OriginalDir != CurrDir && + "No point trying to resolve the file if the PCH dir didn't change"); + using namespace llvm::sys; + SmallString<128> filePath(Filename); + fs::make_absolute(filePath); + assert(path::is_absolute(OriginalDir)); + SmallString<128> currPCHPath(CurrDir); + + path::const_iterator fileDirI = path::begin(path::parent_path(filePath)), + fileDirE = path::end(path::parent_path(filePath)); + path::const_iterator origDirI = path::begin(OriginalDir), + origDirE = path::end(OriginalDir); + // Skip the common path components from filePath and OriginalDir. + while (fileDirI != fileDirE && origDirI != origDirE && + *fileDirI == *origDirI) { + ++fileDirI; + ++origDirI; + } + for (; origDirI != origDirE; ++origDirI) + path::append(currPCHPath, ".."); + path::append(currPCHPath, fileDirI, fileDirE); + path::append(currPCHPath, path::filename(Filename)); + return currPCHPath.str(); +} + +bool ASTReader::ReadSLocEntry(int ID) { + if (ID == 0) + return false; + + if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { + Error("source location entry ID out-of-range for AST file"); + return true; + } + + ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; + F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); + llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; + unsigned BaseOffset = F->SLocEntryBaseOffset; + + ++NumSLocEntriesRead; + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK || + Code == llvm::bitc::ENTER_SUBBLOCK || + Code == llvm::bitc::DEFINE_ABBREV) { + Error("incorrectly-formatted source location entry in AST file"); + return true; + } + + RecordData Record; + const char *BlobStart; + unsigned BlobLen; + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + 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.getPointer(); + bool OverriddenBuffer = IF.getInt(); + + if (!IF.getPointer()) + return true; + + SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); + if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { + // This is the module's main file. + IncludeLoc = getImportLocation(F); + } + SrcMgr::CharacteristicKind + FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; + FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter, + ID, BaseOffset + Record[0]); + SrcMgr::FileInfo &FileInfo = + const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()); + FileInfo.NumCreatedFIDs = Record[5]; + if (Record[3]) + FileInfo.setHasLineDirectives(); + + const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; + unsigned NumFileDecls = Record[7]; + if (NumFileDecls) { + assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); + FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, + NumFileDecls)); + } + + const SrcMgr::ContentCache *ContentCache + = SourceMgr.getOrCreateContentCache(File, + /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + if (OverriddenBuffer && !ContentCache->BufferOverridden && + ContentCache->ContentsEntry == ContentCache->OrigEntry) { + unsigned Code = SLocEntryCursor.ReadCode(); + Record.clear(); + unsigned RecCode + = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); + + if (RecCode != SM_SLOC_BUFFER_BLOB) { + Error("AST record has invalid code"); + return true; + } + + llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), + File->getName()); + SourceMgr.overrideFileContents(File, Buffer); + } + + break; + } + + case SM_SLOC_BUFFER_ENTRY: { + const char *Name = BlobStart; + unsigned Offset = Record[0]; + SrcMgr::CharacteristicKind + FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; + SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); + if (IncludeLoc.isInvalid() && F->Kind == MK_Module) { + IncludeLoc = getImportLocation(F); + } + unsigned Code = SLocEntryCursor.ReadCode(); + Record.clear(); + unsigned RecCode + = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); + + if (RecCode != SM_SLOC_BUFFER_BLOB) { + Error("AST record has invalid code"); + return true; + } + + llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), + Name); + SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID, + BaseOffset + Offset, IncludeLoc); + break; + } + + case SM_SLOC_EXPANSION_ENTRY: { + SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]); + SourceMgr.createExpansionLoc(SpellingLoc, + ReadSourceLocation(*F, Record[2]), + ReadSourceLocation(*F, Record[3]), + Record[4], + ID, + BaseOffset + Record[0]); + break; + } + } + + return false; +} + +std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) { + if (ID == 0) + return std::make_pair(SourceLocation(), ""); + + if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { + Error("source location entry ID out-of-range for AST file"); + return std::make_pair(SourceLocation(), ""); + } + + // Find which module file this entry lands in. + ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; + if (M->Kind != MK_Module) + return std::make_pair(SourceLocation(), ""); + + // FIXME: Can we map this down to a particular submodule? That would be + // ideal. + return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName)); +} + +/// \brief Find the location where the module F is imported. +SourceLocation ASTReader::getImportLocation(ModuleFile *F) { + if (F->ImportLoc.isValid()) + return F->ImportLoc; + + // Otherwise we have a PCH. It's considered to be "imported" at the first + // location of its includer. + if (F->ImportedBy.empty() || !F->ImportedBy[0]) { + // Main file is the importer. We assume that it is the first entry in the + // entry table. We can't ask the manager, because at the time of PCH loading + // the main file entry doesn't exist yet. + // The very first entry is the invalid instantiation loc, which takes up + // offsets 0 and 1. + return SourceLocation::getFromRawEncoding(2U); + } + //return F->Loaders[0]->FirstLoc; + return F->ImportedBy[0]->FirstLoc; +} + +/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the +/// specified cursor. Read the abbreviations that are at the top of the block +/// and then leave the cursor pointing into the block. +bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, + unsigned BlockID) { + if (Cursor.EnterSubBlock(BlockID)) { + Error("malformed block record in AST file"); + return Failure; + } + + while (true) { + uint64_t Offset = Cursor.GetCurrentBitNo(); + unsigned Code = Cursor.ReadCode(); + + // We expect all abbrevs to be at the start of the block. + if (Code != llvm::bitc::DEFINE_ABBREV) { + Cursor.JumpToBit(Offset); + return false; + } + Cursor.ReadAbbrevRecord(); + } +} + +void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, + MacroInfo *Hint) { + llvm::BitstreamCursor &Stream = F.MacroCursor; + + // Keep track of where we are in the stream, then jump back there + // after reading this macro. + SavedStreamPosition SavedPosition(Stream); + + Stream.JumpToBit(Offset); + RecordData Record; + SmallVector<IdentifierInfo*, 16> MacroArgs; + MacroInfo *Macro = 0; + + // RAII object to add the loaded macro information once we're done + // adding tokens. + struct AddLoadedMacroInfoRAII { + Preprocessor &PP; + MacroInfo *Hint; + MacroInfo *MI; + IdentifierInfo *II; + + AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint) + : PP(PP), Hint(Hint), MI(), II() { } + ~AddLoadedMacroInfoRAII( ) { + if (MI) { + // Finally, install the macro. + PP.addLoadedMacroInfo(II, MI, Hint); + } + } + } AddLoadedMacroInfo(PP, Hint); + + while (true) { + unsigned Code = Stream.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + return; + + case llvm::bitc::ENTER_SUBBLOCK: + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return; + } + continue; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + default: break; + } + + // Read a record. + const char *BlobStart = 0; + unsigned BlobLen = 0; + Record.clear(); + PreprocessorRecordTypes RecType = + (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart, + BlobLen); + switch (RecType) { + 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; + + IdentifierInfo *II = getLocalIdentifier(F, Record[0]); + if (II == 0) { + Error("macro must have a name in AST file"); + return; + } + + unsigned GlobalID = getGlobalMacroID(F, Record[1]); + + // If this macro has already been loaded, don't do so again. + if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS]) + return; + + SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]); + unsigned NextIndex = 3; + SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); + MacroInfo *MI = PP.AllocateMacroInfo(Loc); + + // Record this macro. + MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI; + + SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex); + if (UndefLoc.isValid()) + MI->setUndefLoc(UndefLoc); + + MI->setIsUsed(Record[NextIndex++]); + MI->setIsFromAST(); + + bool IsPublic = Record[NextIndex++]; + MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); + + if (RecType == PP_MACRO_FUNCTION_LIKE) { + // Decode function-like macro info. + bool isC99VarArgs = Record[NextIndex++]; + bool isGNUVarArgs = Record[NextIndex++]; + bool hasCommaPasting = Record[NextIndex++]; + MacroArgs.clear(); + unsigned NumArgs = Record[NextIndex++]; + for (unsigned i = 0; i != NumArgs; ++i) + MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++])); + + // Install function-like macro info. + MI->setIsFunctionLike(); + if (isC99VarArgs) MI->setIsC99Varargs(); + if (isGNUVarArgs) MI->setIsGNUVarargs(); + if (hasCommaPasting) MI->setHasCommaPasting(); + MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), + PP.getPreprocessorAllocator()); + } + + if (DeserializationListener) + DeserializationListener->MacroRead(GlobalID, MI); + + // If an update record marked this as undefined, do so now. + // FIXME: Only if the submodule this update came from is visible? + MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); + if (Update != MacroUpdates.end()) { + if (MI->getUndefLoc().isInvalid()) { + for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { + bool Hidden = false; + if (unsigned SubmoduleID = Update->second[I].first) { + if (Module *Owner = getSubmodule(SubmoduleID)) { + if (Owner->NameVisibility == Module::Hidden) { + // Note that this #undef is hidden. + Hidden = true; + + // Record this hiding for later. + HiddenNamesMap[Owner].push_back( + HiddenName(II, MI, Update->second[I].second.UndefLoc)); + } + } + } + + if (!Hidden) { + MI->setUndefLoc(Update->second[I].second.UndefLoc); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(MI); + break; + } + } + } + MacroUpdates.erase(Update); + } + + // Determine whether this macro definition is visible. + bool Hidden = !MI->isPublic(); + if (!Hidden && GlobalSubmoduleID) { + if (Module *Owner = getSubmodule(GlobalSubmoduleID)) { + if (Owner->NameVisibility == Module::Hidden) { + // The owning module is not visible, and this macro definition + // should not be, either. + Hidden = true; + + // Note that this macro definition was hidden because its owning + // module is not yet visible. + HiddenNamesMap[Owner].push_back(HiddenName(II, MI)); + } + } + } + MI->setHidden(Hidden); + + // Make sure we install the macro once we're done. + AddLoadedMacroInfo.MI = MI; + AddLoadedMacroInfo.II = II; + + // 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(); + PPRec.RegisterMacroDefinition(Macro, + PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true)); + } + + ++NumMacrosRead; + break; + } + + case PP_TOKEN: { + // If we see a TOKEN before a PP_MACRO_*, then the file is + // erroneous, just pretend we didn't see this. + if (Macro == 0) break; + + Token Tok; + Tok.startToken(); + Tok.setLocation(ReadSourceLocation(F, Record[0])); + Tok.setLength(Record[1]); + if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) + Tok.setIdentifierInfo(II); + Tok.setKind((tok::TokenKind)Record[3]); + Tok.setFlag((Token::TokenFlags)Record[4]); + Macro->AddTokenToBody(Tok); + break; + } + } + } +} + +PreprocessedEntityID +ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { + ContinuousRangeMap<uint32_t, int, 2>::const_iterator + I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); + assert(I != M.PreprocessedEntityRemap.end() + && "Invalid index into preprocessed entity index remap"); + + return LocalID + I->second; +} + +unsigned HeaderFileInfoTrait::ComputeHash(const char *path) { + return llvm::HashString(llvm::sys::path::filename(path)); +} + +HeaderFileInfoTrait::internal_key_type +HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } + +bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { + if (strcmp(a, b) == 0) + return true; + + if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) + return false; + + // Determine whether the actual files are equivalent. + bool Result = false; + if (llvm::sys::fs::equivalent(a, b, Result)) + return false; + + return Result; +} + +std::pair<unsigned, unsigned> +HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { + unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); + unsigned DataLen = (unsigned) *d++; + return std::make_pair(KeyLen + 1, DataLen); +} + +HeaderFileInfoTrait::data_type +HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, + unsigned DataLen) { + const unsigned char *End = d + DataLen; + using namespace clang::io; + HeaderFileInfo HFI; + unsigned Flags = *d++; + HFI.isImport = (Flags >> 5) & 0x01; + HFI.isPragmaOnce = (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 2) & 0x03; + HFI.Resolved = (Flags >> 1) & 0x01; + HFI.IndexHeaderMapHeader = Flags & 0x01; + HFI.NumIncludes = ReadUnalignedLE16(d); + HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M, + ReadUnalignedLE32(d)); + if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) { + // The framework offset is 1 greater than the actual offset, + // since 0 is used as an indicator for "no framework name". + StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); + HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); + } + + assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); + (void)End; + + // This HeaderFileInfo was externally loaded. + HFI.External = true; + return HFI; +} + +void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){ + II->setHadMacroDefinition(true); + assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); + PendingMacroIDs[II].append(IDs.begin(), IDs.end()); +} + +void ASTReader::ReadDefinedMacros() { + // Note that we are loading defined macros. + Deserializing Macros(this); + + for (ModuleReverseIterator I = ModuleMgr.rbegin(), + E = ModuleMgr.rend(); I != E; ++I) { + llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; + + // If there was no preprocessor block, skip this file. + if (!MacroCursor.getBitStreamReader()) + continue; + + llvm::BitstreamCursor Cursor = MacroCursor; + Cursor.JumpToBit((*I)->MacroStartOffset); + + RecordData Record; + while (true) { + unsigned Code = Cursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) + break; + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Cursor.ReadSubBlockID(); + if (Cursor.SkipBlock()) { + Error("malformed block record in AST file"); + return; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Cursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case PP_MACRO_OBJECT_LIKE: + case PP_MACRO_FUNCTION_LIKE: + getLocalIdentifier(**I, Record[0]); + break; + + case PP_TOKEN: + // Ignore tokens. + break; + } + } + } +} + +namespace { + /// \brief Visitor class used to look up identifirs in an AST file. + class IdentifierLookupVisitor { + StringRef Name; + unsigned PriorGeneration; + IdentifierInfo *Found; + public: + IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration) + : Name(Name), PriorGeneration(PriorGeneration), Found() { } + + static bool visit(ModuleFile &M, void *UserData) { + IdentifierLookupVisitor *This + = static_cast<IdentifierLookupVisitor *>(UserData); + + // If we've already searched this module file, skip it now. + if (M.Generation <= This->PriorGeneration) + return true; + + ASTIdentifierLookupTable *IdTable + = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; + if (!IdTable) + return false; + + ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), + M, This->Found); + + std::pair<const char*, unsigned> Key(This->Name.begin(), + This->Name.size()); + ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait); + if (Pos == IdTable->end()) + return false; + + // Dereferencing the iterator has the effect of building the + // IdentifierInfo node and populating it with the various + // declarations it needs. + This->Found = *Pos; + return true; + } + + // \brief Retrieve the identifier info found within the module + // files. + IdentifierInfo *getIdentifierInfo() const { return Found; } + }; +} + +void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + + unsigned PriorGeneration = 0; + if (getContext().getLangOpts().Modules) + PriorGeneration = IdentifierGeneration[&II]; + + IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + markIdentifierUpToDate(&II); +} + +void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { + if (!II) + return; + + II->setOutOfDate(false); + + // Update the generation for this identifier. + if (getContext().getLangOpts().Modules) + IdentifierGeneration[II] = CurrentGeneration; +} + +llvm::PointerIntPair<const FileEntry *, 1, bool> +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].getPointer()) + return F.InputFilesLoaded[ID-1]; + + // Go find this input file. + llvm::BitstreamCursor &Cursor = F.InputFilesCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(F.InputFileOffsets[ID-1]); + + unsigned Code = Cursor.ReadCode(); + RecordData Record; + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + case INPUT_FILE: { + unsigned StoredID = Record[0]; + assert(ID == StoredID && "Bogus stored ID or offset"); + (void)StoredID; + off_t StoredSize = (off_t)Record[1]; + time_t StoredTime = (time_t)Record[2]; + bool Overridden = (bool)Record[3]; + + // Get the file entry for this input file. + StringRef OrigFilename(BlobStart, BlobLen); + std::string Filename = OrigFilename; + MaybeAddSystemRootToFilename(F, Filename); + const FileEntry *File + = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime) + : FileMgr.getFile(Filename, /*OpenFile=*/false); + + // If we didn't find the file, resolve it relative to the + // original directory from which this AST file was created. + if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() && + F.OriginalDir != CurrentDir) { + std::string Resolved = resolveFileRelativeToOriginalDir(Filename, + F.OriginalDir, + CurrentDir); + if (!Resolved.empty()) + File = FileMgr.getFile(Resolved); + } + + // For an overridden file, create a virtual file with the stored + // size/timestamp. + if (Overridden && File == 0) { + File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); + } + + if (File == 0) { + if (Complain) { + std::string ErrorStr = "could not find file '"; + ErrorStr += Filename; + ErrorStr += "' referenced by AST file"; + Error(ErrorStr.c_str()); + } + return InputFile(); + } + + // Note that we've loaded this input file. + F.InputFilesLoaded[ID-1] = InputFile(File, Overridden); + + // Check if there was a request to override the contents of the file + // that was part of the precompiled header. Overridding such a file + // can lead to problems when lexing using the source locations from the + // PCH. + SourceManager &SM = getSourceManager(); + if (!Overridden && SM.isFileOverridden(File)) { + Error(diag::err_fe_pch_file_overridden, Filename); + // After emitting the diagnostic, recover by disabling the override so + // that the original file will be used. + SM.disableFileContentsOverride(File); + // The FileEntry is a virtual file entry with the size of the contents + // that would override the original contents. Set it to the original's + // size/time. + FileMgr.modifyFileEntry(const_cast<FileEntry*>(File), + StoredSize, StoredTime); + } + + // For an overridden file, there is nothing to validate. + if (Overridden) + return InputFile(File, Overridden); + + if ((StoredSize != File->getSize() +#if !defined(LLVM_ON_WIN32) + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || StoredTime != File->getModificationTime() +#endif + )) { + if (Complain) + Error(diag::err_fe_pch_file_modified, Filename); + + return InputFile(); + } + + return InputFile(File, Overridden); + } + } + + return InputFile(); +} + +const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { + ModuleFile &M = ModuleMgr.getPrimaryModule(); + std::string Filename = filenameStrRef; + MaybeAddSystemRootToFilename(M, Filename); + const FileEntry *File = FileMgr.getFile(Filename); + if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() && + M.OriginalDir != CurrentDir) { + std::string resolved = resolveFileRelativeToOriginalDir(Filename, + M.OriginalDir, + CurrentDir); + if (!resolved.empty()) + File = FileMgr.getFile(resolved); + } + + return File; +} + +/// \brief If we are loading a relocatable PCH file, and the filename is +/// not an absolute path, add the system root to the beginning of the file +/// name. +void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M, + std::string &Filename) { + // If this is not a relocatable PCH file, there's nothing to do. + if (!M.RelocatablePCH) + return; + + if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) + return; + + if (isysroot.empty()) { + // If no system root was given, default to '/' + Filename.insert(Filename.begin(), '/'); + return; + } + + unsigned Length = isysroot.size(); + if (isysroot[Length - 1] != '/') + Filename.insert(Filename.begin(), '/'); + + Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end()); +} + +ASTReader::ASTReadResult +ASTReader::ReadControlBlock(ModuleFile &F, + llvm::SmallVectorImpl<ImportedModule> &Loaded, + unsigned ClientLoadCapabilities) { + llvm::BitstreamCursor &Stream = F.Stream; + + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + Error("malformed block record in AST file"); + return Failure; + } + + // Read all of the records and blocks in the control block. + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Error("error at end of control block in AST file"); + return Failure; + } + + // Validate all of the input files. + if (!DisableValidation) { + bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; + for (unsigned I = 0, N = Record[0]; I < N; ++I) + if (!getInputFile(F, I+1, Complain).getPointer()) + return OutOfDate; + } + + return Success; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + case INPUT_FILES_BLOCK_ID: + F.InputFilesCursor = Stream; + if (Stream.SkipBlock() || // Skip with the main cursor + // Read the abbreviations + ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) { + Error("malformed block record in AST file"); + return Failure; + } + continue; + + default: + if (!Stream.SkipBlock()) + continue; + break; + } + + Error("malformed block record in AST file"); + return Failure; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read and process a record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + case METADATA: { + if (Record[0] != VERSION_MAJOR && !DisableValidation) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old + : diag::warn_pch_version_too_new); + return VersionMismatch; + } + + bool hasErrors = Record[5]; + if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { + Diag(diag::err_pch_with_compiler_errors); + return HadErrors; + } + + F.RelocatablePCH = Record[4]; + + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; + return VersionMismatch; + } + break; + } + + case IMPORTS: { + // Load each of the imported PCH files. + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + // The import location will be the local one for now; we will adjust + // all import locations of module imports after the global source + // location info are setup. + SourceLocation ImportLoc = + SourceLocation::getFromRawEncoding(Record[Idx++]); + unsigned Length = Record[Idx++]; + SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + + // Load the AST file. + switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, + ClientLoadCapabilities)) { + case Failure: return Failure; + // If we have to ignore the dependency, we'll have to ignore this too. + case OutOfDate: return OutOfDate; + case VersionMismatch: return VersionMismatch; + case ConfigurationMismatch: return ConfigurationMismatch; + case HadErrors: return HadErrors; + case Success: break; + } + } + break; + } + + case LANGUAGE_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (Listener && &F == *ModuleMgr.begin() && + ParseLanguageOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case TARGET_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseTargetOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case DIAGNOSTIC_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseDiagnosticOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case FILE_SYSTEM_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseFileSystemOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case HEADER_SEARCH_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseHeaderSearchOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case PREPROCESSOR_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParsePreprocessorOptions(Record, Complain, *Listener, + SuggestedPredefines) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case ORIGINAL_FILE: + F.OriginalSourceFileID = FileID::get(Record[0]); + F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen); + F.OriginalSourceFileName = F.ActualOriginalSourceFileName; + MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName); + break; + + case ORIGINAL_FILE_ID: + F.OriginalSourceFileID = FileID::get(Record[0]); + break; + + case ORIGINAL_PCH_DIR: + F.OriginalDir.assign(BlobStart, BlobLen); + break; + + case INPUT_FILE_OFFSETS: + F.InputFileOffsets = (const uint32_t *)BlobStart; + F.InputFilesLoaded.resize(Record[0]); + break; + } + } + + Error("premature end of bitstream in AST file"); + return Failure; +} + +bool ASTReader::ReadASTBlock(ModuleFile &F) { + llvm::BitstreamCursor &Stream = F.Stream; + + if (Stream.EnterSubBlock(AST_BLOCK_ID)) { + Error("malformed block record in AST file"); + return true; + } + + // Read all of the records and blocks for the AST file. + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Error("error at end of module block in AST file"); + return true; + } + + DeclContext *DC = Context.getTranslationUnitDecl(); + if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) + DC->setMustBuildLookupTable(); + + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + case DECLTYPES_BLOCK_ID: + // We lazily load the decls block, but we want to set up the + // DeclsCursor cursor to point into it. Clone our current bitcode + // cursor to it, enter the block and read the abbrevs in that block. + // With the main cursor, we just skip over it. + F.DeclsCursor = Stream; + if (Stream.SkipBlock() || // Skip with the main cursor. + // Read the abbrevs. + ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) { + Error("malformed block record in AST file"); + return true; + } + break; + + case DECL_UPDATES_BLOCK_ID: + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return true; + } + 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 true; + } + 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 true; + } + 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 true; + break; + + case SUBMODULE_BLOCK_ID: + if (ReadSubmoduleBlock(F)) + return true; + break; + + case COMMENTS_BLOCK_ID: { + llvm::BitstreamCursor C = Stream; + if (Stream.SkipBlock() || + ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { + Error("malformed comments block in AST file"); + return true; + } + CommentsCursors.push_back(std::make_pair(C, &F)); + break; + } + + default: + if (!Stream.SkipBlock()) + break; + Error("malformed block record in AST file"); + return true; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read and process a record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case TYPE_OFFSET: { + if (F.LocalNumTypes != 0) { + Error("duplicate TYPE_OFFSET record in AST file"); + return true; + } + F.TypeOffsets = (const uint32_t *)BlobStart; + F.LocalNumTypes = Record[0]; + unsigned LocalBaseTypeIndex = Record[1]; + F.BaseTypeIndex = getTotalNumTypes(); + + if (F.LocalNumTypes > 0) { + // Introduce the global -> local mapping for types within this module. + GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F)); + + // Introduce the local -> global mapping for types within this module. + F.TypeRemap.insertOrReplace( + std::make_pair(LocalBaseTypeIndex, + F.BaseTypeIndex - LocalBaseTypeIndex)); + + TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); + } + break; + } + + case DECL_OFFSET: { + if (F.LocalNumDecls != 0) { + Error("duplicate DECL_OFFSET record in AST file"); + return true; + } + F.DeclOffsets = (const DeclOffset *)BlobStart; + F.LocalNumDecls = Record[0]; + unsigned LocalBaseDeclID = Record[1]; + F.BaseDeclID = getTotalNumDecls(); + + if (F.LocalNumDecls > 0) { + // Introduce the global -> local mapping for declarations within this + // module. + GlobalDeclMap.insert( + std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F)); + + // Introduce the local -> global mapping for declarations within this + // module. + F.DeclRemap.insertOrReplace( + std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID)); + + // Introduce the global -> local mapping for declarations within this + // module. + F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID; + + DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); + } + break; + } + + case TU_UPDATE_LEXICAL: { + DeclContext *TU = Context.getTranslationUnitDecl(); + DeclContextInfo &Info = F.DeclContextInfos[TU]; + Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart); + Info.NumLexicalDecls + = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair)); + TU->setHasExternalLexicalStorage(true); + break; + } + + case UPDATE_VISIBLE: { + unsigned Idx = 0; + serialization::DeclID ID = ReadDeclID(F, Record, Idx); + ASTDeclContextNameLookupTable *Table = + ASTDeclContextNameLookupTable::Create( + (const unsigned char *)BlobStart + Record[Idx++], + (const unsigned char *)BlobStart, + ASTDeclContextNameLookupTrait(*this, F)); + if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? + DeclContext *TU = Context.getTranslationUnitDecl(); + F.DeclContextInfos[TU].NameLookupTableData = Table; + TU->setHasExternalVisibleStorage(true); + } else + PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); + break; + } + + case IDENTIFIER_TABLE: + F.IdentifierTableData = BlobStart; + if (Record[0]) { + F.IdentifierLookupTable + = ASTIdentifierLookupTable::Create( + (const unsigned char *)F.IdentifierTableData + Record[0], + (const unsigned char *)F.IdentifierTableData, + ASTIdentifierLookupTrait(*this, F)); + + PP.getIdentifierTable().setExternalIdentifierLookup(this); + } + break; + + case IDENTIFIER_OFFSET: { + if (F.LocalNumIdentifiers != 0) { + Error("duplicate IDENTIFIER_OFFSET record in AST file"); + return true; + } + F.IdentifierOffsets = (const uint32_t *)BlobStart; + 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 EXTERNAL_DEFINITIONS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I])); + break; + + case SPECIAL_TYPES: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); + break; + + case STATISTICS: + TotalNumStatements += Record[0]; + TotalNumMacros += Record[1]; + TotalLexicalDeclContexts += Record[2]; + TotalVisibleDeclContexts += Record[3]; + break; + + case UNUSED_FILESCOPED_DECLS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + + case DELEGATING_CTORS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + + case WEAK_UNDECLARED_IDENTIFIERS: + if (Record.size() % 4 != 0) { + Error("invalid weak identifiers record"); + return true; + } + + // FIXME: Ignore weak undeclared identifiers from non-original PCH + // files. This isn't the way to do it :) + WeakUndeclaredIdentifiers.clear(); + + // Translate the weak, undeclared identifiers into global IDs. + for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) { + WeakUndeclaredIdentifiers.push_back( + getGlobalIdentifierID(F, Record[I++])); + WeakUndeclaredIdentifiers.push_back( + getGlobalIdentifierID(F, Record[I++])); + WeakUndeclaredIdentifiers.push_back( + ReadSourceLocation(F, Record, I).getRawEncoding()); + WeakUndeclaredIdentifiers.push_back(Record[I++]); + } + break; + + case LOCALLY_SCOPED_EXTERNAL_DECLS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + + case SELECTOR_OFFSETS: { + F.SelectorOffsets = (const uint32_t *)BlobStart; + 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 *)BlobStart; + if (Record[0]) + F.SelectorLookupTable + = ASTSelectorLookupTable::Create( + F.SelectorLookupTableData + Record[0], + F.SelectorLookupTableData, + ASTSelectorLookupTrait(*this, F)); + TotalNumMethodPoolEntries += Record[1]; + break; + + case REFERENCED_SELECTOR_POOL: + if (!Record.empty()) { + for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { + ReferencedSelectorsData.push_back(getGlobalSelectorID(F, + Record[Idx++])); + ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx). + getRawEncoding()); + } + } + break; + + case PP_COUNTER_VALUE: + if (!Record.empty() && Listener) + Listener->ReadCounter(F, Record[0]); + break; + + case FILE_SORTED_DECLS: + F.FileSortedDecls = (const DeclID *)BlobStart; + F.NumFileSortedDecls = Record[0]; + break; + + case SOURCE_LOCATION_OFFSETS: { + F.SLocEntryOffsets = (const uint32_t *)BlobStart; + F.LocalNumSLocEntries = Record[0]; + unsigned SLocSpaceSize = Record[1]; + llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = + SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, + SLocSpaceSize); + // Make our entry in the range map. BaseID is negative and growing, so + // we invert it. Because we invert it, though, we need the other end of + // the range. + unsigned RangeStart = + unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1; + GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); + F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); + + // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. + assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0); + GlobalSLocOffsetMap.insert( + std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset + - SLocSpaceSize,&F)); + + // Initialize the remapping table. + // Invalid stays invalid. + F.SLocRemap.insert(std::make_pair(0U, 0)); + // This module. Base was 2 when being compiled. + F.SLocRemap.insert(std::make_pair(2U, + static_cast<int>(F.SLocEntryBaseOffset - 2))); + + TotalNumSLocEntries += F.LocalNumSLocEntries; + break; + } + + case MODULE_OFFSET_MAP: { + // Additional remapping information. + const unsigned char *Data = (const unsigned char*)BlobStart; + const unsigned char *DataEnd = Data + BlobLen; + + // Continuous range maps we may be updating in our module. + ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + IdentifierRemap(F.IdentifierRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + MacroRemap(F.MacroRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + PreprocessedEntityRemap(F.PreprocessedEntityRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + SubmoduleRemap(F.SubmoduleRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + SelectorRemap(F.SelectorRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap); + + while(Data < DataEnd) { + uint16_t Len = io::ReadUnalignedLE16(Data); + StringRef Name = StringRef((const char*)Data, Len); + Data += Len; + ModuleFile *OM = ModuleMgr.lookup(Name); + if (!OM) { + Error("SourceLocation remap refers to unknown module"); + return true; + } + + uint32_t SLocOffset = io::ReadUnalignedLE32(Data); + uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data); + uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data); + uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data); + uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data); + uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data); + uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data); + uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data); + + // Source location offset is mapped to OM->SLocEntryBaseOffset. + SLocRemap.insert(std::make_pair(SLocOffset, + static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset))); + IdentifierRemap.insert( + std::make_pair(IdentifierIDOffset, + OM->BaseIdentifierID - IdentifierIDOffset)); + MacroRemap.insert(std::make_pair(MacroIDOffset, + OM->BaseMacroID - MacroIDOffset)); + PreprocessedEntityRemap.insert( + std::make_pair(PreprocessedEntityIDOffset, + OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset)); + SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset, + OM->BaseSubmoduleID - SubmoduleIDOffset)); + SelectorRemap.insert(std::make_pair(SelectorIDOffset, + OM->BaseSelectorID - SelectorIDOffset)); + DeclRemap.insert(std::make_pair(DeclIDOffset, + OM->BaseDeclID - DeclIDOffset)); + + TypeRemap.insert(std::make_pair(TypeIndexOffset, + OM->BaseTypeIndex - TypeIndexOffset)); + + // Global -> local mappings. + F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; + } + break; + } + + case SOURCE_MANAGER_LINE_TABLE: + if (ParseLineTable(F, Record)) + return true; + break; + + case SOURCE_LOCATION_PRELOADS: { + // Need to transform from the local view (1-based IDs) to the global view, + // which is based off F.SLocEntryBaseID. + if (!F.PreloadSLocEntries.empty()) { + Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); + return true; + } + + F.PreloadSLocEntries.swap(Record); + break; + } + + case EXT_VECTOR_DECLS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + + case VTABLE_USES: + if (Record.size() % 3 != 0) { + Error("Invalid VTABLE_USES record"); + return true; + } + + // Later tables overwrite earlier ones. + // FIXME: Modules will have some trouble with this. This is clearly not + // the right way to do this. + VTableUses.clear(); + + for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { + VTableUses.push_back(getGlobalDeclID(F, Record[Idx++])); + VTableUses.push_back( + ReadSourceLocation(F, Record, Idx).getRawEncoding()); + VTableUses.push_back(Record[Idx++]); + } + break; + + case DYNAMIC_CLASSES: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + DynamicClasses.push_back(getGlobalDeclID(F, Record[I])); + break; + + case PENDING_IMPLICIT_INSTANTIATIONS: + if (PendingInstantiations.size() % 2 != 0) { + Error("Invalid existing PendingInstantiations"); + return true; + } + + if (Record.size() % 2 != 0) { + Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); + return true; + } + + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); + PendingInstantiations.push_back( + ReadSourceLocation(F, Record, I).getRawEncoding()); + } + break; + + case SEMA_DECL_REFS: + // Later tables overwrite earlier ones. + // FIXME: Modules will have some trouble with this. + SemaDeclRefs.clear(); + 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 *)BlobStart; + assert(BlobLen % sizeof(PPEntityOffset) == 0); + F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); + + unsigned LocalBasePreprocessedEntityID = Record[0]; + + unsigned StartingID; + if (!PP.getPreprocessingRecord()) + PP.createPreprocessingRecord(); + if (!PP.getPreprocessingRecord()->getExternalSource()) + PP.getPreprocessingRecord()->SetExternalSource(*this); + StartingID + = PP.getPreprocessingRecord() + ->allocateLoadedEntities(F.NumPreprocessedEntities); + F.BasePreprocessedEntityID = StartingID; + + if (F.NumPreprocessedEntities > 0) { + // Introduce the global -> local mapping for preprocessed entities in + // this module. + GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F)); + + // Introduce the local -> global mapping for preprocessed entities in + // this module. + F.PreprocessedEntityRemap.insertOrReplace( + std::make_pair(LocalBasePreprocessedEntityID, + F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID)); + } + + break; + } + + case DECL_UPDATE_OFFSETS: { + if (Record.size() % 2 != 0) { + Error("invalid DECL_UPDATE_OFFSETS block in AST file"); + return true; + } + for (unsigned I = 0, N = Record.size(); I != N; I += 2) + DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] + .push_back(std::make_pair(&F, Record[I+1])); + break; + } + + case DECL_REPLACEMENTS: { + if (Record.size() % 3 != 0) { + Error("invalid DECL_REPLACEMENTS block in AST file"); + return true; + } + for (unsigned I = 0, N = Record.size(); I != N; I += 3) + ReplacedDecls[getGlobalDeclID(F, Record[I])] + = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]); + break; + } + + case OBJC_CATEGORIES_MAP: { + if (F.LocalNumObjCCategoriesInMap != 0) { + Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); + return true; + } + + F.LocalNumObjCCategoriesInMap = Record[0]; + F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart; + break; + } + + case OBJC_CATEGORIES: + F.ObjCCategories.swap(Record); + break; + + case CXX_BASE_SPECIFIER_OFFSETS: { + if (F.LocalNumCXXBaseSpecifiers != 0) { + Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file"); + return true; + } + + F.LocalNumCXXBaseSpecifiers = Record[0]; + F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; + NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers; + break; + } + + case DIAG_PRAGMA_MAPPINGS: + if (F.PragmaDiagMappings.empty()) + F.PragmaDiagMappings.swap(Record); + else + F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(), + Record.begin(), Record.end()); + break; + + case CUDA_SPECIAL_DECL_REFS: + // Later tables overwrite earlier ones. + // FIXME: Modules will have trouble with this. + CUDASpecialDeclRefs.clear(); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I])); + break; + + case HEADER_SEARCH_TABLE: { + F.HeaderFileInfoTableData = BlobStart; + F.LocalNumHeaderFileInfos = Record[1]; + F.HeaderFileFrameworkStrings = BlobStart + Record[2]; + if (Record[0]) { + F.HeaderFileInfoTable + = HeaderFileInfoLookupTable::Create( + (const unsigned char *)F.HeaderFileInfoTableData + Record[0], + (const unsigned char *)F.HeaderFileInfoTableData, + HeaderFileInfoTrait(*this, F, + &PP.getHeaderSearchInfo(), + BlobStart + Record[2])); + + PP.getHeaderSearchInfo().SetExternalSource(this); + if (!PP.getHeaderSearchInfo().getExternalLookup()) + PP.getHeaderSearchInfo().SetExternalLookup(this); + } + break; + } + + case FP_PRAGMA_OPTIONS: + // Later tables overwrite earlier ones. + FPPragmaOptions.swap(Record); + break; + + case OPENCL_EXTENSIONS: + // Later tables overwrite earlier ones. + OpenCLExtensions.swap(Record); + break; + + case TENTATIVE_DEFINITIONS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I])); + break; + + case KNOWN_NAMESPACES: + for (unsigned I = 0, N = Record.size(); I != N; ++I) + KnownNamespaces.push_back(getGlobalDeclID(F, Record[I])); + break; + + case IMPORTED_MODULES: { + if (F.Kind != MK_Module) { + // If we aren't loading a module (which has its own exports), make + // all of the imported modules visible. + // FIXME: Deal with macros-only imports. + for (unsigned I = 0, N = Record.size(); I != N; ++I) { + if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I])) + ImportedModules.push_back(GlobalID); + } + } + break; + } + + case LOCAL_REDECLARATIONS: { + F.RedeclarationChains.swap(Record); + break; + } + + case LOCAL_REDECLARATIONS_MAP: { + if (F.LocalNumRedeclarationsInMap != 0) { + Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file"); + return true; + } + + F.LocalNumRedeclarationsInMap = Record[0]; + F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart; + break; + } + + case MERGED_DECLARATIONS: { + for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) { + GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]); + SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID]; + for (unsigned N = Record[Idx++]; N > 0; --N) + Decls.push_back(getGlobalDeclID(F, Record[Idx++])); + } + break; + } + + case MACRO_OFFSET: { + if (F.LocalNumMacros != 0) { + Error("duplicate MACRO_OFFSET record in AST file"); + return true; + } + F.MacroOffsets = (const uint32_t *)BlobStart; + 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 MACRO_UPDATES: { + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + MacroID ID = getGlobalMacroID(F, Record[I++]); + if (I == N) + break; + + SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); + SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; + MacroUpdate Update; + Update.UndefLoc = UndefLoc; + MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); + } + break; + } + } + } + Error("premature end of bitstream in AST file"); + return true; +} + +void ASTReader::makeNamesVisible(const HiddenNames &Names) { + for (unsigned I = 0, N = Names.size(); I != N; ++I) { + switch (Names[I].getKind()) { + case HiddenName::Declaration: + Names[I].getDecl()->Hidden = false; + break; + + case HiddenName::MacroVisibility: { + std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); + Macro.second->setHidden(!Macro.second->isPublic()); + if (Macro.second->isDefined()) { + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + } + break; + } + + case HiddenName::MacroUndef: { + std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); + if (Macro.second->isDefined()) { + Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(Macro.second); + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + } + break; + } + } + } +} + +void ASTReader::makeModuleVisible(Module *Mod, + Module::NameVisibilityKind NameVisibility) { + llvm::SmallPtrSet<Module *, 4> Visited; + llvm::SmallVector<Module *, 4> Stack; + Stack.push_back(Mod); + while (!Stack.empty()) { + Mod = Stack.back(); + Stack.pop_back(); + + 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()) { + makeNamesVisible(Hidden->second); + HiddenNamesMap.erase(Hidden); + } + + // Push any non-explicit submodules onto the stack to be marked as + // visible. + for (Module::submodule_iterator Sub = Mod->submodule_begin(), + SubEnd = Mod->submodule_end(); + Sub != SubEnd; ++Sub) { + if (!(*Sub)->IsExplicit && Visited.insert(*Sub)) + Stack.push_back(*Sub); + } + + // Push any exported modules onto the stack to be marked as visible. + bool AnyWildcard = false; + bool UnrestrictedWildcard = false; + llvm::SmallVector<Module *, 4> WildcardRestrictions; + for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { + Module *Exported = Mod->Exports[I].getPointer(); + if (!Mod->Exports[I].getInt()) { + // Export a named module directly; no wildcards involved. + if (Visited.insert(Exported)) + Stack.push_back(Exported); + + continue; + } + + // Wildcard export: export all of the imported modules that match + // the given pattern. + AnyWildcard = true; + if (UnrestrictedWildcard) + continue; + + if (Module *Restriction = Mod->Exports[I].getPointer()) + WildcardRestrictions.push_back(Restriction); + else { + WildcardRestrictions.clear(); + UnrestrictedWildcard = true; + } + } + + // If there were any wildcards, push any imported modules that were + // re-exported by the wildcard restriction. + if (!AnyWildcard) + continue; + + for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { + Module *Imported = Mod->Imports[I]; + if (!Visited.insert(Imported)) + continue; + + bool Acceptable = UnrestrictedWildcard; + if (!Acceptable) { + // Check whether this module meets one of the restrictions. + for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { + Module *Restriction = WildcardRestrictions[R]; + if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) { + Acceptable = true; + break; + } + } + } + + if (!Acceptable) + continue; + + Stack.push_back(Imported); + } + } +} + +ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, + ModuleKind Type, + SourceLocation ImportLoc, + unsigned ClientLoadCapabilities) { + // Bump the generation number. + unsigned PreviousGeneration = CurrentGeneration++; + + unsigned NumModules = ModuleMgr.size(); + llvm::SmallVector<ImportedModule, 4> Loaded; + switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, + /*ImportedBy=*/0, Loaded, + ClientLoadCapabilities)) { + case Failure: + case OutOfDate: + case VersionMismatch: + case ConfigurationMismatch: + case HadErrors: + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end()); + 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 (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); + M != MEnd; ++M) { + ModuleFile &F = *M->Mod; + + // Read the AST block. + if (ReadASTBlock(F)) + return Failure; + + // Once read, set the ModuleFile bit base offset and update the size in + // bits of all files we've seen. + F.GlobalBitOffset = TotalModulesSizeInBits; + TotalModulesSizeInBits += F.SizeInBits; + GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); + + // Preload SLocEntries. + for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { + int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; + // Load it through the SourceManager and don't call ReadSLocEntry() + // directly because the entry may have already been loaded in which case + // calling ReadSLocEntry() directly would trigger an assertion in + // SourceManager. + SourceMgr.getLoadedSLocEntryByID(Index); + } + } + + // Setup the import locations. + for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); + M != MEnd; ++M) { + ModuleFile &F = *M->Mod; + if (!M->ImportedBy) + F.ImportLoc = M->ImportLoc; + else + F.ImportLoc = ReadSourceLocation(*M->ImportedBy, + M->ImportLoc.getRawEncoding()); + } + + // Mark all of the identifiers in the identifier table as being out of date, + // so that various accessors know to check the loaded modules when the + // identifier is used. + for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), + IdEnd = PP.getIdentifierTable().end(); + Id != IdEnd; ++Id) + Id->second->setOutOfDate(true); + + // Resolve any unresolved module exports. + for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { + UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; + SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); + Module *ResolvedMod = getSubmodule(GlobalID); + + if (Unresolved.IsImport) { + if (ResolvedMod) + Unresolved.Mod->Imports.push_back(ResolvedMod); + continue; + } + + if (ResolvedMod || Unresolved.IsWildcard) + Unresolved.Mod->Exports.push_back( + Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); + } + UnresolvedModuleImportExports.clear(); + + InitializeContext(); + + if (DeserializationListener) + DeserializationListener->ReaderInitialized(this); + + ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); + if (!PrimaryModule.OriginalSourceFileID.isInvalid()) { + PrimaryModule.OriginalSourceFileID + = FileID::get(PrimaryModule.SLocEntryBaseID + + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); + + // If this AST file is a precompiled preamble, then set the + // preamble file ID of the source manager to the file source file + // from which the preamble was built. + if (Type == MK_Preamble) { + SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID); + } else if (Type == MK_MainFile) { + SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID); + } + } + + // For any Objective-C class definitions we have already loaded, make sure + // that we load any additional categories. + for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { + loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), + ObjCClassesLoaded[I], + PreviousGeneration); + } + + return Success; +} + +ASTReader::ASTReadResult +ASTReader::ReadASTCore(StringRef FileName, + ModuleKind Type, + SourceLocation ImportLoc, + ModuleFile *ImportedBy, + llvm::SmallVectorImpl<ImportedModule> &Loaded, + unsigned ClientLoadCapabilities) { + ModuleFile *M; + bool NewModule; + std::string ErrorStr; + llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc, + ImportedBy, CurrentGeneration, + ErrorStr); + + if (!M) { + // We couldn't load the module. + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + return Failure; + } + + if (!NewModule) { + // We've already loaded this module. + return Success; + } + + // FIXME: This seems rather a hack. Should CurrentDir be part of the + // module? + if (FileName != "-") { + CurrentDir = llvm::sys::path::parent_path(FileName); + if (CurrentDir.empty()) CurrentDir = "."; + } + + ModuleFile &F = *M; + llvm::BitstreamCursor &Stream = F.Stream; + Stream.init(F.StreamFile); + F.SizeInBits = F.Buffer->getBufferSize() * 8; + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + Diag(diag::err_not_a_pch_file) << FileName; + return Failure; + } + + // This is used for compatibility with older PCH formats. + bool HaveReadControlBlock = false; + + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code != llvm::bitc::ENTER_SUBBLOCK) { + Error("invalid record at top-level of AST file"); + return Failure; + } + + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the control subblock ID. + switch (BlockID) { + case llvm::bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) { + Error("malformed BlockInfoBlock in AST file"); + return Failure; + } + break; + case CONTROL_BLOCK_ID: + HaveReadControlBlock = true; + switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) { + case Success: + break; + + case Failure: return Failure; + 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::warn_pch_version_too_old); + return VersionMismatch; + } + + // Record that we've loaded this module. + Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); + return Success; + + default: + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return Failure; + } + break; + } + } + + return Success; +} + +void ASTReader::InitializeContext() { + // If there's a listener, notify them that we "read" the translation unit. + if (DeserializationListener) + DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, + Context.getTranslationUnitDecl()); + + // Make sure we load the declaration update records for the translation unit, + // if there are any. + loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, + Context.getTranslationUnitDecl()); + + // FIXME: Find a better way to deal with collisions between these + // built-in types. Right now, we just ignore the problem. + + // Load the special types. + if (SpecialTypes.size() >= NumSpecialTypeIDs) { + if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { + if (!Context.CFConstantStringTypeDecl) + Context.setCFConstantStringType(GetType(String)); + } + + if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { + QualType FileType = GetType(File); + if (FileType.isNull()) { + Error("FILE type is NULL"); + return; + } + + if (!Context.FILEDecl) { + if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) + Context.setFILEDecl(Typedef->getDecl()); + else { + const TagType *Tag = FileType->getAs<TagType>(); + if (!Tag) { + Error("Invalid FILE type in AST file"); + return; + } + Context.setFILEDecl(Tag->getDecl()); + } + } + } + + if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) { + QualType Jmp_bufType = GetType(Jmp_buf); + if (Jmp_bufType.isNull()) { + Error("jmp_buf type is NULL"); + return; + } + + if (!Context.jmp_bufDecl) { + if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) + Context.setjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Jmp_bufType->getAs<TagType>(); + if (!Tag) { + Error("Invalid jmp_buf type in AST file"); + return; + } + Context.setjmp_bufDecl(Tag->getDecl()); + } + } + } + + if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) { + QualType Sigjmp_bufType = GetType(Sigjmp_buf); + if (Sigjmp_bufType.isNull()) { + Error("sigjmp_buf type is NULL"); + return; + } + + if (!Context.sigjmp_bufDecl) { + if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) + Context.setsigjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Sigjmp_bufType->getAs<TagType>(); + assert(Tag && "Invalid sigjmp_buf type in AST file"); + Context.setsigjmp_bufDecl(Tag->getDecl()); + } + } + } + + if (unsigned ObjCIdRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { + if (Context.ObjCIdRedefinitionType.isNull()) + Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); + } + + if (unsigned ObjCClassRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { + if (Context.ObjCClassRedefinitionType.isNull()) + Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); + } + + if (unsigned ObjCSelRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { + if (Context.ObjCSelRedefinitionType.isNull()) + Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); + } + + if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) { + QualType Ucontext_tType = GetType(Ucontext_t); + if (Ucontext_tType.isNull()) { + Error("ucontext_t type is NULL"); + return; + } + + if (!Context.ucontext_tDecl) { + if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>()) + Context.setucontext_tDecl(Typedef->getDecl()); + else { + const TagType *Tag = Ucontext_tType->getAs<TagType>(); + assert(Tag && "Invalid ucontext_t type in AST file"); + Context.setucontext_tDecl(Tag->getDecl()); + } + } + } + } + + ReadPragmaDiagnosticMappings(Context.getDiagnostics()); + + // If there were any CUDA special declarations, deserialize them. + if (!CUDASpecialDeclRefs.empty()) { + assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!"); + Context.setcudaConfigureCallDecl( + cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0]))); + } + + // Re-export any modules that were imported by a non-module AST file. + for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) { + if (Module *Imported = getSubmodule(ImportedModules[I])) + makeModuleVisible(Imported, Module::AllVisible); + } + ImportedModules.clear(); +} + +void ASTReader::finalizeForWriting() { + for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), + HiddenEnd = HiddenNamesMap.end(); + Hidden != HiddenEnd; ++Hidden) { + makeNamesVisible(Hidden->second); + } + HiddenNamesMap.clear(); +} + +/// \brief Retrieve the name of the original source file name +/// directly from the AST file, without actually loading the AST +/// file. +std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, + FileManager &FileMgr, + DiagnosticsEngine &Diags) { + // Open the AST file. + std::string ErrStr; + OwningPtr<llvm::MemoryBuffer> Buffer; + Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr)); + if (!Buffer) { + Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr; + return std::string(); + } + + // Initialize the stream + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName; + return std::string(); + } + + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the AST subblock ID. + switch (BlockID) { + case CONTROL_BLOCK_ID: + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; + return std::string(); + } + break; + + default: + if (Stream.SkipBlock()) { + Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; + return std::string(); + } + break; + } + continue; + } + + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName; + return std::string(); + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE) + return std::string(BlobStart, BlobLen); + } + + return std::string(); +} + +namespace { + class SimplePCHValidator : public ASTReaderListener { + const LangOptions &ExistingLangOpts; + const TargetOptions &ExistingTargetOpts; + const PreprocessorOptions &ExistingPPOpts; + FileManager &FileMgr; + + public: + SimplePCHValidator(const LangOptions &ExistingLangOpts, + const TargetOptions &ExistingTargetOpts, + const PreprocessorOptions &ExistingPPOpts, + FileManager &FileMgr) + : ExistingLangOpts(ExistingLangOpts), + ExistingTargetOpts(ExistingTargetOpts), + ExistingPPOpts(ExistingPPOpts), + FileMgr(FileMgr) + { + } + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + return checkLanguageOptions(ExistingLangOpts, LangOpts, 0); + } + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0); + } + virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr, + SuggestedPredefines); + } + }; +} + +bool ASTReader::readASTFileControlBlock(StringRef Filename, + FileManager &FileMgr, + ASTReaderListener &Listener) { + // Open the AST file. + std::string ErrStr; + OwningPtr<llvm::MemoryBuffer> Buffer; + Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr)); + if (!Buffer) { + return true; + } + + // Initialize the stream + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + return true; + } + + RecordData Record; + bool InControlBlock = false; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the control subblock ID. + switch (BlockID) { + case CONTROL_BLOCK_ID: + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + return true; + } else { + InControlBlock = true; + } + break; + + default: + if (Stream.SkipBlock()) + return true; + break; + } + continue; + } + + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + return true; + } + + InControlBlock = false; + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen); + if (InControlBlock) { + switch ((ControlRecordTypes)RecCode) { + case METADATA: { + if (Record[0] != VERSION_MAJOR) { + return true; + } + + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch) + return true; + + break; + } + case LANGUAGE_OPTIONS: + if (ParseLanguageOptions(Record, false, Listener)) + return true; + break; + + case TARGET_OPTIONS: + if (ParseTargetOptions(Record, false, Listener)) + return true; + break; + + case DIAGNOSTIC_OPTIONS: + if (ParseDiagnosticOptions(Record, false, Listener)) + return true; + break; + + case FILE_SYSTEM_OPTIONS: + if (ParseFileSystemOptions(Record, false, Listener)) + return true; + break; + + case HEADER_SEARCH_OPTIONS: + if (ParseHeaderSearchOptions(Record, false, Listener)) + return true; + break; + + case PREPROCESSOR_OPTIONS: { + std::string IgnoredSuggestedPredefines; + if (ParsePreprocessorOptions(Record, false, Listener, + IgnoredSuggestedPredefines)) + return true; + break; + } + + default: + // No other validation to perform. + break; + } + } + } + + return false; +} + + +bool ASTReader::isAcceptableASTFile(StringRef Filename, + FileManager &FileMgr, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + const PreprocessorOptions &PPOpts) { + SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr); + return !readASTFileControlBlock(Filename, FileMgr, validator); +} + +bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { + // Enter the submodule block. + if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) { + Error("malformed submodule block record in AST file"); + return true; + } + + ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); + bool First = true; + Module *CurrentModule = 0; + RecordData Record; + while (true) { + unsigned Code = F.Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (F.Stream.ReadBlockEnd()) { + Error("error at end of submodule block in AST file"); + return true; + } + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + F.Stream.ReadSubBlockID(); + if (F.Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return true; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + F.Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case SUBMODULE_DEFINITION: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (Record.size() < 7) { + Error("malformed module definition"); + return true; + } + + StringRef Name(BlobStart, BlobLen); + SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]); + SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]); + bool IsFramework = Record[2]; + bool IsExplicit = Record[3]; + bool IsSystem = Record[4]; + bool InferSubmodules = Record[5]; + bool InferExplicitSubmodules = Record[6]; + bool InferExportWildcard = Record[7]; + + Module *ParentModule = 0; + if (Parent) + ParentModule = getSubmodule(Parent); + + // Retrieve this (sub)module from the module map, creating it if + // necessary. + CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, + IsFramework, + IsExplicit).first; + SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; + if (GlobalIndex >= SubmodulesLoaded.size() || + SubmodulesLoaded[GlobalIndex]) { + Error("too many submodules"); + return true; + } + + CurrentModule->setASTFile(F.File); + CurrentModule->IsFromModuleFile = true; + CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; + CurrentModule->InferSubmodules = InferSubmodules; + CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; + CurrentModule->InferExportWildcard = InferExportWildcard; + if (DeserializationListener) + DeserializationListener->ModuleRead(GlobalID, CurrentModule); + + SubmodulesLoaded[GlobalIndex] = CurrentModule; + break; + } + + case SUBMODULE_UMBRELLA_HEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) { + if (!CurrentModule->getUmbrellaHeader()) + ModMap.setUmbrellaHeader(CurrentModule, Umbrella); + else if (CurrentModule->getUmbrellaHeader() != Umbrella) { + Error("mismatched umbrella headers in submodule"); + return true; + } + } + break; + } + + case SUBMODULE_HEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // FIXME: Be more lazy about this! + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { + if (std::find(CurrentModule->Headers.begin(), + CurrentModule->Headers.end(), + File) == CurrentModule->Headers.end()) + ModMap.addHeader(CurrentModule, File, false); + } + break; + } + + case SUBMODULE_EXCLUDED_HEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // FIXME: Be more lazy about this! + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { + if (std::find(CurrentModule->Headers.begin(), + CurrentModule->Headers.end(), + File) == CurrentModule->Headers.end()) + ModMap.addHeader(CurrentModule, File, true); + } + break; + } + + case SUBMODULE_TOPHEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // FIXME: Be more lazy about this! + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *File = PP.getFileManager().getFile(FileName)) + CurrentModule->TopHeaders.insert(File); + break; + } + + case SUBMODULE_UMBRELLA_DIR: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + StringRef DirName(BlobStart, BlobLen); + if (const DirectoryEntry *Umbrella + = PP.getFileManager().getDirectory(DirName)) { + if (!CurrentModule->getUmbrellaDir()) + ModMap.setUmbrellaDir(CurrentModule, Umbrella); + else if (CurrentModule->getUmbrellaDir() != Umbrella) { + Error("mismatched umbrella directories in submodule"); + return true; + } + } + break; + } + + case SUBMODULE_METADATA: { + if (!First) { + Error("submodule metadata record not at beginning of block"); + return true; + } + First = false; + + F.BaseSubmoduleID = getTotalNumSubmodules(); + F.LocalNumSubmodules = Record[0]; + unsigned LocalBaseSubmoduleID = Record[1]; + if (F.LocalNumSubmodules > 0) { + // Introduce the global -> local mapping for submodules within this + // module. + GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F)); + + // Introduce the local -> global mapping for submodules within this + // module. + F.SubmoduleRemap.insertOrReplace( + std::make_pair(LocalBaseSubmoduleID, + F.BaseSubmoduleID - LocalBaseSubmoduleID)); + + SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); + } + break; + } + + case SUBMODULE_IMPORTS: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { + UnresolvedModuleImportExport Unresolved; + Unresolved.File = &F; + Unresolved.Mod = CurrentModule; + Unresolved.ID = Record[Idx]; + Unresolved.IsImport = true; + Unresolved.IsWildcard = false; + UnresolvedModuleImportExports.push_back(Unresolved); + } + break; + } + + case SUBMODULE_EXPORTS: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { + UnresolvedModuleImportExport Unresolved; + Unresolved.File = &F; + Unresolved.Mod = CurrentModule; + Unresolved.ID = Record[Idx]; + Unresolved.IsImport = false; + Unresolved.IsWildcard = Record[Idx + 1]; + UnresolvedModuleImportExports.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: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + CurrentModule->addRequirement(StringRef(BlobStart, BlobLen), + Context.getLangOpts(), + Context.getTargetInfo()); + break; + } + } + } +} + +/// \brief Parse the record that corresponds to a LangOptions data +/// structure. +/// +/// This routine parses the language options from the AST file and then gives +/// them to the AST listener if one is set. +/// +/// \returns true if the listener deems the file unacceptable, false otherwise. +bool ASTReader::ParseLanguageOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + 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" + + ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; + VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); + LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); + + unsigned Length = Record[Idx++]; + LangOpts.CurrentModule.assign(Record.begin() + Idx, + Record.begin() + Idx + Length); + return Listener.ReadLanguageOptions(LangOpts, Complain); +} + +bool ASTReader::ParseTargetOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + unsigned Idx = 0; + TargetOptions TargetOpts; + TargetOpts.Triple = ReadString(Record, Idx); + TargetOpts.CPU = ReadString(Record, Idx); + TargetOpts.ABI = ReadString(Record, Idx); + TargetOpts.CXXABI = ReadString(Record, Idx); + TargetOpts.LinkerVersion = ReadString(Record, Idx); + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); + } + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.Features.push_back(ReadString(Record, Idx)); + } + + return Listener.ReadTargetOptions(TargetOpts, Complain); +} + +bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener) { + DiagnosticOptions DiagOpts; + unsigned Idx = 0; +#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++]; +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + DiagOpts.set##Name(static_cast<Type>(Record[Idx++])); +#include "clang/Basic/DiagnosticOptions.def" + + for (unsigned N = Record[Idx++]; N; --N) { + DiagOpts.Warnings.push_back(ReadString(Record, Idx)); + } + + return Listener.ReadDiagnosticOptions(DiagOpts, Complain); +} + +bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener) { + FileSystemOptions FSOpts; + unsigned Idx = 0; + FSOpts.WorkingDir = ReadString(Record, Idx); + return Listener.ReadFileSystemOptions(FSOpts, Complain); +} + +bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + HeaderSearchOptions HSOpts; + unsigned Idx = 0; + HSOpts.Sysroot = ReadString(Record, Idx); + + // Include entries. + for (unsigned N = Record[Idx++]; N; --N) { + std::string Path = ReadString(Record, Idx); + frontend::IncludeDirGroup Group + = static_cast<frontend::IncludeDirGroup>(Record[Idx++]); + bool IsUserSupplied = Record[Idx++]; + bool IsFramework = Record[Idx++]; + bool IgnoreSysRoot = Record[Idx++]; + bool IsInternal = Record[Idx++]; + bool ImplicitExternC = Record[Idx++]; + HSOpts.UserEntries.push_back( + HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework, + IgnoreSysRoot, IsInternal, ImplicitExternC)); + } + + // System header prefixes. + for (unsigned N = Record[Idx++]; N; --N) { + std::string Prefix = ReadString(Record, Idx); + bool IsSystemHeader = Record[Idx++]; + HSOpts.SystemHeaderPrefixes.push_back( + HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader)); + } + + HSOpts.ResourceDir = ReadString(Record, Idx); + HSOpts.ModuleCachePath = ReadString(Record, Idx); + HSOpts.DisableModuleHash = Record[Idx++]; + HSOpts.UseBuiltinIncludes = Record[Idx++]; + HSOpts.UseStandardSystemIncludes = Record[Idx++]; + HSOpts.UseStandardCXXIncludes = Record[Idx++]; + HSOpts.UseLibcxx = Record[Idx++]; + + return Listener.ReadHeaderSearchOptions(HSOpts, Complain); +} + +bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener, + std::string &SuggestedPredefines) { + PreprocessorOptions PPOpts; + unsigned Idx = 0; + + // Macro definitions/undefs + for (unsigned N = Record[Idx++]; N; --N) { + std::string Macro = ReadString(Record, Idx); + bool IsUndef = Record[Idx++]; + PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef)); + } + + // Includes + for (unsigned N = Record[Idx++]; N; --N) { + PPOpts.Includes.push_back(ReadString(Record, Idx)); + } + + // Macro Includes + for (unsigned N = Record[Idx++]; N; --N) { + PPOpts.MacroIncludes.push_back(ReadString(Record, Idx)); + } + + PPOpts.UsePredefines = Record[Idx++]; + PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); + PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); + PPOpts.ObjCXXARCStandardLibrary = + static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]); + SuggestedPredefines.clear(); + return Listener.ReadPreprocessorOptions(PPOpts, Complain, + SuggestedPredefines); +} + +std::pair<ModuleFile *, unsigned> +ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { + GlobalPreprocessedEntityMapType::iterator + I = GlobalPreprocessedEntityMap.find(GlobalIndex); + assert(I != GlobalPreprocessedEntityMap.end() && + "Corrupted global preprocessed entity map"); + ModuleFile *M = I->second; + unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID; + return std::make_pair(M, LocalIndex); +} + +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const { + if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord()) + return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID, + Mod.NumPreprocessedEntities); + + return std::make_pair(PreprocessingRecord::iterator(), + PreprocessingRecord::iterator()); +} + +std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator> +ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) { + return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls), + ModuleDeclIterator(this, &Mod, + Mod.FileSortedDecls + Mod.NumFileSortedDecls)); +} + +PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { + PreprocessedEntityID PPID = Index+1; + std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index); + ModuleFile &M = *PPInfo.first; + unsigned LocalIndex = PPInfo.second; + const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; + + SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); + M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); + + unsigned Code = M.PreprocessorDetailCursor.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + return 0; + + case llvm::bitc::ENTER_SUBBLOCK: + Error("unexpected subblock record in preprocessor detail block"); + return 0; + + case llvm::bitc::DEFINE_ABBREV: + Error("unexpected abbrevation record in preprocessor detail block"); + return 0; + + default: + break; + } + + if (!PP.getPreprocessingRecord()) { + Error("no preprocessing record"); + return 0; + } + + // Read the record. + SourceRange Range(ReadSourceLocation(M, PPOffs.Begin), + ReadSourceLocation(M, PPOffs.End)); + PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + RecordData Record; + PreprocessorDetailRecordTypes RecType = + (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord( + Code, Record, BlobStart, BlobLen); + switch (RecType) { + case PPD_MACRO_EXPANSION: { + bool isBuiltin = Record[0]; + IdentifierInfo *Name = 0; + MacroDefinition *Def = 0; + if (isBuiltin) + Name = getLocalIdentifier(M, Record[1]); + else { + PreprocessedEntityID + GlobalID = getGlobalPreprocessedEntityID(M, Record[1]); + Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1)); + } + + MacroExpansion *ME; + if (isBuiltin) + ME = new (PPRec) MacroExpansion(Name, Range); + else + ME = new (PPRec) MacroExpansion(Def, Range); + + return ME; + } + + case PPD_MACRO_DEFINITION: { + // Decode the identifier info and then check again; if the macro is + // still defined and associated with the identifier, + IdentifierInfo *II = getLocalIdentifier(M, Record[0]); + MacroDefinition *MD + = new (PPRec) MacroDefinition(II, Range); + + if (DeserializationListener) + DeserializationListener->MacroDefinitionRead(PPID, MD); + + return MD; + } + + case PPD_INCLUSION_DIRECTIVE: { + const char *FullFileNameStart = BlobStart + Record[0]; + StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]); + const FileEntry *File = 0; + if (!FullFileName.empty()) + File = PP.getFileManager().getFile(FullFileName); + + // FIXME: Stable encoding + InclusionDirective::InclusionKind Kind + = static_cast<InclusionDirective::InclusionKind>(Record[2]); + InclusionDirective *ID + = new (PPRec) InclusionDirective(PPRec, Kind, + StringRef(BlobStart, Record[0]), + Record[1], Record[3], + File, + Range); + return ID; + } + } + + llvm_unreachable("Invalid PreprocessorDetailRecordTypes"); +} + +/// \brief \arg SLocMapI points at a chunk of a module that contains no +/// preprocessed entities or the entities it contains are not the ones we are +/// looking for. Find the next module that contains entities and return the ID +/// of the first entry. +PreprocessedEntityID ASTReader::findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const { + ++SLocMapI; + for (GlobalSLocOffsetMapType::const_iterator + EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { + ModuleFile &M = *SLocMapI->second; + if (M.NumPreprocessedEntities) + return M.BasePreprocessedEntityID; + } + + return getTotalNumPreprocessedEntities(); +} + +namespace { + +template <unsigned PPEntityOffset::*PPLoc> +struct PPEntityComp { + const ASTReader &Reader; + ModuleFile &M; + + PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { } + + bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { + SourceLocation LHS = getLoc(L); + SourceLocation RHS = getLoc(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(const PPEntityOffset &L, SourceLocation RHS) const { + SourceLocation LHS = getLoc(L); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, const PPEntityOffset &R) const { + SourceLocation RHS = getLoc(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLoc(const PPEntityOffset &PPE) const { + return Reader.ReadSourceLocation(M, PPE.*PPLoc); + } +}; + +} + +/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. +PreprocessedEntityID +ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { + if (SourceMgr.isLocalSourceLocation(BLoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + BLoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + ModuleFile &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + + size_t Count = M.NumPreprocessedEntities; + size_t Half; + pp_iterator First = pp_begin; + pp_iterator PPI; + + // Do a binary search manually instead of using std::lower_bound because + // The end locations of entities may be unordered (when a macro expansion + // is inside another macro argument), but for this case it is not important + // whether we get the first macro expansion or its containing macro. + while (Count > 0) { + Half = Count/2; + PPI = First; + std::advance(PPI, Half); + if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End), + BLoc)){ + First = PPI; + ++First; + Count = Count - Half - 1; + } else + Count = Half; + } + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return M.BasePreprocessedEntityID + (PPI - pp_begin); +} + +/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. +PreprocessedEntityID +ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { + if (SourceMgr.isLocalSourceLocation(ELoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + ELoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + ModuleFile &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + pp_iterator PPI = + std::upper_bound(pp_begin, pp_end, ELoc, + PPEntityComp<&PPEntityOffset::Begin>(*this, M)); + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return M.BasePreprocessedEntityID + (PPI - pp_begin); +} + +/// \brief Returns a pair of [Begin, End) indices of preallocated +/// preprocessed entities that \arg Range encompasses. +std::pair<unsigned, unsigned> + ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { + if (Range.isInvalid()) + return std::make_pair(0,0); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin()); + PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd()); + return std::make_pair(BeginID, EndID); +} + +/// \brief Optionally returns true or false if the preallocated preprocessed +/// entity with index \arg Index came from file \arg FID. +llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index, + FileID FID) { + if (FID.isInvalid()) + return false; + + std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index); + ModuleFile &M = *PPInfo.first; + unsigned LocalIndex = PPInfo.second; + const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; + + SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin); + if (Loc.isInvalid()) + return false; + + if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID)) + return true; + else + return false; +} + +namespace { + /// \brief Visitor used to search for information about a header file. + class HeaderFileInfoVisitor { + ASTReader &Reader; + const FileEntry *FE; + + llvm::Optional<HeaderFileInfo> HFI; + + public: + HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE) + : Reader(Reader), FE(FE) { } + + static bool visit(ModuleFile &M, void *UserData) { + HeaderFileInfoVisitor *This + = static_cast<HeaderFileInfoVisitor *>(UserData); + + HeaderFileInfoTrait Trait(This->Reader, M, + &This->Reader.getPreprocessor().getHeaderSearchInfo(), + M.HeaderFileFrameworkStrings, + This->FE->getName()); + + HeaderFileInfoLookupTable *Table + = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable); + if (!Table) + return false; + + // Look in the on-disk hash table for an entry for this file name. + HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(), + &Trait); + if (Pos == Table->end()) + return false; + + This->HFI = *Pos; + return true; + } + + llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } + }; +} + +HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { + HeaderFileInfoVisitor Visitor(*this, FE); + ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); + if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) { + if (Listener) + Listener->ReadHeaderFileInfo(*HFI, FE->getUID()); + return *HFI; + } + + return HeaderFileInfo(); +} + +void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { + // FIXME: Make it work properly with modules. + llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; + for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { + ModuleFile &F = *(*I); + unsigned Idx = 0; + DiagStates.clear(); + assert(!Diag.DiagStates.empty()); + DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one. + while (Idx < F.PragmaDiagMappings.size()) { + SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); + unsigned DiagStateID = F.PragmaDiagMappings[Idx++]; + if (DiagStateID != 0) { + Diag.DiagStatePoints.push_back( + DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1], + FullSourceLoc(Loc, SourceMgr))); + continue; + } + + assert(DiagStateID == 0); + // A new DiagState was created here. + Diag.DiagStates.push_back(*Diag.GetCurDiagState()); + DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back(); + DiagStates.push_back(NewState); + Diag.DiagStatePoints.push_back( + DiagnosticsEngine::DiagStatePoint(NewState, + FullSourceLoc(Loc, SourceMgr))); + while (1) { + assert(Idx < F.PragmaDiagMappings.size() && + "Invalid data, didn't find '-1' marking end of diag/map pairs"); + if (Idx >= F.PragmaDiagMappings.size()) { + break; // Something is messed up but at least avoid infinite loop in + // release build. + } + unsigned DiagID = F.PragmaDiagMappings[Idx++]; + if (DiagID == (unsigned)-1) { + break; // no more diag/map pairs for this location. + } + diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++]; + DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc); + Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo); + } + } + } +} + +/// \brief Get the correct cursor and offset for loading a type. +ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { + GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index); + assert(I != GlobalTypeMap.end() && "Corrupted global type map"); + ModuleFile *M = I->second; + return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]); +} + +/// \brief Read and return the type with the given index.. +/// +/// The index is the type ID, shifted and minus the number of predefs. This +/// routine actually reads the record corresponding to the type at the given +/// location. It is a helper routine for GetType, which deals with reading type +/// IDs. +QualType ASTReader::readTypeRecord(unsigned Index) { + RecordLocation Loc = TypeCursorForIndex(Index); + llvm::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_BLOCK_POINTER: { + if (Record.size() != 1) { + Error("Incorrect encoding of block pointer type"); + return QualType(); + } + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getBlockPointerType(PointeeType); + } + + case TYPE_LVALUE_REFERENCE: { + if (Record.size() != 2) { + Error("Incorrect encoding of lvalue reference type"); + return QualType(); + } + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getLValueReferenceType(PointeeType, Record[1]); + } + + case TYPE_RVALUE_REFERENCE: { + if (Record.size() != 1) { + Error("Incorrect encoding of rvalue reference type"); + return QualType(); + } + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getRValueReferenceType(PointeeType); + } + + case TYPE_MEMBER_POINTER: { + if (Record.size() != 2) { + Error("Incorrect encoding of member pointer type"); + return QualType(); + } + QualType PointeeType = readType(*Loc.F, Record, Idx); + QualType ClassType = readType(*Loc.F, Record, Idx); + if (PointeeType.isNull() || ClassType.isNull()) + return QualType(); + + return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); + } + + case TYPE_CONSTANT_ARRAY: { + QualType ElementType = readType(*Loc.F, Record, Idx); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + unsigned Idx = 3; + llvm::APInt Size = ReadAPInt(Record, Idx); + return Context.getConstantArrayType(ElementType, Size, + ASM, IndexTypeQuals); + } + + case TYPE_INCOMPLETE_ARRAY: { + QualType ElementType = readType(*Loc.F, Record, Idx); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); + } + + case TYPE_VARIABLE_ARRAY: { + QualType ElementType = readType(*Loc.F, Record, Idx); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]); + SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]); + return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F), + ASM, IndexTypeQuals, + SourceRange(LBLoc, RBLoc)); + } + + case TYPE_VECTOR: { + if (Record.size() != 3) { + Error("incorrect encoding of vector type in AST file"); + return QualType(); + } + + QualType ElementType = readType(*Loc.F, Record, Idx); + unsigned NumElements = Record[1]; + unsigned VecKind = Record[2]; + return Context.getVectorType(ElementType, NumElements, + (VectorType::VectorKind)VecKind); + } + + case TYPE_EXT_VECTOR: { + if (Record.size() != 3) { + Error("incorrect encoding of extended vector type in AST file"); + return QualType(); + } + + QualType ElementType = readType(*Loc.F, Record, Idx); + unsigned NumElements = Record[1]; + return Context.getExtVectorType(ElementType, NumElements); + } + + case TYPE_FUNCTION_NO_PROTO: { + if (Record.size() != 6) { + Error("incorrect encoding of no-proto function type"); + return QualType(); + } + QualType ResultType = readType(*Loc.F, Record, Idx); + FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], + (CallingConv)Record[4], Record[5]); + return Context.getFunctionNoProtoType(ResultType, Info); + } + + case TYPE_FUNCTION_PROTO: { + QualType ResultType = readType(*Loc.F, Record, Idx); + + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], + /*hasregparm*/ Record[2], + /*regparm*/ Record[3], + static_cast<CallingConv>(Record[4]), + /*produces*/ Record[5]); + + unsigned Idx = 6; + unsigned NumParams = Record[Idx++]; + SmallVector<QualType, 16> ParamTypes; + for (unsigned I = 0; I != NumParams; ++I) + ParamTypes.push_back(readType(*Loc.F, Record, Idx)); + + EPI.Variadic = Record[Idx++]; + EPI.HasTrailingReturn = Record[Idx++]; + EPI.TypeQuals = Record[Idx++]; + EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]); + ExceptionSpecificationType EST = + static_cast<ExceptionSpecificationType>(Record[Idx++]); + EPI.ExceptionSpecType = EST; + SmallVector<QualType, 2> Exceptions; + if (EST == EST_Dynamic) { + EPI.NumExceptions = Record[Idx++]; + for (unsigned I = 0; I != EPI.NumExceptions; ++I) + Exceptions.push_back(readType(*Loc.F, Record, Idx)); + EPI.Exceptions = Exceptions.data(); + } else if (EST == EST_ComputedNoexcept) { + EPI.NoexceptExpr = ReadExpr(*Loc.F); + } else if (EST == EST_Uninstantiated) { + EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); + EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); + } else if (EST == EST_Unevaluated) { + EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); + } + return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, + 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: + return Context.getAutoType(readType(*Loc.F, Record, Idx)); + + 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(); + llvm::Optional<unsigned> NumExpansions; + if (Record[1]) + NumExpansions = Record[1] - 1; + return Context.getPackExpansionType(Pattern, NumExpansions); + } + + case TYPE_ELABORATED: { + unsigned Idx = 0; + ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + QualType NamedType = readType(*Loc.F, Record, Idx); + return Context.getElaboratedType(Keyword, NNS, NamedType); + } + + case TYPE_OBJC_INTERFACE: { + unsigned Idx = 0; + ObjCInterfaceDecl *ItfD + = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx); + return Context.getObjCInterfaceType(ItfD->getCanonicalDecl()); + } + + case TYPE_OBJC_OBJECT: { + unsigned Idx = 0; + QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumProtos = Record[Idx++]; + SmallVector<ObjCProtocolDecl*, 4> Protos; + for (unsigned I = 0; I != NumProtos; ++I) + Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); + return Context.getObjCObjectType(Base, Protos.data(), NumProtos); + } + + case TYPE_OBJC_OBJECT_POINTER: { + unsigned Idx = 0; + QualType Pointee = readType(*Loc.F, Record, Idx); + return Context.getObjCObjectPointerType(Pointee); + } + + case TYPE_SUBST_TEMPLATE_TYPE_PARM: { + unsigned Idx = 0; + QualType Parm = readType(*Loc.F, Record, Idx); + QualType Replacement = readType(*Loc.F, Record, Idx); + return + Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + 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. + return + QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0); + } + + case TYPE_TEMPLATE_TYPE_PARM: { + unsigned Idx = 0; + unsigned Depth = Record[Idx++]; + unsigned Index = Record[Idx++]; + bool Pack = Record[Idx++]; + TemplateTypeParmDecl *D + = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx); + return Context.getTemplateTypeParmType(Depth, Index, Pack, D); + } + + case TYPE_DEPENDENT_NAME: { + unsigned Idx = 0; + ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); + QualType Canon = readType(*Loc.F, Record, Idx); + if (!Canon.isNull()) + Canon = Context.getCanonicalType(Canon); + return Context.getDependentNameType(Keyword, NNS, Name, Canon); + } + + case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { + unsigned Idx = 0; + ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); + unsigned NumArgs = Record[Idx++]; + SmallVector<TemplateArgument, 8> Args; + Args.reserve(NumArgs); + while (NumArgs--) + Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx)); + return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, + Args.size(), Args.data()); + } + + case TYPE_DEPENDENT_SIZED_ARRAY: { + unsigned Idx = 0; + + // ArrayType + QualType ElementType = readType(*Loc.F, Record, Idx); + ArrayType::ArraySizeModifier ASM + = (ArrayType::ArraySizeModifier)Record[Idx++]; + unsigned IndexTypeQuals = Record[Idx++]; + + // DependentSizedArrayType + Expr *NumElts = ReadExpr(*Loc.F); + SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx); + + return Context.getDependentSizedArrayType(ElementType, NumElts, ASM, + IndexTypeQuals, Brackets); + } + + case TYPE_TEMPLATE_SPECIALIZATION: { + unsigned Idx = 0; + bool IsDependent = Record[Idx++]; + TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); + SmallVector<TemplateArgument, 8> Args; + ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); + QualType Underlying = readType(*Loc.F, Record, Idx); + QualType T; + if (Underlying.isNull()) + T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(), + Args.size()); + else + T = Context.getTemplateSpecializationType(Name, Args.data(), + Args.size(), Underlying); + const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); + return T; + } + + case TYPE_ATOMIC: { + if (Record.size() != 1) { + Error("Incorrect encoding of atomic type"); + return QualType(); + } + QualType ValueType = readType(*Loc.F, Record, Idx); + return Context.getAtomicType(ValueType); + } + } + llvm_unreachable("Invalid TypeCode!"); +} + +class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> { + ASTReader &Reader; + ModuleFile &F; + const ASTReader::RecordData &Record; + unsigned &Idx; + + SourceLocation ReadSourceLocation(const ASTReader::RecordData &R, + unsigned &I) { + return Reader.ReadSourceLocation(F, R, I); + } + + template<typename T> + T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) { + return Reader.ReadDeclAs<T>(F, Record, Idx); + } + +public: + TypeLocReader(ASTReader &Reader, ModuleFile &F, + const ASTReader::RecordData &Record, unsigned &Idx) + : Reader(Reader), F(F), Record(Record), Idx(Idx) + { } + + // We want compile-time assurance that we've enumerated all of + // these, so unfortunately we have to declare them first, then + // define them out-of-line. +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitFunctionTypeLoc(FunctionTypeLoc); + void VisitArrayTypeLoc(ArrayTypeLoc); +}; + +void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + TL.setBuiltinLoc(ReadSourceLocation(Record, Idx)); + if (TL.needsExtraLocalData()) { + TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); + TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); + TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); + TL.setModeAttr(Record[Idx++]); + } +} +void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + TL.setCaretLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + TL.setAmpLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation(Record, Idx)); + TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); +} +void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { + TL.setLBracketLoc(ReadSourceLocation(Record, Idx)); + TL.setRBracketLoc(ReadSourceLocation(Record, Idx)); + if (Record[Idx++]) + TL.setSizeExpr(Reader.ReadExpr(F)); + else + TL.setSizeExpr(0); +} +void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx)); + } +} +void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); +} +void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); +} +void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { + TL.setAttrNameLoc(ReadSourceLocation(Record, Idx)); + if (TL.hasAttrOperand()) { + SourceRange range; + range.setBegin(ReadSourceLocation(Record, Idx)); + range.setEnd(ReadSourceLocation(Record, Idx)); + TL.setAttrOperandParensRange(range); + } + if (TL.hasAttrExprOperand()) { + if (Record[Idx++]) + TL.setAttrExprOperand(Reader.ReadExpr(F)); + else + TL.setAttrExprOperand(0); + } else if (TL.hasAttrEnumOperand()) + TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); + TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); + TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, + Reader.GetTemplateArgumentLocInfo(F, + TL.getTypePtr()->getArg(i).getKind(), + Record, Idx)); +} +void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); +} +void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL) { + TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); + TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); + TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); + TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + TL.setArgLocInfo(I, + Reader.GetTemplateArgumentLocInfo(F, + TL.getTypePtr()->getArg(I).getKind(), + Record, Idx)); +} +void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + TL.setEllipsisLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + TL.setHasBaseTypeAsWritten(Record[Idx++]); + TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + TL.setStarLoc(ReadSourceLocation(Record, Idx)); +} +void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); +} + +TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F, + const RecordData &Record, + unsigned &Idx) { + QualType InfoTy = readType(F, Record, Idx); + if (InfoTy.isNull()) + return 0; + + TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); + TypeLocReader TLR(*this, F, Record, Idx); + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLR.Visit(TL); + return TInfo; +} + +QualType ASTReader::GetType(TypeID ID) { + unsigned FastQuals = ID & Qualifiers::FastMask; + unsigned Index = ID >> Qualifiers::FastWidth; + + if (Index < NUM_PREDEF_TYPE_IDS) { + QualType T; + switch ((PredefinedTypeIDs)Index) { + case PREDEF_TYPE_NULL_ID: return QualType(); + case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; + case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; + + case PREDEF_TYPE_CHAR_U_ID: + case PREDEF_TYPE_CHAR_S_ID: + // FIXME: Check that the signedness of CharTy is correct! + T = Context.CharTy; + break; + + case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; + case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; + case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; + case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; + case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; + case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; + case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; + case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; + case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; + case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; + case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; + case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; + case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; + case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; + case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; + case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; + case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; + case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; + case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; + case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break; + case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; + case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; + case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; + case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; + case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; + case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; + case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; + case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; + case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; + + case PREDEF_TYPE_AUTO_RREF_DEDUCT: + T = Context.getAutoRRefDeductType(); + break; + + case PREDEF_TYPE_ARC_UNBRIDGED_CAST: + T = Context.ARCUnbridgedCastTy; + break; + + case PREDEF_TYPE_VA_LIST_TAG: + T = Context.getVaListTagType(); + break; + + case PREDEF_TYPE_BUILTIN_FN: + T = Context.BuiltinFnTy; + break; + } + + assert(!T.isNull() && "Unknown predefined type"); + return T.withFastQualifiers(FastQuals); + } + + Index -= NUM_PREDEF_TYPE_IDS; + assert(Index < TypesLoaded.size() && "Type index out-of-range"); + if (TypesLoaded[Index].isNull()) { + TypesLoaded[Index] = readTypeRecord(Index); + if (TypesLoaded[Index].isNull()) + return QualType(); + + TypesLoaded[Index]->setFromAST(); + if (DeserializationListener) + DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID), + TypesLoaded[Index]); + } + + return TypesLoaded[Index].withFastQualifiers(FastQuals); +} + +QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) { + return GetType(getGlobalTypeID(F, LocalID)); +} + +serialization::TypeID +ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { + unsigned FastQuals = LocalID & Qualifiers::FastMask; + unsigned LocalIndex = LocalID >> Qualifiers::FastWidth; + + if (LocalIndex < NUM_PREDEF_TYPE_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); + assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); + + unsigned GlobalIndex = LocalIndex + I->second; + return (GlobalIndex << Qualifiers::FastWidth) | FastQuals; +} + +TemplateArgumentLocInfo +ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, + TemplateArgument::ArgKind Kind, + const RecordData &Record, + unsigned &Index) { + switch (Kind) { + case TemplateArgument::Expression: + return ReadExpr(F); + case TemplateArgument::Type: + return GetTypeSourceInfo(F, Record, Index); + case TemplateArgument::Template: { + NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, + Index); + SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); + return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, + SourceLocation()); + } + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, + Index); + SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); + SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index); + return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, + EllipsisLoc); + } + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::Pack: + // FIXME: Is this right? + return TemplateArgumentLocInfo(); + } + llvm_unreachable("unexpected template argument loc"); +} + +TemplateArgumentLoc +ASTReader::ReadTemplateArgumentLoc(ModuleFile &F, + const RecordData &Record, unsigned &Index) { + TemplateArgument Arg = ReadTemplateArgument(F, Record, Index); + + if (Arg.getKind() == TemplateArgument::Expression) { + if (Record[Index++]) // bool InfoHasSameExpr. + return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); + } + return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(), + Record, Index)); +} + +Decl *ASTReader::GetExternalDecl(uint32_t ID) { + return GetDecl(ID); +} + +uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, + unsigned &Idx){ + if (Idx >= Record.size()) + return 0; + + unsigned LocalID = Record[Idx++]; + return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]); +} + +CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + RecordLocation Loc = getLocalBitOffset(Offset); + llvm::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 0; + } + + unsigned Idx = 0; + unsigned NumBases = Record[Idx++]; + void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); + CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; + for (unsigned I = 0; I != NumBases; ++I) + Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx); + return Bases; +} + +serialization::DeclID +ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { + if (LocalID < NUM_PREDEF_DECL_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS); + assert(I != F.DeclRemap.end() && "Invalid index into decl index remap"); + + return LocalID + I->second; +} + +bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, + ModuleFile &M) const { + GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + return &M == I->second; +} + +ModuleFile *ASTReader::getOwningModuleFile(Decl *D) { + if (!D->isFromASTFile()) + return 0; + GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID()); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + return I->second; +} + +SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { + if (ID < NUM_PREDEF_DECL_IDS) + return SourceLocation(); + + unsigned Index = ID - NUM_PREDEF_DECL_IDS; + + if (Index > DeclsLoaded.size()) { + Error("declaration ID out-of-range for AST file"); + return SourceLocation(); + } + + if (Decl *D = DeclsLoaded[Index]) + return D->getLocation(); + + unsigned RawLocation = 0; + RecordLocation Rec = DeclCursorForID(ID, RawLocation); + return ReadSourceLocation(*Rec.F, RawLocation); +} + +Decl *ASTReader::GetDecl(DeclID ID) { + if (ID < NUM_PREDEF_DECL_IDS) { + switch ((PredefinedDeclIDs)ID) { + case PREDEF_DECL_NULL_ID: + return 0; + + case PREDEF_DECL_TRANSLATION_UNIT_ID: + return Context.getTranslationUnitDecl(); + + case PREDEF_DECL_OBJC_ID_ID: + return Context.getObjCIdDecl(); + + case PREDEF_DECL_OBJC_SEL_ID: + return Context.getObjCSelDecl(); + + case PREDEF_DECL_OBJC_CLASS_ID: + return Context.getObjCClassDecl(); + + case PREDEF_DECL_OBJC_PROTOCOL_ID: + return Context.getObjCProtocolDecl(); + + case PREDEF_DECL_INT_128_ID: + return Context.getInt128Decl(); + + case PREDEF_DECL_UNSIGNED_INT_128_ID: + return Context.getUInt128Decl(); + + case PREDEF_DECL_OBJC_INSTANCETYPE_ID: + return Context.getObjCInstanceTypeDecl(); + + case PREDEF_DECL_BUILTIN_VA_LIST_ID: + return Context.getBuiltinVaListDecl(); + } + } + + unsigned Index = ID - NUM_PREDEF_DECL_IDS; + + if (Index >= DeclsLoaded.size()) { + assert(0 && "declaration ID out-of-range for AST file"); + Error("declaration ID out-of-range for AST file"); + return 0; + } + + if (!DeclsLoaded[Index]) { + ReadDeclRecord(ID); + if (DeserializationListener) + DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); + } + + return DeclsLoaded[Index]; +} + +DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + DeclID GlobalID) { + if (GlobalID < NUM_PREDEF_DECL_IDS) + return GlobalID; + + GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + ModuleFile *Owner = I->second; + + llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos + = M.GlobalToLocalDeclIDs.find(Owner); + if (Pos == M.GlobalToLocalDeclIDs.end()) + return 0; + + return GlobalID - Owner->BaseDeclID + Pos->second; +} + +serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F, + const RecordData &Record, + unsigned &Idx) { + if (Idx >= Record.size()) { + Error("Corrupted AST file"); + return 0; + } + + return getGlobalDeclID(F, Record[Idx++]); +} + +/// \brief Resolve the offset of a statement into a statement. +/// +/// This operation will read a new statement from the external +/// source each time it is called, and is meant to be used via a +/// LazyOffsetPtr (which is used by Decls for the body of functions, etc). +Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { + // Switch case IDs are per Decl. + ClearSwitchCaseIDs(); + + // Offset here is a global offset across the entire chain. + RecordLocation Loc = getLocalBitOffset(Offset); + Loc.F->DeclsCursor.JumpToBit(Loc.Offset); + return ReadStmtFromStream(*Loc.F); +} + +namespace { + class FindExternalLexicalDeclsVisitor { + ASTReader &Reader; + const DeclContext *DC; + bool (*isKindWeWant)(Decl::Kind); + + SmallVectorImpl<Decl*> &Decls; + bool PredefsVisited[NUM_PREDEF_DECL_IDS]; + + public: + FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls) + : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) + { + for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) + PredefsVisited[I] = false; + } + + static bool visit(ModuleFile &M, bool Preorder, void *UserData) { + if (Preorder) + return false; + + FindExternalLexicalDeclsVisitor *This + = static_cast<FindExternalLexicalDeclsVisitor *>(UserData); + + ModuleFile::DeclContextInfosMap::iterator Info + = M.DeclContextInfos.find(This->DC); + if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) + return false; + + // Load all of the declaration IDs + for (const KindDeclIDPair *ID = Info->second.LexicalDecls, + *IDE = ID + Info->second.NumLexicalDecls; + ID != IDE; ++ID) { + if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) + continue; + + // Don't add predefined declarations to the lexical context more + // than once. + if (ID->second < NUM_PREDEF_DECL_IDS) { + if (This->PredefsVisited[ID->second]) + continue; + + This->PredefsVisited[ID->second] = true; + } + + if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) { + if (!This->DC->isDeclInLexicalTraversal(D)) + This->Decls.push_back(D); + } + } + + return false; + } + }; +} + +ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls) { + // There might be lexical decls in multiple modules, for the TU at + // least. Walk all of the modules in the order they were loaded. + FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); + ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor); + ++NumLexicalDeclContextsRead; + return ELR_Success; +} + +namespace { + +class DeclIDComp { + ASTReader &Reader; + ModuleFile &Mod; + +public: + DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {} + + bool operator()(LocalDeclID L, LocalDeclID R) const { + SourceLocation LHS = getLocation(L); + SourceLocation RHS = getLocation(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, LocalDeclID R) const { + SourceLocation RHS = getLocation(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(LocalDeclID L, SourceLocation RHS) const { + SourceLocation LHS = getLocation(L); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLocation(LocalDeclID ID) const { + return Reader.getSourceManager().getFileLoc( + Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID))); + } +}; + +} + +void ASTReader::FindFileRegionDecls(FileID File, + unsigned Offset, unsigned Length, + SmallVectorImpl<Decl *> &Decls) { + SourceManager &SM = getSourceManager(); + + llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File); + if (I == FileDeclIDs.end()) + return; + + FileDeclsInfo &DInfo = I->second; + if (DInfo.Decls.empty()) + return; + + SourceLocation + BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset); + SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length); + + DeclIDComp DIDComp(*this, *DInfo.Mod); + ArrayRef<serialization::LocalDeclID>::iterator + BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(), + BeginLoc, DIDComp); + if (BeginIt != DInfo.Decls.begin()) + --BeginIt; + + // If we are pointing at a top-level decl inside an objc container, we need + // to backtrack until we find it otherwise we will fail to report that the + // region overlaps with an objc container. + while (BeginIt != DInfo.Decls.begin() && + GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt)) + ->isTopLevelDeclInObjCContainer()) + --BeginIt; + + ArrayRef<serialization::LocalDeclID>::iterator + EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(), + EndLoc, DIDComp); + if (EndIt != DInfo.Decls.end()) + ++EndIt; + + for (ArrayRef<serialization::LocalDeclID>::iterator + DIt = BeginIt; DIt != EndIt; ++DIt) + Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); +} + +namespace { + /// \brief ModuleFile visitor used to perform name lookup into a + /// declaration context. + class DeclContextNameLookupVisitor { + ASTReader &Reader; + llvm::SmallVectorImpl<const DeclContext *> &Contexts; + DeclarationName Name; + SmallVectorImpl<NamedDecl *> &Decls; + + public: + DeclContextNameLookupVisitor(ASTReader &Reader, + SmallVectorImpl<const DeclContext *> &Contexts, + DeclarationName Name, + SmallVectorImpl<NamedDecl *> &Decls) + : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { } + + static bool visit(ModuleFile &M, void *UserData) { + DeclContextNameLookupVisitor *This + = static_cast<DeclContextNameLookupVisitor *>(UserData); + + // Check whether we have any visible declaration information for + // this context in this module. + ModuleFile::DeclContextInfosMap::iterator Info; + bool FoundInfo = false; + for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { + Info = M.DeclContextInfos.find(This->Contexts[I]); + if (Info != M.DeclContextInfos.end() && + Info->second.NameLookupTableData) { + FoundInfo = true; + break; + } + } + + if (!FoundInfo) + return false; + + // Look for this name within this module. + ASTDeclContextNameLookupTable *LookupTable = + Info->second.NameLookupTableData; + ASTDeclContextNameLookupTable::iterator Pos + = LookupTable->find(This->Name); + if (Pos == LookupTable->end()) + return false; + + bool FoundAnything = false; + ASTDeclContextNameLookupTrait::data_type Data = *Pos; + for (; Data.first != Data.second; ++Data.first) { + NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first); + if (!ND) + continue; + + if (ND->getDeclName() != This->Name) { + // A name might be null because the decl's redeclarable part is + // currently read before reading its name. The lookup is triggered by + // building that decl (likely indirectly), and so it is later in the + // sense of "already existing" and can be ignored here. + continue; + } + + // Record this declaration. + FoundAnything = true; + This->Decls.push_back(ND); + } + + return FoundAnything; + } + }; +} + +DeclContext::lookup_result +ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + assert(DC->hasExternalVisibleStorage() && + "DeclContext has no visible decls in storage"); + if (!Name) + return DeclContext::lookup_result(DeclContext::lookup_iterator(0), + DeclContext::lookup_iterator(0)); + + SmallVector<NamedDecl *, 64> Decls; + + // Compute the declaration contexts we need to look into. Multiple such + // declaration contexts occur when two declaration contexts from disjoint + // modules get merged, e.g., when two namespaces with the same name are + // independently defined in separate modules. + SmallVector<const DeclContext *, 2> Contexts; + Contexts.push_back(DC); + + if (DC->isNamespace()) { + MergedDeclsMap::iterator Merged + = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Merged != MergedDecls.end()) { + for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + } + } + + DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); + ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); + ++NumVisibleDeclContextsRead; + SetExternalVisibleDeclsForName(DC, Name, Decls); + return const_cast<DeclContext*>(DC)->lookup(Name); +} + +namespace { + /// \brief ModuleFile visitor used to retrieve all visible names in a + /// declaration context. + class DeclContextAllNamesVisitor { + ASTReader &Reader; + llvm::SmallVectorImpl<const DeclContext *> &Contexts; + llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls; + + public: + DeclContextAllNamesVisitor(ASTReader &Reader, + SmallVectorImpl<const DeclContext *> &Contexts, + llvm::DenseMap<DeclarationName, + SmallVector<NamedDecl *, 8> > &Decls) + : Reader(Reader), Contexts(Contexts), Decls(Decls) { } + + static bool visit(ModuleFile &M, void *UserData) { + DeclContextAllNamesVisitor *This + = static_cast<DeclContextAllNamesVisitor *>(UserData); + + // Check whether we have any visible declaration information for + // this context in this module. + ModuleFile::DeclContextInfosMap::iterator Info; + bool FoundInfo = false; + for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { + Info = M.DeclContextInfos.find(This->Contexts[I]); + if (Info != M.DeclContextInfos.end() && + Info->second.NameLookupTableData) { + FoundInfo = true; + break; + } + } + + if (!FoundInfo) + return false; + + ASTDeclContextNameLookupTable *LookupTable = + Info->second.NameLookupTableData; + bool FoundAnything = false; + for (ASTDeclContextNameLookupTable::data_iterator + I = LookupTable->data_begin(), E = LookupTable->data_end(); + I != E; ++I) { + ASTDeclContextNameLookupTrait::data_type Data = *I; + for (; Data.first != Data.second; ++Data.first) { + NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, + *Data.first); + if (!ND) + continue; + + // Record this declaration. + FoundAnything = true; + This->Decls[ND->getDeclName()].push_back(ND); + } + } + + return FoundAnything; + } + }; +} + +void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { + if (!DC->hasExternalVisibleStorage()) + return; + llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls; + + // Compute the declaration contexts we need to look into. Multiple such + // declaration contexts occur when two declaration contexts from disjoint + // modules get merged, e.g., when two namespaces with the same name are + // independently defined in separate modules. + SmallVector<const DeclContext *, 2> Contexts; + Contexts.push_back(DC); + + if (DC->isNamespace()) { + MergedDeclsMap::iterator Merged + = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); + if (Merged != MergedDecls.end()) { + for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) + Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); + } + } + + DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls); + ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); + ++NumVisibleDeclContextsRead; + + for (llvm::DenseMap<DeclarationName, + llvm::SmallVector<NamedDecl*, 8> >::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + SetExternalVisibleDeclsForName(DC, I->first, I->second); + } + const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false); +} + +/// \brief Under non-PCH compilation the consumer receives the objc methods +/// before receiving the implementation, and codegen depends on this. +/// We simulate this by deserializing and passing to consumer the methods of the +/// implementation before passing the deserialized implementation decl. +static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, + ASTConsumer *Consumer) { + assert(ImplD && Consumer); + + for (ObjCImplDecl::method_iterator + I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I) + Consumer->HandleInterestingDecl(DeclGroupRef(*I)); + + Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); +} + +void ASTReader::PassInterestingDeclsToConsumer() { + assert(Consumer); + while (!InterestingDecls.empty()) { + Decl *D = InterestingDecls.front(); + InterestingDecls.pop_front(); + + PassInterestingDeclToConsumer(D); + } +} + +void ASTReader::PassInterestingDeclToConsumer(Decl *D) { + if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) + PassObjCImplDeclToConsumer(ImplD, Consumer); + else + Consumer->HandleInterestingDecl(DeclGroupRef(D)); +} + +void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { + this->Consumer = Consumer; + + if (!Consumer) + return; + + for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) { + // Force deserialization of this decl, which will cause it to be queued for + // passing to the consumer. + GetDecl(ExternalDefinitions[I]); + } + ExternalDefinitions.clear(); + + PassInterestingDeclsToConsumer(); +} + +void ASTReader::PrintStats() { + std::fprintf(stderr, "*** AST File Statistics:\n"); + + unsigned NumTypesLoaded + = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), + QualType()); + unsigned NumDeclsLoaded + = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), + (Decl *)0); + unsigned NumIdentifiersLoaded + = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), + IdentifiersLoaded.end(), + (IdentifierInfo *)0); + unsigned NumMacrosLoaded + = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), + MacrosLoaded.end(), + (MacroInfo *)0); + 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)); + std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); + } + std::fprintf(stderr, "\n"); + dump(); + std::fprintf(stderr, "\n"); +} + +template<typename Key, typename ModuleFile, unsigned InitialCapacity> +static void +dumpModuleIDMap(StringRef Name, + const ContinuousRangeMap<Key, ModuleFile *, + InitialCapacity> &Map) { + if (Map.begin() == Map.end()) + return; + + typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType; + llvm::errs() << Name << ":\n"; + for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); + I != IEnd; ++I) { + llvm::errs() << " " << I->first << " -> " << I->second->FileName + << "\n"; + } +} + +void ASTReader::dump() { + llvm::errs() << "*** PCH/ModuleFile Remappings:\n"; + dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap); + dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap); + dumpModuleIDMap("Global type map", GlobalTypeMap); + dumpModuleIDMap("Global declaration map", GlobalDeclMap); + dumpModuleIDMap("Global identifier map", GlobalIdentifierMap); + dumpModuleIDMap("Global macro map", GlobalMacroMap); + dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); + dumpModuleIDMap("Global selector map", GlobalSelectorMap); + dumpModuleIDMap("Global preprocessed entity map", + GlobalPreprocessedEntityMap); + + llvm::errs() << "\n*** PCH/Modules Loaded:"; + for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(), + MEnd = ModuleMgr.end(); + M != MEnd; ++M) + (*M)->dump(); +} + +/// Return the amount of memory used by memory buffers, breaking down +/// by heap-backed versus mmap'ed memory. +void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { + for (ModuleConstIterator I = ModuleMgr.begin(), + E = ModuleMgr.end(); I != E; ++I) { + if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) { + size_t bytes = buf->getBufferSize(); + switch (buf->getBufferKind()) { + case llvm::MemoryBuffer::MemoryBuffer_Malloc: + sizes.malloc_bytes += bytes; + break; + case llvm::MemoryBuffer::MemoryBuffer_MMap: + sizes.mmap_bytes += bytes; + break; + } + } + } +} + +void ASTReader::InitializeSema(Sema &S) { + SemaObj = &S; + S.addExternalSource(this); + + // Makes sure any declarations that were deserialized "too early" + // still get added to the identifier's declaration chains. + for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { + SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I], + PreloadedDecls[I]->getDeclName()); + } + PreloadedDecls.clear(); + + // Load the offsets of the declarations that Sema references. + // They will be lazily deserialized when needed. + if (!SemaDeclRefs.empty()) { + assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!"); + if (!SemaObj->StdNamespace) + SemaObj->StdNamespace = SemaDeclRefs[0]; + if (!SemaObj->StdBadAlloc) + SemaObj->StdBadAlloc = SemaDeclRefs[1]; + } + + if (!FPPragmaOptions.empty()) { + assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); + SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0]; + } + + if (!OpenCLExtensions.empty()) { + unsigned I = 0; +#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++]; +#include "clang/Basic/OpenCLExtensions.def" + + assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS"); + } +} + +IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + + IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), + /*PriorGeneration=*/0); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + IdentifierInfo *II = Visitor.getIdentifierInfo(); + markIdentifierUpToDate(II); + return II; +} + +namespace clang { + /// \brief An identifier-lookup iterator that enumerates all of the + /// identifiers stored within a set of AST files. + class ASTIdentifierIterator : public IdentifierIterator { + /// \brief The AST reader whose identifiers are being enumerated. + const ASTReader &Reader; + + /// \brief The current index into the chain of AST files stored in + /// the AST reader. + unsigned Index; + + /// \brief The current position within the identifier lookup table + /// of the current AST file. + ASTIdentifierLookupTable::key_iterator Current; + + /// \brief The end position within the identifier lookup table of + /// the current AST file. + ASTIdentifierLookupTable::key_iterator End; + + public: + explicit ASTIdentifierIterator(const ASTReader &Reader); + + virtual StringRef Next(); + }; +} + +ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader) + : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) { + ASTIdentifierLookupTable *IdTable + = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable; + Current = IdTable->key_begin(); + End = IdTable->key_end(); +} + +StringRef ASTIdentifierIterator::Next() { + while (Current == End) { + // If we have exhausted all of our AST files, we're done. + if (Index == 0) + return StringRef(); + + --Index; + ASTIdentifierLookupTable *IdTable + = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index]. + IdentifierLookupTable; + Current = IdTable->key_begin(); + End = IdTable->key_end(); + } + + // We have any identifiers remaining in the current AST file; return + // the next one. + std::pair<const char*, unsigned> Key = *Current; + ++Current; + return StringRef(Key.first, Key.second); +} + +IdentifierIterator *ASTReader::getIdentifiers() const { + return new ASTIdentifierIterator(*this); +} + +namespace clang { namespace serialization { + class ReadMethodPoolVisitor { + ASTReader &Reader; + Selector Sel; + unsigned PriorGeneration; + llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods; + llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods; + + public: + ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, + unsigned PriorGeneration) + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } + + static bool visit(ModuleFile &M, void *UserData) { + ReadMethodPoolVisitor *This + = static_cast<ReadMethodPoolVisitor *>(UserData); + + if (!M.SelectorLookupTable) + return false; + + // If we've already searched this module file, skip it now. + if (M.Generation <= This->PriorGeneration) + return true; + + ASTSelectorLookupTable *PoolTable + = (ASTSelectorLookupTable*)M.SelectorLookupTable; + ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); + if (Pos == PoolTable->end()) + return false; + + ++This->Reader.NumSelectorsRead; + // FIXME: Not quite happy with the statistics here. We probably should + // disable this tracking when called via LoadSelector. + // Also, should entries without methods count as misses? + ++This->Reader.NumMethodPoolEntriesRead; + ASTSelectorLookupTrait::data_type Data = *Pos; + if (This->Reader.DeserializationListener) + This->Reader.DeserializationListener->SelectorRead(Data.ID, + This->Sel); + + This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); + This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + return true; + } + + /// \brief Retrieve the instance methods found by this visitor. + ArrayRef<ObjCMethodDecl *> getInstanceMethods() const { + return InstanceMethods; + } + + /// \brief Retrieve the instance methods found by this visitor. + ArrayRef<ObjCMethodDecl *> getFactoryMethods() const { + return FactoryMethods; + } + }; +} } // end namespace clang::serialization + +/// \brief Add the given set of methods to the method list. +static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods, + ObjCMethodList &List) { + for (unsigned I = 0, N = Methods.size(); I != N; ++I) { + S.addMethodToGlobalList(&List, Methods[I]); + } +} + +void ASTReader::ReadMethodPool(Selector Sel) { + // Get the selector generation and update it to the current generation. + unsigned &Generation = SelectorGeneration[Sel]; + unsigned PriorGeneration = Generation; + Generation = CurrentGeneration; + + // Search for methods defined with this selector. + ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); + ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); + + if (Visitor.getInstanceMethods().empty() && + Visitor.getFactoryMethods().empty()) { + ++NumMethodPoolMisses; + return; + } + + if (!getSema()) + return; + + Sema &S = *getSema(); + Sema::GlobalMethodPool::iterator Pos + = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; + + addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); + addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); +} + +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::ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) { + for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { + VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I])); + if (Var) + TentativeDefs.push_back(Var); + } + TentativeDefinitions.clear(); +} + +void ASTReader::ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) { + for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { + DeclaratorDecl *D + = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I])); + if (D) + Decls.push_back(D); + } + UnusedFileScopedDecls.clear(); +} + +void ASTReader::ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) { + for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { + CXXConstructorDecl *D + = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); + if (D) + Decls.push_back(D); + } + DelegatingCtorDecls.clear(); +} + +void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) { + for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) { + TypedefNameDecl *D + = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I])); + if (D) + Decls.push_back(D); + } + ExtVectorDecls.clear(); +} + +void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) { + for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + CXXRecordDecl *D + = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I])); + if (D) + Decls.push_back(D); + } + DynamicClasses.clear(); +} + +void +ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) { + for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { + NamedDecl *D + = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); + if (D) + Decls.push_back(D); + } + LocallyScopedExternalDecls.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::LoadSelector(Selector Sel) { + // It would be complicated to avoid reading the methods anyway. So don't. + ReadMethodPool(Sel); +} + +void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { + assert(ID && "Non-zero identifier ID required"); + assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); + IdentifiersLoaded[ID - 1] = II; + if (DeserializationListener) + DeserializationListener->IdentifierRead(ID, II); +} + +/// \brief Set the globally-visible declarations associated with the given +/// identifier. +/// +/// If the AST reader is currently in a state where the given declaration IDs +/// cannot safely be resolved, they are queued until it is safe to resolve +/// them. +/// +/// \param II an IdentifierInfo that refers to one or more globally-visible +/// declarations. +/// +/// \param DeclIDs the set of declaration IDs with the name @p II that are +/// visible at global scope. +/// +/// \param Nonrecursive should be true to indicate that the caller knows that +/// this call is non-recursive, and therefore the globally-visible declarations +/// will not be placed onto the pending queue. +void +ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, + const SmallVectorImpl<uint32_t> &DeclIDs, + bool Nonrecursive) { + if (NumCurrentElementsDeserializing && !Nonrecursive) { + PendingIdentifierInfos.push_back(PendingIdentifierInfo()); + PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); + PII.II = II; + PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end()); + return; + } + + for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { + NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I])); + if (SemaObj) { + // Introduce this declaration into the translation-unit scope + // and add it to the declaration chain for this identifier, so + // that (unqualified) name lookup will find it. + SemaObj->pushExternalDeclIntoScope(D, II); + } else { + // Queue this declaration so that it will be added to the + // translation unit scope and identifier's declaration chain + // once a Sema object is known. + PreloadedDecls.push_back(D); + } + } +} + +IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { + if (ID == 0) + return 0; + + if (IdentifiersLoaded.empty()) { + Error("no identifier table in AST file"); + return 0; + } + + ID -= 1; + if (!IdentifiersLoaded[ID]) { + GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1); + assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map"); + ModuleFile *M = I->second; + unsigned Index = ID - M->BaseIdentifierID; + const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index]; + + // All of the strings in the AST file are preceded by a 16-bit length. + // Extract that 16-bit length to avoid having to execute strlen(). + // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as + // unsigned integers. This is important to avoid integer overflow when + // we cast them to 'unsigned'. + const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; + unsigned StrLen = (((unsigned) StrLenPtr[0]) + | (((unsigned) StrLenPtr[1]) << 8)) - 1; + IdentifiersLoaded[ID] + = &PP.getIdentifierTable().get(StringRef(Str, StrLen)); + if (DeserializationListener) + DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]); + } + + return IdentifiersLoaded[ID]; +} + +IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) { + return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID)); +} + +IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { + if (LocalID < NUM_PREDEF_IDENT_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS); + assert(I != M.IdentifierRemap.end() + && "Invalid index into identifier index remap"); + + return LocalID + I->second; +} + +MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) { + if (ID == 0) + return 0; + + if (MacrosLoaded.empty()) { + Error("no macro table in AST file"); + return 0; + } + + ID -= NUM_PREDEF_MACRO_IDS; + if (!MacrosLoaded[ID]) { + GlobalMacroMapType::iterator I + = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS); + assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); + ModuleFile *M = I->second; + unsigned Index = ID - M->BaseMacroID; + ReadMacroRecord(*M, M->MacroOffsets[Index], Hint); + } + + return MacrosLoaded[ID]; +} + +MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { + if (LocalID < NUM_PREDEF_MACRO_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); + assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); + + return LocalID + I->second; +} + +serialization::SubmoduleID +ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { + if (LocalID < NUM_PREDEF_SUBMODULE_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); + assert(I != M.SubmoduleRemap.end() + && "Invalid index into submodule index remap"); + + return LocalID + I->second; +} + +Module *ASTReader::getSubmodule(SubmoduleID GlobalID) { + if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) { + assert(GlobalID == 0 && "Unhandled global submodule ID"); + return 0; + } + + if (GlobalID > SubmodulesLoaded.size()) { + Error("submodule ID out of range in AST file"); + return 0; + } + + return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; +} + +Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { + return DecodeSelector(getGlobalSelectorID(M, LocalID)); +} + +Selector ASTReader::DecodeSelector(serialization::SelectorID ID) { + if (ID == 0) + return Selector(); + + if (ID > SelectorsLoaded.size()) { + Error("selector ID out of range in AST file"); + return Selector(); + } + + if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) { + // Load this selector from the selector table. + GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID); + assert(I != GlobalSelectorMap.end() && "Corrupted global selector map"); + ModuleFile &M = *I->second; + ASTSelectorLookupTrait Trait(*this, M); + unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS; + SelectorsLoaded[ID - 1] = + Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0); + if (DeserializationListener) + DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); + } + + return SelectorsLoaded[ID - 1]; +} + +Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) { + return DecodeSelector(ID); +} + +uint32_t ASTReader::GetNumExternalSelectors() { + // ID 0 (the null selector) is considered an external selector. + return getTotalNumSelectors() + 1; +} + +serialization::SelectorID +ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { + if (LocalID < NUM_PREDEF_SELECTOR_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); + assert(I != M.SelectorRemap.end() + && "Invalid index into selector index remap"); + + return LocalID + I->second; +} + +DeclarationName +ASTReader::ReadDeclarationName(ModuleFile &F, + const RecordData &Record, unsigned &Idx) { + DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; + switch (Kind) { + case DeclarationName::Identifier: + return DeclarationName(GetIdentifierInfo(F, Record, Idx)); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return DeclarationName(ReadSelector(F, Record, Idx)); + + case DeclarationName::CXXConstructorName: + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(readType(F, Record, Idx))); + + case DeclarationName::CXXDestructorName: + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(readType(F, Record, Idx))); + + case DeclarationName::CXXConversionFunctionName: + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(readType(F, Record, Idx))); + + case DeclarationName::CXXOperatorName: + return Context.DeclarationNames.getCXXOperatorName( + (OverloadedOperatorKind)Record[Idx++]); + + case DeclarationName::CXXLiteralOperatorName: + return Context.DeclarationNames.getCXXLiteralOperatorName( + GetIdentifierInfo(F, Record, Idx)); + + case DeclarationName::CXXUsingDirective: + return DeclarationName::getUsingDirectiveName(); + } + + llvm_unreachable("Invalid NameKind!"); +} + +void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, + DeclarationNameLoc &DNLoc, + DeclarationName Name, + const RecordData &Record, unsigned &Idx) { + switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx); + break; + + case DeclarationName::CXXOperatorName: + DNLoc.CXXOperatorName.BeginOpNameLoc + = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + DNLoc.CXXOperatorName.EndOpNameLoc + = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + break; + + case DeclarationName::CXXLiteralOperatorName: + DNLoc.CXXLiteralOperatorName.OpNameLoc + = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + break; + } +} + +void ASTReader::ReadDeclarationNameInfo(ModuleFile &F, + DeclarationNameInfo &NameInfo, + const RecordData &Record, unsigned &Idx) { + NameInfo.setName(ReadDeclarationName(F, Record, Idx)); + NameInfo.setLoc(ReadSourceLocation(F, Record, Idx)); + DeclarationNameLoc DNLoc; + ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx); + NameInfo.setInfo(DNLoc); +} + +void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, + const RecordData &Record, unsigned &Idx) { + Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); + unsigned NumTPLists = Record[Idx++]; + Info.NumTemplParamLists = NumTPLists; + if (NumTPLists) { + Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; + for (unsigned i=0; i != NumTPLists; ++i) + Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); + } +} + +TemplateName +ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; + switch (Kind) { + case TemplateName::Template: + return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx)); + + case TemplateName::OverloadedTemplate: { + unsigned size = Record[Idx++]; + UnresolvedSet<8> Decls; + while (size--) + Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx)); + + return Context.getOverloadedTemplateName(Decls.begin(), Decls.end()); + } + + case TemplateName::QualifiedTemplate: { + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); + bool hasTemplKeyword = Record[Idx++]; + TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx); + return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template); + } + + case TemplateName::DependentTemplate: { + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); + if (Record[Idx++]) // isIdentifier + return Context.getDependentTemplateName(NNS, + GetIdentifierInfo(F, Record, + Idx)); + return Context.getDependentTemplateName(NNS, + (OverloadedOperatorKind)Record[Idx++]); + } + + case TemplateName::SubstTemplateTemplateParm: { + TemplateTemplateParmDecl *param + = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); + if (!param) return TemplateName(); + TemplateName replacement = ReadTemplateName(F, Record, Idx); + return Context.getSubstTemplateTemplateParm(param, replacement); + } + + case TemplateName::SubstTemplateTemplateParmPack: { + TemplateTemplateParmDecl *Param + = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); + if (!Param) + return TemplateName(); + + TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx); + if (ArgPack.getKind() != TemplateArgument::Pack) + return TemplateName(); + + return Context.getSubstTemplateTemplateParmPack(Param, ArgPack); + } + } + + llvm_unreachable("Unhandled template name kind!"); +} + +TemplateArgument +ASTReader::ReadTemplateArgument(ModuleFile &F, + const RecordData &Record, unsigned &Idx) { + TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; + switch (Kind) { + case TemplateArgument::Null: + return TemplateArgument(); + case TemplateArgument::Type: + return TemplateArgument(readType(F, Record, Idx)); + case TemplateArgument::Declaration: { + ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx); + bool ForReferenceParam = Record[Idx++]; + return TemplateArgument(D, ForReferenceParam); + } + case TemplateArgument::NullPtr: + return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true); + case TemplateArgument::Integral: { + llvm::APSInt Value = ReadAPSInt(Record, Idx); + QualType T = readType(F, Record, Idx); + return TemplateArgument(Context, Value, T); + } + case TemplateArgument::Template: + return TemplateArgument(ReadTemplateName(F, Record, Idx)); + case TemplateArgument::TemplateExpansion: { + TemplateName Name = ReadTemplateName(F, Record, Idx); + llvm::Optional<unsigned> NumTemplateExpansions; + if (unsigned NumExpansions = Record[Idx++]) + NumTemplateExpansions = NumExpansions - 1; + return TemplateArgument(Name, NumTemplateExpansions); + } + case TemplateArgument::Expression: + return TemplateArgument(ReadExpr(F)); + case TemplateArgument::Pack: { + unsigned NumArgs = Record[Idx++]; + TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; + for (unsigned I = 0; I != NumArgs; ++I) + Args[I] = ReadTemplateArgument(F, Record, Idx); + return TemplateArgument(Args, NumArgs); + } + } + + llvm_unreachable("Unhandled template argument kind!"); +} + +TemplateParameterList * +ASTReader::ReadTemplateParameterList(ModuleFile &F, + const RecordData &Record, unsigned &Idx) { + SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx); + + unsigned NumParams = Record[Idx++]; + SmallVector<NamedDecl *, 16> Params; + Params.reserve(NumParams); + while (NumParams--) + Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); + + TemplateParameterList* TemplateParams = + TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, + Params.data(), Params.size(), RAngleLoc); + return TemplateParams; +} + +void +ASTReader:: +ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs, + ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + unsigned NumTemplateArgs = Record[Idx++]; + TemplArgs.reserve(NumTemplateArgs); + while (NumTemplateArgs--) + TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx)); +} + +/// \brief Read a UnresolvedSet structure. +void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set, + const RecordData &Record, unsigned &Idx) { + unsigned NumDecls = Record[Idx++]; + Set.reserve(Context, NumDecls); + while (NumDecls--) { + NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx); + AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; + Set.addDecl(Context, D, 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; +} + +std::pair<CXXCtorInitializer **, unsigned> +ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + CXXCtorInitializer **CtorInitializers = 0; + unsigned NumInitializers = Record[Idx++]; + if (NumInitializers) { + CtorInitializers + = new (Context) CXXCtorInitializer*[NumInitializers]; + for (unsigned i=0; i != NumInitializers; ++i) { + TypeSourceInfo *TInfo = 0; + bool IsBaseVirtual = false; + FieldDecl *Member = 0; + IndirectFieldDecl *IndirectMember = 0; + + CtorInitializerType Type = (CtorInitializerType)Record[Idx++]; + switch (Type) { + case CTOR_INITIALIZER_BASE: + TInfo = GetTypeSourceInfo(F, Record, Idx); + IsBaseVirtual = Record[Idx++]; + break; + + case CTOR_INITIALIZER_DELEGATING: + TInfo = GetTypeSourceInfo(F, Record, Idx); + break; + + case CTOR_INITIALIZER_MEMBER: + Member = ReadDeclAs<FieldDecl>(F, Record, Idx); + break; + + case CTOR_INITIALIZER_INDIRECT_MEMBER: + IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx); + break; + } + + SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx); + Expr *Init = ReadExpr(F); + SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx); + bool IsWritten = Record[Idx++]; + unsigned SourceOrderOrNumArrayIndices; + SmallVector<VarDecl *, 8> Indices; + if (IsWritten) { + SourceOrderOrNumArrayIndices = Record[Idx++]; + } else { + SourceOrderOrNumArrayIndices = Record[Idx++]; + Indices.reserve(SourceOrderOrNumArrayIndices); + for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i) + Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx)); + } + + CXXCtorInitializer *BOMInit; + if (Type == CTOR_INITIALIZER_BASE) { + BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual, + LParenLoc, Init, RParenLoc, + MemberOrEllipsisLoc); + } else if (Type == CTOR_INITIALIZER_DELEGATING) { + BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc, + Init, RParenLoc); + } else if (IsWritten) { + if (Member) + BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, + LParenLoc, Init, RParenLoc); + else + BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, + MemberOrEllipsisLoc, LParenLoc, + Init, RParenLoc); + } else { + BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc, + LParenLoc, Init, RParenLoc, + Indices.data(), Indices.size()); + } + + if (IsWritten) + BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices); + CtorInitializers[i] = BOMInit; + } + } + + return std::make_pair(CtorInitializers, NumInitializers); +} + +NestedNameSpecifier * +ASTReader::ReadNestedNameSpecifier(ModuleFile &F, + const RecordData &Record, unsigned &Idx) { + unsigned N = Record[Idx++]; + NestedNameSpecifier *NNS = 0, *Prev = 0; + for (unsigned I = 0; I != N; ++I) { + NestedNameSpecifier::SpecifierKind Kind + = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; + switch (Kind) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, II); + break; + } + + case NestedNameSpecifier::Namespace: { + NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, NS); + break; + } + + case NestedNameSpecifier::NamespaceAlias: { + NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, Alias); + break; + } + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *T = readType(F, Record, Idx).getTypePtrOrNull(); + if (!T) + return 0; + + bool Template = Record[Idx++]; + NNS = NestedNameSpecifier::Create(Context, Prev, Template, T); + break; + } + + case NestedNameSpecifier::Global: { + NNS = NestedNameSpecifier::GlobalSpecifier(Context); + // No associated value, and there can't be a prefix. + break; + } + } + Prev = NNS; + } + return NNS; +} + +NestedNameSpecifierLoc +ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + unsigned N = Record[Idx++]; + NestedNameSpecifierLocBuilder Builder; + for (unsigned I = 0; I != N; ++I) { + NestedNameSpecifier::SpecifierKind Kind + = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; + switch (Kind) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); + Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); + break; + } + + case NestedNameSpecifier::Namespace: { + NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); + Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); + break; + } + + case NestedNameSpecifier::NamespaceAlias: { + NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); + Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); + break; + } + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + bool Template = Record[Idx++]; + TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx); + if (!T) + return NestedNameSpecifierLoc(); + SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); + + // FIXME: 'template' keyword location not saved anywhere, so we fake it. + Builder.Extend(Context, + Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), + T->getTypeLoc(), ColonColonLoc); + break; + } + + case NestedNameSpecifier::Global: { + SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); + Builder.MakeGlobal(Context, ColonColonLoc); + break; + } + } + } + + return Builder.getWithLocInContext(Context); +} + +SourceRange +ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + SourceLocation beg = ReadSourceLocation(F, Record, Idx); + SourceLocation end = ReadSourceLocation(F, Record, Idx); + return SourceRange(beg, end); +} + +/// \brief Read an integral value +llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { + unsigned BitWidth = Record[Idx++]; + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); + Idx += NumWords; + return Result; +} + +/// \brief Read a signed integral value +llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { + bool isUnsigned = Record[Idx++]; + return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); +} + +/// \brief Read a floating-point value +llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { + return llvm::APFloat(ReadAPInt(Record, Idx)); +} + +// \brief Read a string +std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) { + unsigned Len = Record[Idx++]; + std::string Result(Record.data() + Idx, Record.data() + Idx + Len); + Idx += Len; + return Result; +} + +VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, + unsigned &Idx) { + unsigned Major = Record[Idx++]; + unsigned Minor = Record[Idx++]; + unsigned Subminor = Record[Idx++]; + if (Minor == 0) + return VersionTuple(Major); + if (Subminor == 0) + return VersionTuple(Major, Minor - 1); + return VersionTuple(Major, Minor - 1, Subminor - 1); +} + +CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, + const RecordData &Record, + unsigned &Idx) { + CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx); + return CXXTemporary::Create(Context, Decl); +} + +DiagnosticBuilder ASTReader::Diag(unsigned DiagID) { + return Diag(SourceLocation(), DiagID); +} + +DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(Loc, DiagID); +} + +/// \brief Retrieve the identifier table associated with the +/// preprocessor. +IdentifierTable &ASTReader::getIdentifierTable() { + return PP.getIdentifierTable(); +} + +/// \brief Record that the given ID maps to the given switch-case +/// statement. +void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { + assert((*CurrSwitchCaseStmts)[ID] == 0 && + "Already have a SwitchCase with this ID"); + (*CurrSwitchCaseStmts)[ID] = SC; +} + +/// \brief Retrieve the switch-case statement with the given ID. +SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) { + assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID"); + return (*CurrSwitchCaseStmts)[ID]; +} + +void ASTReader::ClearSwitchCaseIDs() { + CurrSwitchCaseStmts->clear(); +} + +void ASTReader::ReadComments() { + std::vector<RawComment *> Comments; + for (SmallVectorImpl<std::pair<llvm::BitstreamCursor, + serialization::ModuleFile *> >::iterator + I = CommentsCursors.begin(), + E = CommentsCursors.end(); + I != E; ++I) { + llvm::BitstreamCursor &Cursor = I->first; + serialization::ModuleFile &F = *I->second; + SavedStreamPosition SavedPosition(Cursor); + + RecordData Record; + while (true) { + unsigned Code = Cursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) + break; + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Cursor.ReadSubBlockID(); + if (Cursor.SkipBlock()) { + Error("malformed block record in AST file"); + return; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Cursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch ((CommentRecordTypes) Cursor.ReadRecord(Code, 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; + } + } + } + } + Context.Comments.addCommentsToFront(Comments); +} + +void ASTReader::finishPendingActions() { + while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || + !PendingMacroIDs.empty()) { + // If any identifiers with corresponding top-level declarations have + // been loaded, load those declarations now. + while (!PendingIdentifierInfos.empty()) { + SetGloballyVisibleDecls(PendingIdentifierInfos.front().II, + PendingIdentifierInfos.front().DeclIDs, true); + PendingIdentifierInfos.pop_front(); + } + + // Load pending declaration chains. + for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { + loadPendingDeclChain(PendingDeclChains[I]); + PendingDeclChainsKnown.erase(PendingDeclChains[I]); + } + PendingDeclChains.clear(); + + // Load any pending macro definitions. + for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { + // FIXME: std::move here + SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second; + MacroInfo *Hint = 0; + for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; + ++IDIdx) { + Hint = getMacro(GlobalIDs[IDIdx], Hint); + } + } + PendingMacroIDs.clear(); + } + + // If we deserialized any C++ or Objective-C class definitions, any + // Objective-C protocol definitions, or any redeclarable templates, make sure + // that all redeclarations point to the definitions. Note that this can only + // happen now, after the redeclaration chains have been fully wired. + for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(), + DEnd = PendingDefinitions.end(); + D != DEnd; ++D) { + if (TagDecl *TD = dyn_cast<TagDecl>(*D)) { + if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) { + // Make sure that the TagType points at the definition. + const_cast<TagType*>(TagT)->decl = TD; + } + + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) { + for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(), + REnd = RD->redecls_end(); + R != REnd; ++R) + cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData; + + } + + continue; + } + + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) { + // Make sure that the ObjCInterfaceType points at the definition. + const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl)) + ->Decl = ID; + + for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(), + REnd = ID->redecls_end(); + R != REnd; ++R) + R->Data = ID->Data; + + continue; + } + + if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) { + for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(), + REnd = PD->redecls_end(); + R != REnd; ++R) + R->Data = PD->Data; + + continue; + } + + RedeclarableTemplateDecl *RTD + = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl(); + for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(), + REnd = RTD->redecls_end(); + R != REnd; ++R) + R->Common = RTD->Common; + } + PendingDefinitions.clear(); + + // Load the bodies of any functions or methods we've encountered. We do + // this now (delayed) so that we can be sure that the declaration chains + // have been fully wired up. + for (PendingBodiesMap::iterator PB = PendingBodies.begin(), + PBEnd = PendingBodies.end(); + PB != PBEnd; ++PB) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) { + // FIXME: Check for =delete/=default? + // FIXME: Complain about ODR violations here? + if (!getContext().getLangOpts().Modules || !FD->hasBody()) + FD->setLazyBody(PB->second); + continue; + } + + ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first); + if (!getContext().getLangOpts().Modules || !MD->hasBody()) + MD->setLazyBody(PB->second); + } + PendingBodies.clear(); +} + +void ASTReader::FinishedDeserializing() { + assert(NumCurrentElementsDeserializing && + "FinishedDeserializing not paired with StartedDeserializing"); + if (NumCurrentElementsDeserializing == 1) { + // We decrease NumCurrentElementsDeserializing only after pending actions + // are finished, to avoid recursively re-calling finishPendingActions(). + finishPendingActions(); + } + --NumCurrentElementsDeserializing; + + if (NumCurrentElementsDeserializing == 0 && + Consumer && !PassingDeclsToConsumer) { + // Guard variable to avoid recursively redoing the process of passing + // decls to consumer. + SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer, + true); + + while (!InterestingDecls.empty()) { + // We are not in recursive loading, so it's safe to pass the "interesting" + // decls to the consumer. + Decl *D = InterestingDecls.front(); + InterestingDecls.pop_front(); + PassInterestingDeclToConsumer(D); + } + } +} + +ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, + StringRef isysroot, bool DisableValidation, + bool AllowASTWithCompilerErrors) + : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), + SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), + Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), + Consumer(0), ModuleMgr(PP.getFileManager()), + isysroot(isysroot), DisableValidation(DisableValidation), + AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), + CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts), + NumSLocEntriesRead(0), TotalNumSLocEntries(0), + NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), + TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), + NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), + NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), + NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), + TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), + PassingDeclsToConsumer(false), + NumCXXBaseSpecifiersLoaded(0) +{ + SourceMgr.setExternalSLocEntrySource(this); +} + +ASTReader::~ASTReader() { + for (DeclContextVisibleUpdatesPending::iterator + I = PendingVisibleUpdates.begin(), + E = PendingVisibleUpdates.end(); + I != E; ++I) { + for (DeclContextVisibleUpdates::iterator J = I->second.begin(), + F = I->second.end(); + J != F; ++J) + delete J->first; + } +} |