[clang] Fix recursive mangling for lambda init-captures (PR #182667)
Tommy Chiang via cfe-commits
cfe-commits at lists.llvm.org
Sat Feb 21 03:20:40 PST 2026
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 <ototot at google.com>
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 <ototot at google.com>
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 {
More information about the cfe-commits
mailing list