https://github.com/oToToT updated 
https://github.com/llvm/llvm-project/pull/182667

>From 61b3822460eb2e2ae7d4141e517058501c0a5c6a 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

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 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        | 12 +++--
 clang/lib/AST/ASTImporter.cpp            | 10 ++--
 clang/lib/AST/DeclCXX.cpp                |  6 ++-
 clang/lib/AST/ItaniumMangle.cpp          | 38 +++++++++++---
 clang/lib/Sema/SemaLambda.cpp            | 24 ++++++---
 clang/test/CodeGenCXX/mangle-lambdas.cpp | 66 ++++++++++++++++++++++++
 6 files changed, 132 insertions(+), 24 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index 15dda098bad47..f6e3c688e19bb 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1791,6 +1791,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 {
@@ -1800,20 +1803,19 @@ class CXXRecordDecl : public RecordDecl {
 
   /// Information about how a lambda is numbered within its context.
   struct LambdaNumbering {
-    Decl *ContextDecl = nullptr;
     unsigned IndexInContext = 0;
     unsigned ManglingNumber = 0;
     unsigned DeviceManglingNumber = 0;
     bool HasKnownInternalLinkage = false;
   };
 
-  /// Set the mangling numbers and context declaration for a lambda class.
+  /// Set the mangling numbers for a lambda class.
   void setLambdaNumbering(LambdaNumbering Numbering);
 
-  // Get the mangling numbers and context declaration for a lambda class.
+  // Get the mangling numbers for a lambda class.
   LambdaNumbering getLambdaNumbering() const {
-    return {getLambdaContextDecl(), getLambdaIndexInContext(),
-            getLambdaManglingNumber(), getDeviceLambdaManglingNumber(),
+    return {getLambdaIndexInContext(), getLambdaManglingNumber(),
+            getDeviceLambdaManglingNumber(),
             hasKnownLambdaInternalLinkage()};
   }
 
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 8d8cc5426146d..c41d0c744e664 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3444,12 +3444,14 @@ ExpectedDecl 
ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
               DC, *TInfoOrErr, Loc, DCXX->getLambdaDependencyKind(),
               DCXX->isGenericLambda(), DCXX->getLambdaCaptureDefault()))
         return D2CXX;
-      CXXRecordDecl::LambdaNumbering Numbering = DCXX->getLambdaNumbering();
-      ExpectedDecl CDeclOrErr = import(Numbering.ContextDecl);
+      Decl *ContextDecl = DCXX->getLambdaContextDecl();
+      ExpectedDecl CDeclOrErr = import(ContextDecl);
       if (!CDeclOrErr)
         return CDeclOrErr.takeError();
-      Numbering.ContextDecl = *CDeclOrErr;
-      D2CXX->setLambdaNumbering(Numbering);
+      if (ContextDecl != nullptr) {
+        D2CXX->setLambdaContextDecl(*CDeclOrErr);
+      }
+      D2CXX->setLambdaNumbering(DCXX->getLambdaNumbering());
     } else {
       if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
                                   D->getTagKind(), DC, *BeginLocOrErr, Loc,
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 37bc61ca35c4b..083c53e28cb91 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1837,6 +1837,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;
@@ -1844,7 +1849,6 @@ void CXXRecordDecl::setLambdaNumbering(LambdaNumbering 
Numbering) {
     getASTContext().DeviceLambdaManglingNumbers[this] =
         Numbering.DeviceManglingNumber;
   getLambdaData().IndexInContext = Numbering.IndexInContext;
-  getLambdaData().ContextDecl = Numbering.ContextDecl;
   getLambdaData().HasKnownInternalLinkage = Numbering.HasKnownInternalLinkage;
 }
 
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index df00760fa911b..94358b6f9c1dc 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -633,6 +633,19 @@ NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() 
{
   return StdNamespace;
 }
 
+/// Retrieve the lambda associated with an init-capture variable.
+static const CXXRecordDecl *getLambdaForInitCapture(const VarDecl *VD) {
+  if (!VD || !VD->isInitCapture())
+    return nullptr;
+
+  const auto *Method = cast<CXXMethodDecl>(VD->getDeclContext());
+  const auto *Lambda = dyn_cast<CXXRecordDecl>(Method->getParent());
+  if (!Lambda || !Lambda->isLambda())
+    return nullptr;
+
+  return Lambda;
+}
+
 /// Retrieve the declaration context that should be used when mangling the 
given
 /// declaration.
 const DeclContext *
@@ -674,9 +687,18 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const 
Decl *D) {
     return getEffectiveDeclContext(cast<Decl>(DC));
   }
 
-  if (const auto *VD = dyn_cast<VarDecl>(D))
+  if (const auto *VD = dyn_cast<VarDecl>(D)) {
+    if (const CXXRecordDecl *Lambda = getLambdaForInitCapture(VD)) {
+      const DeclContext *ParentDC = getEffectiveParentContext(Lambda);
+      // Init-captures in local lambdas are mangled relative to the enclosing
+      // local context rather than operator() to avoid recursive local-name
+      // encoding through the call operator type.
+      if (isLocalContainerContext(ParentDC))
+        return ParentDC;
+    }
     if (VD->isExternC())
       return getASTContext().getTranslationUnitDecl();
+  }
 
   if (const auto *FD = getASTContext().getLangOpts().getClangABICompat() >
                                LangOptions::ClangABI::Ver19
@@ -1873,12 +1895,13 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
   {
     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
+    } else {
       mangleFunctionEncoding(getParentOfLocalEntity(DC));
+    }
 
     // Implicit ABI tags (from namespace) are not available in the following
     // entity; reset to actually emitted tags, which are available.
@@ -2277,6 +2300,9 @@ const NamedDecl *CXXNameMangler::getClosurePrefix(const 
Decl *ND) {
   const NamedDecl *Context = nullptr;
   if (auto *Block = dyn_cast<BlockDecl>(ND)) {
     Context = 
dyn_cast_or_null<NamedDecl>(Block->getBlockManglingContextDecl());
+  } else if (auto *VD = dyn_cast<VarDecl>(ND)) {
+    if (const CXXRecordDecl *Lambda = getLambdaForInitCapture(VD))
+      Context = dyn_cast_or_null<NamedDecl>(Lambda->getLambdaContextDecl());
   } else if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
     if (RD->isLambda())
       Context = dyn_cast_or_null<NamedDecl>(RD->getLambdaContextDecl());
@@ -2284,8 +2310,8 @@ const NamedDecl *CXXNameMangler::getClosurePrefix(const 
Decl *ND) {
   if (!Context)
     return nullptr;
 
-  // Only lambdas within the initializer of a non-local variable or non-static
-  // data member get a <closure-prefix>.
+  // Only entities associated with lambdas within the initializer of a
+  // non-local variable or non-static data member get a <closure-prefix>.
   if ((isa<VarDecl>(Context) && cast<VarDecl>(Context)->hasGlobalStorage()) ||
       isa<FieldDecl>(Context))
     return Context;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e74fe02bd0cf5..013d2de62b977 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -478,11 +478,6 @@ bool Sema::DiagnoseInvalidExplicitObjectParameterInLambda(
 void Sema::handleLambdaNumbering(
     CXXRecordDecl *Class, CXXMethodDecl *Method,
     std::optional<CXXRecordDecl::LambdaNumbering> NumberingOverride) {
-  if (NumberingOverride) {
-    Class->setLambdaNumbering(*NumberingOverride);
-    return;
-  }
-
   ContextRAII ManglingContext(*this, Class->getDeclContext());
 
   auto getMangleNumberingContext =
@@ -499,10 +494,23 @@ void Sema::handleLambdaNumbering(
     return &Context.getManglingNumberContext(DC);
   };
 
-  CXXRecordDecl::LambdaNumbering Numbering;
   MangleNumberingContext *MCtx;
-  std::tie(MCtx, Numbering.ContextDecl) =
+  Decl *ContextDecl;
+  std::tie(MCtx, 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 (ContextDecl)
+    Class->setLambdaContextDecl(ContextDecl);
+  if (NumberingOverride) {
+    Class->setLambdaNumbering(*NumberingOverride);
+    return;
+  }
+
+  CXXRecordDecl::LambdaNumbering Numbering;
   if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice ||
                 getLangOpts().SYCLIsHost)) {
     // Force lambda numbering in CUDA/HIP as we need to name lambdas following
@@ -512,7 +520,7 @@ void Sema::handleLambdaNumbering(
     // Also force for SYCL, since we need this for the
     // __builtin_sycl_unique_stable_name implementation, which depends on 
lambda
     // mangling.
-    MCtx = getMangleNumberingContext(Class, Numbering.ContextDecl);
+    MCtx = getMangleNumberingContext(Class, ContextDecl);
     assert(MCtx && "Retrieving mangle numbering context failed!");
     Numbering.HasKnownInternalLinkage = true;
   }
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