Index: vendor/clang/dist-release_80/lib/AST/MicrosoftMangle.cpp =================================================================== --- vendor/clang/dist-release_80/lib/AST/MicrosoftMangle.cpp (revision 349778) +++ vendor/clang/dist-release_80/lib/AST/MicrosoftMangle.cpp (revision 349779) @@ -1,3488 +1,3491 @@ //===--- 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/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/VTableBuilder.h" #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/JamCRC.h" #include "llvm/Support/xxhash.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" using namespace clang; namespace { struct msvc_hashing_ostream : public llvm::raw_svector_ostream { raw_ostream &OS; llvm::SmallString<64> Buffer; msvc_hashing_ostream(raw_ostream &OS) : llvm::raw_svector_ostream(Buffer), OS(OS) {} ~msvc_hashing_ostream() override { StringRef MangledName = str(); bool StartsWithEscape = MangledName.startswith("\01"); if (StartsWithEscape) MangledName = MangledName.drop_front(1); if (MangledName.size() <= 4096) { OS << str(); return; } llvm::MD5 Hasher; llvm::MD5::MD5Result Hash; Hasher.update(MangledName); Hasher.final(Hash); SmallString<32> HexString; llvm::MD5::stringifyResult(Hash, HexString); if (StartsWithEscape) OS << '\01'; OS << "??@" << HexString << '@'; } }; static const DeclContext * getLambdaDefaultArgumentDeclContext(const Decl *D) { if (const auto *RD = dyn_cast(D)) if (RD->isLambda()) if (const auto *Parm = dyn_cast_or_null(RD->getLambdaContextDecl())) return Parm->getDeclContext(); return nullptr; } /// 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 auto *LDADC = getLambdaDefaultArgumentDeclContext(D)) return LDADC; // Perform the same check for block literals. if (const BlockDecl *BD = dyn_cast(D)) { if (ParmVarDecl *ContextParam = dyn_cast_or_null(BD->getBlockManglingContextDecl())) return ContextParam->getDeclContext(); } const DeclContext *DC = D->getDeclContext(); if (isa(DC) || isa(DC)) { return getEffectiveDeclContext(cast(DC)); } return DC->getRedeclContext(); } static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { return getEffectiveDeclContext(cast(DC)); } static const FunctionDecl *getStructor(const NamedDecl *ND) { if (const auto *FTD = dyn_cast(ND)) return FTD->getTemplatedDecl()->getCanonicalDecl(); const auto *FD = cast(ND); if (const auto *FTD = FD->getPrimaryTemplate()) return FTD->getTemplatedDecl()->getCanonicalDecl(); return FD->getCanonicalDecl(); } /// MicrosoftMangleContextImpl - Overrides the default MangleContext for the /// Microsoft Visual C++ ABI. class MicrosoftMangleContextImpl : public MicrosoftMangleContext { typedef std::pair DiscriminatorKeyTy; llvm::DenseMap Discriminator; llvm::DenseMap Uniquifier; llvm::DenseMap LambdaIds; llvm::DenseMap SEHFilterIds; llvm::DenseMap SEHFinallyIds; SmallString<16> AnonymousNamespaceHash; public: MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags); bool shouldMangleCXXName(const NamedDecl *D) override; bool shouldMangleStringLiteral(const StringLiteral *SL) override; void mangleCXXName(const NamedDecl *D, raw_ostream &Out) override; void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML, raw_ostream &Out) override; void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &) override; void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &ThisAdjustment, raw_ostream &) override; void mangleCXXVFTable(const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) override; void mangleCXXVBTable(const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) override; void mangleCXXVirtualDisplacementMap(const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) override; void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, bool IsUnaligned, uint32_t NumEntries, raw_ostream &Out) override; void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, raw_ostream &Out) override; void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex, raw_ostream &Out) override; void mangleCXXRTTI(QualType T, raw_ostream &Out) override; void mangleCXXRTTIName(QualType T, raw_ostream &Out) override; void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) override; void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived, raw_ostream &Out) override; void mangleCXXRTTIClassHierarchyDescriptor(const CXXRecordDecl *Derived, raw_ostream &Out) override; void mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) override; void mangleTypeName(QualType T, raw_ostream &) override; void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &) override; void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &) override; void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber, raw_ostream &) override; void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override; void mangleThreadSafeStaticGuardVariable(const VarDecl *D, unsigned GuardNum, raw_ostream &Out) override; void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override; void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out) override; void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, raw_ostream &Out) override; void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, raw_ostream &Out) override; void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override; bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { const DeclContext *DC = getEffectiveDeclContext(ND); if (!DC->isFunctionOrMethod()) return false; // Lambda closure types are already numbered, give out a phony number so // that they demangle nicely. if (const auto *RD = dyn_cast(ND)) { if (RD->isLambda()) { disc = 1; return true; } } // Use the canonical number for externally visible decls. if (ND->isExternallyVisible()) { disc = getASTContext().getManglingNumber(ND); return true; } // Anonymous tags are already numbered. if (const TagDecl *Tag = dyn_cast(ND)) { if (!Tag->hasNameForLinkage() && !getASTContext().getDeclaratorForUnnamedTagDecl(Tag) && !getASTContext().getTypedefNameForUnnamedTagDecl(Tag)) return false; } // Make up a reasonable number for internal decls. unsigned &discriminator = Uniquifier[ND]; if (!discriminator) discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())]; disc = discriminator + 1; return true; } unsigned getLambdaId(const CXXRecordDecl *RD) { assert(RD->isLambda() && "RD must be a lambda!"); assert(!RD->isExternallyVisible() && "RD must not be visible!"); assert(RD->getLambdaManglingNumber() == 0 && "RD must not have a mangling number!"); std::pair::iterator, bool> Result = LambdaIds.insert(std::make_pair(RD, LambdaIds.size())); return Result.first->second; } /// Return a character sequence that is (somewhat) unique to the TU suitable /// for mangling anonymous namespaces. StringRef getAnonymousNamespaceHash() const { return AnonymousNamespaceHash; } private: void mangleInitFiniStub(const VarDecl *D, char CharCode, raw_ostream &Out); }; /// MicrosoftCXXNameMangler - Manage the mangling of a single name for the /// Microsoft Visual C++ ABI. class MicrosoftCXXNameMangler { MicrosoftMangleContextImpl &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; typedef llvm::SmallVector BackRefVec; BackRefVec NameBackReferences; typedef llvm::DenseMap ArgBackRefMap; ArgBackRefMap TypeBackReferences; typedef std::set PassObjectSizeArgsSet; PassObjectSizeArgsSet PassObjectSizeArgs; ASTContext &getASTContext() const { return Context.getASTContext(); } // FIXME: If we add support for __ptr32/64 qualifiers, then we should push // this check into mangleQualifiers(). const bool PointersAre64Bit; public: enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(nullptr), StructorType(-1), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} raw_ostream &getStream() const { return Out; } void mangle(const NamedDecl *D, StringRef Prefix = "?"); void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, const CXXMethodDecl *MD); void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML); void mangleNumber(int64_t Number); void mangleTagTypeKind(TagTypeKind TK); void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName, ArrayRef NestedNames = None); void mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range); void mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = nullptr, bool ForceThisQuals = false, bool MangleExceptionSpec = true); void mangleNestedName(const NamedDecl *ND); private: bool isStructorDecl(const NamedDecl *ND) const { return ND == Structor || getStructor(ND) == Structor; } void mangleUnqualifiedName(const NamedDecl *ND) { mangleUnqualifiedName(ND, ND->getDeclName()); } void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); void mangleSourceName(StringRef Name); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); void mangleQualifiers(Qualifiers Quals, bool IsMember); void mangleRefQualifier(RefQualifierKind RefQualifier); void manglePointerCVQualifiers(Qualifiers Quals); void manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType); void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleTemplateInstantiationName(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleArgumentType(QualType T, SourceRange Range); void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA); bool isArtificialTagType(QualType T) const; // 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, \ Qualifiers Quals, \ SourceRange Range); #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE #undef NON_CANONICAL_TYPE #undef TYPE void mangleType(const TagDecl *TD); void mangleDecayedArrayType(const ArrayType *T); void mangleArrayType(const ArrayType *T); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(CallingConv CC); void mangleCallingConvention(const FunctionType *T); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); void mangleTemplateArgs(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs); void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, const NamedDecl *Parm); void mangleObjCProtocol(const ObjCProtocolDecl *PD); void mangleObjCLifetime(const QualType T, Qualifiers Quals, SourceRange Range); void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals, SourceRange Range); }; } MicrosoftMangleContextImpl::MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) : MicrosoftMangleContext(Context, Diags) { // To mangle anonymous namespaces, hash the path to the main source file. The // path should be whatever (probably relative) path was passed on the command // line. The goal is for the compiler to produce the same output regardless of // working directory, so use the uncanonicalized relative path. // // It's important to make the mangled names unique because, when CodeView // debug info is in use, the debugger uses mangled type names to distinguish // between otherwise identically named types in anonymous namespaces. // // These symbols are always internal, so there is no need for the hash to // match what MSVC produces. For the same reason, clang is free to change the // hash at any time without breaking compatibility with old versions of clang. // The generated names are intended to look similar to what MSVC generates, // which are something like "?A0x01234567@". SourceManager &SM = Context.getSourceManager(); if (const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID())) { // Truncate the hash so we get 8 characters of hexadecimal. uint32_t TruncatedHash = uint32_t(xxHash64(FE->getName())); AnonymousNamespaceHash = llvm::utohexstr(TruncatedHash); } else { // If we don't have a path to the main file, we'll just use 0. AnonymousNamespaceHash = "0"; } } bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { if (const FunctionDecl *FD = dyn_cast(D)) { LanguageLinkage L = FD->getLanguageLinkage(); // Overloadable functions need mangling. if (FD->hasAttr()) return true; // The ABI expects that we would never mangle "typical" user-defined entry // points regardless of visibility or freestanding-ness. // // N.B. This is distinct from asking about "main". "main" has a lot of // special rules associated with it in the standard while these // user-defined entry points are outside of the purview of the standard. // For example, there can be only one definition for "main" in a standards // compliant program; however nothing forbids the existence of wmain and // WinMain in the same translation unit. if (FD->isMSVCRTEntryPoint()) return false; // C++ functions and those whose names are not a simple identifier need // mangling. if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage) return true; // C functions are not mangled. if (L == CLanguageLinkage) return false; } // Otherwise, no mangling is done outside C++ mode. if (!getASTContext().getLangOpts().CPlusPlus) return false; const VarDecl *VD = dyn_cast(D); if (VD && !isa(D)) { // C variables are not mangled. if (VD->isExternC()) return false; // Variables at global scope with non-internal linkage are not mangled. 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->getFormalLinkage() == InternalLinkage && !isa(D) && D->getIdentifier() != nullptr) return false; } return true; } bool MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) { 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. // ::= ? Out << Prefix; mangleName(D); if (const FunctionDecl *FD = dyn_cast(D)) mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD)); else if (const VarDecl *VD = dyn_cast(D)) mangleVariableEncoding(VD); else llvm_unreachable("Tried to mangle unexpected NamedDecl!"); } void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle) { // ::= // Since MSVC operates on the type as written and not the canonical type, it // actually matters which decl we have here. MSVC appears to choose the // first, since it is most likely to be the declaration in a header file. FD = FD->getFirstDecl(); // 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(); // extern "C" functions can hold entities that must be mangled. // As it stands, these functions still need to get expressed in the full // external name. They have their class and type omitted, replaced with '9'. if (ShouldMangle) { // We would like to mangle all extern "C" functions using this additional // component but this would break compatibility with MSVC's behavior. // Instead, do this when we know that compatibility isn't important (in // other words, when it is an overloaded extern "C" function). if (FD->isExternC() && FD->hasAttr()) Out << "$$J0"; mangleFunctionClass(FD); mangleFunctionType(FT, FD, false, false); } else { Out << '9'; } } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { // ::= // ::= 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. // ::= // ::= # pointers, references // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. SourceRange SR = VD->getSourceRange(); QualType Ty = VD->getType(); if (Ty->isPointerType() || Ty->isReferenceType() || Ty->isMemberPointerType()) { mangleType(Ty, SR, QMM_Drop); manglePointerExtQualifiers( Ty.getDesugaredType(getASTContext()).getLocalQualifiers(), QualType()); if (const MemberPointerType *MPT = Ty->getAs()) { mangleQualifiers(MPT->getPointeeType().getQualifiers(), true); // Member pointers are suffixed with a back reference to the member // pointer's class name. mangleName(MPT->getClass()->getAsCXXRecordDecl()); } else mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. mangleDecayedArrayType(AT); if (AT->getElementType()->isArrayType()) Out << 'A'; else mangleQualifiers(Ty.getQualifiers(), false); } else { mangleType(Ty, SR, QMM_Drop); mangleQualifiers(Ty.getQualifiers(), false); } } void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD) { // ::= // ::= $F // ::= $G int64_t FieldOffset; int64_t VBTableOffset; MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); if (VD) { FieldOffset = getASTContext().getFieldOffset(VD); assert(FieldOffset % getASTContext().getCharWidth() == 0 && "cannot take address of bitfield"); FieldOffset /= getASTContext().getCharWidth(); VBTableOffset = 0; if (IM == MSInheritanceAttr::Keyword_virtual_inheritance) FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity(); } else { FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1; VBTableOffset = -1; } char Code = '\0'; switch (IM) { case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break; case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break; case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break; case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break; } Out << '$' << Code; mangleNumber(FieldOffset); // The C++ standard doesn't allow base-to-derived member pointer conversions // in template parameter contexts, so the vbptr offset of data member pointers // is always zero. if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) mangleNumber(0); if (MSInheritanceAttr::hasVBTableOffsetField(IM)) mangleNumber(VBTableOffset); } void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, const CXXMethodDecl *MD) { // ::= $1? // ::= $H? // ::= $I? // ::= $J? MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); char Code = '\0'; switch (IM) { case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break; case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break; case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break; case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break; } // If non-virtual, mangle the name. If virtual, mangle as a virtual memptr // thunk. uint64_t NVOffset = 0; uint64_t VBTableOffset = 0; uint64_t VBPtrOffset = 0; if (MD) { Out << '$' << Code << '?'; if (MD->isVirtual()) { MicrosoftVTableContext *VTContext = cast(getASTContext().getVTableContext()); MethodVFTableLocation ML = VTContext->getMethodVFTableLocation(GlobalDecl(MD)); mangleVirtualMemPtrThunk(MD, ML); NVOffset = ML.VFPtrOffset.getQuantity(); VBTableOffset = ML.VBTableIndex * 4; if (ML.VBase) { const ASTRecordLayout &Layout = getASTContext().getASTRecordLayout(RD); VBPtrOffset = Layout.getVBPtrOffset().getQuantity(); } } else { mangleName(MD); mangleFunctionEncoding(MD, /*ShouldMangle=*/true); } if (VBTableOffset == 0 && IM == MSInheritanceAttr::Keyword_virtual_inheritance) NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity(); } else { // Null single inheritance member functions are encoded as a simple nullptr. if (IM == MSInheritanceAttr::Keyword_single_inheritance) { Out << "$0A@"; return; } if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance) VBTableOffset = -1; Out << '$' << Code; } if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM)) mangleNumber(static_cast(NVOffset)); if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) mangleNumber(VBPtrOffset); if (MSInheritanceAttr::hasVBTableOffsetField(IM)) mangleNumber(VBTableOffset); } void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( const CXXMethodDecl *MD, const MethodVFTableLocation &ML) { // Get the vftable offset. CharUnits PointerWidth = getASTContext().toCharUnitsFromBits( getASTContext().getTargetInfo().getPointerWidth(0)); uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity(); Out << "?_9"; mangleName(MD->getParent()); Out << "$B"; mangleNumber(OffsetInVFTable); Out << 'A'; mangleCallingConvention(MD->getType()->getAs()); } void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { // ::= {[]+ | []}? @ // Always start with the unqualified name. mangleUnqualifiedName(ND); mangleNestedName(ND); // Terminate the whole name with an '@'. Out << '@'; } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { // ::= A@ # when Number == 0 // ::= # when 1 <= Number <= 10 // ::= + @ # when Number >= 10 // // ::= [?] uint64_t Value = static_cast(Number); if (Number < 0) { Value = -Value; Out << '?'; } if (Value == 0) Out << "A@"; else if (Value >= 1 && Value <= 10) Out << (Value - 1); else { // Numbers that are not encoded as decimal digits are represented as nibbles // in the range of ASCII characters 'A' to 'P'. // The number 0x123450 would be encoded as 'BCDEFA' char EncodedNumberBuffer[sizeof(uint64_t) * 2]; MutableArrayRef BufferRef(EncodedNumberBuffer); MutableArrayRef::reverse_iterator I = BufferRef.rbegin(); for (; Value != 0; Value >>= 4) *I++ = 'A' + (Value & 0xf); Out.write(I.base(), I - BufferRef.rbegin()); Out << '@'; } } static const TemplateDecl * isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { // Check if we have a function template. if (const FunctionDecl *FD = dyn_cast(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(ND)) { TemplateArgs = &Spec->getTemplateArgs(); return Spec->getSpecializedTemplate(); } // Check if we have a variable template. if (const VarTemplateSpecializationDecl *Spec = dyn_cast(ND)) { TemplateArgs = &Spec->getTemplateArgs(); return Spec->getSpecializedTemplate(); } return nullptr; } void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name) { // ::= // ::= // ::= // ::= // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { // Function templates aren't considered for name back referencing. This // makes sense since function templates aren't likely to occur multiple // times in a symbol. if (isa(TD)) { mangleTemplateInstantiationName(TD, *TemplateArgs); Out << '@'; return; } // Here comes the tricky thing: if we need to mangle something like // void foo(A::X, B::X), // the X part is aliased. However, if you need to mangle // void foo(A::X, A::X), // 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) to a string using the extra mangler and then use // the mangled type name as a key to check the mangling of different types // for aliasing. llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Extra.mangleTemplateInstantiationName(TD, *TemplateArgs); mangleSourceName(TemplateMangling); return; } switch (Name.getNameKind()) { case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { mangleSourceName(II->getName()); break; } // Otherwise, an anonymous entity. We must have a declaration. assert(ND && "mangling empty name without declaration"); if (const NamespaceDecl *NS = dyn_cast(ND)) { if (NS->isAnonymousNamespace()) { Out << "?A0x" << Context.getAnonymousNamespaceHash() << '@'; break; } } if (const DecompositionDecl *DD = dyn_cast(ND)) { // FIXME: Invented mangling for decomposition declarations: // [X,Y,Z] // where X,Y,Z are the names of the bindings. llvm::SmallString<128> Name("["); for (auto *BD : DD->bindings()) { if (Name.size() > 1) Name += ','; Name += BD->getDeclName().getAsIdentifierInfo()->getName(); } Name += ']'; mangleSourceName(Name); break; } if (const VarDecl *VD = dyn_cast(ND)) { // We must have an anonymous union or struct declaration. const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl(); assert(RD && "expected variable decl to have a record type"); // Anonymous types with no tag or typedef get the name of their // declarator mangled in. If they have no declarator, number them with // a $S prefix. llvm::SmallString<64> Name("$S"); // Get a unique id for the anonymous struct. Name += llvm::utostr(Context.getAnonymousStructId(RD) + 1); mangleSourceName(Name.str()); break; } // We must have an anonymous struct. const TagDecl *TD = cast(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()->getName()); break; } if (const CXXRecordDecl *Record = dyn_cast(TD)) { if (Record->isLambda()) { llvm::SmallString<10> Name("getLambdaContextDecl(); unsigned LambdaManglingNumber = Record->getLambdaManglingNumber(); unsigned LambdaId; const ParmVarDecl *Parm = dyn_cast_or_null(LambdaContextDecl); const FunctionDecl *Func = Parm ? dyn_cast(Parm->getDeclContext()) : nullptr; if (Func) { unsigned DefaultArgNo = Func->getNumParams() - Parm->getFunctionScopeIndex(); Name += llvm::utostr(DefaultArgNo); Name += "_"; } if (LambdaManglingNumber) LambdaId = LambdaManglingNumber; else LambdaId = Context.getLambdaId(Record); Name += llvm::utostr(LambdaId); Name += ">"; mangleSourceName(Name); // If the context of a closure type is an initializer for a class // member (static or nonstatic), it is encoded in a qualified name. if (LambdaManglingNumber && LambdaContextDecl) { if ((isa(LambdaContextDecl) || isa(LambdaContextDecl)) && LambdaContextDecl->getDeclContext()->isRecord()) { mangleUnqualifiedName(cast(LambdaContextDecl)); } } break; } } llvm::SmallString<64> Name; if (DeclaratorDecl *DD = Context.getASTContext().getDeclaratorForUnnamedTagDecl(TD)) { // Anonymous types without a name for linkage purposes have their // declarator mangled in if they have one. Name += "getName(); } else if (TypedefNameDecl *TND = Context.getASTContext().getTypedefNameForUnnamedTagDecl( TD)) { // Anonymous types without a name for linkage purposes have their // associate typedef mangled in if they have one. Name += "getName(); } else if (isa(TD) && cast(TD)->enumerator_begin() != cast(TD)->enumerator_end()) { // Anonymous non-empty enums mangle in the first enumerator. auto *ED = cast(TD); Name += "enumerator_begin()->getName(); } else { // Otherwise, number the types using a $S prefix. Name += " Name; mangleSourceName(Name.str()); break; } case DeclarationName::CXXConstructorName: if (isStructorDecl(ND)) { if (StructorType == Ctor_CopyingClosure) { Out << "?_O"; return; } if (StructorType == Ctor_DefaultClosure) { Out << "?_F"; return; } } Out << "?0"; return; case DeclarationName::CXXDestructorName: if (isStructorDecl(ND)) // If the named decl is the C++ destructor we're mangling, // use the type we were given. mangleCXXDtorType(static_cast(StructorType)); else // Otherwise, use the base destructor name. This is relevant if a // class with a destructor is declared within a destructor. mangleCXXDtorType(Dtor_Base); break; case DeclarationName::CXXConversionFunctionName: // ::= ?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: { Out << "?__K"; mangleSourceName(Name.getCXXLiteralIdentifier()->getName()); break; } case DeclarationName::CXXDeductionGuideName: llvm_unreachable("Can't mangle a deduction guide name!"); case DeclarationName::CXXUsingDirective: llvm_unreachable("Can't mangle a using directive name!"); } } // ::= [] // ::= [] void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { const DeclContext *DC = getEffectiveDeclContext(ND); while (!DC->isTranslationUnit()) { if (isa(ND) || isa(ND)) { unsigned Disc; if (Context.getNextDiscriminator(ND, Disc)) { Out << '?'; mangleNumber(Disc); Out << '?'; } } if (const BlockDecl *BD = dyn_cast(DC)) { auto Discriminate = [](StringRef Name, const unsigned Discriminator, const unsigned ParameterDiscriminator) -> std::string { std::string Buffer; llvm::raw_string_ostream Stream(Buffer); Stream << Name; if (Discriminator) Stream << '_' << Discriminator; if (ParameterDiscriminator) Stream << '_' << ParameterDiscriminator; return Stream.str(); }; unsigned Discriminator = BD->getBlockManglingNumber(); if (!Discriminator) Discriminator = Context.getBlockId(BD, /*Local=*/false); // Mangle the parameter position as a discriminator to deal with unnamed // parameters. Rather than mangling the unqualified parameter name, // always use the position to give a uniform mangling. unsigned ParameterDiscriminator = 0; if (const auto *MC = BD->getBlockManglingContextDecl()) if (const auto *P = dyn_cast(MC)) if (const auto *F = dyn_cast(P->getDeclContext())) ParameterDiscriminator = F->getNumParams() - P->getFunctionScopeIndex(); DC = getEffectiveDeclContext(BD); Out << '?'; mangleSourceName(Discriminate("_block_invoke", Discriminator, ParameterDiscriminator)); // If we have a block mangling context, encode that now. This allows us // to discriminate between named static data initializers in the same // scope. This is handled differently from parameters, which use // positions to discriminate between multiple instances. if (const auto *MC = BD->getBlockManglingContextDecl()) if (!isa(MC)) if (const auto *ND = dyn_cast(MC)) mangleUnqualifiedName(ND); // MS ABI and Itanium manglings are in inverted scopes. In the case of a // RecordDecl, mangle the entire scope hierarchy at this point rather than // just the unqualified name to get the ordering correct. if (const auto *RD = dyn_cast(DC)) mangleName(RD); else Out << '@'; // void __cdecl Out << "YAX"; // struct __block_literal * Out << 'P'; // __ptr64 if (PointersAre64Bit) Out << 'E'; Out << 'A'; mangleArtificialTagType(TTK_Struct, Discriminate("__block_literal", Discriminator, ParameterDiscriminator)); Out << "@Z"; // If the effective context was a Record, we have fully mangled the // qualified name and do not need to continue. if (isa(DC)) break; continue; } else if (const ObjCMethodDecl *Method = dyn_cast(DC)) { mangleObjCMethodName(Method); } else if (isa(DC)) { ND = cast(DC); if (const FunctionDecl *FD = dyn_cast(ND)) { mangle(FD, "?"); break; } else { mangleUnqualifiedName(ND); // Lambdas in default arguments conceptually belong to the function the // parameter corresponds to. if (const auto *LDADC = getLambdaDefaultArgumentDeclContext(ND)) { DC = LDADC; continue; } } } DC = DC->getParent(); } } void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) { // Microsoft uses the names on the case labels for these dtor variants. Clang // uses the Itanium terminology internally. Everything in this ABI delegates // towards the base dtor. switch (T) { // ::= ?1 # destructor case Dtor_Base: Out << "?1"; return; // ::= ?_D # vbase destructor case Dtor_Complete: Out << "?_D"; return; // ::= ?_G # scalar deleting destructor case Dtor_Deleting: Out << "?_G"; return; // ::= ?_E # vector deleting destructor // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need // it. case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT"); } llvm_unreachable("Unsupported dtor type?"); } void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc) { switch (OO) { // ?0 # constructor // ?1 # destructor // ::= ?2 # new case OO_New: Out << "?2"; break; // ::= ?3 # delete case OO_Delete: Out << "?3"; break; // ::= ?4 # = case OO_Equal: Out << "?4"; break; // ::= ?5 # >> case OO_GreaterGreater: Out << "?5"; break; // ::= ?6 # << case OO_LessLess: Out << "?6"; break; // ::= ?7 # ! case OO_Exclaim: Out << "?7"; break; // ::= ?8 # == case OO_EqualEqual: Out << "?8"; break; // ::= ?9 # != case OO_ExclaimEqual: Out << "?9"; break; // ::= ?A # [] case OO_Subscript: Out << "?A"; break; // ?B # conversion // ::= ?C # -> case OO_Arrow: Out << "?C"; break; // ::= ?D # * case OO_Star: Out << "?D"; break; // ::= ?E # ++ case OO_PlusPlus: Out << "?E"; break; // ::= ?F # -- case OO_MinusMinus: Out << "?F"; break; // ::= ?G # - case OO_Minus: Out << "?G"; break; // ::= ?H # + case OO_Plus: Out << "?H"; break; // ::= ?I # & case OO_Amp: Out << "?I"; break; // ::= ?J # ->* case OO_ArrowStar: Out << "?J"; break; // ::= ?K # / case OO_Slash: Out << "?K"; break; // ::= ?L # % case OO_Percent: Out << "?L"; break; // ::= ?M # < case OO_Less: Out << "?M"; break; // ::= ?N # <= case OO_LessEqual: Out << "?N"; break; // ::= ?O # > case OO_Greater: Out << "?O"; break; // ::= ?P # >= case OO_GreaterEqual: Out << "?P"; break; // ::= ?Q # , case OO_Comma: Out << "?Q"; break; // ::= ?R # () case OO_Call: Out << "?R"; break; // ::= ?S # ~ case OO_Tilde: Out << "?S"; break; // ::= ?T # ^ case OO_Caret: Out << "?T"; break; // ::= ?U # | case OO_Pipe: Out << "?U"; break; // ::= ?V # && case OO_AmpAmp: Out << "?V"; break; // ::= ?W # || case OO_PipePipe: Out << "?W"; break; // ::= ?X # *= case OO_StarEqual: Out << "?X"; break; // ::= ?Y # += case OO_PlusEqual: Out << "?Y"; break; // ::= ?Z # -= case OO_MinusEqual: Out << "?Z"; break; // ::= ?_0 # /= case OO_SlashEqual: Out << "?_0"; break; // ::= ?_1 # %= case OO_PercentEqual: Out << "?_1"; break; // ::= ?_2 # >>= case OO_GreaterGreaterEqual: Out << "?_2"; break; // ::= ?_3 # <<= case OO_LessLessEqual: Out << "?_3"; break; // ::= ?_4 # &= case OO_AmpEqual: Out << "?_4"; break; // ::= ?_5 # |= case OO_PipeEqual: Out << "?_5"; break; // ::= ?_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 # udt returning // ?_Q # // ?_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 // ::= ?_U # new[] case OO_Array_New: Out << "?_U"; break; // ::= ?_V # delete[] case OO_Array_Delete: Out << "?_V"; break; // ::= ?__L # co_await case OO_Coawait: Out << "?__L"; break; case OO_Spaceship: { // FIXME: Once MS picks a mangling, use it. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this three-way comparison operator yet"); Diags.Report(Loc, DiagID); 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(StringRef Name) { // ::= @ BackRefVec::iterator Found = std::find(NameBackReferences.begin(), NameBackReferences.end(), Name); if (Found == NameBackReferences.end()) { if (NameBackReferences.size() < 10) NameBackReferences.push_back(Name); Out << Name << '@'; } else { Out << (Found - NameBackReferences.begin()); } } void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { // ::= // ::= // Always start with the unqualified name. // Templates have their own context for back references. ArgBackRefMap OuterArgsContext; BackRefVec OuterTemplateContext; PassObjectSizeArgsSet OuterPassObjectSizeArgs; NameBackReferences.swap(OuterTemplateContext); TypeBackReferences.swap(OuterArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); mangleUnscopedTemplateName(TD); mangleTemplateArgs(TD, TemplateArgs); // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); TypeBackReferences.swap(OuterArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); } void MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) { // ::= ?$ Out << "?$"; mangleUnqualifiedName(TD); } void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value, bool IsBoolean) { // ::= $0 Out << "$0"; // Make sure booleans are encoded as 0/1. if (IsBoolean && Value.getBoolValue()) mangleNumber(1); else if (Value.isSigned()) mangleNumber(Value.getSExtValue()); else mangleNumber(Value.getZExtValue()); } 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; } // Look through no-op casts like template parameter substitutions. E = E->IgnoreParenNoopCasts(Context.getASTContext()); const CXXUuidofExpr *UE = nullptr; if (const UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_AddrOf) UE = dyn_cast(UO->getSubExpr()); } else UE = dyn_cast(E); if (UE) { // If we had to peek through an address-of operator, treat this like we are // dealing with a pointer type. Otherwise, treat it like a const reference. // // N.B. This matches up with the handling of TemplateArgument::Declaration // in mangleTemplateArg if (UE == E) Out << "$E?"; else Out << "$1?"; // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from // const __s_GUID _GUID_{lower case UUID with underscores} StringRef Uuid = UE->getUuidStr(); std::string Name = "_GUID_" + Uuid.lower(); std::replace(Name.begin(), Name.end(), '-', '_'); mangleSourceName(Name); // Terminate the whole name with an '@'. Out << '@'; // It's a global variable. Out << '3'; // It's a struct called __s_GUID. mangleArtificialTagType(TTK_Struct, "__s_GUID"); // It's const. Out << 'B'; 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 TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { // ::= + const TemplateParameterList *TPL = TD->getTemplateParameters(); assert(TPL->size() == TemplateArgs.size() && "size mismatch between args and parms!"); for (size_t i = 0; i < TemplateArgs.size(); ++i) { const TemplateArgument &TA = TemplateArgs[i]; // Separate consecutive packs by $$Z. if (i > 0 && TA.getKind() == TemplateArgument::Pack && TemplateArgs[i - 1].getKind() == TemplateArgument::Pack) Out << "$$Z"; mangleTemplateArg(TD, TA, TPL->getParam(i)); } } void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, const NamedDecl *Parm) { // ::= // ::= // ::= // ::= // ::= $E? // ::= $1? // ::= $0A@ // ::= switch (TA.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't mangle null template arguments!"); case TemplateArgument::TemplateExpansion: llvm_unreachable("Can't mangle template expansion arguments!"); case TemplateArgument::Type: { QualType T = TA.getAsType(); mangleType(T, SourceRange(), QMM_Escape); break; } case TemplateArgument::Declaration: { const NamedDecl *ND = TA.getAsDecl(); if (isa(ND) || isa(ND)) { mangleMemberDataPointer(cast(ND->getDeclContext()) ->getMostRecentNonInjectedDecl(), cast(ND)); } else if (const FunctionDecl *FD = dyn_cast(ND)) { const CXXMethodDecl *MD = dyn_cast(FD); if (MD && MD->isInstance()) { mangleMemberFunctionPointer( MD->getParent()->getMostRecentNonInjectedDecl(), MD); } else { Out << "$1?"; mangleName(FD); mangleFunctionEncoding(FD, /*ShouldMangle=*/true); } } else { mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); } break; } case TemplateArgument::Integral: mangleIntegerLiteral(TA.getAsIntegral(), TA.getIntegralType()->isBooleanType()); break; case TemplateArgument::NullPtr: { QualType T = TA.getNullPtrType(); if (const MemberPointerType *MPT = T->getAs()) { const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); if (MPT->isMemberFunctionPointerType() && !isa(TD)) { mangleMemberFunctionPointer(RD, nullptr); return; } if (MPT->isMemberDataPointer()) { if (!isa(TD)) { mangleMemberDataPointer(RD, nullptr); return; } // nullptr data pointers are always represented with a single field // which is initialized with either 0 or -1. Why -1? Well, we need to // distinguish the case where the data member is at offset zero in the // record. // However, we are free to use 0 *if* we would use multiple fields for // non-nullptr member pointers. if (!RD->nullFieldOffsetIsZero()) { mangleIntegerLiteral(llvm::APSInt::get(-1), /*IsBoolean=*/false); return; } } } mangleIntegerLiteral(llvm::APSInt::getUnsigned(0), /*IsBoolean=*/false); break; } case TemplateArgument::Expression: mangleExpression(TA.getAsExpr()); break; case TemplateArgument::Pack: { ArrayRef TemplateArgs = TA.getPackAsArray(); if (TemplateArgs.empty()) { if (isa(Parm) || isa(Parm)) // MSVC 2015 changed the mangling for empty expanded template packs, // use the old mangling for link compatibility for old versions. Out << (Context.getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2015) ? "$$V" : "$$$V"); else if (isa(Parm)) Out << "$S"; else llvm_unreachable("unexpected template parameter decl!"); } else { for (const TemplateArgument &PA : TemplateArgs) mangleTemplateArg(TD, PA, Parm); } break; } case TemplateArgument::Template: { const NamedDecl *ND = TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl(); if (const auto *TD = dyn_cast(ND)) { mangleType(TD); } else if (isa(ND)) { Out << "$$Y"; mangleName(ND); } else { llvm_unreachable("unexpected template template NamedDecl!"); } break; } } } void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) { llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; Extra.mangleSourceName("Protocol"); Extra.mangleArtificialTagType(TTK_Struct, PD->getName()); mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"}); } void MicrosoftCXXNameMangler::mangleObjCLifetime(const QualType Type, Qualifiers Quals, SourceRange Range) { llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; switch (Quals.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: break; case Qualifiers::OCL_Autoreleasing: Extra.mangleSourceName("Autoreleasing"); break; case Qualifiers::OCL_Strong: Extra.mangleSourceName("Strong"); break; case Qualifiers::OCL_Weak: Extra.mangleSourceName("Weak"); break; } Extra.manglePointerCVQualifiers(Quals); Extra.manglePointerExtQualifiers(Quals, Type); Extra.mangleType(Type, Range); mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"}); } void MicrosoftCXXNameMangler::mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals, SourceRange Range) { llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; Extra.mangleSourceName("KindOf"); Extra.mangleType(QualType(T, 0) .stripObjCKindOfType(getASTContext()) ->getAs(), Quals, Range); mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"}); } void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, bool IsMember) { // ::= [E] [F] [I] // '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! // ::= 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 # based // ::= N # based const // ::= O # based volatile // ::= P # 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 # based member // ::= 3 # based const member // ::= 4 # based volatile member // ::= 5 # 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 # based function (pointers only) // ::= _B # based function (far?) (pointers only) // ::= _C # based method (pointers only) // ::= _D # based method (far?) (pointers only) // ::= _E # block (Clang) // ::= 0 # __based(void) // ::= 1 # __based(segment)? // ::= 2 # __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::mangleRefQualifier(RefQualifierKind RefQualifier) { // ::= G # lvalue reference // ::= H # rvalue-reference switch (RefQualifier) { case RQ_None: break; case RQ_LValue: Out << 'G'; break; case RQ_RValue: Out << 'H'; break; } } void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType) { if (PointersAre64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType())) Out << 'E'; if (Quals.hasRestrict()) Out << 'I'; if (Quals.hasUnaligned() || (!PointeeType.isNull() && PointeeType.getLocalQualifiers().hasUnaligned())) Out << 'F'; } void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) { // ::= 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) { // MSVC will backreference two canonically equivalent types that have slightly // different manglings when mangled alone. // Decayed types do not match up with non-decayed versions of the same type. // // e.g. // void (*x)(void) will not form a backreference with void x(void) void *TypePtr; if (const auto *DT = T->getAs()) { QualType OriginalType = DT->getOriginalType(); // All decayed ArrayTypes should be treated identically; as-if they were // a decayed IncompleteArrayType. if (const auto *AT = getASTContext().getAsArrayType(OriginalType)) OriginalType = getASTContext().getIncompleteArrayType( AT->getElementType(), AT->getSizeModifier(), AT->getIndexTypeCVRQualifiers()); TypePtr = OriginalType.getCanonicalType().getAsOpaquePtr(); // If the original parameter was textually written as an array, // instead treat the decayed parameter like it's const. // // e.g. // int [] -> int * const if (OriginalType->isArrayType()) T = T.withConst(); } else { TypePtr = T.getCanonicalType().getAsOpaquePtr(); } ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.tell(); mangleType(T, Range, QMM_Drop); // 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.tell() - OutSizeBefore > 1); if (LongerThanOneChar && TypeBackReferences.size() < 10) { size_t Size = TypeBackReferences.size(); TypeBackReferences[TypePtr] = Size; } } else { Out << Found->second; } } void MicrosoftCXXNameMangler::manglePassObjectSizeArg( const PassObjectSizeAttr *POSA) { int Type = POSA->getType(); auto Iter = PassObjectSizeArgs.insert(Type).first; auto *TypePtr = (const void *)&*Iter; ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type), {"__clang"}); if (TypeBackReferences.size() < 10) { size_t Size = TypeBackReferences.size(); TypeBackReferences[TypePtr] = Size; } } else { Out << Found->second; } } void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range) { // Address space is mangled as an unqualified templated type in the __clang // namespace. The demangled version of this is: // In the case of a language specific address space: // __clang::struct _AS[language_addr_space] // where: // ::= | // ::= "CL" [ "global" | "local" | "constant" | // "private"| "generic" ] // ::= "CU" [ "device" | "constant" | "shared" ] // Note that the above were chosen to match the Itanium mangling for this. // // In the case of a non-language specific address space: // __clang::struct _AS assert(Quals.hasAddressSpace() && "Not valid without address space"); llvm::SmallString<32> ASMangling; llvm::raw_svector_ostream Stream(ASMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; LangAS AS = Quals.getAddressSpace(); if (Context.getASTContext().addressSpaceMapManglingFor(AS)) { unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS); Extra.mangleSourceName("_AS"); Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(TargetAS), /*IsBoolean*/ false); } else { switch (AS) { default: llvm_unreachable("Not a language specific address space"); case LangAS::opencl_global: Extra.mangleSourceName("_ASCLglobal"); break; case LangAS::opencl_local: Extra.mangleSourceName("_ASCLlocal"); break; case LangAS::opencl_constant: Extra.mangleSourceName("_ASCLconstant"); break; case LangAS::opencl_private: Extra.mangleSourceName("_ASCLprivate"); break; case LangAS::opencl_generic: Extra.mangleSourceName("_ASCLgeneric"); break; case LangAS::cuda_device: Extra.mangleSourceName("_ASCUdevice"); break; case LangAS::cuda_constant: Extra.mangleSourceName("_ASCUconstant"); break; case LangAS::cuda_shared: Extra.mangleSourceName("_ASCUshared"); break; } } Extra.mangleType(T, Range, QMM_Escape); mangleQualifiers(Qualifiers(), false); mangleArtificialTagType(TTK_Struct, ASMangling, {"__clang"}); } void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM) { // Don't use the canonical types. MSVC includes things like 'const' on // pointer arguments to function pointers that canonicalization strips away. T = T.getDesugaredType(getASTContext()); Qualifiers Quals = T.getLocalQualifiers(); if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { // If there were any Quals, getAsArrayType() pushed them onto the array // element type. if (QMM == QMM_Mangle) Out << 'A'; else if (QMM == QMM_Escape || QMM == QMM_Result) Out << "$$B"; mangleArrayType(AT); return; } bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || T->isReferenceType() || T->isBlockPointerType(); switch (QMM) { case QMM_Drop: if (Quals.hasObjCLifetime()) Quals = Quals.withoutObjCLifetime(); break; case QMM_Mangle: if (const FunctionType *FT = dyn_cast(T)) { Out << '6'; mangleFunctionType(FT); return; } mangleQualifiers(Quals, false); break; case QMM_Escape: if (!IsPointer && Quals) { Out << "$$C"; mangleQualifiers(Quals, false); } break; case QMM_Result: // Presence of __unaligned qualifier shouldn't affect mangling here. Quals.removeUnaligned(); if (Quals.hasObjCLifetime()) Quals = Quals.withoutObjCLifetime(); if ((!IsPointer && Quals) || isa(T) || isArtificialTagType(T)) { Out << '?'; mangleQualifiers(Quals, false); } break; } const Type *ty = T.getTypePtr(); 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(ty), Quals, Range); \ break; #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE #undef NON_CANONICAL_TYPE #undef TYPE } } void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, SourceRange Range) { // ::= // ::= 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 # // ::= 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 # - // ::= _T # __float80 (Intel) + // ::= _Q # char8_t // ::= _S # char16_t + // ::= _T # __float80 (Intel) // ::= _U # char32_t // ::= _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::Char8: + Out << "_Q"; + break; case BuiltinType::Char16: Out << "_S"; break; case BuiltinType::Char32: Out << "_U"; 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: mangleArtificialTagType(TTK_Struct, "objc_object"); break; case BuiltinType::ObjCClass: mangleArtificialTagType(TTK_Struct, "objc_class"); break; case BuiltinType::ObjCSel: mangleArtificialTagType(TTK_Struct, "objc_selector"); break; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: \ Out << "PAUocl_" #ImgType "_" #Suffix "@@"; \ break; #include "clang/Basic/OpenCLImageTypes.def" case BuiltinType::OCLSampler: Out << "PA"; mangleArtificialTagType(TTK_Struct, "ocl_sampler"); break; case BuiltinType::OCLEvent: Out << "PA"; mangleArtificialTagType(TTK_Struct, "ocl_event"); break; case BuiltinType::OCLClkEvent: Out << "PA"; mangleArtificialTagType(TTK_Struct, "ocl_clkevent"); break; case BuiltinType::OCLQueue: Out << "PA"; mangleArtificialTagType(TTK_Struct, "ocl_queue"); break; case BuiltinType::OCLReserveID: Out << "PA"; mangleArtificialTagType(TTK_Struct, "ocl_reserveid"); break; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: \ mangleArtificialTagType(TTK_Struct, "ocl_" #ExtType); \ break; #include "clang/Basic/OpenCLExtensionTypes.def" case BuiltinType::NullPtr: Out << "$$T"; break; case BuiltinType::Float16: mangleArtificialTagType(TTK_Struct, "_Float16", {"__clang"}); break; case BuiltinType::Half: mangleArtificialTagType(TTK_Struct, "_Half", {"__clang"}); break; case BuiltinType::ShortAccum: case BuiltinType::Accum: case BuiltinType::LongAccum: case BuiltinType::UShortAccum: case BuiltinType::UAccum: case BuiltinType::ULongAccum: case BuiltinType::ShortFract: case BuiltinType::Fract: case BuiltinType::LongFract: case BuiltinType::UShortFract: case BuiltinType::UFract: case BuiltinType::ULongFract: case BuiltinType::SatShortAccum: case BuiltinType::SatAccum: case BuiltinType::SatLongAccum: case BuiltinType::SatUShortAccum: case BuiltinType::SatUAccum: case BuiltinType::SatULongAccum: case BuiltinType::SatShortFract: case BuiltinType::SatFract: case BuiltinType::SatLongFract: case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: - case BuiltinType::Char8: case BuiltinType::Float128: { 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; } } } // ::= void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers, 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. if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) { Out << "$$A8@@"; mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true); } else { Out << "$$A6"; mangleFunctionType(T); } } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, Qualifiers, SourceRange) { Out << "$$A6"; mangleFunctionType(T); } void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, const FunctionDecl *D, bool ForceThisQuals, bool MangleExceptionSpec) { // ::= // const FunctionProtoType *Proto = dyn_cast(T); SourceRange Range; if (D) Range = D->getSourceRange(); bool IsInLambda = false; bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false; CallingConv CC = T->getCallConv(); if (const CXXMethodDecl *MD = dyn_cast_or_null(D)) { if (MD->getParent()->isLambda()) IsInLambda = true; if (MD->isInstance()) HasThisQuals = true; if (isa(MD)) { IsStructor = true; } else if (isa(MD)) { IsStructor = true; IsCtorClosure = (StructorType == Ctor_CopyingClosure || StructorType == Ctor_DefaultClosure) && isStructorDecl(MD); if (IsCtorClosure) CC = getASTContext().getDefaultCallingConvention( /*IsVariadic=*/false, /*IsCXXMethod=*/true); } } // If this is a C++ instance method, mangle the CVR qualifiers for the // this pointer. if (HasThisQuals) { Qualifiers Quals = Proto->getTypeQuals(); manglePointerExtQualifiers(Quals, /*PointeeType=*/QualType()); mangleRefQualifier(Proto->getRefQualifier()); mangleQualifiers(Quals, /*IsMember=*/false); } mangleCallingConvention(CC); // ::= // ::= @ # structors (they have no declared return type) if (IsStructor) { if (isa(D) && isStructorDecl(D)) { // The scalar deleting destructor takes an extra int argument which is not // reflected in the AST. if (StructorType == Dtor_Deleting) { Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); return; } // The vbase destructor returns void which is not reflected in the AST. if (StructorType == Dtor_Complete) { Out << "XXZ"; return; } } if (IsCtorClosure) { // Default constructor closure and copy constructor closure both return // void. Out << 'X'; if (StructorType == Ctor_DefaultClosure) { // Default constructor closure always has no arguments. Out << 'X'; } else if (StructorType == Ctor_CopyingClosure) { // Copy constructor closure always takes an unqualified reference. mangleArgumentType(getASTContext().getLValueReferenceType( Proto->getParamType(0) ->getAs() ->getPointeeType(), /*SpelledAsLValue=*/true), Range); Out << '@'; } else { llvm_unreachable("unexpected constructor closure!"); } Out << 'Z'; return; } Out << '@'; } else { QualType ResultType = T->getReturnType(); if (const auto *AT = dyn_cast_or_null(ResultType->getContainedAutoType())) { Out << '?'; mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false); Out << '?'; assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType && "shouldn't need to mangle __auto_type!"); mangleSourceName(AT->isDecltypeAuto() ? "" : ""); Out << '@'; } else if (IsInLambda) { Out << '@'; } else { if (ResultType->isVoidType()) ResultType = ResultType.getUnqualifiedType(); mangleType(ResultType, Range, QMM_Result); } } // ::= X # void // ::= + @ // ::= * Z # varargs if (!Proto) { // Function types without prototypes can arise when mangling a function type // within an overloadable function in C. We mangle these as the absence of // any parameter types (not even an empty parameter list). Out << '@'; } else if (Proto->getNumParams() == 0 && !Proto->isVariadic()) { Out << 'X'; } else { // Happens for function pointer type arguments for example. for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { mangleArgumentType(Proto->getParamType(I), Range); // Mangle each pass_object_size parameter as if it's a parameter of enum // type passed directly after the parameter with the pass_object_size // attribute. The aforementioned enum's name is __pass_object_size, and we // pretend it resides in a top-level namespace called __clang. // // FIXME: Is there a defined extension notation for the MS ABI, or is it // necessary to just cross our fingers and hope this type+namespace // combination doesn't conflict with anything? if (D) if (const auto *P = D->getParamDecl(I)->getAttr()) manglePassObjectSizeArg(P); } // ::= Z # ellipsis if (Proto->isVariadic()) Out << 'Z'; else Out << '@'; } if (MangleExceptionSpec && getASTContext().getLangOpts().CPlusPlus17 && getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2017_5)) mangleThrowSpecification(Proto); else Out << 'Z'; } void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { // ::= E? # E designates a 64-bit 'this' // # pointer. in 64-bit mode *all* // # 'this' pointers are 64-bit. // ::= // ::= A # private: near // ::= B # private: far // ::= C # private: static near // ::= D # private: static far // ::= E # private: virtual near // ::= F # private: virtual far // ::= I # protected: near // ::= J # protected: far // ::= K # protected: static near // ::= L # protected: static far // ::= M # protected: virtual near // ::= N # protected: virtual far // ::= Q # public: near // ::= R # public: far // ::= S # public: static near // ::= T # public: static far // ::= U # public: virtual near // ::= V # public: virtual far // ::= Y # global near // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast(FD)) { bool IsVirtual = MD->isVirtual(); // When mangling vbase destructor variants, ignore whether or not the // underlying destructor was defined to be virtual. if (isa(MD) && isStructorDecl(MD) && StructorType == Dtor_Complete) { IsVirtual = false; } switch (MD->getAccess()) { case AS_none: llvm_unreachable("Unsupported access specifier"); case AS_private: if (MD->isStatic()) Out << 'C'; else if (IsVirtual) Out << 'E'; else Out << 'A'; break; case AS_protected: if (MD->isStatic()) Out << 'K'; else if (IsVirtual) Out << 'M'; else Out << 'I'; break; case AS_public: if (MD->isStatic()) Out << 'S'; else if (IsVirtual) Out << 'U'; else Out << 'Q'; } } else { Out << 'Y'; } } void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { // ::= 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 // ::= Q # __vectorcall // ::= w # __regcall // 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.) switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); case CC_Win64: case CC_X86_64SysV: 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; case CC_X86VectorCall: Out << 'Q'; break; case CC_Swift: Out << 'S'; break; case CC_PreserveMost: Out << 'U'; break; case CC_X86RegCall: Out << 'w'; break; } } void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { mangleCallingConvention(T->getCallConv()); } void MicrosoftCXXNameMangler::mangleThrowSpecification( const FunctionProtoType *FT) { // ::= Z # (default) // ::= _E # noexcept if (FT->canThrow()) Out << 'Z'; else Out << "_E"; } void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, Qualifiers, 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; } // ::= | | | // ::= T // ::= U // ::= V // ::= W4 void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) { switch (TTK) { 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 << "W4"; break; } } void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers, SourceRange) { mangleType(cast(T)->getDecl()); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers, SourceRange) { mangleType(cast(T)->getDecl()); } void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { mangleTagTypeKind(TD->getTagKind()); mangleName(TD); } // If you add a call to this, consider updating isArtificialTagType() too. void MicrosoftCXXNameMangler::mangleArtificialTagType( TagTypeKind TK, StringRef UnqualifiedName, ArrayRef NestedNames) { // ::= {[]+ | []}? @ mangleTagTypeKind(TK); // Always start with the unqualified name. mangleSourceName(UnqualifiedName); for (auto I = NestedNames.rbegin(), E = NestedNames.rend(); I != E; ++I) mangleSourceName(*I); // Terminate the whole name with an '@'. Out << '@'; } // ::= // ::= // [Y +] // # as global, E is never required // 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::mangleDecayedArrayType(const ArrayType *T) { // This isn't a recursive mangling, so now we have to do it all in this // one call. manglePointerCVQualifiers(T->getElementType().getQualifiers()); mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { QualType ElementTy(T, 0); SmallVector Dimensions; for (;;) { if (ElementTy->isConstantArrayType()) { const ConstantArrayType *CAT = getASTContext().getAsConstantArrayType(ElementTy); Dimensions.push_back(CAT->getSize()); ElementTy = CAT->getElementType(); } else if (ElementTy->isIncompleteArrayType()) { const IncompleteArrayType *IAT = getASTContext().getAsIncompleteArrayType(ElementTy); Dimensions.push_back(llvm::APInt(32, 0)); ElementTy = IAT->getElementType(); } else if (ElementTy->isVariableArrayType()) { const VariableArrayType *VAT = getASTContext().getAsVariableArrayType(ElementTy); Dimensions.push_back(llvm::APInt(32, 0)); ElementTy = VAT->getElementType(); } 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 { break; } } Out << 'Y'; // ::= # number of extra dimensions mangleNumber(Dimensions.size()); for (const llvm::APInt &Dimension : Dimensions) mangleNumber(Dimension.getLimitedValue()); mangleType(ElementTy, SourceRange(), QMM_Escape); } // ::= // ::= // void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); if (const FunctionProtoType *FPT = PointeeType->getAs()) { Out << '8'; mangleName(T->getClass()->castAs()->getDecl()); mangleFunctionType(FPT, nullptr, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs()->getDecl()); mangleType(PointeeType, Range, QMM_Drop); } } void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, Qualifiers, 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, Qualifiers, 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; } // ::= // ::= E? // # the E is required for 64-bit non-static pointers void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); if (PointeeType.getQualifiers().hasAddressSpace()) mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range); else mangleType(PointeeType, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); switch (Quals.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: break; case Qualifiers::OCL_Autoreleasing: case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: return mangleObjCLifetime(PointeeType, Quals, Range); } manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); mangleType(PointeeType, Range); } // ::= // ::= A E? // # the E is required for 64-bit non-static lvalue references void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!"); Out << 'A'; manglePointerExtQualifiers(Quals, PointeeType); mangleType(PointeeType, Range); } // ::= // ::= $$Q E? // # the E is required for 64-bit non-static rvalue references void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!"); Out << "$$Q"; manglePointerExtQualifiers(Quals, PointeeType); mangleType(PointeeType, Range); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers, SourceRange Range) { QualType ElementType = T->getElementType(); llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; Extra.mangleSourceName("_Complex"); Extra.mangleType(ElementType, Range, QMM_Escape); mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__clang"}); } // Returns true for types that mangleArtificialTagType() gets called for with // TTK_Union, TTK_Struct, TTK_Class and where compatibility with MSVC's // mangling matters. // (It doesn't matter for Objective-C types and the like that cl.exe doesn't // support.) bool MicrosoftCXXNameMangler::isArtificialTagType(QualType T) const { const Type *ty = T.getTypePtr(); switch (ty->getTypeClass()) { default: return false; case Type::Vector: { // For ABI compatibility only __m64, __m128(id), and __m256(id) matter, // but since mangleType(VectorType*) always calls mangleArtificialTagType() // just always return true (the other vector types are clang-only). return true; } } } void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals, SourceRange Range) { const BuiltinType *ET = T->getElementType()->getAs(); assert(ET && "vectors with non-builtin elements are unsupported"); uint64_t Width = getASTContext().getTypeSize(T); // Pattern match exactly the typedefs in our intrinsic headers. Anything that // doesn't match the Intel types uses a custom mangling below. size_t OutSizeBefore = Out.tell(); if (!isa(T)) { llvm::Triple::ArchType AT = getASTContext().getTargetInfo().getTriple().getArch(); if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) { if (Width == 64 && ET->getKind() == BuiltinType::LongLong) { mangleArtificialTagType(TTK_Union, "__m64"); } else if (Width >= 128) { if (ET->getKind() == BuiltinType::Float) mangleArtificialTagType(TTK_Union, "__m" + llvm::utostr(Width)); else if (ET->getKind() == BuiltinType::LongLong) mangleArtificialTagType(TTK_Union, "__m" + llvm::utostr(Width) + 'i'); else if (ET->getKind() == BuiltinType::Double) mangleArtificialTagType(TTK_Struct, "__m" + llvm::utostr(Width) + 'd'); } } } bool IsBuiltin = Out.tell() != OutSizeBefore; if (!IsBuiltin) { // The MS ABI doesn't have a special mangling for vector types, so we define // our own mangling to handle uses of __vector_size__ on user-specified // types, and for extensions like __v4sf. llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; Extra.mangleSourceName("__vector"); Extra.mangleType(QualType(ET, 0), Range, QMM_Escape); Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(T->getNumElements()), /*IsBoolean=*/false); mangleArtificialTagType(TTK_Union, TemplateMangling, {"__clang"}); } } void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, Qualifiers Quals, SourceRange Range) { mangleType(static_cast(T), Quals, Range); } void MicrosoftCXXNameMangler::mangleType(const DependentVectorType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "cannot mangle this dependent-sized vector type yet"); Diags.Report(Range.getBegin(), DiagID) << Range; } void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, Qualifiers, 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 DependentAddressSpaceType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "cannot mangle this dependent address space type yet"); Diags.Report(Range.getBegin(), DiagID) << Range; } void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers, SourceRange) { // ObjC interfaces have structs underlying them. mangleTagTypeKind(TTK_Struct); mangleName(T->getDecl()); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers Quals, SourceRange Range) { if (T->isKindOfType()) return mangleObjCKindOfType(T, Quals, Range); if (T->qual_empty() && !T->isSpecialized()) return mangleType(T->getBaseType(), Range, QMM_Drop); ArgBackRefMap OuterArgsContext; BackRefVec OuterTemplateContext; TypeBackReferences.swap(OuterArgsContext); NameBackReferences.swap(OuterTemplateContext); mangleTagTypeKind(TTK_Struct); Out << "?$"; if (T->isObjCId()) mangleSourceName("objc_object"); else if (T->isObjCClass()) mangleSourceName("objc_class"); else mangleSourceName(T->getInterface()->getName()); for (const auto &Q : T->quals()) mangleObjCProtocol(Q); if (T->isSpecialized()) for (const auto &TA : T->getTypeArgs()) mangleType(TA, Range, QMM_Drop); Out << '@'; Out << '@'; TypeBackReferences.swap(OuterArgsContext); NameBackReferences.swap(OuterTemplateContext); } void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); Out << "_E"; mangleFunctionType(PointeeType->castAs()); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *, Qualifiers, SourceRange) { llvm_unreachable("Cannot mangle injected class name type."); } void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, 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, Qualifiers, SourceRange Range) { assert(T->getDeducedType().isNull() && "expecting a dependent type!"); 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 DeducedTemplateSpecializationType *T, Qualifiers, SourceRange Range) { assert(T->getDeducedType().isNull() && "expecting a dependent type!"); DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this deduced class template specialization type yet"); Diags.Report(Range.getBegin(), DiagID) << Range; } void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, SourceRange Range) { QualType ValueType = T->getValueType(); llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); MicrosoftCXXNameMangler Extra(Context, Stream); Stream << "?$"; Extra.mangleSourceName("_Atomic"); Extra.mangleType(ValueType, Range, QMM_Escape); mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__clang"}); } void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this OpenCL pipe type yet"); Diags.Report(Range.getBegin(), DiagID) << Range; } void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, raw_ostream &Out) { assert((isa(D) || isa(D)) && "Invalid mangleName() call, argument is not a variable or function!"); assert(!isa(D) && !isa(D) && "Invalid mangleName() call on 'structor decl!"); PrettyStackTraceDecl CrashInfo(D, SourceLocation(), getASTContext().getSourceManager(), "Mangling declaration"); msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); return Mangler.mangle(D); } // ::= | | // // ::= A # private near // ::= B # private far // ::= I # protected near // ::= J # protected far // ::= Q # public near // ::= R # public far // ::= G # private near // ::= H # private far // ::= O # protected near // ::= P # protected far // ::= W # public near // ::= X # public far // ::= $0 # private near // ::= $1 # private far // ::= $2 # protected near // ::= $3 # protected far // ::= $4 # public near // ::= $5 # public far // ::= | // ::= // ::= // static void mangleThunkThisAdjustment(AccessSpecifier AS, const ThisAdjustment &Adjustment, MicrosoftCXXNameMangler &Mangler, raw_ostream &Out) { if (!Adjustment.Virtual.isEmpty()) { Out << '$'; char AccessSpec; switch (AS) { case AS_none: llvm_unreachable("Unsupported access specifier"); case AS_private: AccessSpec = '0'; break; case AS_protected: AccessSpec = '2'; break; case AS_public: AccessSpec = '4'; } if (Adjustment.Virtual.Microsoft.VBPtrOffset) { Out << 'R' << AccessSpec; Mangler.mangleNumber( static_cast(Adjustment.Virtual.Microsoft.VBPtrOffset)); Mangler.mangleNumber( static_cast(Adjustment.Virtual.Microsoft.VBOffsetOffset)); Mangler.mangleNumber( static_cast(Adjustment.Virtual.Microsoft.VtordispOffset)); Mangler.mangleNumber(static_cast(Adjustment.NonVirtual)); } else { Out << AccessSpec; Mangler.mangleNumber( static_cast(Adjustment.Virtual.Microsoft.VtordispOffset)); Mangler.mangleNumber(-static_cast(Adjustment.NonVirtual)); } } else if (Adjustment.NonVirtual != 0) { switch (AS) { case AS_none: llvm_unreachable("Unsupported access specifier"); case AS_private: Out << 'G'; break; case AS_protected: Out << 'O'; break; case AS_public: Out << 'W'; } Mangler.mangleNumber(-static_cast(Adjustment.NonVirtual)); } else { switch (AS) { case AS_none: llvm_unreachable("Unsupported access specifier"); case AS_private: Out << 'A'; break; case AS_protected: Out << 'I'; break; case AS_public: Out << 'Q'; } } } void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk( const CXXMethodDecl *MD, const MethodVFTableLocation &ML, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << '?'; Mangler.mangleVirtualMemPtrThunk(MD, ML); } void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << '?'; Mangler.mangleName(MD); // Usually the thunk uses the access specifier of the new method, but if this // is a covariant return thunk, then MSVC always uses the public access // specifier, and we do the same. AccessSpecifier AS = Thunk.Return.isEmpty() ? MD->getAccess() : AS_public; mangleThunkThisAdjustment(AS, Thunk.This, Mangler, MHO); if (!Thunk.Return.isEmpty()) assert(Thunk.Method != nullptr && "Thunk info should hold the overridee decl"); const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD; Mangler.mangleFunctionType( DeclForFPT->getType()->castAs(), MD); } void MicrosoftMangleContextImpl::mangleCXXDtorThunk( const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &Adjustment, raw_ostream &Out) { // FIXME: Actually, the dtor thunk should be emitted for vector deleting // dtors rather than scalar deleting dtors. Just use the vector deleting dtor // mangling manually until we support both deleting dtor types. assert(Type == Dtor_Deleting); msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO, DD, Type); Mangler.getStream() << "??_E"; Mangler.mangleName(DD->getParent()); mangleThunkThisAdjustment(DD->getAccess(), Adjustment, Mangler, MHO); Mangler.mangleFunctionType(DD->getType()->castAs(), DD); } void MicrosoftMangleContextImpl::mangleCXXVFTable( const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) { // ::= ?_7 // [] @ // NOTE: here is always 'B' (const). // is always '6' for vftables. msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); if (Derived->hasAttr()) Mangler.getStream() << "??_S"; else Mangler.getStream() << "??_7"; Mangler.mangleName(Derived); Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const. for (const CXXRecordDecl *RD : BasePath) Mangler.mangleName(RD); Mangler.getStream() << '@'; } void MicrosoftMangleContextImpl::mangleCXXVBTable( const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) { // ::= ?_8 // [] @ // NOTE: here is always 'B' (const). // is always '7' for vbtables. msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_8"; Mangler.mangleName(Derived); Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const. for (const CXXRecordDecl *RD : BasePath) Mangler.mangleName(RD); Mangler.getStream() << '@'; } void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_R0"; Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); Mangler.getStream() << "@8"; } void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, raw_ostream &Out) { MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << '.'; Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } void MicrosoftMangleContextImpl::mangleCXXVirtualDisplacementMap( const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_K"; Mangler.mangleName(SrcRD); Mangler.getStream() << "$C"; Mangler.mangleName(DstRD); } void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, bool IsUnaligned, uint32_t NumEntries, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "_TI"; if (IsConst) Mangler.getStream() << 'C'; if (IsVolatile) Mangler.getStream() << 'V'; if (IsUnaligned) Mangler.getStream() << 'U'; Mangler.getStream() << NumEntries; Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray( QualType T, uint32_t NumEntries, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "_CTA"; Mangler.getStream() << NumEntries; Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } void MicrosoftMangleContextImpl::mangleCXXCatchableType( QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex, raw_ostream &Out) { MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_CT"; llvm::SmallString<64> RTTIMangling; { llvm::raw_svector_ostream Stream(RTTIMangling); msvc_hashing_ostream MHO(Stream); mangleCXXRTTI(T, MHO); } Mangler.getStream() << RTTIMangling; // VS2015 CTP6 omits the copy-constructor in the mangled name. This name is, // in fact, superfluous but I'm not sure the change was made consciously. llvm::SmallString<64> CopyCtorMangling; if (!getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2015) && CD) { llvm::raw_svector_ostream Stream(CopyCtorMangling); msvc_hashing_ostream MHO(Stream); mangleCXXCtor(CD, CT, MHO); } Mangler.getStream() << CopyCtorMangling; Mangler.getStream() << Size; if (VBPtrOffset == -1) { if (NVOffset) { Mangler.getStream() << NVOffset; } } else { Mangler.getStream() << NVOffset; Mangler.getStream() << VBPtrOffset; Mangler.getStream() << VBIndex; } } void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_R1"; Mangler.mangleNumber(NVOffset); Mangler.mangleNumber(VBPtrOffset); Mangler.mangleNumber(VBTableOffset); Mangler.mangleNumber(Flags); Mangler.mangleName(Derived); Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray( const CXXRecordDecl *Derived, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_R2"; Mangler.mangleName(Derived); Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor( const CXXRecordDecl *Derived, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??_R3"; Mangler.mangleName(Derived); Mangler.getStream() << "8"; } void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator( const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) { // ::= ?_R4 // [] @ // NOTE: here is always 'B' (const). // is always '6' for vftables. llvm::SmallString<64> VFTableMangling; llvm::raw_svector_ostream Stream(VFTableMangling); mangleCXXVFTable(Derived, BasePath, Stream); if (VFTableMangling.startswith("??@")) { assert(VFTableMangling.endswith("@")); Out << VFTableMangling << "??_R4@"; return; } assert(VFTableMangling.startswith("??_7") || VFTableMangling.startswith("??_S")); Out << "??_R4" << StringRef(VFTableMangling).drop_front(4); } void MicrosoftMangleContextImpl::mangleSEHFilterExpression( const NamedDecl *EnclosingDecl, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); // The function body is in the same comdat as the function with the handler, // so the numbering here doesn't have to be the same across TUs. // // ::= ?filt$ @0 Mangler.getStream() << "?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@"; Mangler.mangleName(EnclosingDecl); } void MicrosoftMangleContextImpl::mangleSEHFinallyBlock( const NamedDecl *EnclosingDecl, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); // The function body is in the same comdat as the function with the handler, // so the numbering here doesn't have to be the same across TUs. // // ::= ?fin$ @0 Mangler.getStream() << "?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@"; Mangler.mangleName(EnclosingDecl); } void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { // This is just a made up unique string for the purposes of tbaa. undname // does *not* know how to demangle it. MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << '?'; Mangler.mangleType(T, SourceRange()); } void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler mangler(*this, MHO, D, Type); mangler.mangle(D); } void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler mangler(*this, MHO, D, Type); mangler.mangle(D); } void MicrosoftMangleContextImpl::mangleReferenceTemporary( const VarDecl *VD, unsigned ManglingNumber, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "?$RT" << ManglingNumber << '@'; Mangler.mangle(VD, ""); } void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable( const VarDecl *VD, unsigned GuardNum, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "?$TSS" << GuardNum << '@'; Mangler.mangleNestedName(VD); Mangler.getStream() << "@4HA"; } void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, raw_ostream &Out) { // ::= ?_B @5 // ::= ?__J @5 // ::= ?$S @ @4IA // The first mangling is what MSVC uses to guard static locals in inline // functions. It uses a different mangling in external functions to support // guarding more than 32 variables. MSVC rejects inline functions with more // than 32 static locals. We don't fully implement the second mangling // because those guards are not externally visible, and instead use LLVM's // default renaming when creating a new guard variable. msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); bool Visible = VD->isExternallyVisible(); if (Visible) { Mangler.getStream() << (VD->getTLSKind() ? "??__J" : "??_B"); } else { Mangler.getStream() << "?$S1@"; } unsigned ScopeDepth = 0; if (Visible && !getNextDiscriminator(VD, ScopeDepth)) // If we do not have a discriminator and are emitting a guard variable for // use at global scope, then mangling the nested name will not be enough to // remove ambiguities. Mangler.mangle(VD, ""); else Mangler.mangleNestedName(VD); Mangler.getStream() << (Visible ? "@5" : "@4IA"); if (ScopeDepth) Mangler.mangleNumber(ScopeDepth); } void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D, char CharCode, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); Mangler.getStream() << "??__" << CharCode; if (D->isStaticDataMember()) { Mangler.getStream() << '?'; Mangler.mangleName(D); Mangler.mangleVariableEncoding(D); Mangler.getStream() << "@@"; } else { Mangler.mangleName(D); } // This is the function class mangling. These stubs are global, non-variadic, // cdecl functions that return void and take no args. Mangler.getStream() << "YAXXZ"; } void MicrosoftMangleContextImpl::mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) { // ::= ?__E YAXXZ mangleInitFiniStub(D, 'E', Out); } void MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out) { // ::= ?__F YAXXZ mangleInitFiniStub(D, 'F', Out); } void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) { // ::= 0 # char, char16_t, char32_t // # (little endian char data in mangling) // ::= 1 # wchar_t (big endian char data in mangling) // // ::= # the length of the literal // // ::= + @ # crc of the literal including // # trailing null bytes // // ::= # uninteresting character // ::= '?$' # these two nibbles // # encode the byte for the // # character // ::= '?' [a-z] # \xe1 - \xfa // ::= '?' [A-Z] # \xc1 - \xda // ::= '?' [0-9] # [,/\:. \n\t'-] // // ::= '??_C@_' // '@' MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "??_C@_"; // The actual string length might be different from that of the string literal // in cases like: // char foo[3] = "foobar"; // char bar[42] = "foobar"; // Where it is truncated or zero-padded to fit the array. This is the length // used for mangling, and any trailing null-bytes also need to be mangled. unsigned StringLength = getASTContext() .getAsConstantArrayType(SL->getType()) ->getSize() .getZExtValue(); unsigned StringByteLength = StringLength * SL->getCharByteWidth(); // : The "kind" of string literal is encoded into the mangled name. if (SL->isWide()) Mangler.getStream() << '1'; else Mangler.getStream() << '0'; // : The next part of the mangled name consists of the length // of the string in bytes. Mangler.mangleNumber(StringByteLength); auto GetLittleEndianByte = [&SL](unsigned Index) { unsigned CharByteWidth = SL->getCharByteWidth(); if (Index / CharByteWidth >= SL->getLength()) return static_cast(0); uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth); unsigned OffsetInCodeUnit = Index % CharByteWidth; return static_cast((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff); }; auto GetBigEndianByte = [&SL](unsigned Index) { unsigned CharByteWidth = SL->getCharByteWidth(); if (Index / CharByteWidth >= SL->getLength()) return static_cast(0); uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth); unsigned OffsetInCodeUnit = (CharByteWidth - 1) - (Index % CharByteWidth); return static_cast((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff); }; // CRC all the bytes of the StringLiteral. llvm::JamCRC JC; for (unsigned I = 0, E = StringByteLength; I != E; ++I) JC.update(GetLittleEndianByte(I)); // : The CRC is encoded utilizing the standard number mangling // scheme. Mangler.mangleNumber(JC.getCRC()); // : The mangled name also contains the first 32 bytes // (including null-terminator bytes) of the encoded StringLiteral. // Each character is encoded by splitting them into bytes and then encoding // the constituent bytes. auto MangleByte = [&Mangler](char Byte) { // There are five different manglings for characters: // - [a-zA-Z0-9_$]: A one-to-one mapping. // - ?[a-z]: The range from \xe1 to \xfa. // - ?[A-Z]: The range from \xc1 to \xda. // - ?[0-9]: The set of [,/\:. \n\t'-]. // - ?$XX: A fallback which maps nibbles. if (isIdentifierBody(Byte, /*AllowDollar=*/true)) { Mangler.getStream() << Byte; } else if (isLetter(Byte & 0x7f)) { Mangler.getStream() << '?' << static_cast(Byte & 0x7f); } else { const char SpecialChars[] = {',', '/', '\\', ':', '.', ' ', '\n', '\t', '\'', '-'}; const char *Pos = std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte); if (Pos != std::end(SpecialChars)) { Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars)); } else { Mangler.getStream() << "?$"; Mangler.getStream() << static_cast('A' + ((Byte >> 4) & 0xf)); Mangler.getStream() << static_cast('A' + (Byte & 0xf)); } } }; // Enforce our 32 bytes max, except wchar_t which gets 32 chars instead. unsigned MaxBytesToMangle = SL->isWide() ? 64U : 32U; unsigned NumBytesToMangle = std::min(MaxBytesToMangle, StringByteLength); for (unsigned I = 0; I != NumBytesToMangle; ++I) { if (SL->isWide()) MangleByte(GetBigEndianByte(I)); else MangleByte(GetLittleEndianByte(I)); } Mangler.getStream() << '@'; } MicrosoftMangleContext * MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { return new MicrosoftMangleContextImpl(Context, Diags); } Index: vendor/clang/dist-release_80/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- vendor/clang/dist-release_80/lib/CodeGen/CGDebugInfo.cpp (revision 349778) +++ vendor/clang/dist-release_80/lib/CodeGen/CGDebugInfo.cpp (revision 349779) @@ -1,4505 +1,4497 @@ //===--- 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 "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.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/CodeGenOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" using namespace clang; using namespace clang::CodeGen; static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); return TI.AlignIsRequired ? TI.Align : 0; } static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) { return getTypeAlignIfRequired(Ty.getTypePtr(), Ctx); } static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { return D->hasAttr() ? D->getMaxAlignment() : 0; } CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), DBuilder(CGM.getModule()) { for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap) DebugPrefixMap[KV.first] = KV.second; CreateCompileUnit(); } CGDebugInfo::~CGDebugInfo() { assert(LexicalBlockStack.empty() && "Region stack mismatch, stack not empty!"); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation) : CGF(&CGF) { init(TemporaryLocation); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, SourceLocation TemporaryLocation) : CGF(&CGF) { init(TemporaryLocation, DefaultToEmpty); } void ApplyDebugLocation::init(SourceLocation TemporaryLocation, bool DefaultToEmpty) { auto *DI = CGF->getDebugInfo(); if (!DI) { CGF = nullptr; return; } OriginalLocation = CGF->Builder.getCurrentDebugLocation(); if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled()) return; if (TemporaryLocation.isValid()) { DI->EmitLocation(CGF->Builder, TemporaryLocation); return; } if (DefaultToEmpty) { CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc()); return; } // Construct a location that has a valid scope, but no line info. assert(!DI->LexicalBlockStack.empty()); CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( 0, 0, DI->LexicalBlockStack.back(), DI->getInlinedAt())); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E) : CGF(&CGF) { init(E->getExprLoc()); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc) : CGF(&CGF) { if (!CGF.getDebugInfo()) { this->CGF = nullptr; return; } OriginalLocation = CGF.Builder.getCurrentDebugLocation(); if (Loc) CGF.Builder.SetCurrentDebugLocation(std::move(Loc)); } ApplyDebugLocation::~ApplyDebugLocation() { // Query CGF so the location isn't overwritten when location updates are // temporarily disabled (for C++ default function arguments) if (CGF) CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation)); } ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn) : CGF(&CGF) { if (!CGF.getDebugInfo()) { this->CGF = nullptr; return; } auto &DI = *CGF.getDebugInfo(); SavedLocation = DI.getLocation(); assert((DI.getInlinedAt() == CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) && "CGDebugInfo and IRBuilder are out of sync"); DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn); } ApplyInlineDebugLocation::~ApplyInlineDebugLocation() { if (!CGF) return; auto &DI = *CGF->getDebugInfo(); DI.EmitInlineFunctionEnd(CGF->Builder); DI.EmitLocation(CGF->Builder, SavedLocation); } void CGDebugInfo::setLocation(SourceLocation Loc) { // If the new location isn't valid return. if (Loc.isInvalid()) 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(); auto *Scope = cast(LexicalBlockStack.back()); PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); if (PCLoc.isInvalid() || Scope->getFile() == getOrCreateFile(CurLoc)) return; if (auto *LBF = dyn_cast(Scope)) { LexicalBlockStack.pop_back(); LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile( LBF->getScope(), getOrCreateFile(CurLoc))); } else if (isa(Scope) || isa(Scope)) { LexicalBlockStack.pop_back(); LexicalBlockStack.emplace_back( DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc))); } } llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) { llvm::DIScope *Mod = getParentModuleOrNull(D); return getContextDescriptor(cast(D->getDeclContext()), Mod ? Mod : TheCU); } llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, llvm::DIScope *Default) { if (!Context) return Default; auto I = RegionMap.find(Context); if (I != RegionMap.end()) { llvm::Metadata *V = I->second; return dyn_cast_or_null(V); } // Check namespace. if (const auto *NSDecl = dyn_cast(Context)) return getOrCreateNamespace(NSDecl); if (const auto *RDecl = dyn_cast(Context)) if (!RDecl->isDependentType()) return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), TheCU->getFile()); return Default; } PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PrintingPolicy PP = CGM.getContext().getPrintingPolicy(); // If we're emitting codeview, it's important to try to match MSVC's naming so // that visualizers written for MSVC will trigger for our class names. In // particular, we can't have spaces between arguments of standard templates // like basic_string and vector. if (CGM.getCodeGenOpts().EmitCodeView) PP.MSVCFormatting = true; // Apply -fdebug-prefix-map. PP.RemapFilePaths = true; PP.remapPath = [this](StringRef Path) { return remapDIPath(Path); }; return PP; } StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert(FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); FunctionTemplateSpecializationInfo *Info = FD->getTemplateSpecializationInfo(); // Emit the unqualified name in normal operation. LLVM and the debugger can // compute the fully qualified name from the scope chain. If we're only // emitting line table info, there won't be any scope chains, so emit the // fully qualified name here so that stack traces are more accurate. // FIXME: Do this when emitting DWARF as well as when emitting CodeView after // evaluating the size impact. bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly && CGM.getCodeGenOpts().EmitCodeView; if (!Info && FII && !UseQualifiedName) return FII->getName(); SmallString<128> NS; llvm::raw_svector_ostream OS(NS); if (!UseQualifiedName) FD->printName(OS); else FD->printQualifiedName(OS, getPrintingPolicy()); // Add any template specialization args. if (Info) { const TemplateArgumentList *TArgs = Info->TemplateArguments; printTemplateArgumentList(OS, TArgs->asArray(), getPrintingPolicy()); } // Copy this name on the side and use its reference. return internString(OS.str()); } 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 auto *OID = dyn_cast(DC)) { OS << OID->getName(); } else if (const auto *OID = dyn_cast(DC)) { OS << OID->getName(); } else if (const auto *OC = dyn_cast(DC)) { if (OC->IsClassExtension()) { OS << OC->getClassInterface()->getName(); } else { OS << OC->getIdentifier()->getNameStart() << '(' << OC->getIdentifier()->getNameStart() << ')'; } } else if (const auto *OCD = dyn_cast(DC)) { OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; } else if (isa(DC)) { // We can extract the type of the class from the self pointer. if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { QualType ClassTy = cast(SelfDecl->getType())->getPointeeType(); ClassTy.print(OS, PrintingPolicy(LangOptions())); } } OS << ' ' << OMD->getSelector().getAsString() << ']'; return internString(OS.str()); } StringRef CGDebugInfo::getSelectorName(Selector S) { return internString(S.getAsString()); } StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { if (isa(RD)) { SmallString<128> Name; llvm::raw_svector_ostream OS(Name); RD->getNameForDiagnostic(OS, getPrintingPolicy(), /*Qualified*/ false); // Copy this name on the side and use its reference. return internString(Name); } // quick optimization to avoid having to intern strings that are already // stored reliably elsewhere if (const IdentifierInfo *II = RD->getIdentifier()) return II->getName(); // The CodeView printer in LLVM wants to see the names of unnamed types: it is // used to reconstruct the fully qualified type names. if (CGM.getCodeGenOpts().EmitCodeView) { if (const TypedefNameDecl *D = RD->getTypedefNameForAnonDecl()) { assert(RD->getDeclContext() == D->getDeclContext() && "Typedef should not be in another decl context!"); assert(D->getDeclName().getAsIdentifierInfo() && "Typedef was not named!"); return D->getDeclName().getAsIdentifierInfo()->getName(); } if (CGM.getLangOpts().CPlusPlus) { StringRef Name; ASTContext &Context = CGM.getContext(); if (const DeclaratorDecl *DD = Context.getDeclaratorForUnnamedTagDecl(RD)) // Anonymous types without a name for linkage purposes have their // declarator mangled in if they have one. Name = DD->getName(); else if (const TypedefNameDecl *TND = Context.getTypedefNameForUnnamedTagDecl(RD)) // Anonymous types without a name for linkage purposes have their // associate typedef mangled in if they have one. Name = TND->getName(); if (!Name.empty()) { SmallString<256> UnnamedType(" CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const { Checksum.clear(); if (!CGM.getCodeGenOpts().EmitCodeView && CGM.getCodeGenOpts().DwarfVersion < 5) return None; SourceManager &SM = CGM.getContext().getSourceManager(); bool Invalid; llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid); if (Invalid) return None; llvm::MD5 Hash; llvm::MD5::MD5Result Result; Hash.update(MemBuffer->getBuffer()); Hash.final(Result); Hash.stringifyResult(Result, Checksum); return llvm::DIFile::CSK_MD5; } Optional CGDebugInfo::getSource(const SourceManager &SM, FileID FID) { if (!CGM.getCodeGenOpts().EmbedSource) return None; bool SourceInvalid = false; StringRef Source = SM.getBufferData(FID, &SourceInvalid); if (SourceInvalid) return None; return Source; } llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (!Loc.isValid()) // If Location is not valid then use main input file. return TheCU->getFile(); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); StringRef FileName = PLoc.getFilename(); if (PLoc.isInvalid() || FileName.empty()) // If the location is not valid then use main input file. return TheCU->getFile(); // Cache the results. auto It = DIFileCache.find(FileName.data()); if (It != DIFileCache.end()) { // Verify that the information still exists. if (llvm::Metadata *V = It->second) return cast(V); } SmallString<32> Checksum; Optional CSKind = computeChecksum(SM.getFileID(Loc), Checksum); Optional> CSInfo; if (CSKind) CSInfo.emplace(*CSKind, Checksum); return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc))); } llvm::DIFile * CGDebugInfo::createFile(StringRef FileName, Optional> CSInfo, Optional Source) { StringRef Dir; StringRef File; std::string RemappedFile = remapDIPath(FileName); std::string CurDir = remapDIPath(getCurrentDirname()); SmallString<128> DirBuf; SmallString<128> FileBuf; if (llvm::sys::path::is_absolute(RemappedFile)) { // Strip the common prefix (if it is more than just "/") from current // directory and FileName for a more space-efficient encoding. auto FileIt = llvm::sys::path::begin(RemappedFile); auto FileE = llvm::sys::path::end(RemappedFile); auto CurDirIt = llvm::sys::path::begin(CurDir); auto CurDirE = llvm::sys::path::end(CurDir); for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt) llvm::sys::path::append(DirBuf, *CurDirIt); if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) { // The common prefix only the root; stripping it would cause // LLVM diagnostic locations to be more confusing. Dir = {}; File = RemappedFile; } else { for (; FileIt != FileE; ++FileIt) llvm::sys::path::append(FileBuf, *FileIt); Dir = DirBuf; File = FileBuf; } } else { Dir = CurDir; File = RemappedFile; } llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source); DIFileCache[FileName.data()].reset(F); return F; } std::string CGDebugInfo::remapDIPath(StringRef Path) const { for (const auto &Entry : DebugPrefixMap) if (Path.startswith(Entry.first)) return (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); return Path.str(); } 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; } unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { // We may not want column information at all. if (!Force && !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); return CWDName = internString(CWD); } void CGDebugInfo::CreateCompileUnit() { SmallString<32> Checksum; Optional CSKind; Optional> CSInfo; // Should we be asking the SourceManager for the main file name, instead of // accepting it as an argument? This just causes the main file name to // mismatch with source locations and create extra lexical scopes or // mismatched debug info (a CU with a DW_AT_file of "-", because that's what // the driver passed, but functions/other things have DW_AT_file of "" // because that's what the SourceManager says) // Get absolute path name. SourceManager &SM = CGM.getContext().getSourceManager(); std::string MainFileName = CGM.getCodeGenOpts().MainFileName; if (MainFileName.empty()) MainFileName = ""; // 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 = remapDIPath(MainFile->getDir()->getName()); if (MainFileDir != ".") { llvm::SmallString<1024> MainFileDirSS(MainFileDir); llvm::sys::path::append(MainFileDirSS, MainFileName); MainFileName = MainFileDirSS.str(); } // If the main file name provided is identical to the input file name, and // if the input file is a preprocessed source, use the module name for // debug info. The module name comes from the name specified in the first // linemarker if the input is a preprocessed source. if (MainFile->getName() == MainFileName && FrontendOptions::getInputKindForExtension( MainFile->getName().rsplit('.').second) .isPreprocessed()) MainFileName = CGM.getModule().getName().str(); CSKind = computeChecksum(SM.getMainFileID(), Checksum); } llvm::dwarf::SourceLanguage LangTag; const LangOptions &LO = CGM.getLangOpts(); if (LO.CPlusPlus) { if (LO.ObjC) LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; else LangTag = llvm::dwarf::DW_LANG_C_plus_plus; } else if (LO.ObjC) { LangTag = llvm::dwarf::DW_LANG_ObjC; } else if (LO.RenderScript) { LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript; } 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.ObjC) RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; llvm::DICompileUnit::DebugEmissionKind EmissionKind; switch (DebugKind) { case codegenoptions::NoDebugInfo: case codegenoptions::LocTrackingOnly: EmissionKind = llvm::DICompileUnit::NoDebug; break; case codegenoptions::DebugLineTablesOnly: EmissionKind = llvm::DICompileUnit::LineTablesOnly; break; case codegenoptions::DebugDirectivesOnly: EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly; break; case codegenoptions::LimitedDebugInfo: case codegenoptions::FullDebugInfo: EmissionKind = llvm::DICompileUnit::FullDebug; break; } uint64_t DwoId = 0; auto &CGOpts = CGM.getCodeGenOpts(); // The DIFile used by the CU is distinct from the main source // file. Its directory part specifies what becomes the // DW_AT_comp_dir (the compilation directory), even if the source // file was specified with an absolute path. if (CSKind) CSInfo.emplace(*CSKind, Checksum); llvm::DIFile *CUFile = DBuilder.createFile( remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo, getSource(SM, SM.getMainFileID())); // Create new compile unit. TheCU = DBuilder.createCompileUnit( LangTag, CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "", LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO, CGOpts.DwarfDebugFlags, RuntimeVers, (CGOpts.getSplitDwarfMode() != CodeGenOptions::NoFission) ? "" : CGOpts.SplitDwarfFile, EmissionKind, DwoId, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, CGM.getTarget().getTriple().isNVPTX() ? llvm::DICompileUnit::DebugNameTableKind::None : static_cast( CGOpts.DebugNameTable), CGOpts.DebugRangesBaseAddress); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::dwarf::TypeKind Encoding; 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(); case BuiltinType::Void: return nullptr; case BuiltinType::ObjCClass: if (!ClassTy) ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_class", TheCU, TheCU->getFile(), 0); return ClassTy; case BuiltinType::ObjCId: { // typedef struct objc_class *Class; // typedef struct objc_object { // Class isa; // } *id; if (ObjTy) return ObjTy; if (!ClassTy) ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_class", TheCU, TheCU->getFile(), 0); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); auto *ISATy = DBuilder.createPointerType(ClassTy, Size); ObjTy = DBuilder.createStructType(TheCU, "objc_object", TheCU->getFile(), 0, 0, 0, llvm::DINode::FlagZero, nullptr, llvm::DINodeArray()); DBuilder.replaceArrays( ObjTy, DBuilder.getOrCreateArray(&*DBuilder.createMemberType( ObjTy, "isa", TheCU->getFile(), 0, Size, 0, 0, llvm::DINode::FlagZero, ISATy))); return ObjTy; } case BuiltinType::ObjCSel: { if (!SelTy) SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_selector", TheCU, TheCU->getFile(), 0); return SelTy; } #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: \ return getOrCreateStructPtrType("opencl_" #ImgType "_" #Suffix "_t", \ SingletonId); #include "clang/Basic/OpenCLImageTypes.def" case BuiltinType::OCLSampler: return getOrCreateStructPtrType("opencl_sampler_t", OCLSamplerDITy); case BuiltinType::OCLEvent: return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy); case BuiltinType::OCLClkEvent: return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy); case BuiltinType::OCLQueue: return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy); case BuiltinType::OCLReserveID: return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy); #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: \ return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty); #include "clang/Basic/OpenCLExtensionTypes.def" 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::Char8: 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::Float16: case BuiltinType::Float128: case BuiltinType::Double: // FIXME: For targets where long double and __float128 have the same size, // they are currently indistinguishable in the debugger without some // special treatment. However, there is currently no consensus on encoding // and this should be updated once a DWARF encoding exists for distinct // floating point types of the same size. Encoding = llvm::dwarf::DW_ATE_float; break; case BuiltinType::ShortAccum: case BuiltinType::Accum: case BuiltinType::LongAccum: case BuiltinType::ShortFract: case BuiltinType::Fract: case BuiltinType::LongFract: case BuiltinType::SatShortFract: case BuiltinType::SatFract: case BuiltinType::SatLongFract: case BuiltinType::SatShortAccum: case BuiltinType::SatAccum: case BuiltinType::SatLongAccum: Encoding = llvm::dwarf::DW_ATE_signed_fixed; break; case BuiltinType::UShortAccum: case BuiltinType::UAccum: case BuiltinType::ULongAccum: case BuiltinType::UShortFract: case BuiltinType::UFract: case BuiltinType::ULongFract: case BuiltinType::SatUShortAccum: case BuiltinType::SatUAccum: case BuiltinType::SatULongAccum: case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: Encoding = llvm::dwarf::DW_ATE_unsigned_fixed; 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 and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(BT); return DBuilder.createBasicType(BTName, Size, Encoding); } llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { // Bit size and offset of the type. llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float; if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; uint64_t Size = CGM.getContext().getTypeSize(Ty); return DBuilder.createBasicType("complex", Size, Encoding); } 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. llvm::dwarf::Tag 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); } auto *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. return DBuilder.createQualifiedType(Tag, FromTy); } llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *Unit) { // The frontend treats 'id' as a typedef to an ObjCObjectType, // whereas 'id' is treated as an ObjCPointerType. For the // debug info, we want to emit 'id' in both cases. if (Ty->isObjCQualifiedIdType()) return getOrCreateType(CGM.getContext().getObjCIdType(), Unit); return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, Ty->getPointeeType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, Ty->getPointeeType(), Unit); } /// \return whether a C++ mangling exists for the type defined by TD. static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) { switch (TheCU->getSourceLanguage()) { case llvm::dwarf::DW_LANG_C_plus_plus: return true; case llvm::dwarf::DW_LANG_ObjC_plus_plus: return isa(TD) || isa(TD); default: return false; } } // Determines if the debug info for this tag declaration needs a type // identifier. The purpose of the unique identifier is to deduplicate type // information for identical types across TUs. Because of the C++ one definition // rule (ODR), it is valid to assume that the type is defined the same way in // every TU and its debug info is equivalent. // // C does not have the ODR, and it is common for codebases to contain multiple // different definitions of a struct with the same name in different TUs. // Therefore, if the type doesn't have a C++ mangling, don't give it an // identifer. Type information in C is smaller and simpler than C++ type // information, so the increase in debug info size is negligible. // // If the type is not externally visible, it should be unique to the current TU, // and should not need an identifier to participate in type deduplication. // However, when emitting CodeView, the format internally uses these // unique type name identifers for references between debug info. For example, // the method of a class in an anonymous namespace uses the identifer to refer // to its parent class. The Microsoft C++ ABI attempts to provide unique names // for such types, so when emitting CodeView, always use identifiers for C++ // types. This may create problems when attempting to emit CodeView when the MS // C++ ABI is not in use. static bool needsTypeIdentifier(const TagDecl *TD, CodeGenModule &CGM, llvm::DICompileUnit *TheCU) { // We only add a type identifier for types with C++ name mangling. if (!hasCXXMangling(TD, TheCU)) return false; // Externally visible types with C++ mangling need a type identifier. if (TD->isExternallyVisible()) return true; // CodeView types with C++ mangling need a type identifier. if (CGM.getCodeGenOpts().EmitCodeView) return true; return false; } // Returns a unique type identifier string if one exists, or an empty string. static SmallString<256> getTypeIdentifier(const TagType *Ty, CodeGenModule &CGM, llvm::DICompileUnit *TheCU) { SmallString<256> Identifier; const TagDecl *TD = Ty->getDecl(); if (!needsTypeIdentifier(TD, CGM, TheCU)) return Identifier; // TODO: This is using the RTTI name. Is there a better way to get // a unique string for a type? llvm::raw_svector_ostream Out(Identifier); CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out); return Identifier; } /// \return the appropriate DWARF tag for a composite type. static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { llvm::dwarf::Tag Tag; if (RD->isStruct() || RD->isInterface()) Tag = llvm::dwarf::DW_TAG_structure_type; else if (RD->isUnion()) Tag = llvm::dwarf::DW_TAG_union_type; else { // FIXME: This could be a struct type giving a default visibility different // than C++ class type, but needs llvm metadata changes first. assert(RD->isClass()); Tag = llvm::dwarf::DW_TAG_class_type; } return Tag; } llvm::DICompositeType * CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DIScope *Ctx) { const RecordDecl *RD = Ty->getDecl(); if (llvm::DIType *T = getTypeOrNull(CGM.getContext().getRecordType(RD))) return cast(T); llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation()); unsigned Line = getLineNumber(RD->getLocation()); StringRef RDName = getClassName(RD); uint64_t Size = 0; uint32_t Align = 0; // Create the type. SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU); llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagFwdDecl, Identifier); if (CGM.getCodeGenOpts().DebugFwdTemplateParams) if (auto *TSpecial = dyn_cast(RD)) DBuilder.replaceArrays(RetTy, llvm::DINodeArray(), CollectCXXTemplateParams(TSpecial, DefUnit)); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast(RetTy))); return RetTy; } llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, llvm::DIFile *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 AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy); uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (Tag == llvm::dwarf::DW_TAG_reference_type || Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); else return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache) { if (Cache) return Cache; Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name, TheCU, TheCU->getFile(), 0); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); Cache = DBuilder.createPointerType(Cache, Size); return Cache; } uint64_t CGDebugInfo::collectDefaultElementTypesForBlockPointer( const BlockPointerType *Ty, llvm::DIFile *Unit, llvm::DIDerivedType *DescTy, unsigned LineNo, SmallVectorImpl &EltTys) { QualType FType; // Advanced by calls to CreateMemberType in increments of FType, then // returned as the overall size of the default elements. uint64_t FieldOffset = 0; // Blocks in OpenCL have unique constraints which make the standard fields // redundant while requiring size and align fields for enqueue_kernel. See // initializeForBlockHeader in CGBlocks.cpp if (CGM.getLangOpts().OpenCL) { FType = CGM.getContext().IntTy; EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "__align", &FieldOffset)); } else { 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(Ty->getPointeeType()); EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); uint64_t FieldSize = CGM.getContext().getTypeSize(Ty); uint32_t FieldAlign = CGM.getContext().getTypeAlign(Ty); EltTys.push_back(DBuilder.createMemberType( Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign, FieldOffset, llvm::DINode::FlagZero, DescTy)); FieldOffset += FieldSize; } return FieldOffset; } llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIFile *Unit) { SmallVector EltTys; QualType FType; uint64_t FieldOffset; llvm::DINodeArray Elements; 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(); llvm::DINode::DIFlags Flags = llvm::DINode::FlagAppleBlock; auto *EltTy = DBuilder.createStructType(Unit, "__block_descriptor", nullptr, 0, FieldOffset, 0, Flags, nullptr, Elements); // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); auto *DescTy = DBuilder.createPointerType(EltTy, Size); FieldOffset = collectDefaultElementTypesForBlockPointer(Ty, Unit, DescTy, 0, EltTys); Elements = DBuilder.getOrCreateArray(EltTys); // The __block_literal_generic structs are marked with a special // DW_AT_APPLE_BLOCK attribute and are an implementation detail only // the debugger needs to know about. To allow type uniquing, emit // them without a name or a location. EltTy = DBuilder.createStructType(Unit, "", nullptr, 0, FieldOffset, 0, Flags, nullptr, Elements); return DBuilder.createPointerType(EltTy, Size); } llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIFile *Unit) { assert(Ty->isTypeAlias()); llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); SmallString<128> NS; llvm::raw_svector_ostream OS(NS); Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false); printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); auto *AliasDecl = cast(Ty->getTemplateName().getAsTemplateDecl()) ->getTemplatedDecl(); SourceLocation Loc = AliasDecl->getLocation(); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(AliasDecl)); } llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile *Unit) { // We don't set size information, but do specify where the typedef was // declared. SourceLocation Loc = Ty->getDecl()->getLocation(); // Typedefs are derived from some other type. return DBuilder.createTypedef( getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit), Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(Ty->getDecl())); } static unsigned getDwarfCC(CallingConv CC) { switch (CC) { case CC_C: // Avoid emitting DW_AT_calling_convention if the C convention was used. return 0; case CC_X86StdCall: return llvm::dwarf::DW_CC_BORLAND_stdcall; case CC_X86FastCall: return llvm::dwarf::DW_CC_BORLAND_msfastcall; case CC_X86ThisCall: return llvm::dwarf::DW_CC_BORLAND_thiscall; case CC_X86VectorCall: return llvm::dwarf::DW_CC_LLVM_vectorcall; case CC_X86Pascal: return llvm::dwarf::DW_CC_BORLAND_pascal; case CC_Win64: return llvm::dwarf::DW_CC_LLVM_Win64; case CC_X86_64SysV: return llvm::dwarf::DW_CC_LLVM_X86_64SysV; case CC_AAPCS: case CC_AArch64VectorCall: return llvm::dwarf::DW_CC_LLVM_AAPCS; case CC_AAPCS_VFP: return llvm::dwarf::DW_CC_LLVM_AAPCS_VFP; case CC_IntelOclBicc: return llvm::dwarf::DW_CC_LLVM_IntelOclBicc; case CC_SpirFunction: return llvm::dwarf::DW_CC_LLVM_SpirFunction; case CC_OpenCLKernel: return llvm::dwarf::DW_CC_LLVM_OpenCLKernel; case CC_Swift: return llvm::dwarf::DW_CC_LLVM_Swift; case CC_PreserveMost: return llvm::dwarf::DW_CC_LLVM_PreserveMost; case CC_PreserveAll: return llvm::dwarf::DW_CC_LLVM_PreserveAll; case CC_X86RegCall: return llvm::dwarf::DW_CC_LLVM_X86RegCall; } return 0; } llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIFile *Unit) { SmallVector EltTys; // Add the result type at least. EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit)); // Set up remainder of arguments if there is a prototype. // otherwise emit it as a variadic function. if (isa(Ty)) EltTys.push_back(DBuilder.createUnspecifiedParameter()); else if (const auto *FPT = dyn_cast(Ty)) { for (const QualType &ParamType : FPT->param_types()) EltTys.push_back(getOrCreateType(ParamType, Unit)); if (FPT->isVariadic()) EltTys.push_back(DBuilder.createUnspecifiedParameter()); } llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(Ty->getCallConv())); } /// Convert an AccessSpecifier into the corresponding DINode flag. /// As an optimization, return 0 if the access specifier equals the /// default for the containing type. static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access, const RecordDecl *RD) { AccessSpecifier Default = clang::AS_none; if (RD && RD->isClass()) Default = clang::AS_private; else if (RD && (RD->isStruct() || RD->isUnion())) Default = clang::AS_public; if (Access == Default) return llvm::DINode::FlagZero; switch (Access) { case clang::AS_private: return llvm::DINode::FlagPrivate; case clang::AS_protected: return llvm::DINode::FlagProtected; case clang::AS_public: return llvm::DINode::FlagPublic; case clang::AS_none: return llvm::DINode::FlagZero; } llvm_unreachable("unexpected access enumerator"); } llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, llvm::DIScope *RecordTy, const RecordDecl *RD) { StringRef Name = BitFieldDecl->getName(); QualType Ty = BitFieldDecl->getType(); SourceLocation Loc = BitFieldDecl->getLocation(); llvm::DIFile *VUnit = getOrCreateFile(Loc); llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); // Get the location for the field. llvm::DIFile *File = getOrCreateFile(Loc); unsigned Line = getLineNumber(Loc); const CGBitFieldInfo &BitFieldInfo = CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl); uint64_t SizeInBits = BitFieldInfo.Size; assert(SizeInBits > 0 && "found named 0-width bitfield"); uint64_t StorageOffsetInBits = CGM.getContext().toBits(BitFieldInfo.StorageOffset); uint64_t Offset = BitFieldInfo.Offset; // The bit offsets for big endian machines are reversed for big // endian target, compensate for that as the DIDerivedType requires // un-reversed offsets. if (CGM.getDataLayout().isBigEndian()) Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset; uint64_t OffsetInBits = StorageOffsetInBits + Offset; llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); return DBuilder.createBitFieldMemberType( RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, Flags, DebugType); } llvm::DIType * CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, llvm::DIScope *scope, const RecordDecl *RD) { 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; auto Align = AlignInBits; if (!type->isIncompleteArrayType()) { TypeInfo TI = CGM.getContext().getTypeInfo(type); SizeInBits = TI.Width; if (!Align) Align = getTypeAlignIfRequired(type, CGM.getContext()); } llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, offsetInBits, flags, debugType); } void CGDebugInfo::CollectRecordLambdaFields( const CXXRecordDecl *CXXDecl, SmallVectorImpl &elements, llvm::DIType *RecordTy) { // 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. const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl); 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 LambdaCapture &C = *I; if (C.capturesVariable()) { SourceLocation Loc = C.getLocation(); assert(!Field->isBitField() && "lambdas don't have bitfield members!"); VarDecl *V = C.getCapturedVar(); StringRef VName = V->getName(); llvm::DIFile *VUnit = getOrCreateFile(Loc); auto Align = getDeclAlignIfRequired(V, CGM.getContext()); llvm::DIType *FieldType = createFieldType( VName, Field->getType(), Loc, Field->getAccess(), layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl); elements.push_back(FieldType); } else if (C.capturesThis()) { // 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. FieldDecl *f = *Field; llvm::DIFile *VUnit = getOrCreateFile(f->getLocation()); QualType type = f->getType(); llvm::DIType *fieldType = createFieldType( "this", type, f->getLocation(), f->getAccess(), layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl); elements.push_back(fieldType); } } } llvm::DIDerivedType * CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, const RecordDecl *RD) { // Create the descriptor for the static variable, with or without // constant initializers. Var = Var->getCanonicalDecl(); llvm::DIFile *VUnit = getOrCreateFile(Var->getLocation()); llvm::DIType *VTy = getOrCreateType(Var->getType(), VUnit); unsigned LineNumber = getLineNumber(Var->getLocation()); StringRef VName = Var->getName(); llvm::Constant *C = nullptr; if (Var->getInit()) { const APValue *Value = Var->evaluateValue(); if (Value) { if (Value->isInt()) C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); if (Value->isFloat()) C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); } } llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD); auto Align = getDeclAlignIfRequired(Var, CGM.getContext()); llvm::DIDerivedType *GV = DBuilder.createStaticMemberType( RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align); StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV); return GV; } void CGDebugInfo::CollectRecordNormalField( const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit, SmallVectorImpl &elements, llvm::DIType *RecordTy, const RecordDecl *RD) { StringRef name = field->getName(); QualType type = field->getType(); // Ignore unnamed fields unless they're anonymous structs/unions. if (name.empty() && !type->isRecordType()) return; llvm::DIType *FieldType; if (field->isBitField()) { FieldType = createBitFieldType(field, RecordTy, RD); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); FieldType = createFieldType(name, type, field->getLocation(), field->getAccess(), OffsetInBits, Align, tunit, RecordTy, RD); } elements.push_back(FieldType); } void CGDebugInfo::CollectRecordNestedType( const TypeDecl *TD, SmallVectorImpl &elements) { QualType Ty = CGM.getContext().getTypeDeclType(TD); // Injected class names are not considered nested records. if (isa(Ty)) return; SourceLocation Loc = TD->getLocation(); llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc)); elements.push_back(nestedType); } void CGDebugInfo::CollectRecordFields( const RecordDecl *record, llvm::DIFile *tunit, SmallVectorImpl &elements, llvm::DICompositeType *RecordTy) { const auto *CXXDecl = dyn_cast(record); if (CXXDecl && CXXDecl->isLambda()) CollectRecordLambdaFields(CXXDecl, elements, RecordTy); else { const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); // Field number for non-static fields. unsigned fieldNo = 0; // Static and non-static members should appear in the same order as // the corresponding declarations in the source program. for (const auto *I : record->decls()) if (const auto *V = dyn_cast(I)) { if (V->hasAttr()) continue; // Skip variable template specializations when emitting CodeView. MSVC // doesn't emit them. if (CGM.getCodeGenOpts().EmitCodeView && isa(V)) continue; // Reuse the existing static member declaration if one exists auto MI = StaticDataMemberCache.find(V->getCanonicalDecl()); if (MI != StaticDataMemberCache.end()) { assert(MI->second && "Static data member declaration should still exist"); elements.push_back(MI->second); } else { auto Field = CreateRecordStaticField(V, RecordTy, record); elements.push_back(Field); } } else if (const auto *field = dyn_cast(I)) { CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit, elements, RecordTy, record); // Bump field number for next field. ++fieldNo; } else if (CGM.getCodeGenOpts().EmitCodeView) { // Debug info for nested types is included in the member list only for // CodeView. if (const auto *nestedType = dyn_cast(I)) if (!nestedType->isImplicit() && nestedType->getDeclContext() == record) CollectRecordNestedType(nestedType, elements); } } } llvm::DISubroutineType * CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *Unit) { const FunctionProtoType *Func = Method->getType()->getAs(); if (Method->isStatic()) return cast_or_null( getOrCreateType(QualType(Func, 0), Unit)); return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit); } llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) { // Add "this" pointer. llvm::DITypeRefArray Args( cast(getOrCreateType(QualType(Func, 0), Unit)) ->getTypeArray()); assert(Args.size() && "Invalid number of arguments!"); SmallVector Elts; // First element is always return type. For 'void' functions it is NULL. Elts.push_back(Args[0]); // "this" pointer is always first argument. const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); if (isa(RD)) { // Create pointer type directly in this case. const PointerType *ThisPtrTy = cast(ThisPtr); QualType PointeeTy = ThisPtrTy->getPointeeType(); unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); uint64_t Size = CGM.getTarget().getPointerWidth(AS); auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit); llvm::DIType *ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); TypeCache[ThisPtr.getAsOpaquePtr()].reset(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()].reset(ThisPtrType); ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); Elts.push_back(ThisPtrType); } // Copy rest of the arguments. for (unsigned i = 1, e = Args.size(); i != e; ++i) Elts.push_back(Args[i]); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) Flags |= llvm::DINode::FlagLValueReference; if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) Flags |= llvm::DINode::FlagRValueReference; return DBuilder.createSubroutineType(EltTypeArray, Flags, getDwarfCC(Func->getCallConv())); } /// isFunctionLocalClass - Return true if CXXRecordDecl is defined /// inside a function. static bool isFunctionLocalClass(const CXXRecordDecl *RD) { if (const auto *NRD = dyn_cast(RD->getDeclContext())) return isFunctionLocalClass(NRD); if (isa(RD->getDeclContext())) return true; return false; } llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { bool IsCtorOrDtor = isa(Method) || isa(Method); StringRef MethodName = getFunctionName(Method); llvm::DISubroutineType *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; // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional // property to use here. It may've been intended to model "is non-external // type" but misses cases of non-function-local but non-external classes such // as those in anonymous namespaces as well as the reverse - external types // that are function local, such as those in (non-local) inline functions. if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) MethodLinkageName = CGM.getMangledName(Method); // Get the location for the method. llvm::DIFile *MethodDefUnit = nullptr; unsigned MethodLine = 0; if (!Method->isImplicit()) { MethodDefUnit = getOrCreateFile(Method->getLocation()); MethodLine = getLineNumber(Method->getLocation()); } // Collect virtual method info. llvm::DIType *ContainingType = nullptr; unsigned VIndex = 0; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; int ThisAdjustment = 0; if (Method->isVirtual()) { if (Method->isPure()) SPFlags |= llvm::DISubprogram::SPFlagPureVirtual; else SPFlags |= llvm::DISubprogram::SPFlagVirtual; if (CGM.getTarget().getCXXABI().isItaniumFamily()) { // 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(Method)) VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method); } else { // Emit MS ABI vftable information. There is only one entry for the // deleting dtor. const auto *DD = dyn_cast(Method); GlobalDecl GD = DD ? GlobalDecl(DD, Dtor_Deleting) : GlobalDecl(Method); MethodVFTableLocation ML = CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD); VIndex = ML.Index; // CodeView only records the vftable offset in the class that introduces // the virtual method. This is possible because, unlike Itanium, the MS // C++ ABI does not include all virtual methods from non-primary bases in // the vtable for the most derived class. For example, if C inherits from // A and B, C's primary vftable will not include B's virtual methods. if (Method->size_overridden_methods() == 0) Flags |= llvm::DINode::FlagIntroducedVirtual; // The 'this' adjustment accounts for both the virtual and non-virtual // portions of the adjustment. Presumably the debugger only uses it when // it knows the dynamic type of an object. ThisAdjustment = CGM.getCXXABI() .getVirtualFunctionPrologueThisAdjustment(GD) .getQuantity(); } ContainingType = RecordTy; } if (Method->isStatic()) Flags |= llvm::DINode::FlagStaticMember; if (Method->isImplicit()) Flags |= llvm::DINode::FlagArtificial; Flags |= getAccessFlag(Method->getAccess(), Method->getParent()); if (const auto *CXXC = dyn_cast(Method)) { if (CXXC->isExplicit()) Flags |= llvm::DINode::FlagExplicit; } else if (const auto *CXXC = dyn_cast(Method)) { if (CXXC->isExplicit()) Flags |= llvm::DINode::FlagExplicit; } if (Method->hasPrototype()) Flags |= llvm::DINode::FlagPrototyped; if (Method->getRefQualifier() == RQ_LValue) Flags |= llvm::DINode::FlagLValueReference; if (Method->getRefQualifier() == RQ_RValue) Flags |= llvm::DINode::FlagRValueReference; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags, TParamsArray.get()); SPCache[Method->getCanonicalDecl()].reset(SP); return SP; } void CGDebugInfo::CollectCXXMemberFunctions( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &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 (const auto *I : RD->decls()) { const auto *Method = dyn_cast(I); // If the member is implicit, don't add it to the member list. This avoids // the member being added to type units by LLVM, while still allowing it // to be emitted into the type declaration/reference inside the compile // unit. // Ditto 'nodebug' methods, for consistency with CodeGenFunction.cpp. // FIXME: Handle Using(Shadow?)Decls here to create // DW_TAG_imported_declarations inside the class for base decls brought into // derived classes. GDB doesn't seem to notice/leverage these when I tried // it, so I'm not rushing to fix this. (GCC seems to produce them, if // referenced) if (!Method || Method->isImplicit() || Method->hasAttr()) continue; if (Method->getType()->getAs()->getContainedAutoType()) continue; // Reuse the existing member function declaration if it exists. // It may be associated with the declaration of the type & should be // reused as we're building the definition. // // This situation can arise in the vtable-based debug info reduction where // implicit members are emitted in a non-vtable TU. auto MI = SPCache.find(Method->getCanonicalDecl()); EltTys.push_back(MI == SPCache.end() ? CreateCXXMemberFunction(Method, Unit, RecordTy) : static_cast(MI->second)); } } void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DIType *RecordTy) { llvm::DenseSet> SeenTypes; CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->bases(), SeenTypes, llvm::DINode::FlagZero); // If we are generating CodeView debug info, we also need to emit records for // indirect virtual base classes. if (CGM.getCodeGenOpts().EmitCodeView) { CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->vbases(), SeenTypes, llvm::DINode::FlagIndirectVirtualBase); } } void CGDebugInfo::CollectCXXBasesAux( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DIType *RecordTy, const CXXRecordDecl::base_class_const_range &Bases, llvm::DenseSet> &SeenTypes, llvm::DINode::DIFlags StartingFlags) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); for (const auto &BI : Bases) { const auto *Base = cast(BI.getType()->getAs()->getDecl()); if (!SeenTypes.insert(Base).second) continue; auto *BaseTy = getOrCreateType(BI.getType(), Unit); llvm::DINode::DIFlags BFlags = StartingFlags; uint64_t BaseOffset; uint32_t VBPtrOffset = 0; if (BI.isVirtual()) { if (CGM.getTarget().getCXXABI().isItaniumFamily()) { // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. BaseOffset = 0 - CGM.getItaniumVTableContext() .getVirtualBaseOffsetOffset(RD, Base) .getQuantity(); } else { // In the MS ABI, store the vbtable offset, which is analogous to the // vbase offset offset in Itanium. BaseOffset = 4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base); VBPtrOffset = CGM.getContext() .getASTRecordLayout(RD) .getVBPtrOffset() .getQuantity(); } BFlags |= llvm::DINode::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. BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD); llvm::DIType *DTy = DBuilder.createInheritance(RecordTy, BaseTy, BaseOffset, VBPtrOffset, BFlags); EltTys.push_back(DTy); } } llvm::DINodeArray CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef TAList, llvm::DIFile *Unit) { SmallVector TemplateParams; for (unsigned i = 0, e = TAList.size(); i != e; ++i) { const TemplateArgument &TA = TAList[i]; StringRef Name; if (TPList) Name = TPList->getParam(i)->getName(); switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); TemplateParams.push_back( DBuilder.createTemplateTypeParameter(TheCU, Name, TTy)); } break; case TemplateArgument::Integral: { llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()))); } break; case TemplateArgument::Declaration: { const ValueDecl *D = TA.getAsDecl(); QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext()); llvm::DIType *TTy = getOrCreateType(T, Unit); llvm::Constant *V = nullptr; const CXXMethodDecl *MD; // Variable pointer template parameters have a value that is the address // of the variable. if (const auto *VD = dyn_cast(D)) V = CGM.GetAddrOfGlobalVar(VD); // Member function pointers have special support for building them, though // this is currently unsupported in LLVM CodeGen. else if ((MD = dyn_cast(D)) && MD->isInstance()) V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); else if (const auto *FD = dyn_cast(D)) V = CGM.GetAddrOfFunction(FD); // Member data pointers have special handling too to compute the fixed // offset within the object. else if (const auto *MPT = dyn_cast(T.getTypePtr())) { // These five lines (& possibly the above member function pointer // handling) might be able to be refactored to use similar code in // CodeGenModule::getMemberPointerConstant uint64_t fieldOffset = CGM.getContext().getFieldOffset(D); CharUnits chars = CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset); V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars); } TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, cast_or_null(V->stripPointerCasts()))); } break; case TemplateArgument::NullPtr: { QualType T = TA.getNullPtrType(); llvm::DIType *TTy = getOrCreateType(T, Unit); llvm::Constant *V = nullptr; // Special case member data pointer null values since they're actually -1 // instead of zero. if (const auto *MPT = dyn_cast(T.getTypePtr())) // But treat member function pointers as simple zero integers because // it's easier than having a special case in LLVM's CodeGen. If LLVM // CodeGen grows handling for values of non-null member function // pointers then perhaps we could remove this special case and rely on // EmitNullMemberPointer for member function pointers. if (MPT->isMemberDataPointer()) V = CGM.getCXXABI().EmitNullMemberPointer(MPT); if (!V) V = llvm::ConstantInt::get(CGM.Int8Ty, 0); TemplateParams.push_back( DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V)); } break; case TemplateArgument::Template: TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( TheCU, Name, nullptr, TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString())); break; case TemplateArgument::Pack: TemplateParams.push_back(DBuilder.createTemplateParameterPack( TheCU, Name, nullptr, CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit))); break; case TemplateArgument::Expression: { const Expr *E = TA.getAsExpr(); QualType T = E->getType(); if (E->isGLValue()) T = CGM.getContext().getLValueReferenceType(T); llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T); assert(V && "Expression in template argument isn't constant"); llvm::DIType *TTy = getOrCreateType(T, Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, V->stripPointerCasts())); } break; // And the following should never occur: case TemplateArgument::TemplateExpansion: case TemplateArgument::Null: llvm_unreachable( "These argument types shouldn't exist in concrete types"); } } return DBuilder.getOrCreateArray(TemplateParams); } llvm::DINodeArray 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()->asArray(), Unit); } return llvm::DINodeArray(); } llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL, - llvm::DIFile *Unit) { - if (auto *TS = dyn_cast(VL)) { - auto T = TS->getSpecializedTemplateOrPartial(); - auto TA = TS->getTemplateArgs().asArray(); - // Collect parameters for a partial specialization - if (T.is()) { - const TemplateParameterList *TList = - T.get() - ->getTemplateParameters(); - return CollectTemplateParams(TList, TA, Unit); - } - - // Collect parameters for an explicit specialization - if (T.is()) { - const TemplateParameterList *TList = T.get() - ->getTemplateParameters(); - return CollectTemplateParams(TList, TA, Unit); - } - } - return llvm::DINodeArray(); + llvm::DIFile *Unit) { + // Always get the full list of parameters, not just the ones from the + // specialization. A partial specialization may have fewer parameters than + // there are arguments. + auto *TS = dyn_cast(VL); + if (!TS) + return llvm::DINodeArray(); + VarTemplateDecl *T = TS->getSpecializedTemplate(); + const TemplateParameterList *TList = T->getTemplateParameters(); + auto TA = TS->getTemplateArgs().asArray(); + return CollectTemplateParams(TList, TA, Unit); } llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { - // Always get the full list of parameters, not just the ones from - // the specialization. + // Always get the full list of parameters, not just the ones from the + // specialization. A partial specialization may have fewer parameters than + // there are arguments. TemplateParameterList *TPList = TSpecial->getSpecializedTemplate()->getTemplateParameters(); const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); return CollectTemplateParams(TPList, TAList.asArray(), Unit); } llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; ASTContext &Context = CGM.getContext(); /* Function type */ llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit); llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy); llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements); unsigned Size = Context.getTypeSize(Context.VoidPtrTy); unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType( SubTy, Size, 0, DWARFAddressSpace, "__vtbl_ptr_type"); VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size); return VTablePtrType; } StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Copy the gdb compatible name on the side and use its reference. return internString("_vptr$", RD->getNameAsString()); } void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DICompositeType *RecordTy) { // If this class is not dynamic then there is not any vtable info to collect. if (!RD->isDynamicClass()) return; // Don't emit any vtable shape or vptr info if this class doesn't have an // extendable vfptr. This can happen if the class doesn't have virtual // methods, or in the MS ABI if those virtual methods only come from virtually // inherited bases. const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (!RL.hasExtendableVFPtr()) return; // CodeView needs to know how large the vtable of every dynamic class is, so // emit a special named pointer type into the element list. The vptr type // points to this type as well. llvm::DIType *VPtrTy = nullptr; bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView && CGM.getTarget().getCXXABI().isMicrosoft(); if (NeedVTableShape) { uint64_t PtrWidth = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); const VTableLayout &VFTLayout = CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero()); unsigned VSlotCount = VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData; unsigned VTableWidth = PtrWidth * VSlotCount; unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); // Create a very wide void* type and insert it directly in the element list. llvm::DIType *VTableType = DBuilder.createPointerType( nullptr, VTableWidth, 0, DWARFAddressSpace, "__vtbl_ptr_type"); EltTys.push_back(VTableType); // The vptr is a pointer to this special vtable type. VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth); } // If there is a primary base then the artificial vptr member lives there. if (RL.getPrimaryBase()) return; if (!VPtrTy) VPtrTy = getOrCreateVTablePtrType(Unit); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType *VPtrMember = DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0, llvm::DINode::FlagArtificial, VPtrTy); EltTys.push_back(VPtrMember); } llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc)); return T; } llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { return getOrCreateStandaloneType(D, Loc); } llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D, SourceLocation Loc) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!D.isNull() && "null type"); llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc)); assert(T && "could not create debug info for type"); RetainedTypes.push_back(D.getAsOpaquePtr()); return T; } void CGDebugInfo::completeType(const EnumDecl *ED) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getEnumType(ED); void *TyPtr = Ty.getAsOpaquePtr(); auto I = TypeCache.find(TyPtr); if (I == TypeCache.end() || !cast(I->second)->isForwardDecl()) return; llvm::DIType *Res = CreateTypeDefinition(Ty->castAs()); assert(!Res->isForwardDecl()); TypeCache[TyPtr].reset(Res); } void CGDebugInfo::completeType(const RecordDecl *RD) { if (DebugKind > codegenoptions::LimitedDebugInfo || !CGM.getLangOpts().CPlusPlus) completeRequiredType(RD); } /// Return true if the class or any of its methods are marked dllimport. static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) { if (RD->hasAttr()) return true; for (const CXXMethodDecl *MD : RD->methods()) if (MD->hasAttr()) return true; return false; } /// Does a type definition exist in an imported clang module? static bool isDefinedInClangModule(const RecordDecl *RD) { // Only definitions that where imported from an AST file come from a module. if (!RD || !RD->isFromASTFile()) return false; // Anonymous entities cannot be addressed. Treat them as not from module. if (!RD->isExternallyVisible() && RD->getName().empty()) return false; if (auto *CXXDecl = dyn_cast(RD)) { if (!CXXDecl->isCompleteDefinition()) return false; // Check wether RD is a template. auto TemplateKind = CXXDecl->getTemplateSpecializationKind(); if (TemplateKind != TSK_Undeclared) { // Unfortunately getOwningModule() isn't accurate enough to find the // owning module of a ClassTemplateSpecializationDecl that is inside a // namespace spanning multiple modules. bool Explicit = false; if (auto *TD = dyn_cast(CXXDecl)) Explicit = TD->isExplicitInstantiationOrSpecialization(); if (!Explicit && CXXDecl->getEnclosingNamespaceContext()) return false; // This is a template, check the origin of the first member. if (CXXDecl->field_begin() == CXXDecl->field_end()) return TemplateKind == TSK_ExplicitInstantiationDeclaration; if (!CXXDecl->field_begin()->isFromASTFile()) return false; } } return true; } void CGDebugInfo::completeClassData(const RecordDecl *RD) { if (auto *CXXRD = dyn_cast(RD)) if (CXXRD->isDynamicClass() && CGM.getVTableLinkage(CXXRD) == llvm::GlobalValue::AvailableExternallyLinkage && !isClassOrMethodDLLImport(CXXRD)) return; if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) return; completeClass(RD); } void CGDebugInfo::completeClass(const RecordDecl *RD) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getRecordType(RD); void *TyPtr = Ty.getAsOpaquePtr(); auto I = TypeCache.find(TyPtr); if (I != TypeCache.end() && !cast(I->second)->isForwardDecl()) return; llvm::DIType *Res = CreateTypeDefinition(Ty->castAs()); assert(!Res->isForwardDecl()); TypeCache[TyPtr].reset(Res); } static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, CXXRecordDecl::method_iterator End) { for (CXXMethodDecl *MD : llvm::make_range(I, End)) if (FunctionDecl *Tmpl = MD->getInstantiatedFromMemberFunction()) if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() && !MD->getMemberSpecializationInfo()->isExplicitSpecialization()) return true; return false; } static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, bool DebugTypeExtRefs, const RecordDecl *RD, const LangOptions &LangOpts) { if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) return true; if (auto *ES = RD->getASTContext().getExternalSource()) if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always) return true; if (DebugKind > codegenoptions::LimitedDebugInfo) return false; if (!LangOpts.CPlusPlus) return false; if (!RD->isCompleteDefinitionRequired()) return true; const auto *CXXDecl = dyn_cast(RD); if (!CXXDecl) return false; // Only emit complete debug info for a dynamic class when its vtable is // emitted. However, Microsoft debuggers don't resolve type information // across DLL boundaries, so skip this optimization if the class or any of its // methods are marked dllimport. This isn't a complete solution, since objects // without any dllimport methods can be used in one DLL and constructed in // another, but it is the current behavior of LimitedDebugInfo. if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass() && !isClassOrMethodDLLImport(CXXDecl)) return true; TemplateSpecializationKind Spec = TSK_Undeclared; if (const auto *SD = dyn_cast(RD)) Spec = SD->getSpecializationKind(); if (Spec == TSK_ExplicitInstantiationDeclaration && hasExplicitMemberDefinition(CXXDecl->method_begin(), CXXDecl->method_end())) return true; return false; } void CGDebugInfo::completeRequiredType(const RecordDecl *RD) { if (shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts())) return; QualType Ty = CGM.getContext().getRecordType(RD); llvm::DIType *T = getTypeOrNull(Ty); if (T && T->isForwardDecl()) completeClassData(RD); } llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); llvm::DIType *T = cast_or_null(getTypeOrNull(QualType(Ty, 0))); if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts())) { if (!T) T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD)); return T; } return CreateTypeDefinition(Ty); } llvm::DIType *CGDebugInfo::CreateTypeDefinition(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::DICompositeType *FwdDecl = getOrCreateLimitedType(Ty, DefUnit); const RecordDecl *D = RD->getDefinition(); if (!D || !D->isCompleteDefinition()) return FwdDecl; if (const auto *CXXDecl = dyn_cast(RD)) CollectContainingType(CXXDecl, FwdDecl); // Push the struct on region stack. LexicalBlockStack.emplace_back(&*FwdDecl); RegionMap[Ty->getDecl()].reset(FwdDecl); // Convert all the elements. SmallVector EltTys; // what about nested types? // 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 auto *CXXDecl = dyn_cast(RD); if (CXXDecl) { CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl); CollectVTableInfo(CXXDecl, DefUnit, EltTys, FwdDecl); } // Collect data fields (including static variables and any initializers). CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); if (CXXDecl) CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); LexicalBlockStack.pop_back(); RegionMap.erase(Ty->getDecl()); llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); DBuilder.replaceArrays(FwdDecl, Elements); if (FwdDecl->isTemporary()) FwdDecl = llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl)); RegionMap[Ty->getDecl()].reset(FwdDecl); return FwdDecl; } llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty, llvm::DIFile *Unit) { // Ignore protocols. return getOrCreateType(Ty->getBaseType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const ObjCTypeParamType *Ty, llvm::DIFile *Unit) { // Ignore protocols. SourceLocation Loc = Ty->getDecl()->getLocation(); // Use Typedefs to represent ObjCTypeParamType. return DBuilder.createTypedef( getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit), Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(Ty->getDecl())); } /// \return true if Getter has the default name for the property PD. static bool hasDefaultGetterName(const ObjCPropertyDecl *PD, const ObjCMethodDecl *Getter) { assert(PD); if (!Getter) return true; assert(Getter->getDeclName().isObjCZeroArgSelector()); return PD->getName() == Getter->getDeclName().getObjCSelector().getNameForSlot(0); } /// \return true if Setter has the default name for the property PD. static bool hasDefaultSetterName(const ObjCPropertyDecl *PD, const ObjCMethodDecl *Setter) { assert(PD); if (!Setter) return true; assert(Setter->getDeclName().isObjCOneArgSelector()); return SelectorTable::constructSetterName(PD->getName()) == Setter->getDeclName().getObjCSelector().getNameForSlot(0); } llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); if (!ID) return nullptr; // Return a forward declaration if this type was imported from a clang module, // and this is not the compile unit with the implementation of the type (which // may contain hidden ivars). if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() && !ID->getImplementation()) return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, ID->getName(), getDeclContextDescriptor(ID), Unit, 0); // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); auto RuntimeLang = static_cast(TheCU->getSourceLanguage()); // 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 || !Def->getImplementation()) { llvm::DIScope *Mod = getParentModuleOrNull(ID); llvm::DIType *FwdDecl = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, ID->getName(), Mod ? Mod : TheCU, DefUnit, Line, RuntimeLang); ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit)); return FwdDecl; } return CreateTypeDefinition(Ty, Unit); } llvm::DIModule * CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, bool CreateSkeletonCU) { // Use the Module pointer as the key into the cache. This is a // nullptr if the "Module" is a PCH, which is safe because we don't // support chained PCH debug info, so there can only be a single PCH. const Module *M = Mod.getModuleOrNull(); auto ModRef = ModuleCache.find(M); if (ModRef != ModuleCache.end()) return cast(ModRef->second); // Macro definitions that were defined with "-D" on the command line. SmallString<128> ConfigMacros; { llvm::raw_svector_ostream OS(ConfigMacros); const auto &PPOpts = CGM.getPreprocessorOpts(); unsigned I = 0; // Translate the macro definitions back into a command line. for (auto &M : PPOpts.Macros) { if (++I > 1) OS << " "; const std::string &Macro = M.first; bool Undef = M.second; OS << "\"-" << (Undef ? 'U' : 'D'); for (char c : Macro) switch (c) { case '\\': OS << "\\\\"; break; case '"': OS << "\\\""; break; default: OS << c; } OS << '\"'; } } bool IsRootModule = M ? !M->Parent : true; if (CreateSkeletonCU && IsRootModule) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. // We use the lower 64 bits for debug info. uint64_t Signature = Mod.getSignature() ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0] : ~1ULL; llvm::DIBuilder DIB(CGM.getModule()); DIB.createCompileUnit(TheCU->getSourceLanguage(), // TODO: Support "Source" from external AST providers? DIB.createFile(Mod.getModuleName(), Mod.getPath()), TheCU->getProducer(), true, StringRef(), 0, Mod.getASTFile(), llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } llvm::DIModule *Parent = IsRootModule ? nullptr : getOrCreateModuleRef( ExternalASTSource::ASTSourceDescriptor(*M->Parent), CreateSkeletonCU); llvm::DIModule *DIMod = DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros, Mod.getPath(), CGM.getHeaderSearchOpts().Sysroot); ModuleCache[M].reset(DIMod); return DIMod; } llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); unsigned RuntimeLang = TheCU->getSourceLanguage(); // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (ID->getImplementation()) Flags |= llvm::DINode::FlagObjcClassComplete; llvm::DIScope *Mod = getParentModuleOrNull(ID); llvm::DICompositeType *RealDecl = DBuilder.createStructType( Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, nullptr, llvm::DINodeArray(), RuntimeLang); QualType QTy(Ty, 0); TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl); // Push the struct on region stack. LexicalBlockStack.emplace_back(RealDecl); RegionMap[Ty->getDecl()].reset(RealDecl); // Convert all the elements. SmallVector EltTys; ObjCInterfaceDecl *SClass = ID->getSuperClass(); if (SClass) { llvm::DIType *SClassTy = getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); if (!SClassTy) return nullptr; llvm::DIType *InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, 0, llvm::DINode::FlagZero); EltTys.push_back(InhTag); } // Create entries for all of the properties. auto AddProperty = [&](const ObjCPropertyDecl *PD) { 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, hasDefaultGetterName(PD, Getter) ? "" : getSelectorName(PD->getGetterName()), hasDefaultSetterName(PD, Setter) ? "" : getSelectorName(PD->getSetterName()), PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit)); EltTys.push_back(PropertyNode); }; { llvm::SmallPtrSet PropertySet; for (const ObjCCategoryDecl *ClassExt : ID->known_extensions()) for (auto *PD : ClassExt->properties()) { PropertySet.insert(PD->getIdentifier()); AddProperty(PD); } for (const auto *PD : ID->properties()) { // Don't emit duplicate metadata for properties that were already in a // class extension. if (!PropertySet.insert(PD->getIdentifier()).second) continue; AddProperty(PD); } } 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) return nullptr; 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; uint32_t 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 = getTypeAlignIfRequired(FType, CGM.getContext()); } 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); } llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Field->getAccessControl() == ObjCIvarDecl::Protected) Flags = llvm::DINode::FlagProtected; else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DINode::FlagPrivate; else if (Field->getAccessControl() == ObjCIvarDecl::Public) Flags = llvm::DINode::FlagPublic; llvm::MDNode *PropertyNode = nullptr; 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, hasDefaultGetterName(PD, Getter) ? "" : getSelectorName(PD->getGetterName()), hasDefaultSetterName(PD, Setter) ? "" : 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::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); DBuilder.replaceArrays(RealDecl, Elements); LexicalBlockStack.pop_back(); return RealDecl; } llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit); int64_t Count = Ty->getNumElements(); llvm::Metadata *Subscript; QualType QTy(Ty, 0); auto SizeExpr = SizeExprCache.find(QTy); if (SizeExpr != SizeExprCache.end()) Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr->getSecond()); else Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1); llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray); } llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) { uint64_t Size; uint32_t Align; // FIXME: make getTypeAlign() aware of VLAs and incomplete array types if (const auto *VAT = dyn_cast(Ty)) { Size = 0; Align = getTypeAlignIfRequired(CGM.getContext().getBaseElementType(VAT), CGM.getContext()); } else if (Ty->isIncompleteArrayType()) { Size = 0; if (Ty->getElementType()->isIncompleteType()) Align = 0; else Align = getTypeAlignIfRequired(Ty->getElementType(), CGM.getContext()); } else if (Ty->isIncompleteType()) { Size = 0; Align = 0; } else { // Size and align of the whole array, not the element type. Size = CGM.getContext().getTypeSize(Ty); Align = getTypeAlignIfRequired(Ty, CGM.getContext()); } // 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 Subscripts; QualType EltTy(Ty, 0); while ((Ty = dyn_cast(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 auto *CAT = dyn_cast(Ty)) Count = CAT->getSize().getZExtValue(); else if (const auto *VAT = dyn_cast(Ty)) { if (Expr *Size = VAT->getSizeExpr()) { Expr::EvalResult Result; if (Size->EvaluateAsInt(Result, CGM.getContext())) Count = Result.Val.getInt().getExtValue(); } } auto SizeNode = SizeExprCache.find(EltTy); if (SizeNode != SizeExprCache.end()) Subscripts.push_back( DBuilder.getOrCreateSubrange(0, SizeNode->getSecond())); else Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); EltTy = Ty->getElementType(); } llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); return DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit), SubscriptArray); } 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) { llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; uint64_t Size = 0; if (!Ty->isIncompleteType()) { Size = CGM.getContext().getTypeSize(Ty); // Set the MS inheritance model. There is no flag for the unspecified model. if (CGM.getTarget().getCXXABI().isMicrosoft()) { switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) { case MSInheritanceAttr::Keyword_single_inheritance: Flags |= llvm::DINode::FlagSingleInheritance; break; case MSInheritanceAttr::Keyword_multiple_inheritance: Flags |= llvm::DINode::FlagMultipleInheritance; break; case MSInheritanceAttr::Keyword_virtual_inheritance: Flags |= llvm::DINode::FlagVirtualInheritance; break; case MSInheritanceAttr::Keyword_unspecified_inheritance: break; } } } llvm::DIType *ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U); if (Ty->isMemberDataPointerType()) return DBuilder.createMemberPointerType( getOrCreateType(Ty->getPointeeType(), U), ClassType, Size, /*Align=*/0, Flags); const FunctionProtoType *FPT = Ty->getPointeeType()->getAs(); return DBuilder.createMemberPointerType( getOrCreateInstanceMethodType( CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()), FPT, U), ClassType, Size, /*Align=*/0, Flags); } llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { auto *FromTy = getOrCreateType(Ty->getValueType(), U); return DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_atomic_type, FromTy); } llvm::DIType *CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getElementType(), U); } llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; uint32_t Align = 0; if (!ED->getTypeForDecl()->isIncompleteType()) { Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); Align = getDeclAlignIfRequired(ED, CGM.getContext()); } SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU); bool isImportedFromModule = DebugTypeExtRefs && ED->isFromASTFile() && ED->getDefinition(); // If this is just a forward declaration, construct an appropriately // marked node and just return it. if (isImportedFromModule || !ED->getDefinition()) { // Note that it is possible for enums to be created as part of // their own declcontext. In this case a FwdDecl will be created // twice. This doesn't cause a problem because both FwdDecls are // entered into the ReplaceMap: finalize() will replace the first // FwdDecl with the second and then replace the second with // complete type. llvm::DIScope *EDContext = getDeclContextDescriptor(ED); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); llvm::TempDIScope TmpContext(DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_enumeration_type, "", TheCU, DefUnit, 0)); unsigned Line = getLineNumber(ED->getLocation()); StringRef EDName = ED->getName(); llvm::DIType *RetTy = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagFwdDecl, Identifier); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast(RetTy))); return RetTy; } return CreateTypeDefinition(Ty); } llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; uint32_t Align = 0; if (!ED->getTypeForDecl()->isIncompleteType()) { Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); Align = getDeclAlignIfRequired(ED, CGM.getContext()); } SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU); // Create elements for each enumerator. SmallVector Enumerators; ED = ED->getDefinition(); bool IsSigned = ED->getIntegerType()->isSignedIntegerType(); for (const auto *Enum : ED->enumerators()) { const auto &InitVal = Enum->getInitVal(); auto Value = IsSigned ? InitVal.getSExtValue() : InitVal.getZExtValue(); Enumerators.push_back( DBuilder.createEnumerator(Enum->getName(), Value, !IsSigned)); } // Return a CompositeType for the enum itself. llvm::DINodeArray EltArray = DBuilder.getOrCreateArray(Enumerators); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); llvm::DIScope *EnumContext = getDeclContextDescriptor(ED); llvm::DIType *ClassTy = getOrCreateType(ED->getIntegerType(), DefUnit); return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, Size, Align, EltArray, ClassTy, Identifier, ED->isScoped()); } llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, unsigned MType, SourceLocation LineLoc, StringRef Name, StringRef Value) { unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); return DBuilder.createMacro(Parent, Line, MType, Name, Value); } llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, SourceLocation LineLoc, SourceLocation FileLoc) { llvm::DIFile *FName = getOrCreateFile(FileLoc); unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); return DBuilder.createTempMacroFile(Parent, Line, FName); } static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { Qualifiers InnerQuals = T.getLocalQualifiers(); // Qualifiers::operator+() doesn't like it if you add a Qualifier // that is already there. Quals += Qualifiers::removeCommonQualifiers(Quals, InnerQuals); Quals += InnerQuals; QualType LastT = T; switch (T->getTypeClass()) { default: return C.getQualifiedType(T.getTypePtr(), Quals); case Type::TemplateSpecialization: { const auto *Spec = cast(T); if (Spec->isTypeAlias()) return C.getQualifiedType(T.getTypePtr(), Quals); T = Spec->desugar(); break; } case Type::TypeOfExpr: T = cast(T)->getUnderlyingExpr()->getType(); break; case Type::TypeOf: T = cast(T)->getUnderlyingType(); break; case Type::Decltype: T = cast(T)->getUnderlyingType(); break; case Type::UnaryTransform: T = cast(T)->getUnderlyingType(); break; case Type::Attributed: T = cast(T)->getEquivalentType(); break; case Type::Elaborated: T = cast(T)->getNamedType(); break; case Type::Paren: T = cast(T)->getInnerType(); break; case Type::SubstTemplateTypeParm: T = cast(T)->getReplacementType(); break; case Type::Auto: case Type::DeducedTemplateSpecialization: { QualType DT = cast(T)->getDeducedType(); assert(!DT.isNull() && "Undeduced types shouldn't reach here."); T = DT; break; } case Type::Adjusted: case Type::Decayed: // Decayed and adjusted types use the adjusted type in LLVM and DWARF. T = cast(T)->getAdjustedType(); break; } assert(T != LastT && "Type unwrapping failed to unwrap!"); (void)LastT; } while (true); } llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) { // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); auto It = TypeCache.find(Ty.getAsOpaquePtr()); if (It != TypeCache.end()) { // Verify that the debug info still exists. if (llvm::Metadata *V = It->second) return cast(V); } return nullptr; } void CGDebugInfo::completeTemplateDefinition( const ClassTemplateSpecializationDecl &SD) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; completeUnusedClass(SD); } void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; completeClassData(&D); // In case this type has no member function definitions being emitted, ensure // it is retained RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr()); } llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (Ty.isNull()) return nullptr; // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); if (auto *T = getTypeOrNull(Ty)) return T; llvm::DIType *Res = CreateTypeNode(Ty, Unit); void *TyPtr = Ty.getAsOpaquePtr(); // And update the type cache. TypeCache[TyPtr].reset(Res); return Res; } llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) { // A forward declaration inside a module header does not belong to the module. if (isa(D) && !cast(D)->getDefinition()) return nullptr; if (DebugTypeExtRefs && D->isFromASTFile()) { // Record a reference to an imported clang module or precompiled header. auto *Reader = CGM.getContext().getExternalSource(); auto Idx = D->getOwningModuleID(); auto Info = Reader->getSourceDescriptor(Idx); if (Info) return getOrCreateModuleRef(*Info, /*SkeletonCU=*/true); } else if (ClangModuleMap) { // We are building a clang module or a precompiled header. // // TODO: When D is a CXXRecordDecl or a C++ Enum, the ODR applies // and it wouldn't be necessary to specify the parent scope // because the type is already unique by definition (it would look // like the output of -fno-standalone-debug). On the other hand, // the parent scope helps a consumer to quickly locate the object // file where the type's definition is located, so it might be // best to make this behavior a command line or debugger tuning // option. if (Module *M = D->getOwningModule()) { // This is a (sub-)module. auto Info = ExternalASTSource::ASTSourceDescriptor(*M); return getOrCreateModuleRef(Info, /*SkeletonCU=*/false); } else { // This the precompiled header being built. return getOrCreateModuleRef(PCHDescriptor, /*SkeletonCU=*/false); } } return nullptr; } 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); // 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(Ty), Unit); case Type::ObjCObjectPointer: return CreateType(cast(Ty), Unit); case Type::ObjCObject: return CreateType(cast(Ty), Unit); case Type::ObjCTypeParam: return CreateType(cast(Ty), Unit); case Type::ObjCInterface: return CreateType(cast(Ty), Unit); case Type::Builtin: return CreateType(cast(Ty)); case Type::Complex: return CreateType(cast(Ty)); case Type::Pointer: return CreateType(cast(Ty), Unit); case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: return CreateType(cast(Ty), Unit); case Type::Record: return CreateType(cast(Ty)); case Type::Enum: return CreateEnumType(cast(Ty)); case Type::FunctionProto: case Type::FunctionNoProto: return CreateType(cast(Ty), Unit); case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: return CreateType(cast(Ty), Unit); case Type::LValueReference: return CreateType(cast(Ty), Unit); case Type::RValueReference: return CreateType(cast(Ty), Unit); case Type::MemberPointer: return CreateType(cast(Ty), Unit); case Type::Atomic: return CreateType(cast(Ty), Unit); case Type::Pipe: return CreateType(cast(Ty), Unit); case Type::TemplateSpecialization: return CreateType(cast(Ty), Unit); case Type::Auto: case Type::Attributed: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: case Type::Elaborated: case Type::Paren: case Type::SubstTemplateTypeParm: case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: case Type::UnaryTransform: case Type::PackExpansion: break; } llvm_unreachable("type should have been unwrapped!"); } llvm::DICompositeType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *Unit) { QualType QTy(Ty, 0); auto *T = cast_or_null(getTypeOrNull(QTy)); // 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 && !T->isForwardDecl()) return T; // Otherwise create the type. llvm::DICompositeType *Res = CreateLimitedType(Ty); // Propagate members from the declaration to the definition // CreateType(const RecordType*) will overwrite this with the members in the // correct order if the full type is needed. DBuilder.replaceArrays(Res, T ? T->getElements() : llvm::DINodeArray()); // And update the type cache. TypeCache[QTy.getAsOpaquePtr()].reset(Res); return Res; } // TODO: Currently used for context chains when limiting debug info. llvm::DICompositeType *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::DIScope *RDContext = getDeclContextDescriptor(RD); // If we ended up creating the type during the context chain construction, // just return that. auto *T = cast_or_null( getTypeOrNull(CGM.getContext().getRecordType(RD))); if (T && (!T->isForwardDecl() || !RD->getDefinition())) return T; // If this is just a forward or incomplete declaration, construct an // appropriately marked node and just return it. const RecordDecl *D = RD->getDefinition(); if (!D || !D->isCompleteDefinition()) return getOrCreateRecordFwdDecl(Ty, RDContext); uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getDeclAlignIfRequired(D, CGM.getContext()); SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU); // Explicitly record the calling convention for C++ records. auto Flags = llvm::DINode::FlagZero; if (auto CXXRD = dyn_cast(RD)) { if (CGM.getCXXABI().getRecordArgABI(CXXRD) == CGCXXABI::RAA_Indirect) Flags |= llvm::DINode::FlagTypePassByReference; else Flags |= llvm::DINode::FlagTypePassByValue; // Record if a C++ record is trivial type. if (CXXRD->isTrivial()) Flags |= llvm::DINode::FlagTrivial; } llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align, Flags, Identifier); // Elements of composite types usually have back to the type, creating // uniquing cycles. Distinct nodes are more efficient. switch (RealDecl->getTag()) { default: llvm_unreachable("invalid composite type tag"); case llvm::dwarf::DW_TAG_array_type: case llvm::dwarf::DW_TAG_enumeration_type: // Array elements and most enumeration elements don't have back references, // so they don't tend to be involved in uniquing cycles and there is some // chance of merging them when linking together two modules. Only make // them distinct if they are ODR-uniqued. if (Identifier.empty()) break; LLVM_FALLTHROUGH; case llvm::dwarf::DW_TAG_structure_type: case llvm::dwarf::DW_TAG_union_type: case llvm::dwarf::DW_TAG_class_type: // Immediately resolve to a distinct node. RealDecl = llvm::MDNode::replaceWithDistinct(llvm::TempDICompositeType(RealDecl)); break; } RegionMap[Ty->getDecl()].reset(RealDecl); TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl); if (const auto *TSpecial = dyn_cast(RD)) DBuilder.replaceArrays(RealDecl, llvm::DINodeArray(), CollectCXXTemplateParams(TSpecial, DefUnit)); return RealDecl; } void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType *RealDecl) { // A class's primary base or the class itself contains the vtable. llvm::DICompositeType *ContainingType = nullptr; 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 = cast( getOrCreateType(QualType(PBase->getTypeForDecl(), 0), getOrCreateFile(RD->getLocation()))); } else if (RD->isDynamicClass()) ContainingType = RealDecl; DBuilder.replaceVTableHolder(RealDecl, ContainingType); } 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); auto FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext()); llvm::DIType *Ty = DBuilder.createMemberType(Unit, Name, Unit, 0, FieldSize, FieldAlign, *Offset, llvm::DINode::FlagZero, FieldTy); *Offset += FieldSize; return Ty; } void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, StringRef &Name, StringRef &LinkageName, llvm::DIScope *&FDContext, llvm::DINodeArray &TParamsArray, llvm::DINode::DIFlags &Flags) { const auto *FD = cast(GD.getDecl()); Name = getFunctionName(FD); // Use mangled name as linkage name for C/C++ functions. if (FD->hasPrototype()) { LinkageName = CGM.getMangledName(GD); Flags |= llvm::DINode::FlagPrototyped; } // No need to replicate the linkage name if it isn't different from the // subprogram name, no need to have it at all unless coverage is enabled or // debug is set to more than just line tables or extra debug info is needed. if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs && !CGM.getCodeGenOpts().EmitGcovNotes && !CGM.getCodeGenOpts().DebugInfoForProfiling && DebugKind <= codegenoptions::DebugLineTablesOnly)) LinkageName = StringRef(); if (DebugKind >= codegenoptions::LimitedDebugInfo) { if (const NamespaceDecl *NSDecl = dyn_cast_or_null(FD->getDeclContext())) FDContext = getOrCreateNamespace(NSDecl); else if (const RecordDecl *RDecl = dyn_cast_or_null(FD->getDeclContext())) { llvm::DIScope *Mod = getParentModuleOrNull(RDecl); FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU); } // Check if it is a noreturn-marked function if (FD->isNoReturn()) Flags |= llvm::DINode::FlagNoReturn; // Collect template parameters. TParamsArray = CollectFunctionTemplateParams(FD, Unit); } } void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, unsigned &LineNo, QualType &T, StringRef &Name, StringRef &LinkageName, llvm::MDTuple *&TemplateParameters, llvm::DIScope *&VDContext) { Unit = getOrCreateFile(VD->getLocation()); LineNo = getLineNumber(VD->getLocation()); setLocation(VD->getLocation()); T = VD->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); } Name = VD->getName(); if (VD->getDeclContext() && !isa(VD->getDeclContext()) && !isa(VD->getDeclContext())) LinkageName = CGM.getMangledName(VD); if (LinkageName == Name) LinkageName = StringRef(); if (isa(VD)) { llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VD, &*Unit); TemplateParameters = parameterNodes.get(); } else { TemplateParameters = nullptr; } // Since we emit declarations (DW_AT_members) for static members, place the // definition of those static members in the namespace they were declared in // in the source code (the lexical decl context). // FIXME: Generalize this for even non-member global variables where the // declaration and definition may have different lexical decl contexts, once // we have support for emitting declarations of (non-member) global variables. const DeclContext *DC = VD->isStaticDataMember() ? VD->getLexicalDeclContext() : VD->getDeclContext(); // When a record type contains an in-line initialization of a static data // member, and the record type is marked as __declspec(dllexport), an implicit // definition of the member will be created in the record context. DWARF // doesn't seem to have a nice way to describe this in a form that consumers // are likely to understand, so fake the "normal" situation of a definition // outside the class by putting it in the global scope. if (DC->isRecord()) DC = CGM.getContext().getTranslationUnitDecl(); llvm::DIScope *Mod = getParentModuleOrNull(VD); VDContext = getContextDescriptor(cast(DC), Mod ? Mod : TheCU); } llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD, bool Stub) { llvm::DINodeArray TParamsArray; StringRef Name, LinkageName; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; SourceLocation Loc = GD.getDecl()->getLocation(); llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *DContext = Unit; unsigned Line = getLineNumber(Loc); collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext, TParamsArray, Flags); auto *FD = dyn_cast(GD.getDecl()); // Build function type. SmallVector ArgTypes; if (FD) for (const ParmVarDecl *Parm : FD->parameters()) ArgTypes.push_back(Parm->getType()); CallingConv CC = FD->getType()->castAs()->getCallConv(); QualType FnType = CGM.getContext().getFunctionType( FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC)); if (!FD->isExternallyVisible()) SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; if (Stub) { Flags |= getCallSiteRelatedAttrs(); SPFlags |= llvm::DISubprogram::SPFlagDefinition; return DBuilder.createFunction( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags, TParamsArray.get(), getFunctionDeclaration(FD)); } llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags, TParamsArray.get(), getFunctionDeclaration(FD)); const FunctionDecl *CanonDecl = FD->getCanonicalDecl(); FwdDeclReplaceMap.emplace_back(std::piecewise_construct, std::make_tuple(CanonDecl), std::make_tuple(SP)); return SP; } llvm::DISubprogram *CGDebugInfo::getFunctionForwardDeclaration(GlobalDecl GD) { return getFunctionFwdDeclOrStub(GD, /* Stub = */ false); } llvm::DISubprogram *CGDebugInfo::getFunctionStub(GlobalDecl GD) { return getFunctionFwdDeclOrStub(GD, /* Stub = */ true); } llvm::DIGlobalVariable * CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) { QualType T; StringRef Name, LinkageName; SourceLocation Loc = VD->getLocation(); llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *DContext = Unit; unsigned Line = getLineNumber(Loc); llvm::MDTuple *TemplateParameters = nullptr; collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, TemplateParameters, DContext); auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); auto *GV = DBuilder.createTempGlobalVariableFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit), !VD->isExternallyVisible(), nullptr, TemplateParameters, Align); FwdDeclReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(cast(VD->getCanonicalDecl())), std::make_tuple(static_cast(GV))); return GV; } llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { // We only need a declaration (not a definition) of the type - so use whatever // we would otherwise do to get a type for a pointee. (forward declarations in // limited debug info, full definitions (if the type definition is available) // in unlimited debug info) if (const auto *TD = dyn_cast(D)) return getOrCreateType(CGM.getContext().getTypeDeclType(TD), getOrCreateFile(TD->getLocation())); auto I = DeclCache.find(D->getCanonicalDecl()); if (I != DeclCache.end()) { auto N = I->second; if (auto *GVE = dyn_cast_or_null(N)) return GVE->getVariable(); return dyn_cast_or_null(N); } // No definition for now. Emit a forward definition that might be // merged with a potential upcoming definition. if (const auto *FD = dyn_cast(D)) return getFunctionForwardDeclaration(FD); else if (const auto *VD = dyn_cast(D)) return getGlobalVariableForwardDeclaration(VD); return nullptr; } llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) return nullptr; const auto *FD = dyn_cast(D); if (!FD) return nullptr; // Setup context. auto *S = getDeclContextDescriptor(D); auto MI = SPCache.find(FD->getCanonicalDecl()); if (MI == SPCache.end()) { if (const auto *MD = dyn_cast(FD->getCanonicalDecl())) { return CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), cast(S)); } } if (MI != SPCache.end()) { auto *SP = dyn_cast_or_null(MI->second); if (SP && !SP->isDefinition()) return SP; } for (auto NextFD : FD->redecls()) { auto MI = SPCache.find(NextFD->getCanonicalDecl()); if (MI != SPCache.end()) { auto *SP = dyn_cast_or_null(MI->second); if (SP && !SP->isDefinition()) return SP; } } return nullptr; } // getOrCreateFunctionType - Construct type. If it is a c++ method, include // implicit parameter "this". llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F) { if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) // Create fake but valid subroutine type. Otherwise -verify would fail, and // subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields. return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None)); if (const auto *Method = dyn_cast(D)) return getOrCreateMethodType(Method, F); const auto *FTy = FnType->getAs(); CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C; if (const auto *OMethod = dyn_cast(D)) { // Add "self" and "_cmd" SmallVector Elts; // First element is always return type. For 'void' functions it is NULL. QualType ResultTy = OMethod->getReturnType(); // Replace the instancetype keyword with the actual type. if (ResultTy == CGM.getContext().getObjCInstanceType()) ResultTy = CGM.getContext().getPointerType( QualType(OMethod->getClassInterface()->getTypeForDecl(), 0)); Elts.push_back(getOrCreateType(ResultTy, F)); // "self" pointer is always first argument. QualType SelfDeclTy; if (auto *SelfDecl = OMethod->getSelfDecl()) SelfDeclTy = SelfDecl->getType(); else if (auto *FPT = dyn_cast(FnType)) if (FPT->getNumParams() > 1) SelfDeclTy = FPT->getParamType(0); if (!SelfDeclTy.isNull()) Elts.push_back( CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F))); // "_cmd" pointer is always second argument. Elts.push_back(DBuilder.createArtificialType( getOrCreateType(CGM.getContext().getObjCSelType(), F))); // Get rest of the arguments. for (const auto *PI : OMethod->parameters()) Elts.push_back(getOrCreateType(PI->getType(), F)); // Variadic methods need a special marker at the end of the type list. if (OMethod->isVariadic()) Elts.push_back(DBuilder.createUnspecifiedParameter()); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(CC)); } // Handle variadic function types; they need an additional // unspecified parameter. if (const auto *FD = dyn_cast(D)) if (FD->isVariadic()) { SmallVector EltTys; EltTys.push_back(getOrCreateType(FD->getReturnType(), F)); if (const auto *FPT = dyn_cast(FnType)) for (QualType ParamType : FPT->param_types()) EltTys.push_back(getOrCreateType(ParamType, F)); EltTys.push_back(DBuilder.createUnspecifiedParameter()); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(CC)); } return cast(getOrCreateType(FnType, F)); } void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, llvm::Function *Fn, bool CurFuncIsThunk, CGBuilderTy &Builder) { StringRef Name; StringRef LinkageName; FnBeginRegionCount.push_back(LexicalBlockStack.size()); const Decl *D = GD.getDecl(); bool HasDecl = (D != nullptr); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *FDContext = Unit; llvm::DINodeArray TParamsArray; if (!HasDecl) { // Use llvm function name. LinkageName = Fn->getName(); } else if (const auto *FD = dyn_cast(D)) { // If there is a subprogram for this function available then use it. auto FI = SPCache.find(FD->getCanonicalDecl()); if (FI != SPCache.end()) { auto *SP = dyn_cast_or_null(FI->second); if (SP && SP->isDefinition()) { LexicalBlockStack.emplace_back(SP); RegionMap[D].reset(SP); return; } } collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext, TParamsArray, Flags); } else if (const auto *OMD = dyn_cast(D)) { Name = getObjCMethodName(OMD); Flags |= llvm::DINode::FlagPrototyped; } else { // Use llvm function name. Name = Fn->getName(); Flags |= llvm::DINode::FlagPrototyped; } if (Name.startswith("\01")) Name = Name.substr(1); if (!HasDecl || D->isImplicit() || D->hasAttr()) { Flags |= llvm::DINode::FlagArtificial; // Artificial functions should not silently reuse CurLoc. CurLoc = SourceLocation(); } if (CurFuncIsThunk) Flags |= llvm::DINode::FlagThunk; if (Fn->hasLocalLinkage()) SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs(); llvm::DISubprogram::DISPFlags SPFlagsForDef = SPFlags | llvm::DISubprogram::SPFlagDefinition; unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); // FIXME: The function declaration we're constructing here is mostly reusing // declarations from CXXMethodDecl and not constructing new ones for arbitrary // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for // all subprograms instead of the actual context since subprogram definitions // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef, SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D)); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating // code for the initialization of globals. Do not record these decls // as they will overwrite the actual VarDecl Decl in the cache. if (HasDecl && isa(D)) DeclCache[D->getCanonicalDecl()].reset(SP); if (CGM.getCodeGenOpts().DwarfVersion >= 5) { // Starting with DWARF V5 method declarations are emitted as children of // the interface type. if (const auto *OMD = dyn_cast_or_null(D)) { const ObjCInterfaceDecl *ID = OMD->getClassInterface(); QualType QTy(ID->getTypeForDecl(), 0); auto It = TypeCache.find(QTy.getAsOpaquePtr()); if (It != TypeCache.end()) { llvm::DICompositeType *InterfaceDecl = cast(It->second); llvm::DISubprogram *FD = DBuilder.createFunction( InterfaceDecl, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, TParamsArray.get()); DBuilder.finalizeSubprogram(FD); ObjCMethodCache[ID].push_back(FD); } } } // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); if (HasDecl) RegionMap[D].reset(SP); } void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType) { StringRef Name; StringRef LinkageName; const Decl *D = GD.getDecl(); if (!D) return; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *FDContext = getDeclContextDescriptor(D); llvm::DINodeArray TParamsArray; if (isa(D)) { // If there is a DISubprogram for this function available then use it. collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext, TParamsArray, Flags); } else if (const auto *OMD = dyn_cast(D)) { Name = getObjCMethodName(OMD); Flags |= llvm::DINode::FlagPrototyped; } else { llvm_unreachable("not a function or ObjC method"); } if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); if (D->isImplicit()) { Flags |= llvm::DINode::FlagArtificial; // Artificial functions without a location should not silently reuse CurLoc. if (Loc.isInvalid()) CurLoc = SourceLocation(); } unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = 0; llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; DBuilder.retainType(DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, TParamsArray.get(), getFunctionDeclaration(D))); } void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) { const auto *FD = cast(GD.getDecl()); // If there is a subprogram for this function available then use it. auto FI = SPCache.find(FD->getCanonicalDecl()); llvm::DISubprogram *SP = nullptr; if (FI != SPCache.end()) SP = dyn_cast_or_null(FI->second); if (!SP || !SP->isDefinition()) SP = getFunctionStub(GD); FnBeginRegionCount.push_back(LexicalBlockStack.size()); LexicalBlockStack.emplace_back(SP); setInlinedAt(Builder.getCurrentDebugLocation()); EmitLocation(Builder, FD->getLocation()); } void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) { assert(CurInlinedAt && "unbalanced inline scope stack"); EmitFunctionEnd(Builder, nullptr); setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt()); } void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { // Update our current location setLocation(Loc); if (CurLoc.isInvalid() || CurLoc.isMacroID() || LexicalBlockStack.empty()) return; llvm::MDNode *Scope = LexicalBlockStack.back(); Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt)); } void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { llvm::MDNode *Back = nullptr; if (!LexicalBlockStack.empty()) Back = LexicalBlockStack.back().get(); LexicalBlockStack.emplace_back(DBuilder.createLexicalBlock( cast(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc), getColumnNumber(CurLoc))); } void CGDebugInfo::AppendAddressSpaceXDeref( unsigned AddressSpace, SmallVectorImpl &Expr) const { Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (!DWARFAddressSpace) return; Expr.push_back(llvm::dwarf::DW_OP_constu); Expr.push_back(DWARFAddressSpace.getValue()); Expr.push_back(llvm::dwarf::DW_OP_swap); Expr.push_back(llvm::dwarf::DW_OP_xderef); } void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { // Set our current location. setLocation(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(), CurInlinedAt)); if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; // Create a new lexical block and push it on the stack. CreateLexicalBlock(Loc); } 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); if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; LexicalBlockStack.pop_back(); } void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) { 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) { // Provide an entry in the line table for the end of the block. EmitLocation(Builder, CurLoc); LexicalBlockStack.pop_back(); } FnBeginRegionCount.pop_back(); if (Fn && Fn->getSubprogram()) DBuilder.finalizeSubprogram(Fn->getSubprogram()); } CGDebugInfo::BlockByRefType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *XOffset) { SmallVector EltTys; QualType FType; uint64_t FieldSize, FieldOffset; uint32_t 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) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back( CreateMemberType(Unit, FType, "__byref_variable_layout", &FieldOffset)); } CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( CGM.getTarget().getPointerAlign(0))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(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 *WrappedTy = getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().toBits(Align); *XOffset = FieldOffset; llvm::DIType *FieldTy = DBuilder.createMemberType( Unit, VD->getName(), Unit, 0, FieldSize, FieldAlign, FieldOffset, llvm::DINode::FlagZero, WrappedTy); EltTys.push_back(FieldTy); FieldOffset += FieldSize; llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); return {DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, llvm::DINode::FlagZero, nullptr, Elements), WrappedTy}; } llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, llvm::Optional ArgNo, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (VD->hasAttr()) return nullptr; bool Unwritten = VD->isImplicit() || (isa(VD->getDeclContext()) && cast(VD->getDeclContext())->isImplicit()); llvm::DIFile *Unit = nullptr; if (!Unwritten) Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; uint64_t XOffset = 0; if (VD->hasAttr()) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType; 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 nullptr; // Get location information. unsigned Line = 0; unsigned Column = 0; if (!Unwritten) { Line = getLineNumber(VD->getLocation()); Column = getColumnNumber(VD->getLocation()); } SmallVector Expr; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (VD->isImplicit()) Flags |= llvm::DINode::FlagArtificial; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); // If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an // object pointer flag. if (const auto *IPD = dyn_cast(VD)) { if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis || IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf) Flags |= llvm::DINode::FlagObjectPointer; } // Note: Older versions of clang used to emit byval references with an extra // DW_OP_deref, because they referenced the IR arg directly instead of // referencing an alloca. Newer versions of LLVM don't treat allocas // differently from other function arguments when used in a dbg.declare. auto *Scope = cast(LexicalBlockStack.back()); StringRef Name = VD->getName(); if (!Name.empty()) { if (VD->hasAttr()) { // Here, we need an offset *into* the alloca. CharUnits offset = CharUnits::fromQuantity(32); Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( CGM.getTarget().getPointerWidth(0)); Expr.push_back(offset.getQuantity()); Expr.push_back(llvm::dwarf::DW_OP_deref); Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); Expr.push_back(offset.getQuantity()); } } else if (const auto *RT = dyn_cast(VD->getType())) { // If VD is an anonymous union then Storage represents value for // all union fields. const RecordDecl *RD = RT->getDecl(); if (RD->isUnion() && RD->isAnonymousStructOrUnion()) { // GDB has trouble finding local variables in anonymous unions, so we emit // artificial local variables for each of the members. // // FIXME: Remove this code as soon as GDB supports this. // The debug info verifier in LLVM operates based on the assumption that a // variable has the same size as its storage and we had to disable the // check for artificial variables. for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); StringRef FieldName = Field->getName(); // Ignore unnamed fields. Do not ignore unnamed records. if (FieldName.empty() && !isa(Field->getType())) continue; // Use VarDecl's Tag, Scope and Line number. auto FieldAlign = getDeclAlignIfRequired(Field, CGM.getContext()); auto *D = DBuilder.createAutoVariable( Scope, FieldName, Unit, Line, FieldTy, CGM.getLangOpts().Optimize, Flags | llvm::DINode::FlagArtificial, FieldAlign); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare( Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); } } } // Create the descriptor for the variable. auto *D = ArgNo ? DBuilder.createParameterVariable( Scope, Name, *ArgNo, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags) : DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags, Align); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); return D; } llvm::DILocalVariable * CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); return EmitDeclare(VD, Storage, llvm::None, Builder); } llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType *Ty) { llvm::DIType *CachedTy = getTypeOrNull(QualTy); if (CachedTy) Ty = CachedTy; return DBuilder.createObjectPointerType(Ty); } void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (Builder.GetInsertBlock() == nullptr) return; if (VD->hasAttr()) return; bool isByRef = VD->hasAttr(); uint64_t XOffset = 0; llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; if (isByRef) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType; 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 (const auto *IPD = dyn_cast(VD)) if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf) Ty = CreateSelfType(VD->getType(), 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 addr; addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus_uconst); addr.push_back(offset.getQuantity()); if (isByRef) { addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0)); addr.push_back(offset.getQuantity()); addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); addr.push_back(offset.getQuantity()); } // Create the descriptor for the variable. auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); auto *D = DBuilder.createAutoVariable( cast(LexicalBlockStack.back()), VD->getName(), Unit, Line, Ty, false, llvm::DINode::FlagZero, Align); // Insert an llvm.dbg.declare into the current block. auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt); auto *Expr = DBuilder.createExpression(addr); if (InsertPoint) DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint); else DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock()); } void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); EmitDeclare(VD, 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; } } // namespace void CGDebugInfo::collectDefaultFieldsForBlockLiteralDeclare( const CGBlockInfo &Block, const ASTContext &Context, SourceLocation Loc, const llvm::StructLayout &BlockLayout, llvm::DIFile *Unit, SmallVectorImpl &Fields) { // Blocks in OpenCL have unique constraints which make the standard fields // redundant while requiring size and align fields for enqueue_kernel. See // initializeForBlockHeader in CGBlocks.cpp if (CGM.getLangOpts().OpenCL) { Fields.push_back(createFieldType("__size", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(0), Unit, Unit)); Fields.push_back(createFieldType("__align", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(1), Unit, Unit)); } else { Fields.push_back(createFieldType("__isa", Context.VoidPtrTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(0), Unit, Unit)); Fields.push_back(createFieldType("__flags", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(1), Unit, Unit)); Fields.push_back( createFieldType("__reserved", Context.IntTy, Loc, AS_public, BlockLayout.getElementOffsetInBits(2), Unit, Unit)); auto *FnTy = Block.getBlockExpr()->getFunctionType(); auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar()); Fields.push_back(createFieldType("__FuncPtr", FnPtrType, Loc, AS_public, BlockLayout.getElementOffsetInBits(3), Unit, Unit)); Fields.push_back(createFieldType( "__descriptor", Context.getPointerType(Block.NeedsCopyDispose ? Context.getBlockDescriptorExtendedType() : Context.getBlockDescriptorType()), Loc, AS_public, BlockLayout.getElementOffsetInBits(4), Unit, Unit)); } } void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, StringRef Name, unsigned ArgNo, llvm::AllocaInst *Alloca, CGBuilderTy &Builder) { assert(DebugKind >= 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. getDeclContextDescriptor(blockDecl); const llvm::StructLayout *blockLayout = CGM.getDataLayout().getStructLayout(block.StructureType); SmallVector fields; collectDefaultFieldsForBlockLiteralDeclare(block, C, loc, *blockLayout, tunit, fields); // We want to sort the captures by offset, not because DWARF // requires this, but because we're paranoid about debuggers. SmallVector chunks; // 'this' capture. if (blockDecl->capturesCXXThis()) { BlockLayoutChunk chunk; chunk.OffsetInBits = blockLayout->getElementOffsetInBits(block.CXXThisIndex); chunk.Capture = nullptr; chunks.push_back(chunk); } // Variable captures. for (const auto &capture : blockDecl->captures()) { 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 (const BlockLayoutChunk &Chunk : chunks) { uint64_t offsetInBits = Chunk.OffsetInBits; const BlockDecl::Capture *capture = Chunk.Capture; // If we have a null capture, this must be the C++ 'this' capture. if (!capture) { QualType type; if (auto *Method = cast_or_null(blockDecl->getNonClosureContext())) type = Method->getThisType(); else if (auto *RDecl = dyn_cast(blockDecl->getParent())) type = QualType(RDecl->getTypeForDecl(), 0); else llvm_unreachable("unexpected block declcontext"); fields.push_back(createFieldType("this", type, loc, AS_public, offsetInBits, tunit, tunit)); continue; } const VarDecl *variable = capture->getVariable(); StringRef name = variable->getName(); llvm::DIType *fieldType; if (capture->isByRef()) { TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy); auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0; // FIXME: This recomputes the layout of the BlockByRefWrapper. uint64_t xoffset; fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset).BlockByRefWrapper; fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width); fieldType = DBuilder.createMemberType(tunit, name, tunit, line, PtrInfo.Width, Align, offsetInBits, llvm::DINode::FlagZero, fieldType); } else { auto Align = getDeclAlignIfRequired(variable, CGM.getContext()); fieldType = createFieldType(name, variable->getType(), loc, AS_public, offsetInBits, Align, tunit, tunit); } fields.push_back(fieldType); } SmallString<36> typeName; llvm::raw_svector_ostream(typeName) << "__block_literal_" << CGM.getUniqueBlockCount(); llvm::DINodeArray fieldsArray = DBuilder.getOrCreateArray(fields); llvm::DIType *type = DBuilder.createStructType(tunit, typeName.str(), tunit, line, CGM.getContext().toBits(block.BlockSize), 0, llvm::DINode::FlagZero, nullptr, fieldsArray); type = DBuilder.createPointerType(type, CGM.PointerWidthInBits); // Get overall information about the block. llvm::DINode::DIFlags flags = llvm::DINode::FlagArtificial; auto *scope = cast(LexicalBlockStack.back()); // Create the descriptor for the parameter. auto *debugVar = DBuilder.createParameterVariable( scope, Name, ArgNo, tunit, line, type, CGM.getLangOpts().Optimize, flags); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(), llvm::DebugLoc::get(line, column, scope, CurInlinedAt), Builder.GetInsertBlock()); } llvm::DIDerivedType * CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { if (!D->isStaticDataMember()) return nullptr; auto MI = StaticDataMemberCache.find(D->getCanonicalDecl()); if (MI != StaticDataMemberCache.end()) { assert(MI->second && "Static data member declaration should still exist"); return MI->second; } // If the member wasn't found in the cache, lazily construct and add it to the // type (used when a limited form of the type is emitted). auto DC = D->getDeclContext(); auto *Ctxt = cast(getDeclContextDescriptor(D)); return CreateRecordStaticField(D, Ctxt, cast(DC)); } llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) { llvm::DIGlobalVariableExpression *GVE = nullptr; for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); StringRef FieldName = Field->getName(); // Ignore unnamed fields, but recurse into anonymous records. if (FieldName.empty()) { if (const auto *RT = dyn_cast(Field->getType())) GVE = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName, Var, DContext); continue; } // Use VarDecl's Tag, Scope and Line number. GVE = DBuilder.createGlobalVariableExpression( DContext, FieldName, LinkageName, Unit, LineNo, FieldTy, Var->hasLocalLinkage()); Var->addDebugInfo(GVE); } return GVE; } void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); if (D->hasAttr()) return; // If we already created a DIGlobalVariable for this declaration, just attach // it to the llvm::GlobalVariable. auto Cached = DeclCache.find(D->getCanonicalDecl()); if (Cached != DeclCache.end()) return Var->addDebugInfo( cast(Cached->second)); // Create global variable debug descriptor. llvm::DIFile *Unit = nullptr; llvm::DIScope *DContext = nullptr; unsigned LineNo; StringRef DeclName, LinkageName; QualType T; llvm::MDTuple *TemplateParameters = nullptr; collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName, TemplateParameters, DContext); // Attempt to store one global variable for the declaration - even if we // emit a lot of fields. llvm::DIGlobalVariableExpression *GVE = nullptr; // If this is an anonymous union then we'll want to emit a global // variable for each member of the anonymous union so that it's possible // to find the name of any field in the union. if (T->isUnionType() && DeclName.empty()) { const RecordDecl *RD = T->castAs()->getDecl(); assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?"); GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext); } else { auto Align = getDeclAlignIfRequired(D, CGM.getContext()); SmallVector Expr; unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(D->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), Var->hasLocalLinkage(), Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, Align); Var->addDebugInfo(GVE); } DeclCache[D->getCanonicalDecl()].reset(GVE); } void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); if (VD->hasAttr()) return; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); // 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 auto *ECD = dyn_cast(VD)) { const auto *ED = cast(ECD->getDeclContext()); assert(isa(ED->getTypeForDecl()) && "Enum without EnumType?"); Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit); } // Do not use global variables for enums. // // FIXME: why not? if (Ty->getTag() == llvm::dwarf::DW_TAG_enumeration_type) return; // Do not emit separate definitions for function local const/statics. if (isa(VD->getDeclContext())) return; VD = cast(VD->getCanonicalDecl()); auto *VarD = cast(VD); if (VarD->isStaticDataMember()) { auto *RD = cast(VarD->getDeclContext()); getDeclContextDescriptor(VarD); // Ensure that the type is retained even though it's otherwise unreferenced. // // FIXME: This is probably unnecessary, since Ty should reference RD // through its scope. RetainedTypes.push_back( CGM.getContext().getRecordType(RD).getAsOpaquePtr()); return; } llvm::DIScope *DContext = getDeclContextDescriptor(VD); auto &GV = DeclCache[VD]; if (GV) return; llvm::DIExpression *InitExpr = nullptr; if (CGM.getContext().getTypeSize(VD->getType()) <= 64) { // FIXME: Add a representation for integer constants wider than 64 bits. if (Init.isInt()) InitExpr = DBuilder.createConstantValueExpression(Init.getInt().getExtValue()); else if (Init.isFloat()) InitExpr = DBuilder.createConstantValueExpression( Init.getFloat().bitcastToAPInt().getZExtValue()); } llvm::MDTuple *TemplateParameters = nullptr; if (isa(VD)) if (VarD) { llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VarD, &*Unit); TemplateParameters = parameterNodes.get(); } GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), TemplateParameters, Align)); } llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); llvm::DIScope *Mod = getParentModuleOrNull(D); return getContextDescriptor(D, Mod ? Mod : TheCU); } void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; const NamespaceDecl *NSDecl = UD.getNominatedNamespace(); if (!NSDecl->isAnonymousNamespace() || CGM.getCodeGenOpts().DebugExplicitImport) { auto Loc = UD.getLocation(); DBuilder.createImportedModule( getCurrentContextDescriptor(cast(UD.getDeclContext())), getOrCreateNamespace(NSDecl), getOrCreateFile(Loc), getLineNumber(Loc)); } } void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; assert(UD.shadow_size() && "We shouldn't be codegening an invalid UsingDecl containing no decls"); // Emitting one decl is sufficient - debuggers can detect that this is an // overloaded name & provide lookup for all the overloads. const UsingShadowDecl &USD = **UD.shadow_begin(); // FIXME: Skip functions with undeduced auto return type for now since we // don't currently have the plumbing for separate declarations & definitions // of free functions and mismatched types (auto in the declaration, concrete // return type in the definition) if (const auto *FD = dyn_cast(USD.getUnderlyingDecl())) if (const auto *AT = FD->getType()->getAs()->getContainedAutoType()) if (AT->getDeducedType().isNull()) return; if (llvm::DINode *Target = getDeclarationOrDefinition(USD.getUnderlyingDecl())) { auto Loc = USD.getLocation(); DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(USD.getDeclContext())), Target, getOrCreateFile(Loc), getLineNumber(Loc)); } } void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) { if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::LLDB) return; if (Module *M = ID.getImportedModule()) { auto Info = ExternalASTSource::ASTSourceDescriptor(*M); auto Loc = ID.getLocation(); DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(ID.getDeclContext())), getOrCreateModuleRef(Info, DebugTypeExtRefs), getOrCreateFile(Loc), getLineNumber(Loc)); } } llvm::DIImportedEntity * CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return nullptr; auto &VH = NamespaceAliasCache[&NA]; if (VH) return cast(VH); llvm::DIImportedEntity *R; auto Loc = NA.getLocation(); if (const auto *Underlying = dyn_cast(NA.getAliasedNamespace())) // This could cache & dedup here rather than relying on metadata deduping. R = DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(NA.getDeclContext())), EmitNamespaceAlias(*Underlying), getOrCreateFile(Loc), getLineNumber(Loc), NA.getName()); else R = DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(NA.getDeclContext())), getOrCreateNamespace(cast(NA.getAliasedNamespace())), getOrCreateFile(Loc), getLineNumber(Loc), NA.getName()); VH.reset(R); return R; } llvm::DINamespace * CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) { // Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued // if necessary, and this way multiple declarations of the same namespace in // different parent modules stay distinct. auto I = NamespaceCache.find(NSDecl); if (I != NamespaceCache.end()) return cast(I->second); llvm::DIScope *Context = getDeclContextDescriptor(NSDecl); // Don't trust the context if it is a DIModule (see comment above). llvm::DINamespace *NS = DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline()); NamespaceCache[NSDecl].reset(NS); return NS; } void CGDebugInfo::setDwoId(uint64_t Signature) { assert(TheCU && "no main compile unit"); TheCU->setDWOId(Signature); } void CGDebugInfo::finalize() { // Creating types might create further types - invalidating the current // element and the size(), so don't cache/reference them. for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) { ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i]; llvm::DIType *Ty = E.Type->getDecl()->getDefinition() ? CreateTypeDefinition(E.Type, E.Unit) : E.Decl; DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } if (CGM.getCodeGenOpts().DwarfVersion >= 5) { // Add methods to interface. for (const auto &P : ObjCMethodCache) { if (P.second.empty()) continue; QualType QTy(P.first->getTypeForDecl(), 0); auto It = TypeCache.find(QTy.getAsOpaquePtr()); assert(It != TypeCache.end()); llvm::DICompositeType *InterfaceDecl = cast(It->second); SmallVector EltTys; auto CurrenetElts = InterfaceDecl->getElements(); EltTys.append(CurrenetElts.begin(), CurrenetElts.end()); for (auto &MD : P.second) EltTys.push_back(MD); llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); DBuilder.replaceArrays(InterfaceDecl, Elements); } } for (const auto &P : ReplaceMap) { assert(P.second); auto *Ty = cast(P.second); assert(Ty->isForwardDecl()); auto It = TypeCache.find(P.first); assert(It != TypeCache.end()); assert(It->second); DBuilder.replaceTemporary(llvm::TempDIType(Ty), cast(It->second)); } for (const auto &P : FwdDeclReplaceMap) { assert(P.second); llvm::TempMDNode FwdDecl(cast(P.second)); llvm::Metadata *Repl; auto It = DeclCache.find(P.first); // If there has been no definition for the declaration, call RAUW // with ourselves, that will destroy the temporary MDNode and // replace it with a standard one, avoiding leaking memory. if (It == DeclCache.end()) Repl = P.second; else Repl = It->second; if (auto *GVE = dyn_cast_or_null(Repl)) Repl = GVE->getVariable(); DBuilder.replaceTemporary(std::move(FwdDecl), cast(Repl)); } // We keep our own list of retained types, because we need to look // up the final type in the type cache. for (auto &RT : RetainedTypes) if (auto MD = TypeCache[RT]) DBuilder.retainType(cast(MD)); DBuilder.finalize(); } void CGDebugInfo::EmitExplicitCastType(QualType Ty) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile())) // Don't ignore in case of explicit cast where it is referenced indirectly. DBuilder.retainType(DieTy); } llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) { if (LexicalBlockStack.empty()) return llvm::DebugLoc(); llvm::MDNode *Scope = LexicalBlockStack.back(); return llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc), Scope); } llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const { // Call site-related attributes are only useful in optimized programs, and // when there's a possibility of debugging backtraces. if (!CGM.getLangOpts().Optimize || DebugKind == codegenoptions::NoDebugInfo || DebugKind == codegenoptions::LocTrackingOnly) return llvm::DINode::FlagZero; // Call site-related attributes are available in DWARF v5. Some debuggers, // while not fully DWARF v5-compliant, may accept these attributes as if they // were part of DWARF v4. bool SupportsDWARFv4Ext = CGM.getCodeGenOpts().DwarfVersion == 4 && CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB; if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5) return llvm::DINode::FlagZero; return llvm::DINode::FlagAllCallsDescribed; } Index: vendor/clang/dist-release_80/lib/Driver/ToolChains/Arch/PPC.cpp =================================================================== --- vendor/clang/dist-release_80/lib/Driver/ToolChains/Arch/PPC.cpp (revision 349778) +++ vendor/clang/dist-release_80/lib/Driver/ToolChains/Arch/PPC.cpp (revision 349779) @@ -1,157 +1,157 @@ //===--- PPC.cpp - PPC Helpers for Tools ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PPC.h" #include "ToolChains/CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; /// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. std::string ppc::getPPCTargetCPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { StringRef CPUName = A->getValue(); if (CPUName == "native") { std::string CPU = llvm::sys::getHostCPUName(); if (!CPU.empty() && CPU != "generic") return CPU; else return ""; } return llvm::StringSwitch(CPUName) .Case("common", "generic") .Case("440", "440") .Case("440fp", "440") .Case("450", "450") .Case("601", "601") .Case("602", "602") .Case("603", "603") .Case("603e", "603e") .Case("603ev", "603ev") .Case("604", "604") .Case("604e", "604e") .Case("620", "620") .Case("630", "pwr3") .Case("G3", "g3") .Case("7400", "7400") .Case("G4", "g4") .Case("7450", "7450") .Case("G4+", "g4+") .Case("750", "750") .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") .Case("a2q", "a2q") .Case("e500mc", "e500mc") .Case("e5500", "e5500") .Case("power3", "pwr3") .Case("power4", "pwr4") .Case("power5", "pwr5") .Case("power5x", "pwr5x") .Case("power6", "pwr6") .Case("power6x", "pwr6x") .Case("power7", "pwr7") .Case("power8", "pwr8") .Case("power9", "pwr9") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") .Case("pwr5", "pwr5") .Case("pwr5x", "pwr5x") .Case("pwr6", "pwr6") .Case("pwr6x", "pwr6x") .Case("pwr7", "pwr7") .Case("pwr8", "pwr8") .Case("pwr9", "pwr9") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") .Case("powerpc64le", "ppc64le") .Default(""); } return ""; } const char *ppc::getPPCAsmModeForCPU(StringRef Name) { return llvm::StringSwitch(Name) .Case("pwr7", "-mpower7") .Case("power7", "-mpower7") .Case("pwr8", "-mpower8") .Case("power8", "-mpower8") .Case("ppc64le", "-mpower8") .Case("pwr9", "-mpower9") .Case("power9", "-mpower9") .Default("-many"); } void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) Features.push_back("-hard-float"); ppc::ReadGOTPtrMode ReadGOT = ppc::getPPCReadGOTPtrMode(D, Triple, Args); if (ReadGOT == ppc::ReadGOTPtrMode::SecurePlt) Features.push_back("+secure-plt"); } ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { if (Args.getLastArg(options::OPT_msecure_plt)) return ppc::ReadGOTPtrMode::SecurePlt; - if (Triple.isOSOpenBSD()) + if (Triple.isOSNetBSD() || Triple.isOSOpenBSD()) return ppc::ReadGOTPtrMode::SecurePlt; else return ppc::ReadGOTPtrMode::Bss; } ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) { ppc::FloatABI ABI = ppc::FloatABI::Invalid; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) ABI = ppc::FloatABI::Soft; else if (A->getOption().matches(options::OPT_mhard_float)) ABI = ppc::FloatABI::Hard; else { ABI = llvm::StringSwitch(A->getValue()) .Case("soft", ppc::FloatABI::Soft) .Case("hard", ppc::FloatABI::Hard) .Default(ppc::FloatABI::Invalid); if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); ABI = ppc::FloatABI::Hard; } } } // If unspecified, choose the default based on the platform. if (ABI == ppc::FloatABI::Invalid) { ABI = ppc::FloatABI::Hard; } return ABI; } bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef(Value)); } Index: vendor/clang/dist-release_80/test/CodeGenCXX/char8_t.cpp =================================================================== --- vendor/clang/dist-release_80/test/CodeGenCXX/char8_t.cpp (revision 349778) +++ vendor/clang/dist-release_80/test/CodeGenCXX/char8_t.cpp (revision 349779) @@ -1,9 +1,11 @@ -// RUN: %clang_cc1 -std=c++17 -emit-llvm -fchar8_t -triple x86_64-linux %s -o - | FileCheck %s -// RUN: %clang_cc1 -std=c++17 -emit-llvm -fchar8_t -triple x86_64-windows %s -o - -verify +// RUN: %clang_cc1 -std=c++17 -emit-llvm -fchar8_t -triple x86_64-linux %s -o - | FileCheck %s --check-prefix=ITANIUM +// RUN: %clang_cc1 -std=c++17 -emit-llvm -fchar8_t -triple x86_64-windows %s -o - | FileCheck %s --check-prefix=MSABI -// CHECK: define void @_Z1fDu( -void f(char8_t c) {} // expected-error {{cannot mangle this built-in char8_t type yet}} +// ITANIUM: define void @_Z1fDu( +// MSABI: define {{.*}}void @"?f@@YAX_Q@Z"( +void f(char8_t c) {} -// CHECK: define weak_odr void @_Z1gIiEvDTplplcvT__ELA4_KDuELDu114EE +// ITANIUM: define weak_odr void @_Z1gIiEvDTplplcvT__ELA4_KDuELDu114EE( +// MSABI: define weak_odr {{.*}}void @"??$g@H@@YAXPEB_Q@Z"( template void g(decltype(T() + u8"foo" + u8'r')) {} template void g(const char8_t*); Index: vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-template-member.cpp =================================================================== --- vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-template-member.cpp (revision 349778) +++ vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-template-member.cpp (revision 349779) @@ -1,130 +1,130 @@ // RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-apple-darwin %s -o - | FileCheck %s // CHECK: @x = global %"struct.outer::inner" zeroinitializer, align 4, !dbg [[X:![0-9]+]] struct MyClass { template int add(int j) { return i + j; } virtual void func() { } }; int add2(int x) { return MyClass().add<2>(x); } inline int add3(int x) { return MyClass().add<3>(x); // even though add<3> is ODR used, don't emit it since we don't codegen it } // The compile unit pulls in the global variables first. // CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:.*]], expr: !DIExpression()) // CHECK: [[XV]] = distinct !DIGlobalVariable(name: "x", // CHECK-SAME: type: ![[OUTER_FOO_INNER_ID:[0-9]+]] // // CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( // CHECK-SAME: name: "var" // CHECK-SAME: templateParams: {{![0-9]+}} // CHECK: !DITemplateTypeParameter(name: "T", type: [[TY:![0-9]+]]) // CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( // CHECK-SAME: name: "var" // CHECK-SAME: templateParams: {{![0-9]+}} -// CHECK: !DITemplateTypeParameter(name: "P", type: {{![0-9]+}}) +// CHECK: !DITemplateTypeParameter(name: "T", type: {{![0-9]+}}) // CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( // CHECK-SAME: name: "varray" // CHECK-SAME: templateParams: {{![0-9]+}} // CHECK: !DITemplateValueParameter(name: "N", type: [[TY]], value: i32 1) // CHECK: ![[OUTER_FOO_INNER_ID:[0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "inner"{{.*}}, identifier: // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo" // CHECK-SAME: elements: [[FOO_MEM:![0-9]*]] // CHECK-SAME: identifier: "_ZTS3foo" // CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]} // CHECK: [[FOO_FUNC]] = !DISubprogram(name: "func", linkageName: "_ZN3foo4funcEN5outerIS_E5innerE", // CHECK-SAME: type: [[FOO_FUNC_TYPE:![0-9]*]] // CHECK: [[FOO_FUNC_TYPE]] = !DISubroutineType(types: [[FOO_FUNC_PARAMS:![0-9]*]]) // CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, ![[OUTER_FOO_INNER_ID]]} // CHECK: [[C:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass" // CHECK-SAME: elements: [[C_MEM:![0-9]*]] // CHECK-SAME: vtableHolder: [[C]] // CHECK-SAME: identifier: "_ZTS7MyClass") // CHECK: [[C_MEM]] = !{[[C_VPTR:![0-9]*]], [[C_FUNC:![0-9]*]]} // CHECK: [[C_VPTR]] = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$MyClass" // CHECK: [[C_FUNC]] = !DISubprogram(name: "func",{{.*}} line: 9, // CHECK: !DISubprogram(name: "add<2>" // CHECK-SAME: scope: [[C]] // // CHECK: [[VIRT_TEMP:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "virt" // CHECK-SAME: elements: [[VIRT_MEM:![0-9]*]] // CHECK-SAME: vtableHolder: [[VIRT_TEMP]] // CHECK-SAME: templateParams: [[VIRT_TEMP_PARAM:![0-9]*]] // CHECK-SAME: identifier: "_ZTS4virtI4elemE" // CHECK: [[ELEM:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "elem" // CHECK-SAME: elements: [[ELEM_MEM:![0-9]*]] // CHECK-SAME: identifier: "_ZTS4elem" // CHECK: [[ELEM_MEM]] = !{[[ELEM_X:![0-9]*]]} // CHECK: [[ELEM_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: [[ELEM]] // CHECK-SAME: baseType: [[VIRT_TEMP:![0-9]+]] // CHECK: [[VIRT_TEMP_PARAM]] = !{[[VIRT_T:![0-9]*]]} // CHECK: [[VIRT_T]] = !DITemplateTypeParameter(name: "T", type: [[ELEM]]) template struct outer { struct inner { int i; }; }; struct foo { void func(outer::inner); }; inline void func() { // require 'foo' to be complete before the emission of 'inner' so that, when // constructing the context chain for 'x' we emit the full definition of // 'foo', which requires the definition of 'inner' again foo f; } outer::inner x; template struct virt { T* values; virtual ~virt(); }; struct elem { static virt x; // ensure that completing 'elem' will require/completing 'virt' }; inline void f1() { elem e; // ensure 'elem' is required to be complete when it is emitted as a template argument for 'virt' }; void f2() { virt d; // emit 'virt' } // Check that the member function template specialization and implicit special // members (the default ctor) refer to their class by scope, even though they // didn't appear in the class's member list (C_MEM). This prevents the functions // from being added to type units, while still appearing in the type // declaration/reference in the compile unit. // CHECK: !DISubprogram(name: "MyClass" // CHECK-SAME: scope: [[C]] template T var = T(); template P var

= P(); template T varray[N]; void f3() { var = 1; var = 1; varray[0] = 1; } Index: vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-var-template-partial.cpp =================================================================== --- vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-var-template-partial.cpp (nonexistent) +++ vendor/clang/dist-release_80/test/CodeGenCXX/debug-info-var-template-partial.cpp (revision 349779) @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - -debug-info-kind=limited | FileCheck %s + +template constexpr bool is_same_v = false; +template constexpr bool is_same_v = true; + +template constexpr bool is_same_v; +static_assert(is_same_v, "should get partial spec"); + +// Note that the template arguments for the instantiated variable use the +// parameter names from the primary template. The partial specialization might +// not have enough parameters. + +// CHECK: distinct !DIGlobalVariable(name: "is_same_v", linkageName: "_ZL9is_same_vIiiE", {{.*}} templateParams: ![[PARAMS:[0-9]+]]) +// CHECK: ![[PARAMS]] = !{![[LHS:[0-9]+]], ![[RHS:[0-9]+]]} +// CHECK: ![[LHS]] = !DITemplateTypeParameter(name: "LHS", type: ![[INT:[0-9]+]]) +// CHECK: ![[INT]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK: ![[RHS]] = !DITemplateTypeParameter(name: "RHS", type: ![[INT]]) Index: vendor/clang/dist-release_80/test/Driver/netbsd.c =================================================================== --- vendor/clang/dist-release_80/test/Driver/netbsd.c (revision 349778) +++ vendor/clang/dist-release_80/test/Driver/netbsd.c (revision 349779) @@ -1,448 +1,453 @@ // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=STATIC %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd \ // RUN: -pie --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=PIE %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd \ // RUN: -static -pie --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=STATIC-PIE %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd \ // RUN: -shared --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=SHARED %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=X86_64 %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd7.0.0 \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=X86_64-7 %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd6.0.0 \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=X86_64-6 %s // RUN: %clang -no-canonical-prefixes -target aarch64-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=AARCH64 %s // RUN: %clang -no-canonical-prefixes -target aarch64-unknown-netbsd7.0.0 \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=AARCH64-7 %s // RUN: %clang -no-canonical-prefixes -target aarch64_be-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=AARCH64_BE %s // RUN: %clang -no-canonical-prefixes -target aarch64_be-unknown-netbsd7.0.0 \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=AARCH64_BE-7 %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARM %s // RUN: %clang -no-canonical-prefixes -target armeb-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARMEB %s // RUN: %clang -no-canonical-prefixes -target armeb-unknown-netbsd-eabi -march=armv7 \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARMV7EB %s // RUN: %clang -no-canonical-prefixes -target armv7eb-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARMV7EB %s // RUN: %clang -r -no-canonical-prefixes -target armeb-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARMEB-R %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARM-APCS %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd-eabihf \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARM-HF %s // RUN: %clang -no-canonical-prefixes -target thumb-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=THUMB %s // RUN: %clang -no-canonical-prefixes -target thumbeb-unknown-netbsd-eabi \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=THUMBEB %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd7.0.0-eabi \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARM-7 %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd6.0.0-eabi \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=ARM-6 %s // RUN: %clang -no-canonical-prefixes -target sparc-unknown-netbsd \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=SPARC %s // RUN: %clang -no-canonical-prefixes -target sparc64-unknown-netbsd \ // RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=SPARC64 %s // RUN: %clang -no-canonical-prefixes -target powerpc-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=POWERPC %s // RUN: %clang -no-canonical-prefixes -target powerpc64-unknown-netbsd \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=POWERPC64 %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-X86_64 %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd7.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-X86_64-7 %s // RUN: %clang -no-canonical-prefixes -target x86_64-unknown-netbsd6.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-X86_64-6 %s // RUN: %clang -no-canonical-prefixes -target aarch64-unknown-netbsd -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-AARCH64 %s // RUN: %clang -no-canonical-prefixes -target aarch64-unknown-netbsd7.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-AARCH64-7 %s // RUN: %clang -no-canonical-prefixes -target aarch64_be-unknown-netbsd -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-AARCH64_BE %s // RUN: %clang -no-canonical-prefixes -target aarch64_be-unknown-netbsd7.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-AARCH64_BE-7 %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd-eabi -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-ARM %s // RUN: %clang -no-canonical-prefixes -target armeb-unknown-netbsd-eabi -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-ARMEB %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd7.0.0-eabi -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-ARM-7 %s // RUN: %clang -no-canonical-prefixes -target arm-unknown-netbsd6.0.0-eabi -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-ARM-6 %s // RUN: %clang -no-canonical-prefixes -target sparc-unknown-netbsd7.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-SPARC-7 %s // RUN: %clang -no-canonical-prefixes -target sparc-unknown-netbsd6.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-SPARC-6 %s // RUN: %clang -no-canonical-prefixes -target sparc64-unknown-netbsd7.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-SPARC64-7 %s // RUN: %clang -no-canonical-prefixes -target sparc64-unknown-netbsd6.0.0 -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-SPARC64-6 %s // RUN: %clang -no-canonical-prefixes -target powerpc-unknown-netbsd -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-POWERPC %s // RUN: %clang -no-canonical-prefixes -target powerpc64-unknown-netbsd -static \ // RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \ // RUN: | FileCheck -check-prefix=S-POWERPC64 %s // RUN: %clang -target x86_64-unknown-netbsd -pthread -dM -E %s \ // RUN: | FileCheck -check-prefix=PTHREAD %s // STATIC: ld{{.*}}" "--eh-frame-hdr" // STATIC-NOT: "-pie" // STATIC-NOT: "-Bshareable" // STATIC: "-dynamic-linker" "/libexec/ld.elf_so" // STATIC-NOT: "-pie" // STATIC-NOT: "-Bshareable" // STATIC: "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // STATIC: "{{.*}}/usr/lib{{/|\\\\}}crti.o" "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" // STATIC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // STATIC-PIE: ld{{.*}}" "--eh-frame-hdr" // STATIC-PIE-NOT: "-dynamic-linker" "/libexec/ld.elf_so" // STATIC-PIE-NOT: "-Bshareable" // STATIC-PIE: "-pie" // STATIC-PIE-NOT: "-dynamic-linker" "/libexec/ld.elf_so" // STATIC-PIE-NOT: "-Bshareable" // STATIC-PIE: "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // STATIC-PIE: "{{.*}}/usr/lib{{/|\\\\}}crti.o" "{{.*}}/usr/lib{{/|\\\\}}crtbeginS.o" // STATIC-PIE: "{{.*}}/usr/lib{{/|\\\\}}crtendS.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // SHARED: ld{{.*}}" "--eh-frame-hdr" // SHARED-NOT: "-pie" // SHARED-NOT: "-dynamic-linker" // SHARED-NOT: "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // SHARED: "{{.*}}/usr/lib{{/|\\\\}}crti.o" "{{.*}}/usr/lib{{/|\\\\}}crtbeginS.o" // SHARED: "{{.*}}/usr/lib{{/|\\\\}}crtendS.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // PIE: ld{{.*}}" "--eh-frame-hdr" // PIE-NOT: "-Bshareable" // PIE "-pie" "-dynamic-linker" "/libexec/ld.elf_so" // PIE-NOT: "-Bshareable" // PIE: "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // PIE: "{{.*}}/usr/lib{{/|\\\\}}crtbeginS.o" // PIE: "{{.*}}/usr/lib{{/|\\\\}}crtendS.o" // PIE: "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd" // X86_64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd7.0.0" // X86_64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd6.0.0" // X86_64-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // AARCH64: clang{{.*}}" "-cc1" "-triple" "aarch64-unknown-netbsd" // AARCH64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64-unknown-netbsd7.0.0" // AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be-unknown-netbsd" // AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be-unknown-netbsd7.0.0" // AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARM: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd-eabi" // ARM: as{{.*}}" "-mcpu=arm926ej-s" "-o" // ARM: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARM: "-m" "armelf_nbsd_eabi" // ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARM: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARMEB: clang{{.*}}" "-cc1" "-triple" "armebv5e-unknown-netbsd-eabi" // ARMEB: as{{.*}}" "-mcpu=arm926ej-s" "-o" // ARMEB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARMEB-NOT: "--be8" // ARMEB: "-m" "armelfb_nbsd_eabi" // ARMEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARMEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARMV7EB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARMV7EB: "--be8" "-m" "armelfb_nbsd_eabi" // ARMEB-R: ld{{.*}}" // ARMEB-R-NOT: "--be8" // ARM-APCS: clang{{.*}}" "-cc1" "-triple" "armv4-unknown-netbsd" // ARM-APCS: as{{.*}}" "-mcpu=strongarm" "-o" // ARM-APCS: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARM-APCS: "-m" "armelf_nbsd" // ARM-APCS: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}oabi{{/|\\\\}}crti.o" // ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARM-HF: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd-eabihf" // ARM-HF: as{{.*}}" "-mcpu=arm926ej-s" "-o" // ARM-HF: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARM-HF: "-m" "armelf_nbsd_eabihf" // ARM-HF: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}eabihf{{/|\\\\}}crti.o" // ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARM-HF: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // THUMB: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd-eabi" // THUMB: as{{.*}}" "-mcpu=arm926ej-s" "-o" // THUMB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // THUMB: "-m" "armelf_nbsd_eabi" // THUMB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // THUMB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // THUMBEB: clang{{.*}}" "-cc1" "-triple" "armebv5e-unknown-netbsd-eabi" // THUMBEB: as{{.*}}" "-mcpu=arm926ej-s" "-o" // THUMBEB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // THUMBEB: "-m" "armelfb_nbsd_eabi" // THUMBEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // THUMBEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd7.0.0-eabi" // ARM-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARM-7: "-m" "armelf_nbsd_eabi" // ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARM-7: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // ARM-6: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd6.0.0-eabi" // ARM-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // ARM-6: "-m" "armelf_nbsd_eabi" // ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // ARM-6: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // SPARC: clang{{.*}}" "-cc1" "-triple" "sparc-unknown-netbsd" // SPARC: as{{.*}}" "-32" "-Av8" "-o" // SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // SPARC: "-m" "elf32_sparc" // SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o" // SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // SPARC64: clang{{.*}}" "-cc1" "-triple" "sparc64-unknown-netbsd" // SPARC64: as{{.*}}" "-64" "-Av9" "-o" // SPARC64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // SPARC64: "-m" "elf64_sparc" // SPARC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc-unknown-netbsd" // POWERPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // POWERPC: "-m" "elf32ppc_nbsd" // POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o" // POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64-unknown-netbsd" // POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so" // POWERPC64: "-m" "elf64ppc" // POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o" // POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-X86_64: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd" // S-X86_64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-X86_64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-X86_64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-X86_64-7: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd7.0.0" // S-X86_64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-X86_64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-X86_64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-X86_64-6: clang{{.*}}" "-cc1" "-triple" "x86_64-unknown-netbsd6.0.0" // S-X86_64-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-X86_64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-X86_64-6: "-lgcc_eh" "-lc" "-lgcc" // S-X86_64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-AARCH64: clang{{.*}}" "-cc1" "-triple" "aarch64-unknown-netbsd" // S-AARCH64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-AARCH64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-AARCH64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-AARCH64-7: clang{{.*}}" "-cc1" "-triple" "aarch64-unknown-netbsd7.0.0" // S-AARCH64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-AARCH64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be-unknown-netbsd" // S-AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be-unknown-netbsd7.0.0" // S-AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-ARM: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd-eabi" // S-ARM: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-ARM: "-m" "armelf_nbsd_eabi" // S-ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-ARM: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-ARMEB: clang{{.*}}" "-cc1" "-triple" "armebv5e-unknown-netbsd-eabi" // S-ARMEB: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-ARMEB: "-m" "armelfb_nbsd_eabi" // S-ARMEB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-ARMEB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd7.0.0-eabi" // S-ARM-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-ARM-7: "-m" "armelf_nbsd_eabi" // S-ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-ARM-6: clang{{.*}}" "-cc1" "-triple" "armv5e-unknown-netbsd6.0.0-eabi" // S-ARM-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-ARM-6: "-m" "armelf_nbsd_eabi" // S-ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o" // S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-ARM-6: "-lgcc_eh" "-lc" "-lgcc" // S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-SPARC-6: clang{{.*}}" "-cc1" "-triple" "sparc-unknown-netbsd6.0.0" // S-SPARC-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-SPARC-6: "-m" "elf32_sparc" // S-SPARC-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o" // S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-SPARC-6: "-lgcc_eh" "-lc" "-lgcc" // S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-SPARC-7: clang{{.*}}" "-cc1" "-triple" "sparc-unknown-netbsd7.0.0" // S-SPARC-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-SPARC-7: "-m" "elf32_sparc" // S-SPARC-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o" // S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-SPARC64-6: clang{{.*}}" "-cc1" "-triple" "sparc64-unknown-netbsd6.0.0" // S-SPARC64-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-SPARC64-6: "-m" "elf64_sparc" // S-SPARC64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-SPARC64-6: "-lgcc_eh" "-lc" "-lgcc" // S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-SPARC64-7: clang{{.*}}" "-cc1" "-triple" "sparc64-unknown-netbsd7.0.0" // S-SPARC64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-SPARC64-7: "-m" "elf64_sparc" // S-SPARC64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc-unknown-netbsd" // S-POWERPC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-POWERPC: "-m" "elf32ppc_nbsd" // S-POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}powerpc{{/|\\\\}}crti.o" // S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-POWERPC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // S-POWERPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64-unknown-netbsd" // S-POWERPC64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic" // S-POWERPC64: "-m" "elf64ppc" // S-POWERPC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" // S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crti.o" // S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc" // S-POWERPC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o" // PTHREAD-NOT: _POSIX_THREADS // PTHREAD: _REENTRANT // PTHREAD-NOT: _POSIX_THREADS + +// Check PowerPC for Secure PLT +// RUN: %clang -target powerpc-unknown-netbsd -### -c %s 2>&1 \ +// RUN: | FileCheck -check-prefix=POWERPC-SECUREPLT %s +// POWERPC-SECUREPLT: "-target-feature" "+secure-plt"