https://github.com/oToToT updated https://github.com/llvm/llvm-project/pull/182667
>From 5bc0c4b152cf0b46256dbc0f757e5916a601c1be Mon Sep 17 00:00:00 2001 From: Tommy Chiang <[email protected]> Date: Fri, 20 Feb 2026 02:40:57 +0800 Subject: [PATCH] [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 70acc8a78ed52..3c4e1aacaf18a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -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)) { + // Init-captures in non-local lambdas should be mangled in the lambda's + // closure-prefix context, not as local entities of operator(). + if (const NamedDecl *PrefixND = getClosurePrefix(MethodDC->getParent())) { + mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags); + return; + } + } + } + Out << 'Z'; { AbiTagState LocalAbiTags(AbiTags); - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { mangleObjCMethodName(MD); - else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { mangleBlockForPrefix(BD); - else - mangleFunctionEncoding(getParentOfLocalEntity(DC)); + } else { + const DeclContext *MangleDC = DC; + if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) { + if (const auto *MethodDC = dyn_cast<CXXMethodDecl>(DC)) { + const DeclContext *ParentDC = + Context.getEffectiveParentContext(MethodDC->getDeclContext()); + // For local lambdas, use the parent context as the local-name base + // to avoid recursively mangling the lambda call operator. + if (isLocalContainerContext(ParentDC)) + MangleDC = ParentDC; + } + } + mangleFunctionEncoding(getParentOfLocalEntity(MangleDC)); + } // Implicit ABI tags (from namespace) are not available in the following // entity; reset to actually emitted tags, which are available. diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index e74fe02bd0cf5..f3f108873ef74 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -503,6 +503,13 @@ void Sema::handleLambdaNumbering( MangleNumberingContext *MCtx; std::tie(MCtx, Numbering.ContextDecl) = getCurrentMangleNumberContext(Class->getDeclContext()); + // getManglingNumber(Method) below may trigger mangling of dependent types + // that reference init-captures. Publish the lambda context declaration early + // so such mangling can resolve the surrounding context without recursing + // through the lambda call operator. This avoids publishing provisional + // numbering state before final numbering is assigned below. + if (Numbering.ContextDecl) + Class->setLambdaContextDecl(Numbering.ContextDecl); if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)) { // Force lambda numbering in CUDA/HIP as we need to name lambdas following diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp index 5a7de97c91858..d9ac0d39956e9 100644 --- a/clang/test/CodeGenCXX/mangle-lambdas.cpp +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -301,6 +301,70 @@ void test_StaticInlineMember() { StaticInlineMember::x(); } +template <typename L> +auto pr63271foo(L l_) { + return [l = l_](decltype(l)) -> void {}; +} + +// CHECK-LABEL: define{{.*}} @_Z10pr63271usev +// CHECK: call void @_ZZ10pr63271fooIiEDaT_ENKUliE_clEi +void pr63271use() { + pr63271foo(0)(0); +} + +template <typename T> +struct pr139089_vlambda { + pr139089_vlambda() { + [&m = m_args](decltype(m) args) { (void)args; }(m_args); + } + int m_args = 0; +}; + +// CHECK-LABEL: define{{.*}} @_Z11pr139089usev +// CHECK: call void @_ZN16pr139089_vlambdaIiEC1Ev +void pr139089use() { + (void)pr139089_vlambda<int>{}; +} + + +template <class RET> struct pr86240_context { + using Ptr = pr86240_context<RET> *; +}; + +template <typename Callable> +void pr86240_schedule_coro(Callable &&coro_function) { + [coro_function{coro_function}]( + typename pr86240_context<decltype(coro_function())>::Ptr ctx) -> int { + return ctx != nullptr; + }(nullptr); +} + +// CHECK-LABEL: define{{.*}} @_Z10pr86240usev +// CHECK: call noundef i32 @"_ZZ21pr86240_schedule_coroIZ10pr86240usevE3$_0EvOT_ENKUlP15pr86240_contextIiEE_clES5_" +void pr86240use() { + pr86240_schedule_coro([] { return 0; }); +} + +template <typename T> +auto nonLocalVarTemplate = [x = T{}](decltype(x) y) { return y; }; + +// CHECK-LABEL: define{{.*}} @_Z22nonLocalVarTemplateUsev +// CHECK: call noundef i32 @_ZNK19nonLocalVarTemplateIiEMUliE_clEi +int nonLocalVarTemplateUse() { + return nonLocalVarTemplate<int>(2); +} + +template <typename T> +struct nonLocalStaticInlineMember { + static inline auto l = [x = T{}](decltype(x) y) { return y; }; +}; + +// CHECK-LABEL: define{{.*}} @_Z29nonLocalStaticInlineMemberUsev +// CHECK: call noundef i32 @_ZNK26nonLocalStaticInlineMemberIiE1lMUliE_clEi +int nonLocalStaticInlineMemberUse() { + return nonLocalStaticInlineMember<int>::l(2); +} + // Check linkage of the various lambdas. // CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv // CHECK: ret i32 1 @@ -331,6 +395,8 @@ void test_StaticInlineMember() { // CHECK-LABEL: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ +// CHECK-LABEL: define linkonce_odr void @_ZZN16pr139089_vlambdaIiEC1EvENKUlRiE_clES1_ + namespace PR12808 { template <typename> struct B { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
