https://github.com/oToToT created https://github.com/llvm/llvm-project/pull/182667
During lambda numbering, ItaniumNumberingContext::getManglingNumber() computes the lambda’s <lambda-sig> by mangling the call operator type. If that type contains decltype(init-capture), mangling re-enters the init-capture VarDecl. For problematic cases, this recurses back into operator() mangling. Make init-capture handling in mangleLocalName() explicit: * If the init-capture belongs to a lambda that has a closure-prefix context, mangle it directly with mangleNestedNameWithClosurePrefix(). * Otherwise keep local-name mangling, but for local lambdas use the parent local container as the function-encoding base to avoid self-recursion. Also publish lambda ContextDecl early in Sema::handleLambdaNumbering() before calling getManglingNumber(Method), via a dedicated CXXRecordDecl::setLambdaContextDecl() helper. This provides the needed context for context-sensitive mangling without publishing provisional numbering state. Add non-local regression tests in mangle-lambdas.cpp for: * variable-template lambda init-capture used in decltype(x) * static inline member lambda init-capture used in decltype(x) This PR * Fixes https://github.com/llvm/llvm-project/issues/63271 * Fixes https://github.com/llvm/llvm-project/issues/86240 * Fixes https://github.com/llvm/llvm-project/issues/139089 >From 95f808bf460eb8f9eebc2e295dae56800a73f2cf Mon Sep 17 00:00:00 2001 From: Tommy Chiang <[email protected]> Date: Fri, 20 Feb 2026 15:50:53 +0800 Subject: [PATCH 1/2] [NFC][ItaniumMangle] Format code and fix `llvm-else-after-return` Run `clang-format -i clang/lib/AST/ItaniumMangle.cpp` and fix the `llvm-else-after-return` clang-tidy warning manually. --- clang/lib/AST/ItaniumMangle.cpp | 717 ++++++++++++++++++-------------- 1 file changed, 416 insertions(+), 301 deletions(-) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 70acc8a78ed52..4618fc58c886a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -68,9 +68,9 @@ static bool isLambda(const NamedDecl *ND) { static const unsigned UnknownArity = ~0U; class ItaniumMangleContextImpl : public ItaniumMangleContext { - typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy; + typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy; llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; - llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier; const DiscriminatorOverrideTy DiscriminatorOverride = nullptr; NamespaceDecl *StdNamespace = nullptr; @@ -162,7 +162,7 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { } if (discriminator == 1) return false; - disc = discriminator-2; + disc = discriminator - 2; return true; } @@ -249,14 +249,10 @@ class CXXNameMangler { FunctionTypeDepthState() = default; /// The number of function types we're inside. - unsigned getDepth() const { - return Bits >> 1; - } + unsigned getDepth() const { return Bits >> 1; } /// True if we're in the return type of the innermost function type. - bool isInResultType() const { - return Bits & InResultTypeMask; - } + bool isInResultType() const { return Bits & InResultTypeMask; } FunctionTypeDepthState push() { FunctionTypeDepthState tmp = *this; @@ -264,13 +260,9 @@ class CXXNameMangler { return tmp; } - void enterResultType() { - Bits |= InResultTypeMask; - } + void enterResultType() { Bits |= InResultTypeMask; } - void leaveResultType() { - Bits &= ~InResultTypeMask; - } + void leaveResultType() { Bits &= ~InResultTypeMask; } void pop(FunctionTypeDepthState saved) { assert(getDepth() == saved.getDepth() + 1); @@ -334,13 +326,9 @@ class CXXNameMangler { } const AbiTagList &getUsedAbiTags() const { return UsedAbiTags; } - void setUsedAbiTags(const AbiTagList &AbiTags) { - UsedAbiTags = AbiTags; - } + void setUsedAbiTags(const AbiTagList &AbiTags) { UsedAbiTags = AbiTags; } - const AbiTagList &getEmittedAbiTags() const { - return EmittedAbiTags; - } + const AbiTagList &getEmittedAbiTags() const { return EmittedAbiTags; } const AbiTagList &getSortedUniqueUsedAbiTags() { llvm::sort(UsedAbiTags); @@ -406,8 +394,7 @@ class CXXNameMangler { : Context(C), Out(Out_), NullOut(NullOut_), Structor(getStructor(D)), AbiTagsRoot(AbiTags) { // These can't be mangled without a ctor type or dtor type. - assert(!D || (!isa<CXXDestructorDecl>(D) && - !isa<CXXConstructorDecl>(D))); + assert(!D || (!isa<CXXDestructorDecl>(D) && !isa<CXXConstructorDecl>(D))); } CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) @@ -434,7 +421,9 @@ class CXXNameMangler { NullOut = true; } - struct WithTemplateDepthOffset { unsigned Offset; }; + struct WithTemplateDepthOffset { + unsigned Offset; + }; CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out, WithTemplateDepthOffset Offset) : CXXNameMangler(C, Out) { @@ -481,7 +470,7 @@ class CXXNameMangler { void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); // Destructive copy substitutions from other mangler. - void extendSubstitutions(CXXNameMangler* Other); + void extendSubstitutions(CXXNameMangler *Other); void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive = false); @@ -513,10 +502,10 @@ class CXXNameMangler { void mangleRegCallName(const IdentifierInfo *II); void mangleDeviceStubName(const IdentifierInfo *II); void mangleOCLDeviceStubName(const IdentifierInfo *II); - void mangleSourceNameWithAbiTags( - const NamedDecl *ND, const AbiTagList *AdditionalAbiTags = nullptr); - void mangleLocalName(GlobalDecl GD, - const AbiTagList *AdditionalAbiTags); + void + mangleSourceNameWithAbiTags(const NamedDecl *ND, + const AbiTagList *AdditionalAbiTags = nullptr); + void mangleLocalName(GlobalDecl GD, const AbiTagList *AdditionalAbiTags); void mangleBlockForPrefix(const BlockDecl *Block); void mangleUnqualifiedBlock(const BlockDecl *Block); void mangleTemplateParamDecl(const NamedDecl *Decl); @@ -528,16 +517,16 @@ class CXXNameMangler { void mangleLambda(const CXXRecordDecl *Lambda); void mangleNestedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, - bool NoFunction=false); + bool NoFunction = false); void mangleNestedName(const TemplateDecl *TD, ArrayRef<TemplateArgument> Args); void mangleNestedNameWithClosurePrefix(GlobalDecl GD, const NamedDecl *PrefixND, const AbiTagList *AdditionalAbiTags); void manglePrefix(NestedNameSpecifier Qualifier); - void manglePrefix(const DeclContext *DC, bool NoFunction=false); + void manglePrefix(const DeclContext *DC, bool NoFunction = false); void manglePrefix(QualType type); - void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false); + void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction = false); void mangleTemplatePrefix(TemplateName Template); const NamedDecl *getClosurePrefix(const Decl *ND); void mangleClosurePrefix(const NamedDecl *ND, bool NoFunction = false); @@ -545,7 +534,8 @@ class CXXNameMangler { StringRef Prefix = ""); void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr); + void mangleQualifiers(Qualifiers Quals, + const DependentAddressSpaceType *DAST = nullptr); void mangleRefQualifier(RefQualifierKind RefQualifier); void mangleObjCMethodName(const ObjCMethodDecl *MD); @@ -556,7 +546,7 @@ class CXXNameMangler { #define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); #include "clang/AST/TypeNodes.inc" - void mangleType(const TagType*); + void mangleType(const TagType *); void mangleType(TemplateName); static StringRef getCallingConvQualifierName(CallingConv CC); void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info); @@ -610,8 +600,7 @@ class CXXNameMangler { void mangleFunctionParam(const ParmVarDecl *parm); - void writeAbiTags(const NamedDecl *ND, - const AbiTagList *AdditionalAbiTags); + void writeAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags); // Returns sorted unique list of ABI tags. AbiTagList makeFunctionReturnTypeTags(const FunctionDecl *FD); @@ -619,7 +608,7 @@ class CXXNameMangler { AbiTagList makeVariableTypeTags(const VarDecl *VD); }; -} +} // namespace NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() { if (!StdNamespace) { @@ -962,8 +951,8 @@ bool CXXNameMangler::isStdNamespace(const DeclContext *DC) { return isStd(cast<NamespaceDecl>(DC)); } -static const GlobalDecl -isTemplate(GlobalDecl GD, const TemplateArgumentList *&TemplateArgs) { +static const GlobalDecl isTemplate(GlobalDecl GD, + const TemplateArgumentList *&TemplateArgs) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); // Check if we have a function template. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { @@ -975,7 +964,7 @@ isTemplate(GlobalDecl GD, const TemplateArgumentList *&TemplateArgs) { // Check if we have a class template. if (const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { TemplateArgs = &Spec->getTemplateArgs(); return GD.getWithDecl(Spec->getSpecializedTemplate()); } @@ -992,7 +981,7 @@ isTemplate(GlobalDecl GD, const TemplateArgumentList *&TemplateArgs) { static TemplateName asTemplateName(GlobalDecl GD) { const TemplateDecl *TD = dyn_cast_or_null<TemplateDecl>(GD.getDecl()); - return TemplateName(const_cast<TemplateDecl*>(TD)); + return TemplateName(const_cast<TemplateDecl *>(TD)); } void CXXNameMangler::mangleName(GlobalDecl GD) { @@ -1040,8 +1029,8 @@ const RecordDecl *CXXNameMangler::GetLocalClassDecl(const Decl *D) { return nullptr; } -void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD, - const AbiTagList *AdditionalAbiTags) { +void CXXNameMangler::mangleNameWithAbiTags( + GlobalDecl GD, const AbiTagList *AdditionalAbiTags) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); // <name> ::= [<module-name>] <nested-name> // ::= [<module-name>] <unscoped-name> @@ -1230,10 +1219,8 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { hexDigit &= 0xF; // Map that over to a lowercase hex digit. - static const char charForHex[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; + static const char charForHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; buffer[stringIndex] = charForHex[hexDigit]; } @@ -1420,32 +1407,32 @@ void CXXNameMangler::mangleUnresolvedName( if (Qualifier) mangleUnresolvedPrefix(Qualifier); switch (name.getNameKind()) { - // <base-unresolved-name> ::= <simple-id> - case DeclarationName::Identifier: - mangleSourceName(name.getAsIdentifierInfo()); - break; - // <base-unresolved-name> ::= dn <destructor-name> - case DeclarationName::CXXDestructorName: - Out << "dn"; - mangleUnresolvedTypeOrSimpleId(name.getCXXNameType()); - break; - // <base-unresolved-name> ::= on <operator-name> - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXLiteralOperatorName: - case DeclarationName::CXXOperatorName: - Out << "on"; - mangleOperatorName(name, knownArity); - break; - case DeclarationName::CXXConstructorName: - llvm_unreachable("Can't mangle a constructor name!"); - case DeclarationName::CXXUsingDirective: - llvm_unreachable("Can't mangle a using directive name!"); - case DeclarationName::CXXDeductionGuideName: - llvm_unreachable("Can't mangle a deduction guide name!"); - case DeclarationName::ObjCMultiArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCZeroArgSelector: - llvm_unreachable("Can't mangle Objective-C selector names here!"); + // <base-unresolved-name> ::= <simple-id> + case DeclarationName::Identifier: + mangleSourceName(name.getAsIdentifierInfo()); + break; + // <base-unresolved-name> ::= dn <destructor-name> + case DeclarationName::CXXDestructorName: + Out << "dn"; + mangleUnresolvedTypeOrSimpleId(name.getCXXNameType()); + break; + // <base-unresolved-name> ::= on <operator-name> + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXOperatorName: + Out << "on"; + mangleOperatorName(name, knownArity); + break; + case DeclarationName::CXXConstructorName: + llvm_unreachable("Can't mangle a constructor name!"); + case DeclarationName::CXXUsingDirective: + llvm_unreachable("Can't mangle a using directive name!"); + case DeclarationName::CXXDeductionGuideName: + llvm_unreachable("Can't mangle a deduction guide name!"); + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCZeroArgSelector: + llvm_unreachable("Can't mangle Objective-C selector names here!"); } // The <simple-id> and on <operator-name> productions end in an optional @@ -1531,9 +1518,9 @@ void CXXNameMangler::mangleUnqualifiedName( if (Context.isInternalLinkageDecl(ND)) Out << 'L'; - bool IsRegCall = FD && - FD->getType()->castAs<FunctionType>()->getCallConv() == - clang::CC_X86RegCall; + bool IsRegCall = + FD && FD->getType()->castAs<FunctionType>()->getCallConv() == + clang::CC_X86RegCall; bool IsDeviceStub = FD && FD->hasAttr<CUDAGlobalAttr>() && GD.getKernelReferenceKind() == KernelReferenceKind::Stub; @@ -1578,14 +1565,15 @@ void CXXNameMangler::mangleUnqualifiedName( // the data members in the union are unnamed), then there is no way for // a program to refer to the anonymous union, and there is therefore no // need to mangle its name. - assert(RD->isAnonymousStructOrUnion() - && "Expected anonymous struct or union!"); + assert(RD->isAnonymousStructOrUnion() && + "Expected anonymous struct or union!"); const FieldDecl *FD = RD->findFirstNamedDataMember(); // It's actually possible for various reasons for us to get here // with an empty anonymous struct / union. Fortunately, it // doesn't really matter what name we generate. - if (!FD) break; + if (!FD) + break; assert(FD->getIdentifier() && "Data member name isn't an identifier!"); mangleSourceName(FD->getIdentifier()); @@ -1778,8 +1766,7 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { Out << II->getLength() << II->getName(); } -void CXXNameMangler::mangleNestedName(GlobalDecl GD, - const DeclContext *DC, +void CXXNameMangler::mangleNestedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, bool NoFunction) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); @@ -1898,10 +1885,10 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD, // -- other default arguments do not affect its encoding. const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD); if (CXXRD && CXXRD->isLambda()) { - if (const ParmVarDecl *Parm - = dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) { - if (const FunctionDecl *Func - = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { + if (const ParmVarDecl *Parm = + dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) { + if (const FunctionDecl *Func = + dyn_cast<FunctionDecl>(Parm->getDeclContext())) { Out << 'd'; unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex(); if (Num > 1) @@ -1913,7 +1900,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD, // Mangle the name relative to the closest enclosing function. // equality ok because RD derived from ND above - if (D == RD) { + if (D == RD) { mangleUnqualifiedName(RD, DC, AdditionalAbiTags); } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { if (const NamedDecl *PrefixND = getClosurePrefix(BD)) @@ -1930,10 +1917,10 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD, } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { // Mangle a block in a default parameter; see above explanation for // lambdas. - if (const ParmVarDecl *Parm - = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) { - if (const FunctionDecl *Func - = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { + if (const ParmVarDecl *Parm = + dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) { + if (const FunctionDecl *Func = + dyn_cast<FunctionDecl>(Parm->getDeclContext())) { Out << 'd'; unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex(); if (Num > 1) @@ -2101,8 +2088,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { if (isCompatibleWith(LangOptions::ClangABI::Ver12) && (isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && !isa<ParmVarDecl>(Context)) { - if (const IdentifierInfo *Name - = cast<NamedDecl>(Context)->getIdentifier()) { + if (const IdentifierInfo *Name = + cast<NamedDecl>(Context)->getIdentifier()) { mangleSourceName(Name); const TemplateArgumentList *TemplateArgs = nullptr; if (GlobalDecl TD = isTemplate(cast<NamedDecl>(Context), TemplateArgs)) @@ -2242,8 +2229,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { addSubstitution(Template); } -void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD, - bool NoFunction) { +void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD, bool NoFunction) { const TemplateDecl *ND = cast<TemplateDecl>(GD.getDecl()); // <template-prefix> ::= <prefix> <template unqualified-name> // ::= <template-param> @@ -2360,8 +2346,8 @@ void CXXNameMangler::mangleType(TemplateName TN) { // template. This will check for the substitution twice, which is // fine, but we have to return early so that we don't try to *add* // the substitution twice. - SubstTemplateTemplateParmStorage *subst - = TN.getAsSubstTemplateTemplateParm(); + SubstTemplateTemplateParmStorage *subst = + TN.getAsSubstTemplateTemplateParm(); mangleType(subst->getReplacement()); return; } @@ -2484,8 +2470,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, break; case Type::UnresolvedUsing: - mangleSourceNameWithAbiTags( - cast<UnresolvedUsingType>(Ty)->getDecl()); + mangleSourceNameWithAbiTags(cast<UnresolvedUsingType>(Ty)->getDecl()); break; case Type::Enum: @@ -2601,113 +2586,199 @@ void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) { } } -void -CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { +void CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, + unsigned Arity) { switch (OO) { // <operator-name> ::= nw # new - case OO_New: Out << "nw"; break; + case OO_New: + Out << "nw"; + break; // ::= na # new[] - case OO_Array_New: Out << "na"; break; + case OO_Array_New: + Out << "na"; + break; // ::= dl # delete - case OO_Delete: Out << "dl"; break; + case OO_Delete: + Out << "dl"; + break; // ::= da # delete[] - case OO_Array_Delete: Out << "da"; break; + case OO_Array_Delete: + Out << "da"; + break; // ::= ps # + (unary) // ::= pl # + (binary or unknown) case OO_Plus: - Out << (Arity == 1? "ps" : "pl"); break; + Out << (Arity == 1 ? "ps" : "pl"); + break; // ::= ng # - (unary) // ::= mi # - (binary or unknown) case OO_Minus: - Out << (Arity == 1? "ng" : "mi"); break; + Out << (Arity == 1 ? "ng" : "mi"); + break; // ::= ad # & (unary) // ::= an # & (binary or unknown) case OO_Amp: - Out << (Arity == 1? "ad" : "an"); break; + Out << (Arity == 1 ? "ad" : "an"); + break; // ::= de # * (unary) // ::= ml # * (binary or unknown) case OO_Star: // Use binary when unknown. - Out << (Arity == 1? "de" : "ml"); break; + Out << (Arity == 1 ? "de" : "ml"); + break; // ::= co # ~ - case OO_Tilde: Out << "co"; break; + case OO_Tilde: + Out << "co"; + break; // ::= dv # / - case OO_Slash: Out << "dv"; break; + case OO_Slash: + Out << "dv"; + break; // ::= rm # % - case OO_Percent: Out << "rm"; break; + case OO_Percent: + Out << "rm"; + break; // ::= or # | - case OO_Pipe: Out << "or"; break; + case OO_Pipe: + Out << "or"; + break; // ::= eo # ^ - case OO_Caret: Out << "eo"; break; + case OO_Caret: + Out << "eo"; + break; // ::= aS # = - case OO_Equal: Out << "aS"; break; + case OO_Equal: + Out << "aS"; + break; // ::= pL # += - case OO_PlusEqual: Out << "pL"; break; + case OO_PlusEqual: + Out << "pL"; + break; // ::= mI # -= - case OO_MinusEqual: Out << "mI"; break; + case OO_MinusEqual: + Out << "mI"; + break; // ::= mL # *= - case OO_StarEqual: Out << "mL"; break; + case OO_StarEqual: + Out << "mL"; + break; // ::= dV # /= - case OO_SlashEqual: Out << "dV"; break; + case OO_SlashEqual: + Out << "dV"; + break; // ::= rM # %= - case OO_PercentEqual: Out << "rM"; break; + case OO_PercentEqual: + Out << "rM"; + break; // ::= aN # &= - case OO_AmpEqual: Out << "aN"; break; + case OO_AmpEqual: + Out << "aN"; + break; // ::= oR # |= - case OO_PipeEqual: Out << "oR"; break; + case OO_PipeEqual: + Out << "oR"; + break; // ::= eO # ^= - case OO_CaretEqual: Out << "eO"; break; + case OO_CaretEqual: + Out << "eO"; + break; // ::= ls # << - case OO_LessLess: Out << "ls"; break; + case OO_LessLess: + Out << "ls"; + break; // ::= rs # >> - case OO_GreaterGreater: Out << "rs"; break; + case OO_GreaterGreater: + Out << "rs"; + break; // ::= lS # <<= - case OO_LessLessEqual: Out << "lS"; break; + case OO_LessLessEqual: + Out << "lS"; + break; // ::= rS # >>= - case OO_GreaterGreaterEqual: Out << "rS"; break; + case OO_GreaterGreaterEqual: + Out << "rS"; + break; // ::= eq # == - case OO_EqualEqual: Out << "eq"; break; + case OO_EqualEqual: + Out << "eq"; + break; // ::= ne # != - case OO_ExclaimEqual: Out << "ne"; break; + case OO_ExclaimEqual: + Out << "ne"; + break; // ::= lt # < - case OO_Less: Out << "lt"; break; + case OO_Less: + Out << "lt"; + break; // ::= gt # > - case OO_Greater: Out << "gt"; break; + case OO_Greater: + Out << "gt"; + break; // ::= le # <= - case OO_LessEqual: Out << "le"; break; + case OO_LessEqual: + Out << "le"; + break; // ::= ge # >= - case OO_GreaterEqual: Out << "ge"; break; + case OO_GreaterEqual: + Out << "ge"; + break; // ::= nt # ! - case OO_Exclaim: Out << "nt"; break; + case OO_Exclaim: + Out << "nt"; + break; // ::= aa # && - case OO_AmpAmp: Out << "aa"; break; + case OO_AmpAmp: + Out << "aa"; + break; // ::= oo # || - case OO_PipePipe: Out << "oo"; break; + case OO_PipePipe: + Out << "oo"; + break; // ::= pp # ++ - case OO_PlusPlus: Out << "pp"; break; + case OO_PlusPlus: + Out << "pp"; + break; // ::= mm # -- - case OO_MinusMinus: Out << "mm"; break; + case OO_MinusMinus: + Out << "mm"; + break; // ::= cm # , - case OO_Comma: Out << "cm"; break; + case OO_Comma: + Out << "cm"; + break; // ::= pm # ->* - case OO_ArrowStar: Out << "pm"; break; + case OO_ArrowStar: + Out << "pm"; + break; // ::= pt # -> - case OO_Arrow: Out << "pt"; break; + case OO_Arrow: + Out << "pt"; + break; // ::= cl # () - case OO_Call: Out << "cl"; break; + case OO_Call: + Out << "cl"; + break; // ::= ix # [] - case OO_Subscript: Out << "ix"; break; + case OO_Subscript: + Out << "ix"; + break; // ::= qu # ? // The conditional operator can't be overloaded, but we still handle it when // mangling expressions. - case OO_Conditional: Out << "qu"; break; + case OO_Conditional: + Out << "qu"; + break; // Proposal on cxx-abi-dev, 2015-10-21. // ::= aw # co_await - case OO_Coawait: Out << "aw"; break; + case OO_Coawait: + Out << "aw"; + break; // Proposed in cxx-abi github issue 43. // ::= ss # <=> - case OO_Spaceship: Out << "ss"; break; + case OO_Spaceship: + Out << "ss"; + break; case OO_None: case NUM_OVERLOADED_OPERATORS: @@ -2715,7 +2786,8 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { } } -void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST) { +void CXXNameMangler::mangleQualifiers(Qualifiers Quals, + const DependentAddressSpaceType *DAST) { // Vendor qualifiers come first and if they are order-insensitive they must // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5. @@ -2745,7 +2817,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp ASString = "AS" + llvm::utostr(TargetAS); } else { switch (AS) { - default: llvm_unreachable("Not a language specific address space"); + default: + llvm_unreachable("Not a language specific address space"); // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" | // "private"| "generic" | "device" | // "host" ] @@ -2987,8 +3060,8 @@ void CXXNameMangler::mangleType(QualType T) { do { // Don't desugar through template specialization types that aren't // type aliases. We need to mangle the template arguments as written. - if (const TemplateSpecializationType *TST - = dyn_cast<TemplateSpecializationType>(T)) + if (const TemplateSpecializationType *TST = + dyn_cast<TemplateSpecializationType>(T)) if (!TST->isTypeAlias()) break; @@ -2996,8 +3069,8 @@ void CXXNameMangler::mangleType(QualType T) { // instantation-dependent qualifiers. See // https://github.com/itanium-cxx-abi/cxx-abi/issues/114. - QualType Desugared - = T.getSingleStepDesugaredType(Context.getASTContext()); + QualType Desugared = + T.getSingleStepDesugaredType(Context.getASTContext()); if (Desugared == T) break; @@ -3009,7 +3082,7 @@ void CXXNameMangler::mangleType(QualType T) { const Type *ty = split.Ty; bool isSubstitutable = - isTypeSubstitutable(quals, ty, Context.getASTContext()); + isTypeSubstitutable(quals, ty, Context.getASTContext()); if (isSubstitutable && mangleSubstitution(T)) return; @@ -3025,7 +3098,7 @@ void CXXNameMangler::mangleType(QualType T) { if (quals || ty->isDependentAddressSpaceType()) { if (const DependentAddressSpaceType *DAST = - dyn_cast<DependentAddressSpaceType>(ty)) { + dyn_cast<DependentAddressSpaceType>(ty)) { SplitQualType splitDAST = DAST->getPointeeType().split(); mangleQualifiers(splitDAST.Quals, DAST); mangleType(QualType(splitDAST.Ty, 0)); @@ -3039,14 +3112,14 @@ void CXXNameMangler::mangleType(QualType T) { } else { switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) -#define NON_CANONICAL_TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ - return; -#define TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - mangleType(static_cast<const CLASS##Type*>(ty)); \ - break; +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + return; +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + mangleType(static_cast<const CLASS##Type *>(ty)); \ + break; #include "clang/AST/TypeNodes.inc" } } @@ -3093,7 +3166,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) // ::= Dh # IEEE 754r half-precision floating point (16 bits) - // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits); + // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point + // type _FloatN (N bits); // ::= Di # char32_t // ::= Ds # char16_t // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) @@ -3370,8 +3444,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { break; #define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" case BuiltinType::Dependent: if (!NullOut) @@ -3386,10 +3459,10 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::ObjCSel: Out << "13objc_selector"; break; -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - case BuiltinType::Id: \ - type_name = "ocl_" #ImgType "_" #Suffix; \ - Out << type_name.size() << type_name; \ +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: \ + type_name = "ocl_" #ImgType "_" #Suffix; \ + Out << type_name.size() << type_name; \ break; #include "clang/Basic/OpenCLImageTypes.def" case BuiltinType::OCLSampler: @@ -3407,15 +3480,15 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::OCLReserveID: Out << "13ocl_reserveid"; break; -#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ - case BuiltinType::Id: \ - type_name = "ocl_" #ExtType; \ - Out << type_name.size() << type_name; \ +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + case BuiltinType::Id: \ + type_name = "ocl_" #ExtType; \ + Out << type_name.size() << type_name; \ break; #include "clang/Basic/OpenCLExtensionTypes.def" - // The SVE types are effectively target-specific. The mangling scheme - // is defined in the appendices to the Procedure Call Standard for the - // Arm Architecture. + // The SVE types are effectively target-specific. The mangling scheme + // is defined in the appendices to the Procedure Call Standard for the + // Arm Architecture. #define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId) \ case BuiltinType::Id: \ if (T->getKind() == BuiltinType::SveBFloat16 && \ @@ -3615,8 +3688,8 @@ void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) { Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE"; } -void -CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) { +void CXXNameMangler::mangleExtParameterInfo( + FunctionProtoType::ExtParameterInfo PI) { // Vendor-specific qualifiers are emitted in reverse alphabetical order. // Note that these are *not* substitution candidates. Demanglers might @@ -3788,10 +3861,10 @@ void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { // <type> ::= <class-enum-type> // <class-enum-type> ::= <name> void CXXNameMangler::mangleType(const EnumType *T) { - mangleType(static_cast<const TagType*>(T)); + mangleType(static_cast<const TagType *>(T)); } void CXXNameMangler::mangleType(const RecordType *T) { - mangleType(static_cast<const TagType*>(T)); + mangleType(static_cast<const TagType *>(T)); } void CXXNameMangler::mangleType(const TagType *T) { mangleName(T->getDecl()->getDefinitionOrSelf()); @@ -3931,22 +4004,47 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { case BuiltinType::ULongLong: EltName = "poly64_t"; break; - default: llvm_unreachable("unexpected Neon polynomial vector element type"); + default: + llvm_unreachable("unexpected Neon polynomial vector element type"); } } else { switch (cast<BuiltinType>(EltType)->getKind()) { - case BuiltinType::SChar: EltName = "int8_t"; break; - case BuiltinType::UChar: EltName = "uint8_t"; break; - case BuiltinType::Short: EltName = "int16_t"; break; - case BuiltinType::UShort: EltName = "uint16_t"; break; - case BuiltinType::Int: EltName = "int32_t"; break; - case BuiltinType::UInt: EltName = "uint32_t"; break; - case BuiltinType::LongLong: EltName = "int64_t"; break; - case BuiltinType::ULongLong: EltName = "uint64_t"; break; - case BuiltinType::Double: EltName = "float64_t"; break; - case BuiltinType::Float: EltName = "float32_t"; break; - case BuiltinType::Half: EltName = "float16_t"; break; - case BuiltinType::BFloat16: EltName = "bfloat16_t"; break; + case BuiltinType::SChar: + EltName = "int8_t"; + break; + case BuiltinType::UChar: + EltName = "uint8_t"; + break; + case BuiltinType::Short: + EltName = "int16_t"; + break; + case BuiltinType::UShort: + EltName = "uint16_t"; + break; + case BuiltinType::Int: + EltName = "int32_t"; + break; + case BuiltinType::UInt: + EltName = "uint32_t"; + break; + case BuiltinType::LongLong: + EltName = "int64_t"; + break; + case BuiltinType::ULongLong: + EltName = "uint64_t"; + break; + case BuiltinType::Double: + EltName = "float64_t"; + break; + case BuiltinType::Float: + EltName = "float32_t"; + break; + case BuiltinType::Half: + EltName = "float16_t"; + break; + case BuiltinType::BFloat16: + EltName = "bfloat16_t"; + break; case BuiltinType::MFloat8: EltName = "mfloat8_t"; break; @@ -3955,8 +4053,8 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { } } const char *BaseName = nullptr; - unsigned BitSize = (T->getNumElements() * - getASTContext().getTypeSize(EltType)); + unsigned BitSize = + (T->getNumElements() * getASTContext().getTypeSize(EltType)); if (BitSize == 64) BaseName = "__simd64_"; else { @@ -4274,21 +4372,23 @@ void CXXNameMangler::mangleType(const VectorType *T) { llvm::Triple Target = getASTContext().getTargetInfo().getTriple(); llvm::Triple::ArchType Arch = getASTContext().getTargetInfo().getTriple().getArch(); - if ((Arch == llvm::Triple::aarch64 || - Arch == llvm::Triple::aarch64_be) && !Target.isOSDarwin()) + if ((Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) && + !Target.isOSDarwin()) mangleAArch64NeonVectorType(T); else mangleNeonVectorType(T); return; - } else if (T->getVectorKind() == VectorKind::SveFixedLengthData || - T->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + } + if (T->getVectorKind() == VectorKind::SveFixedLengthData || + T->getVectorKind() == VectorKind::SveFixedLengthPredicate) { mangleAArch64FixedSveVectorType(T); return; - } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData || - T->getVectorKind() == VectorKind::RVVFixedLengthMask || - T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 || - T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || - T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) { + } + if (T->getVectorKind() == VectorKind::RVVFixedLengthData || + T->getVectorKind() == VectorKind::RVVFixedLengthMask || + T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 || + T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || + T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) { mangleRISCVFixedRVVVectorType(T); return; } @@ -4313,11 +4413,13 @@ void CXXNameMangler::mangleType(const DependentVectorType *T) { else mangleNeonVectorType(T); return; - } else if (T->getVectorKind() == VectorKind::SveFixedLengthData || - T->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + } + if (T->getVectorKind() == VectorKind::SveFixedLengthData || + T->getVectorKind() == VectorKind::SveFixedLengthPredicate) { mangleAArch64FixedSveVectorType(T); return; - } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData) { + } + if (T->getVectorKind() == VectorKind::RVVFixedLengthData) { mangleRISCVFixedRVVVectorType(T); return; } @@ -4334,7 +4436,7 @@ void CXXNameMangler::mangleType(const DependentVectorType *T) { } void CXXNameMangler::mangleType(const ExtVectorType *T) { - mangleType(static_cast<const VectorType*>(T)); + mangleType(static_cast<const VectorType *>(T)); } void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { Out << "Dv"; @@ -4510,12 +4612,9 @@ void CXXNameMangler::mangleType(const DecltypeType *T) { // class member accesses. Note that we do not ignore parentheses; // parentheses change the semantics of decltype for these // expressions (and cause the mangler to use the other form). - if (isa<DeclRefExpr>(E) || - isa<MemberExpr>(E) || - isa<UnresolvedLookupExpr>(E) || - isa<DependentScopeDeclRefExpr>(E) || - isa<CXXDependentScopeMemberExpr>(E) || - isa<UnresolvedMemberExpr>(E)) + if (isa<DeclRefExpr>(E) || isa<MemberExpr>(E) || + isa<UnresolvedLookupExpr>(E) || isa<DependentScopeDeclRefExpr>(E) || + isa<CXXDependentScopeMemberExpr>(E) || isa<UnresolvedMemberExpr>(E)) Out << "Dt"; else Out << "DT"; @@ -4741,28 +4840,31 @@ static bool isParenthesizedADLCallee(const CallExpr *call) { // Must be parenthesized. IgnoreParens() skips __extension__ nodes, // too, but for those to appear in the callee, it would have to be // parenthesized. - if (callee == fn) return false; + if (callee == fn) + return false; // Must be an unresolved lookup. const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn); - if (!lookup) return false; + if (!lookup) + return false; assert(!lookup->requiresADL()); // Must be an unqualified lookup. - if (lookup->getQualifier()) return false; + if (lookup->getQualifier()) + return false; // Must not have found a class member. Note that if one is a class // member, they're all class members. - if (lookup->getNumDecls() > 0 && - (*lookup->decls_begin())->isCXXClassMember()) + if (lookup->getNumDecls() > 0 && (*lookup->decls_begin())->isCXXClassMember()) return false; // Otherwise, ADL would have been triggered. return true; } -void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef CastEncoding) { +void CXXNameMangler::mangleCastExpression(const Expr *E, + StringRef CastEncoding) { const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); Out << CastEncoding; mangleType(ECE->getType()); @@ -4783,15 +4885,14 @@ void CXXNameMangler::mangleRequirement(SourceLocation RequiresExprLoc, // TODO: We can't mangle the result of a failed substitution. It's not clear // whether we should be mangling the original form prior to any substitution // instead. See https://lists.isocpp.org/core/2023/04/14118.php - auto HandleSubstitutionFailure = - [&](SourceLocation Loc) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, "cannot mangle this requires-expression " - "containing a substitution failure"); - Diags.Report(Loc, DiagID); - Out << 'F'; - }; + auto HandleSubstitutionFailure = [&](SourceLocation Loc) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this requires-expression " + "containing a substitution failure"); + Diags.Report(Loc, DiagID); + Out << 'F'; + }; switch (Req->getKind()) { case Requirement::RK_Type: { @@ -4848,31 +4949,46 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, bool AsTemplateArg) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> - // ::= <trinary operator-name> <expression> <expression> <expression> - // ::= cv <type> expression # conversion with one argument - // ::= cv <type> _ <expression>* E # conversion with a different number of arguments - // ::= dc <type> <expression> # dynamic_cast<type> (expression) - // ::= sc <type> <expression> # static_cast<type> (expression) - // ::= cc <type> <expression> # const_cast<type> (expression) - // ::= rc <type> <expression> # reinterpret_cast<type> (expression) + // ::= <trinary operator-name> <expression> <expression> + // <expression> + // ::= cv <type> expression # conversion with one + // argument + // ::= cv <type> _ <expression>* E # conversion with a different + // number of arguments + // ::= dc <type> <expression> # dynamic_cast<type> + // (expression) + // ::= sc <type> <expression> # static_cast<type> + // (expression) + // ::= cc <type> <expression> # const_cast<type> + // (expression) + // ::= rc <type> <expression> # reinterpret_cast<type> + // (expression) // ::= st <type> # sizeof (a type) // ::= at <type> # alignof (a type) // ::= <template-param> // ::= <function-param> - // ::= fpT # 'this' expression (part of <function-param>) - // ::= sr <type> <unqualified-name> # dependent name - // ::= sr <type> <unqualified-name> <template-args> # dependent template-id - // ::= ds <expression> <expression> # expr.*expr - // ::= sZ <template-param> # size of a parameter pack + // ::= fpT # 'this' expression (part + // of <function-param>) + // ::= sr <type> <unqualified-name> # dependent + // name + // ::= sr <type> <unqualified-name> <template-args> # dependent + // template-id + // ::= ds <expression> <expression> # + // expr.*expr + // ::= sZ <template-param> # size of a + // parameter pack // ::= sZ <function-param> # size of a function parameter pack - // ::= u <source-name> <template-arg>* E # vendor extended expression + // ::= u <source-name> <template-arg>* E # vendor extended + // expression // ::= <expr-primary> // <expr-primary> ::= L <type> <value number> E # integer literal // ::= L <type> <value float> E # floating literal // ::= L <type> <string type> E # string literal // ::= L <nullptr type> E # nullptr literal "LDnE" - // ::= L <pointer type> 0 E # null pointer template argument - // ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C99); not used by clang + // ::= L <pointer type> 0 E # null pointer template + // argument + // ::= L <type> <real-part float> _ <imag-part float> E # + // complex floating point literal (C99); not used by clang // ::= L <mangled-name> E # external name QualType ImplicitlyConvertedToType; @@ -4922,8 +5038,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::NoStmtClass: #define ABSTRACT_STMT(Type) #define EXPR(Type, Base) -#define STMT(Type, Base) \ - case Expr::Type##Class: +#define STMT(Type, Base) case Expr::Type##Class: #include "clang/AST/StmtNodes.inc" // fallthrough @@ -4997,10 +5112,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, if (!NullOut) { // 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"); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot yet mangle expression type %0"); Diags.Report(E->getExprLoc(), DiagID) - << E->getStmtClassName() << E->getSourceRange(); + << E->getStmtClassName() << E->getSourceRange(); return; } break; @@ -5036,11 +5151,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::BinaryConditionalOperatorClass: { NotPrimaryExpr(); DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = - Diags.getCustomDiagID(DiagnosticsEngine::Error, - "?: operator with omitted middle operand cannot be mangled"); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "?: operator with omitted middle operand cannot be mangled"); Diags.Report(E->getExprLoc(), DiagID) - << E->getStmtClassName() << E->getSourceRange(); + << E->getStmtClassName() << E->getSourceRange(); return; } @@ -5126,7 +5241,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, // no qualifier and should always get mangled as a <simple-id> // anyway. - // <expression> ::= cl <expression>* E + // <expression> ::= cl <expression>* E } else { Out << "cl"; } @@ -5146,10 +5261,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::CXXNewExprClass: { NotPrimaryExpr(); const CXXNewExpr *New = cast<CXXNewExpr>(E); - if (New->isGlobalNew()) Out << "gs"; + if (New->isGlobalNew()) + Out << "gs"; Out << (New->isArray() ? "na" : "nw"); for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(), - E = New->placement_arg_end(); I != E; ++I) + E = New->placement_arg_end(); + I != E; ++I) mangleExpression(*I); Out << '_'; mangleType(New->getAllocatedType()); @@ -5210,11 +5327,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::MemberExprClass: { NotPrimaryExpr(); const MemberExpr *ME = cast<MemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), nullptr, - ME->getMemberDecl()->getDeclName(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), nullptr, + ME->getMemberDecl()->getDeclName(), ME->getTemplateArgs(), + ME->getNumTemplateArgs(), Arity); break; } @@ -5223,22 +5338,19 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), ME->isArrow(), ME->getQualifier(), nullptr, - ME->getMemberName(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + ME->getMemberName(), ME->getTemplateArgs(), + ME->getNumTemplateArgs(), Arity); break; } case Expr::CXXDependentScopeMemberExprClass: { NotPrimaryExpr(); - const CXXDependentScopeMemberExpr *ME - = cast<CXXDependentScopeMemberExpr>(E); + const CXXDependentScopeMemberExpr *ME = + cast<CXXDependentScopeMemberExpr>(E); mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), ME->isArrow(), ME->getQualifier(), - ME->getFirstQualifierFoundInScope(), - ME->getMember(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + ME->getFirstQualifierFoundInScope(), ME->getMember(), + ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity); break; } @@ -5268,9 +5380,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, Out << "cv"; mangleType(CE->getType()); - if (N != 1) Out << '_'; - for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << 'E'; + if (N != 1) + Out << '_'; + for (unsigned I = 0; I != N; ++I) + mangleExpression(CE->getArg(I)); + if (N != 1) + Out << 'E'; break; } @@ -5278,10 +5393,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, // An implicit cast is silent, thus may contain <expr-primary>. const auto *CE = cast<CXXConstructExpr>(E); if (!CE->isListInitialization() || CE->isStdInitListInitialization()) { - assert( - CE->getNumArgs() >= 1 && - (CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) && - "implicit CXXConstructExpr must have one argument"); + assert(CE->getNumArgs() >= 1 && + (CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) && + "implicit CXXConstructExpr must have one argument"); E = cast<CXXConstructExpr>(E)->getArg(0); goto recurse; } @@ -5354,8 +5468,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, // can lead to mangling collisions between function templates that we // consider to be different. QualType T = (ImplicitlyConvertedToType.isNull() || - !ImplicitlyConvertedToType->isIntegerType())? SAE->getType() - : ImplicitlyConvertedToType; + !ImplicitlyConvertedToType->isIntegerType()) + ? SAE->getType() + : ImplicitlyConvertedToType; llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext()); mangleIntegerLiteral(T, V); break; @@ -5467,7 +5582,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); // <expression> ::= [gs] dl <expression> # [::] delete expr // ::= [gs] da <expression> # [::] delete [] expr - if (DE->isGlobalDelete()) Out << "gs"; + if (DE->isGlobalDelete()) + Out << "gs"; Out << (DE->isArrayForm() ? "da" : "dl"); mangleExpression(DE->getArgument()); break; @@ -5776,7 +5892,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, Out << 'L'; mangleType(E->getType()); if (const FloatingLiteral *Imag = - dyn_cast<FloatingLiteral>(IE->getSubExpr())) { + dyn_cast<FloatingLiteral>(IE->getSubExpr())) { // Mangle a floating-point zero of the appropriate type. mangleFloat(llvm::APFloat(Imag->getValue().getSemantics())); Out << '_'; @@ -5846,11 +5962,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, const NamedDecl *Pack = SPE->getPack(); if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack)) mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); - else if (const NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Pack)) + else if (const NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Pack)) mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex()); - else if (const TemplateTemplateParmDecl *TempTP - = dyn_cast<TemplateTemplateParmDecl>(Pack)) + else if (const TemplateTemplateParmDecl *TempTP = + dyn_cast<TemplateTemplateParmDecl>(Pack)) mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex()); else mangleFunctionParam(cast<ParmVarDecl>(Pack)); @@ -5986,11 +6102,11 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { // because parameters declared as arrays should already have been // transformed to have pointer type. FIXME: apparently these don't // get mangled if used as an rvalue of a known non-class type? - assert(!parm->getType()->isArrayType() - && "parameter's type is still an array type?"); + assert(!parm->getType()->isArrayType() && + "parameter's type is still an array type?"); if (const DependentAddressSpaceType *DAST = - dyn_cast<DependentAddressSpaceType>(parm->getType())) { + dyn_cast<DependentAddressSpaceType>(parm->getType())) { mangleQualifiers(DAST->getPointeeType().getQualifiers(), DAST); } else { mangleQualifiers(parm->getType().getQualifiers()); @@ -6819,11 +6935,11 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, } QualType TypeSoFar = B.getType(); - if (auto *VD = B.dyn_cast<const ValueDecl*>()) { + if (auto *VD = B.dyn_cast<const ValueDecl *>()) { Out << 'L'; mangle(VD); Out << 'E'; - } else if (auto *E = B.dyn_cast<const Expr*>()) { + } else if (auto *E = B.dyn_cast<const Expr *>()) { NotPrimaryExpr(); mangleExpression(E); } else if (auto TI = B.dyn_cast<TypeInfoLValue>()) { @@ -6968,7 +7084,7 @@ void CXXNameMangler::mangleSeqID(unsigned SeqID) { void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { bool result = mangleSubstitution(tname); assert(result && "no existing substitution for template name"); - (void) result; + (void)result; } // <substitution> ::= S <seq-id> _ @@ -7006,7 +7122,7 @@ bool CXXNameMangler::mangleSubstitution(TemplateName Template) { Template = Context.getASTContext().getCanonicalTemplateName(Template); return mangleSubstitution( - reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); + reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); } bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { @@ -7118,7 +7234,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { } if (const ClassTemplateSpecializationDecl *SD = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { if (!isStdNamespace(Context.getEffectiveDeclContext(SD))) return false; @@ -7184,7 +7300,7 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) { Substitutions[Ptr] = SeqID++; } -void CXXNameMangler::extendSubstitutions(CXXNameMangler* Other) { +void CXXNameMangler::extendSubstitutions(CXXNameMangler *Other) { assert(Other->SeqID >= SeqID && "Must be superset of substitutions!"); if (Other->SeqID > SeqID) { Substitutions.swap(Other->Substitutions); @@ -7246,8 +7362,7 @@ bool CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C, /// and this routine will return false. In this case, the caller should just /// emit the identifier of the declaration (\c D->getIdentifier()) as its /// name. -void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD, raw_ostream &Out) { const NamedDecl *D = cast<NamedDecl>(GD.getDecl()); assert((isa<FunctionDecl, VarDecl, TemplateParamObjectDecl>(D)) && "Invalid mangleName() call, argument is not a variable or function!"); @@ -7459,8 +7574,8 @@ void ItaniumMangleContextImpl::mangleSEHFilterExpression( Mangler.getStream() << EnclosingFD->getName(); } -void ItaniumMangleContextImpl::mangleSEHFinallyBlock( - GlobalDecl EnclosingDecl, raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleSEHFinallyBlock(GlobalDecl EnclosingDecl, + raw_ostream &Out) { CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "__fin_"; auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl()); @@ -7478,9 +7593,8 @@ void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D, Mangler.mangleName(D); } -void -ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper( + const VarDecl *D, raw_ostream &Out) { // <special-name> ::= TW <object name> CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTW"; @@ -7554,7 +7668,8 @@ void ItaniumMangleContextImpl::mangleCanonicalTypeName( mangleCXXRTTIName(Ty, Out, NormalizeIntegers); } -void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) { +void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, + raw_ostream &) { llvm_unreachable("Can't mangle string literals"); } >From 7baf23020bde8f227ffa5c2d23c054151700b03b Mon Sep 17 00:00:00 2001 From: Tommy Chiang <[email protected]> Date: Fri, 20 Feb 2026 02:40:57 +0800 Subject: [PATCH 2/2] [Clang][ItaniumMangle] Fix recursive mangling for lambda init-captures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During lambda numbering, ItaniumNumberingContext::getManglingNumber() computes the lambda’s <lambda-sig> by mangling the call operator type. If that type contains decltype(init-capture), mangling re-enters the init-capture VarDecl. For problematic cases, this recurses back into operator() mangling. Make init-capture handling in mangleLocalName() explicit: * If the init-capture belongs to a lambda that has a closure-prefix context, mangle it directly with mangleNestedNameWithClosurePrefix(). * Otherwise keep local-name mangling, but for local lambdas use the parent local container as the function-encoding base to avoid self-recursion. Also publish lambda ContextDecl early in Sema::handleLambdaNumbering() before calling getManglingNumber(Method), via a dedicated CXXRecordDecl::setLambdaContextDecl() helper. This provides the needed context for context-sensitive mangling without publishing provisional numbering state. Add non-local regression tests in mangle-lambdas.cpp for: * variable-template lambda init-capture used in decltype(x) * static inline member lambda init-capture used in decltype(x) * Fixes https://github.com/llvm/llvm-project/issues/63271 * Fixes https://github.com/llvm/llvm-project/issues/86240 * Fixes https://github.com/llvm/llvm-project/issues/139089 --- clang/include/clang/AST/DeclCXX.h | 3 ++ clang/lib/AST/DeclCXX.cpp | 5 ++ clang/lib/AST/ItaniumMangle.cpp | 31 +++++++++-- clang/lib/Sema/SemaLambda.cpp | 7 +++ clang/test/CodeGenCXX/mangle-lambdas.cpp | 66 ++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 5c4ad3c45da19..0c9bba17d09ef 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1785,6 +1785,9 @@ class CXXRecordDecl : public RecordDecl { /// the declaration context suffices. Decl *getLambdaContextDecl() const; + /// Set the context declaration for a lambda class. + void setLambdaContextDecl(Decl *ContextDecl); + /// Retrieve the index of this lambda within the context declaration returned /// by getLambdaContextDecl(). unsigned getLambdaIndexInContext() const { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index c16b1bb7a3453..55c34605f7513 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1831,6 +1831,11 @@ Decl *CXXRecordDecl::getLambdaContextDecl() const { return getLambdaData().ContextDecl.get(Source); } +void CXXRecordDecl::setLambdaContextDecl(Decl *ContextDecl) { + assert(isLambda() && "Not a lambda closure type!"); + getLambdaData().ContextDecl = ContextDecl; +} + void CXXRecordDecl::setLambdaNumbering(LambdaNumbering Numbering) { assert(isLambda() && "Not a lambda closure type!"); getLambdaData().ManglingNumber = Numbering.ManglingNumber; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 4618fc58c886a..6017f3bb3cd5f 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1855,17 +1855,40 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD, const RecordDecl *RD = GetLocalClassDecl(D); const DeclContext *DC = Context.getEffectiveDeclContext(RD ? RD : D); + if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) { + if (const auto *MethodDC = dyn_cast<CXXMethodDecl>(DC)) { + // Init-captures in non-local lambdas should be mangled in the lambda's + // closure-prefix context, not as local entities of operator(). + if (const NamedDecl *PrefixND = getClosurePrefix(MethodDC->getParent())) { + mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags); + return; + } + } + } + Out << 'Z'; { AbiTagState LocalAbiTags(AbiTags); - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { mangleObjCMethodName(MD); - else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { mangleBlockForPrefix(BD); - else - mangleFunctionEncoding(getParentOfLocalEntity(DC)); + } else { + const DeclContext *MangleDC = DC; + if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) { + if (const auto *MethodDC = dyn_cast<CXXMethodDecl>(DC)) { + const DeclContext *ParentDC = + Context.getEffectiveParentContext(MethodDC->getDeclContext()); + // For local lambdas, use the parent context as the local-name base + // to avoid recursively mangling the lambda call operator. + if (isLocalContainerContext(ParentDC)) + MangleDC = ParentDC; + } + } + mangleFunctionEncoding(getParentOfLocalEntity(MangleDC)); + } // Implicit ABI tags (from namespace) are not available in the following // entity; reset to actually emitted tags, which are available. diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index e74fe02bd0cf5..f3f108873ef74 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -503,6 +503,13 @@ void Sema::handleLambdaNumbering( MangleNumberingContext *MCtx; std::tie(MCtx, Numbering.ContextDecl) = getCurrentMangleNumberContext(Class->getDeclContext()); + // getManglingNumber(Method) below may trigger mangling of dependent types + // that reference init-captures. Publish the lambda context declaration early + // so such mangling can resolve the surrounding context without recursing + // through the lambda call operator. This avoids publishing provisional + // numbering state before final numbering is assigned below. + if (Numbering.ContextDecl) + Class->setLambdaContextDecl(Numbering.ContextDecl); if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)) { // Force lambda numbering in CUDA/HIP as we need to name lambdas following diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp index 5a7de97c91858..d9ac0d39956e9 100644 --- a/clang/test/CodeGenCXX/mangle-lambdas.cpp +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -301,6 +301,70 @@ void test_StaticInlineMember() { StaticInlineMember::x(); } +template <typename L> +auto pr63271foo(L l_) { + return [l = l_](decltype(l)) -> void {}; +} + +// CHECK-LABEL: define{{.*}} @_Z10pr63271usev +// CHECK: call void @_ZZ10pr63271fooIiEDaT_ENKUliE_clEi +void pr63271use() { + pr63271foo(0)(0); +} + +template <typename T> +struct pr139089_vlambda { + pr139089_vlambda() { + [&m = m_args](decltype(m) args) { (void)args; }(m_args); + } + int m_args = 0; +}; + +// CHECK-LABEL: define{{.*}} @_Z11pr139089usev +// CHECK: call void @_ZN16pr139089_vlambdaIiEC1Ev +void pr139089use() { + (void)pr139089_vlambda<int>{}; +} + + +template <class RET> struct pr86240_context { + using Ptr = pr86240_context<RET> *; +}; + +template <typename Callable> +void pr86240_schedule_coro(Callable &&coro_function) { + [coro_function{coro_function}]( + typename pr86240_context<decltype(coro_function())>::Ptr ctx) -> int { + return ctx != nullptr; + }(nullptr); +} + +// CHECK-LABEL: define{{.*}} @_Z10pr86240usev +// CHECK: call noundef i32 @"_ZZ21pr86240_schedule_coroIZ10pr86240usevE3$_0EvOT_ENKUlP15pr86240_contextIiEE_clES5_" +void pr86240use() { + pr86240_schedule_coro([] { return 0; }); +} + +template <typename T> +auto nonLocalVarTemplate = [x = T{}](decltype(x) y) { return y; }; + +// CHECK-LABEL: define{{.*}} @_Z22nonLocalVarTemplateUsev +// CHECK: call noundef i32 @_ZNK19nonLocalVarTemplateIiEMUliE_clEi +int nonLocalVarTemplateUse() { + return nonLocalVarTemplate<int>(2); +} + +template <typename T> +struct nonLocalStaticInlineMember { + static inline auto l = [x = T{}](decltype(x) y) { return y; }; +}; + +// CHECK-LABEL: define{{.*}} @_Z29nonLocalStaticInlineMemberUsev +// CHECK: call noundef i32 @_ZNK26nonLocalStaticInlineMemberIiE1lMUliE_clEi +int nonLocalStaticInlineMemberUse() { + return nonLocalStaticInlineMember<int>::l(2); +} + // Check linkage of the various lambdas. // CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv // CHECK: ret i32 1 @@ -331,6 +395,8 @@ void test_StaticInlineMember() { // CHECK-LABEL: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ +// CHECK-LABEL: define linkonce_odr void @_ZZN16pr139089_vlambdaIiEC1EvENKUlRiE_clES1_ + namespace PR12808 { template <typename> struct B { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
