[clang] [Clang] Avoid numbering lambdas with invalid types (PR #232606)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 15 23:09:11 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Kunal Dubey (xakep8)
<details>
<summary>Changes</summary>
This is stacked on #<!-- -->232357. The first commit belongs to that PR; the lambda error-recovery change is the second commit.
During error recovery, a lambda parameter can contain an invalid type. Clang still tries to assign the lambda a stable number, which requires mangling its parameter types and can reach an internal compiler error.
Skip lambda numbering when the lambda's call-operator type already contains errors. This lets Clang report the original source error instead of crashing.
Fixes #<!-- -->170185
---
Full diff: https://github.com/llvm/llvm-project/pull/232606.diff
5 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+8)
- (modified) clang/lib/AST/ItaniumMangle.cpp (+21-2)
- (modified) clang/lib/Sema/SemaLambda.cpp (+3)
- (modified) clang/test/CodeGenCXX/mangle-cxx2a.cpp (+46)
- (added) clang/test/SemaCXX/crash-GH170185.cpp (+14)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index aba1dba5854fe..3710ab8e36abb 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -64,6 +64,11 @@ in a future version of Clang.
### ABI Changes in This Version
+- Clang now correctly mangles C++20 parenthesized aggregate initialization
+ expressions. Previously, initializer arguments could be omitted from the
+ mangled name, causing distinct entities to receive the same name.
+ (#GH231953)
+
- Except on PlayStation, Clang now derives the x86-64 System V AVX ABI level
for 256- and 512-bit vector arguments and returns from effective per-function
target features. Features and `arch=` CPUs that imply AVX or AVX512F are
@@ -799,6 +804,9 @@ features cannot lower the translation-unit ABI level;
#### Bug Fixes to C++ Support
+- Fixed a crash when a lambda parameter type contains an invalid non-type
+ template argument. (#GH170185)
+
- Fixed lambdas with specifiers or attributes after the capture list being
misparsed as function declarations in direct-initialization contexts under
`-fms-extensions` or in HLSL mode.
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 0e32839a77be5..ddde9d48606df 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4945,7 +4945,13 @@ void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef CastEncoding)
const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
Out << CastEncoding;
mangleType(ECE->getType());
- mangleExpression(ECE->getSubExpr());
+ if (const auto *PLIE = dyn_cast<CXXParenListInitExpr>(ECE->getSubExpr())) {
+ ArrayRef<Expr *> Inits = PLIE->getUserSpecifiedInitExprs();
+ assert(Inits.size() == 1 && "cast must have exactly one operand");
+ mangleExpression(Inits.front());
+ } else {
+ mangleExpression(ECE->getSubExpr());
+ }
}
void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) {
@@ -5344,6 +5350,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
E = CCE->arg_end();
I != E; ++I)
mangleExpression(*I);
+ } else if (const auto *PLE = dyn_cast<CXXParenListInitExpr>(Init)) {
+ for (const Expr *Arg : PLE->getUserSpecifiedInitExprs())
+ mangleExpression(Arg);
} else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
mangleExpression(PLE->getExpr(i));
@@ -5770,7 +5779,17 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Sub = CCE->getArg(0)->IgnoreImplicit();
if (auto *StdInitList = dyn_cast<CXXStdInitializerListExpr>(Sub))
Sub = StdInitList->getSubExpr()->IgnoreImplicit();
- if (auto *IL = dyn_cast<InitListExpr>(Sub)) {
+ if (auto *PLIE = dyn_cast<CXXParenListInitExpr>(Sub)) {
+ ArrayRef<Expr *> Inits = PLIE->getUserSpecifiedInitExprs();
+ Out << "cv";
+ mangleType(E->getType());
+ if (Inits.size() != 1)
+ Out << '_';
+ for (const Expr *Init : Inits)
+ mangleExpression(Init);
+ if (Inits.size() != 1)
+ Out << 'E';
+ } else if (auto *IL = dyn_cast<InitListExpr>(Sub)) {
Out << "tl";
mangleType(E->getType());
mangleInitListElements(IL);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0c9a92cdd0c32..ec74102c0ecaf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -489,6 +489,9 @@ bool Sema::DiagnoseInvalidExplicitObjectParameterInLambda(
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
std::optional<CXXRecordDecl::LambdaNumbering> NumberingOverride) {
+ if (Method->getType()->containsErrors())
+ return;
+
ContextRAII ManglingContext(*this, Class->getDeclContext());
auto getMangleNumberingContext =
diff --git a/clang/test/CodeGenCXX/mangle-cxx2a.cpp b/clang/test/CodeGenCXX/mangle-cxx2a.cpp
index 3e4689948a7a7..82dad5cdeb83b 100644
--- a/clang/test/CodeGenCXX/mangle-cxx2a.cpp
+++ b/clang/test/CodeGenCXX/mangle-cxx2a.cpp
@@ -9,3 +9,49 @@ namespace spaceship {
template<typename T> void f(decltype(Y() < X(), T()) x) {}
template void f<int>(int);
}
+
+namespace paren_init {
+ struct A { int a; };
+ struct B { int a, b; };
+ struct D { int a, b = 7; };
+ template <int> struct X {};
+
+ template <int N> void f(X<N + A(1).a>) {}
+ template <int N> void f(X<N + A(2).a>) {}
+
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init1fILi0EEEvNS_1XIXplT_dtcvNS_1AELi1E1aEEE
+ template void f<0>(X<1>);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init1fILi0EEEvNS_1XIXplT_dtcvNS_1AELi2E1aEEE
+ template void f<0>(X<2>);
+
+ template <int N> void c_style(X<N + ((A)1).a>) {}
+ template <int N> void static_style(X<N + static_cast<A>(1).a>) {}
+
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init7c_styleILi0EEEvNS_1XIXplT_dtcvNS_1AELi1E1aEEE
+ template void c_style<0>(X<1>);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init12static_styleILi0EEEvNS_1XIXplT_dtscNS_1AELi1E1aEEE
+ template void static_style<0>(X<1>);
+
+ // Check zero and multiple arguments, and a default member initializer.
+ template <int N> void zero(X<N + A().a>) {}
+ template <int N> void two(X<N + B(1, 2).b>) {}
+ template <int N> void defaulted(X<N + D(1).b>) {}
+
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init4zeroILi0EEEvNS_1XIXplT_dtcvNS_1AE_E1aEEE
+ template void zero<0>(X<0>);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init3twoILi0EEEvNS_1XIXplT_dtcvNS_1BE_Li1ELi2EE1bEEE
+ template void two<0>(X<2>);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init9defaultedILi0EEEvNS_1XIXplT_dtcvNS_1DELi1E1bEEE
+ template void defaulted<0>(X<7>);
+
+ template <int N> void new_zero(decltype((N, new A()))) {}
+ template <int N> void new_one(decltype((N, new A(1)))) {}
+ template <int N> void new_two(decltype((N, new B(1, 2)))) {}
+
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init8new_zeroILi0EEEvDTcmT_nw_NS_1AEpiEE
+ template void new_zero<0>(A *);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init7new_oneILi0EEEvDTcmT_nw_NS_1AEpiLi1EEE
+ template void new_one<0>(A *);
+ // CHECK-LABEL: define {{.*}} @_ZN10paren_init7new_twoILi0EEEvDTcmT_nw_NS_1BEpiLi1ELi2EEE
+ template void new_two<0>(B *);
+}
diff --git a/clang/test/SemaCXX/crash-GH170185.cpp b/clang/test/SemaCXX/crash-GH170185.cpp
new file mode 100644
index 0000000000000..21fb071a1e80f
--- /dev/null
+++ b/clang/test/SemaCXX/crash-GH170185.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+struct Foo; // expected-note 2 {{forward declaration of 'Foo'}}
+
+template <Foo X> // expected-error {{non-type template parameter has incomplete type 'Foo'}}
+struct Arr;
+
+Foo f; // expected-error {{variable has incomplete type 'Foo'}}
+
+void foo() {
+ []() {
+ (void)[&](Arr<f>) {};
+ }();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/232606
More information about the cfe-commits
mailing list