[clang] [Clang][ItaniumMangle] Fix infinite recursion mangling a lambda in an enable_if condition (PR #234686)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 22 09:48:16 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Usef Ahmed (usefahmed07)

<details>
<summary>Changes</summary>

Fixes #<!-- -->233807

When a function template with an `enable_if` (or `diagnose_if`) attribute whose condition contains a lambda is instantiated, the lambda closure type is created with the instantiated function as its `DeclContext` (the condition is substituted under `ContextRAII(S, New)`, which is needed so that parameters and `this` resolve). The lambda has no `LambdaContextDecl`.

When mangling, this causes infinite recursion:

mangle `get<0>` -> mangle the `enable_if` condition -> mangle the lambda's local name -> mangle `get<0>` -> ...

The dependent pattern's lambda lives in the function's parent context, so this patch makes `getEffectiveDeclContext` do the same for a lambda that sits inside an `EnableIfAttr`/`DiagnoseIfAttr` condition of its own `DeclContext` function (detected by source location). This breaks the cycle.

I first tried changing the context used for substitution in `instantiateDependentFunctionAttrCondition`, but that breaks lookup of parameters and `this` (it regressed `SemaCXX/enable_if.cpp`, `SemaCXX/diagnose_if.cpp` and `CodeGenCXX/enable_if.cpp`), so the fix is in the mangler instead.

Test: added `clang/test/CodeGenCXX/mangle-lambda-enable-if.cpp`. It crashes without the patch and passes with it. Also ran `SemaCXX/enable_if.cpp`, `SemaCXX/diagnose_if.cpp`, `CodeGenCXX/enable_if.cpp`, `CodeGenCXX/mangle-lambdas*.cpp` and `SemaTemplate/`; no regressions.

---
Full diff: https://github.com/llvm/llvm-project/pull/234686.diff


2 Files Affected:

- (modified) clang/lib/AST/ItaniumMangle.cpp (+21) 
- (added) clang/test/CodeGenCXX/mangle-lambda-enable-if.cpp (+10) 


``````````diff
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 02f27cec53f69..48da61996d0f1 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -30,6 +30,7 @@
 #include "clang/Basic/ABI.h"
 #include "clang/Basic/DiagnosticAST.h"
 #include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/Thunk.h"
 #include "llvm/ADT/StringExtras.h"
@@ -664,6 +665,26 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const Decl *D) {
       if (ParmVarDecl *ContextParam =
               dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
         return ContextParam->getDeclContext();
+
+    // A lambda in the condition of an enable_if/diagnose_if attribute is
+    // instantiated with the function as its DeclContext, but the ABI treats it
+    // like the dependent pattern: it lives in the function's parent context.
+    // Mangling it relative to the function would recurse forever, since the
+    // function's encoding includes the attribute condition.
+    if (RD->isLambda() && !RD->getLambdaContextDecl())
+      if (const auto *FD = dyn_cast<FunctionDecl>(RD->getDeclContext())) {
+        const SourceManager &SM = getASTContext().getSourceManager();
+        SourceLocation Loc = RD->getLocation();
+        for (const Attr *A : FD->attrs()) {
+          if (!isa<EnableIfAttr, DiagnoseIfAttr>(A))
+            continue;
+          SourceRange R = A->getRange();
+          if (R.isValid() && Loc.isValid() &&
+              !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) &&
+              !SM.isBeforeInTranslationUnit(R.getEnd(), Loc))
+            return FD->getDeclContext();
+        }
+      }
   }
 
   // Perform the same check for block literals.
diff --git a/clang/test/CodeGenCXX/mangle-lambda-enable-if.cpp b/clang/test/CodeGenCXX/mangle-lambda-enable-if.cpp
new file mode 100644
index 0000000000000..fd92cd1aa65d3
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-lambda-enable-if.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++20 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+// Mangling a lambda in an enable_if condition must not recurse infinitely.
+// https://github.com/llvm/llvm-project/issues/233807
+template <int = 0>
+int get() __attribute__((enable_if([]() { return true; }(), ""))) { return 0; }
+
+// CHECK-LABEL: define {{.*}} @__cxx_global_var_init
+// CHECK: call {{.*}} @_Z3getILi0EEUa9enable_ifIXclLUlvE_EEEiv()
+int y = get();

``````````

</details>


https://github.com/llvm/llvm-project/pull/234686


More information about the cfe-commits mailing list