llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Tommy Chiang (oToToT) <details> <summary>Changes</summary> 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 --- 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: - (modified) clang/include/clang/AST/DeclCXX.h (+3) - (modified) clang/lib/AST/DeclCXX.cpp (+5) - (modified) clang/lib/AST/ItaniumMangle.cpp (+443-305) - (modified) clang/lib/Sema/SemaLambda.cpp (+7) - (modified) clang/test/CodeGenCXX/mangle-lambdas.cpp (+66) ``````````diff 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] `````````` </details> https://github.com/llvm/llvm-project/pull/182667 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
