[clang] [Clang] Re-analyze parenthesized aggregate mem-initializers on instantiation (PR #224918)
Akash Manna via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 22 11:48:42 PDT 2026
https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/224918
>From f2bdc5dd3748b3daa0ae401c5276de5b4c0c1455 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Sun, 20 Sep 2026 17:19:35 +0530
Subject: [PATCH 1/2] [Clang] Re-analyze parenthesized aggregate
mem-initializers on instantiation
Since #138518, template instantiation preserves a parenthesized aggregate
initialization as a CXXParenListInitExpr whose elements have been reverted
to their written form, and the consumer is expected to redo the
initialization from them. BuildMemberInitializer still treated the node as
a single argument, so the malformed node was reused as the member's
initializer. This crashed CodeGen for braced-list elements, rejected valid
array members and left union members uninitialized.
Treat a CXXParenListInitExpr like a ParenListExpr in BuildMemberInitializer
and perform the initialization from its user-specified elements.
Fixes #176161
---
clang/docs/ReleaseNotes.md | 4 +++
clang/lib/Sema/SemaDeclCXX.cpp | 4 +++
clang/test/CodeGenCXX/GH176161.cpp | 41 ++++++++++++++++++++++
clang/test/SemaCXX/paren-list-agg-init.cpp | 41 ++++++++++++++++++++++
4 files changed, 90 insertions(+)
create mode 100644 clang/test/CodeGenCXX/GH176161.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52e..5f6e65fdb10a70 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -707,6 +707,10 @@ features cannot lower the translation-unit ABI level;
inside a union caused the union to be treated as a polymorphic class.
(#GH213854)
+- Fixed a crash, a rejected-valid case and a miscompile when instantiating a
+ constructor whose mem-initializer used parenthesized aggregate initialization,
+ e.g. ``: agg({1, 2})`` or ``: arr(1, 2)``. (#GH176161)
+
- Fixed an assertion when a type-trait keyword that had already been made
available as an identifier (e.g. `struct __make_unsigned`) was seen again
in a token that was lexed and cached before the first occurrence was parsed.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 02b4c347dee094..ffd6d6cbf8596c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4685,6 +4685,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs());
} else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
Args = MultiExprArg(InitList->getInits(), InitList->getNumInits());
+ } else if (auto *ParenListInit = dyn_cast<CXXParenListInitExpr>(Init)) {
+ // Template instantiation reverts the elements to their syntactic form;
+ // redo the initialization from the written arguments.
+ Args = ParenListInit->getUserSpecifiedInitExprs();
} else {
// Template instantiation doesn't reconstruct ParenListExprs for us.
Args = Init;
diff --git a/clang/test/CodeGenCXX/GH176161.cpp b/clang/test/CodeGenCXX/GH176161.cpp
new file mode 100644
index 00000000000000..98b1fe4d97340b
--- /dev/null
+++ b/clang/test/CodeGenCXX/GH176161.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -emit-llvm -o - %s | FileCheck %s
+
+template <typename T> struct ConfigFlag { T value; };
+
+struct Tuple {
+ Tuple(ConfigFlag<bool> &&a, ConfigFlag<bool> &&b) : first(a), second(b) {}
+ ConfigFlag<bool> first, second;
+};
+
+struct ConfigSystem {
+ Tuple flags;
+};
+
+template <unsigned R> class M {
+public:
+ M(const int *arr) {
+ auto flagProcessing = [] {
+ struct Configurator {
+ ConfigSystem config;
+ Configurator()
+ : config({ConfigFlag<bool>(true), ConfigFlag<bool>(false)}) {}
+ };
+ Configurator configurator;
+ };
+ flagProcessing();
+ for (unsigned long r = 0; r < R; ++r)
+ m[r] = arr[r];
+ }
+ int m[R];
+};
+
+int main() {
+ int arr[2] = {1, 2};
+ M<2> m(arr);
+}
+
+// CHECK-LABEL: define {{.*}}12ConfiguratorC2Ev(
+// CHECK: store i8 1, ptr
+// CHECK: store i8 0, ptr
+// CHECK: call void @_ZN5TupleC{{[12]}}E
+// CHECK: ret void
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp b/clang/test/SemaCXX/paren-list-agg-init.cpp
index 680fdcdbe7b1ce..90414dbd5a78fd 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -425,3 +425,44 @@ void test() {
}
}
+
+namespace GH176161 {
+struct Inner {
+ constexpr Inner(int a, int b) : x(a), y(b) {}
+ int x, y;
+};
+struct Agg {
+ Inner i;
+ int k = 7;
+};
+
+template <class T> struct S {
+ Agg a;
+ constexpr S() : a({1, 2}) {} // beforecxx20-warning 2{{C++20 extension}}
+};
+
+constexpr S<int> s; // beforecxx20-note {{requested here}}
+static_assert(s.a.i.x == 1);
+static_assert(s.a.i.y == 2);
+static_assert(s.a.k == 7);
+
+struct X {
+ constexpr X() : v(5) {}
+ constexpr X(int v) : v(v) {}
+ int v;
+};
+template <class T> struct Arr {
+ X arr[3];
+ constexpr Arr() : arr(1, 2) {} // beforecxx20-warning 2{{C++20 extension}}
+};
+constexpr Arr<int> arr; // beforecxx20-note {{requested here}}
+static_assert(arr.arr[0].v == 1 && arr.arr[1].v == 2 && arr.arr[2].v == 5);
+
+union U { int a; float b; };
+template <class T> struct Un {
+ U u;
+ constexpr Un() : u('a') {} // beforecxx20-warning 2{{C++20 extension}}
+};
+constexpr Un<int> un; // beforecxx20-note {{requested here}}
+static_assert(un.u.a == 'a');
+}
>From 5392ae9c73f49d9047950966f501f97d7284d7c9 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Wed, 23 Sep 2026 00:17:40 +0530
Subject: [PATCH 2/2] [Clang] Re-analyze parenthesized aggregate
mem-initializers on instantiation
Since #138518, template instantiation preserves a parenthesized aggregate
initialization as a CXXParenListInitExpr whose elements have been reverted
to their written form, and the consumer is expected to redo the
initialization from them. BuildMemberInitializer still treated the node as
a single argument, so the malformed node was reused as the member's
initializer. This crashed CodeGen for braced-list elements, dropped the
conversions of scalar elements, rejected valid array members and left
union members uninitialized.
Treat a CXXParenListInitExpr like a ParenListExpr in BuildMemberInitializer
and perform the initialization from its user-specified elements.
Fixes #176161
Fixes #189005
Fixes #213284
---
clang/docs/ReleaseNotes.md | 4 ++--
clang/test/CodeGenCXX/GH176161.cpp | 12 ++++++++++++
clang/test/SemaCXX/paren-list-agg-init.cpp | 11 +++++++++++
3 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 5f6e65fdb10a70..65c51853009deb 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -707,9 +707,9 @@ features cannot lower the translation-unit ABI level;
inside a union caused the union to be treated as a polymorphic class.
(#GH213854)
-- Fixed a crash, a rejected-valid case and a miscompile when instantiating a
+- Fixed a crash, a miscompile and a rejected-valid case when instantiating a
constructor whose mem-initializer used parenthesized aggregate initialization,
- e.g. ``: agg({1, 2})`` or ``: arr(1, 2)``. (#GH176161)
+ e.g. ``: agg({1, 2})`` or ``: arr(1, 2)``. (#GH176161, #GH189005, #GH213284)
- Fixed an assertion when a type-trait keyword that had already been made
available as an identifier (e.g. `struct __make_unsigned`) was seen again
diff --git a/clang/test/CodeGenCXX/GH176161.cpp b/clang/test/CodeGenCXX/GH176161.cpp
index 98b1fe4d97340b..d175b4d58dc249 100644
--- a/clang/test/CodeGenCXX/GH176161.cpp
+++ b/clang/test/CodeGenCXX/GH176161.cpp
@@ -39,3 +39,15 @@ int main() {
// CHECK: store i8 0, ptr
// CHECK: call void @_ZN5TupleC{{[12]}}E
// CHECK: ret void
+
+namespace GH213284 {
+struct Ref { unsigned long long bits; };
+template <typename> struct Result {
+ Result() : thing(0) {}
+ Ref thing;
+};
+Result<void> construct() { return Result<void>(); }
+}
+
+// CHECK-LABEL: define {{.*}}@_ZN8GH2132846ResultIvEC2Ev(
+// CHECK: store i64 0, ptr
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp b/clang/test/SemaCXX/paren-list-agg-init.cpp
index 90414dbd5a78fd..01e8e7638141f6 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -466,3 +466,14 @@ template <class T> struct Un {
constexpr Un<int> un; // beforecxx20-note {{requested here}}
static_assert(un.u.a == 'a');
}
+
+namespace GH189005 {
+struct Elem { int x; };
+struct Outer { Elem arr[2]; };
+template <class T> struct Nested {
+ Outer m;
+ constexpr Nested() : m({{1}, {2}}) {} // beforecxx20-warning 2{{C++20 extension}}
+};
+constexpr Nested<int> n; // beforecxx20-note {{requested here}}
+static_assert(n.m.arr[0].x == 1 && n.m.arr[1].x == 2);
+}
More information about the cfe-commits
mailing list