[Clang][ItaniumMangle] Fix recursive mangling for lambda init-captures - #182667
Conversation
|
@llvm/pr-subscribers-clang Author: Tommy Chiang (oToToT) ChangesDuring lambda numbering, ItaniumNumberingContext::getManglingNumber() computes Make init-capture handling in mangleLocalName() explicit:
Also publish lambda ContextDecl early in Sema::handleLambdaNumbering() before Add non-local regression tests in mangle-lambdas.cpp for:
This PR
Patch is 64.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/182667.diff 5 Files Affected:
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 70acc8a78ed52..6017f3bb3cd5f 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());
@@ -1868,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.
@@ -1898,10 +1908,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 +1923,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 +1940,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 +2111,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 +2252,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
addSubstitution(Template);
}
-void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
- bool NoFunction) {
+void CXXNameMangler::mang...
[truncated]
|
mizvekov
left a comment
There was a problem hiding this comment.
There are a lot of pure formatting changes here, can you please offload these to an NFC patch and just pre-commit them?
|
Created a new PR #182803 per https://llvm.org/docs/Contributing.html#:~:text=separate%20Pull%20Request I'll rebase this PR once the NFC PR merged. |
7baf230 to
5bc0c4b
Compare
|
Removed the unnecessary format change |
5bc0c4b to
4a61972
Compare
shafik
left a comment
There was a problem hiding this comment.
This looks sensible but not my expertise, I checked the mangling w/ gcc and it is consistent.
erichkeane
left a comment
There was a problem hiding this comment.
This seems reasonable to me, but since it is mangling related, @efriedma-quic should be taking a look.
| // through the lambda call operator. This avoids publishing provisional | ||
| // numbering state before final numbering is assigned below. | ||
| if (Numbering.ContextDecl) | ||
| Class->setLambdaContextDecl(Numbering.ContextDecl); |
There was a problem hiding this comment.
If we're going to set the context here, should we drop the ContextDecl from CXXRecordDecl::LambdaNumbering?
There was a problem hiding this comment.
I was also thinking about this, but I'm not sure if this is preferred. Anyway, the updated commit drops ContextDecl from CXXRecordDecl::LambdaNumbering.
| @@ -1868,17 +1868,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()) { | |||
There was a problem hiding this comment.
The logic in this function for handling init-captures goes through a lot of cases: you separately handle init captures with a closure prefix, init captures in a local lambda, and init captures which are neither. Is it possible to unify the cases by fixing the "context" computation? Maybe something in getEffectiveDeclContext()?
There was a problem hiding this comment.
Ok. Updated around. It's a bit large now as I don't find a (very) simple way to do so.
| @@ -301,6 +301,70 @@ void test_StaticInlineMember() { | |||
| StaticInlineMember::x(); | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
Does the Itanium ABI specify how to mangle these cases? Does gcc produce the same mangling? (I think at least some of these cases are externally visible.)
There was a problem hiding this comment.
IIUC, this still aligns to the Itanium ABI spec. The 5.1.8 rule "If the context is the body of a function (inline and/or template), the closure type is encoded like any other local entity", and some relevant statements in both 5.1.7 and 5.1.8.
Basically, I think this is a recursion bug in Clang’s mangling path. This fix is to break recursive re-entry by resolving/publishing lambda context early. I do not invent a new recursive-type encoding.
For GCC, it produces the same output of all the test files. (except the existing differences of how we mangle lambda, e.g. main::$_0 vs main::{lambda()#1})
| @@ -1868,17 +1868,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)) { | |||
There was a problem hiding this comment.
I think an init-capture's DeclContext is always a CXXMethodDecl, by construction; you can just cast<CXXMethodDecl>(DC).
4a61972 to
61b3822
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Mangle computation for lambda signatures can recurse when a call operator type
references an init-capture (for example via decltype(init-capture)). In these
cases, mangling can re-enter the init-capture declaration and cycle back through
operator() mangling.
Make lambda context publication explicit and independent from numbering state,
then use that context uniformly during mangling:
* Publish lambda `ContextDecl` in `Sema::handleLambdaNumbering()` before
numbering, so dependent type mangling can resolve the lambda context without
recursing through the call operator.
* Introduce `CXXRecordDecl::setLambdaContextDecl()` and remove `ContextDecl`
from `CXXRecordDecl::LambdaNumbering`.
* Update `ASTImporter` to import/set lambda context separately from numbering.
* In Itanium mangling, derive init-capture handling from context computation:
- map local-lambda init-captures to the enclosing local context in
`getEffectiveDeclContext()`
- support init-capture variables in `getClosurePrefix()`
- keep `mangleLocalName()` generic and rely on the computed context
Add mangling regression coverage in mangle-lambdas.cpp, including:
* local init-captures used through decltype
* non-local variable-template init-captures in decltype
* non-local static inline member init-captures in decltype
* Fixes llvm#63271
* Fixes llvm#86240
* Fixes llvm#139089
61b3822 to
731efa8
Compare
llvm#182667) [Clang][ItaniumMangle] Fix recursive mangling for lambda init-captures Mangle computation for lambda signatures can recurse when a call operator type references an init-capture (for example via decltype(init-capture)). In these cases, mangling can re-enter the init-capture declaration and cycle back through operator() mangling. Make lambda context publication explicit and independent from numbering state, then use that context uniformly during mangling: * Publish lambda `ContextDecl` in `Sema::handleLambdaNumbering()` before numbering, so dependent type mangling can resolve the lambda context without recursing through the call operator. * Introduce `CXXRecordDecl::setLambdaContextDecl()` and remove `ContextDecl` from `CXXRecordDecl::LambdaNumbering`. * Update `ASTImporter` to import/set lambda context separately from numbering. * In Itanium mangling, derive init-capture handling from context computation: - map local-lambda init-captures to the enclosing local context in `getEffectiveDeclContext()` - support init-capture variables in `getClosurePrefix()` - keep `mangleLocalName()` generic and rely on the computed context Add mangling regression coverage in mangle-lambdas.cpp, including: * local init-captures used through decltype * non-local variable-template init-captures in decltype * non-local static inline member init-captures in decltype * Fixes llvm#63271 * Fixes llvm#86240 * Fixes llvm#139089
[Clang][ItaniumMangle] Fix recursive mangling for lambda init-captures
Mangle computation for lambda signatures can recurse when a call operator type
references an init-capture (for example via decltype(init-capture)). In these
cases, mangling can re-enter the init-capture declaration and cycle back through
operator() mangling.
Make lambda context publication explicit and independent from numbering state,
then use that context uniformly during mangling:
ContextDeclinSema::handleLambdaNumbering()beforenumbering, so dependent type mangling can resolve the lambda context without
recursing through the call operator.
CXXRecordDecl::setLambdaContextDecl()and removeContextDeclfrom
CXXRecordDecl::LambdaNumbering.ASTImporterto import/set lambda context separately from numbering.getEffectiveDeclContext()getClosurePrefix()mangleLocalName()generic and rely on the computed contextAdd mangling regression coverage in mangle-lambdas.cpp, including:
local init-captures used through decltype
non-local variable-template init-captures in decltype
non-local static inline member init-captures in decltype
Fixes Clang frontend C++ crash on decltype in lambda params #63271
Fixes Stack overflow in clang-query 17, ItaniumMangle.cpp #86240
Fixes ICE in Clang 21 with recursive lambda capture — infinite name mangling loop since clang-17 #139089