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

Reply via email to