[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