https://github.com/xakep8 updated https://github.com/llvm/llvm-project/pull/232629
>From c23f661c69466afa760b38e60ebf2c498d0a97d6 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Thu, 15 Oct 2026 20:13:08 +0530 Subject: [PATCH 1/4] [Clang] Fix mangling of parenthesized aggregate initialization Clang was not correctly including the arguments used to initialize a struct with parentheses in the generated symbol name. This could give different template expressions the same symbol name, and some cast forms could crash while being mangled. Used the arguments written in the source when generating the symbol name, including for C-style casts and static_cast. --- clang/docs/ReleaseNotes.md | 5 +++ clang/lib/AST/ItaniumMangle.cpp | 23 +++++++++++-- clang/test/CodeGenCXX/mangle-cxx2a.cpp | 46 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index aba1dba5854fea..0d5ef39c8d6bd7 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 diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0e32839a77be50..ddde9d48606df3 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/test/CodeGenCXX/mangle-cxx2a.cpp b/clang/test/CodeGenCXX/mangle-cxx2a.cpp index 3e4689948a7a7e..82dad5cdeb83b2 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 *); +} >From 3d6ef66dcfc5f8bc1c11168e4d2368d51e8d4e95 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Fri, 16 Oct 2026 11:37:51 +0530 Subject: [PATCH 2/4] [Clang] Avoid numbering lambdas with invalid types While reporting an error, Clang can still create a lambda whose type is invalid. It then tries to assign an internal number to that lambda, which requires processing the invalid type and could crash the compiler. Skipped this numbering step when the lambda type already contains errors. The original source error is still reported without the extra crash. --- clang/docs/ReleaseNotes.md | 3 +++ clang/lib/Sema/SemaLambda.cpp | 3 +++ clang/test/SemaCXX/crash-GH170185.cpp | 14 ++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 clang/test/SemaCXX/crash-GH170185.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 0d5ef39c8d6bd7..3710ab8e36abb6 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -804,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/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 0c9a92cdd0c320..ec74102c0ecaf7 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/SemaCXX/crash-GH170185.cpp b/clang/test/SemaCXX/crash-GH170185.cpp new file mode 100644 index 00000000000000..21fb071a1e80fe --- /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>) {}; + }(); +} >From 40787a24812877373640b553e07dcbaff74a4dc6 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Fri, 16 Oct 2026 15:40:35 +0530 Subject: [PATCH 3/4] [Clang] Move the invalid lambda check before numbering Check the lambda type in ActOnStartOfLambdaDefinition before calling handleLambdaNumbering, instead of handling invalid types inside the numbering function. --- clang/lib/Sema/SemaLambda.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index ec74102c0ecaf7..ec883d2ccb1d12 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -489,9 +489,6 @@ 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 = @@ -1534,7 +1531,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (LangOpts.OpenMP) OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method); - handleLambdaNumbering(Class, Method); + if (!Method->getType()->containsErrors()) + handleLambdaNumbering(Class, Method); for (auto &&C : LSI->Captures) { if (!C.isVariableCapture()) >From 08edccf2774800d746b85966844a78dc77a324ef Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Fri, 16 Oct 2026 12:32:04 +0530 Subject: [PATCH 4/4] [Clang] Fix Incorrect mangling for "new std::initializer_list<int>{1}" --- clang/lib/AST/ItaniumMangle.cpp | 2 ++ clang/test/CodeGenCXX/mangle-exprs.cpp | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index ddde9d48606df3..441aad41edc0d2 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5344,6 +5344,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, else Out << "pi"; const Expr *Init = New->getInitializer(); + if (const auto *SILE = dyn_cast<CXXStdInitializerListExpr>(Init)) + Init = SILE->getSubExpr()->IgnoreImplicit(); if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { // Directly inline the initializers. for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(), diff --git a/clang/test/CodeGenCXX/mangle-exprs.cpp b/clang/test/CodeGenCXX/mangle-exprs.cpp index b75f2cf3607b3f..574cd81952d9ae 100644 --- a/clang/test/CodeGenCXX/mangle-exprs.cpp +++ b/clang/test/CodeGenCXX/mangle-exprs.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Wno-error=return-type -std=c++11 -fclang-abi-compat=latest -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +// RUN: %clang_cc1 -Wno-error=return-type -Wno-dangling-initializer-list -std=c++11 -fclang-abi-compat=latest -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s namespace std { typedef decltype(sizeof(int)) size_t; @@ -212,6 +212,24 @@ namespace test4 { } +namespace new_std_initializer_list { + template <int N> + void empty(decltype((N, new std::initializer_list<int>{}))) {} + + template <int N> + void one(decltype((N, new std::initializer_list<int>{1}))) {} + + template <int N> + void two(decltype((N, new std::initializer_list<int>{1, 2}))) {} + + // CHECK-LABEL: define {{.*}} @_ZN24new_std_initializer_list5emptyILi0EEEvDTcmT_nw_St16initializer_listIiEilEE + template void empty<0>(std::initializer_list<int> *); + // CHECK-LABEL: define {{.*}} @_ZN24new_std_initializer_list3oneILi0EEEvDTcmT_nw_St16initializer_listIiEilLi1EEE + template void one<0>(std::initializer_list<int> *); + // CHECK-LABEL: define {{.*}} @_ZN24new_std_initializer_list3twoILi0EEEvDTcmT_nw_St16initializer_listIiEilLi1ELi2EEE + template void two<0>(std::initializer_list<int> *); +} + namespace test5 { template <typename T> void a(decltype(noexcept(T()))) {} template void a<int>(decltype(noexcept(int()))); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
