[clang] [Clang] Handle CXXParenListInitExpr in BuildMemberInitializer (#213284, #189005) (PR #213565)

via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 2 11:45:08 PDT 2026


https://github.com/babadany2999 created https://github.com/llvm/llvm-project/pull/213565

### Summary
Fixes a miscompilation (#213284) and an assertion crash / ICE (#189005) when template instantiation performs C++20 parenthesized aggregate member initialization.

Fixes #213284

Fixes #189005

### Root Cause
When instantiating a template class constructor containing C++20 parenthesized aggregate member initializers (e.g., `Result() : thing(0) {}` or `S() : m({{1}, {2}}) {}`), template instantiation creates a `CXXParenListInitExpr` AST node for the initializer.

In `Sema::BuildMemberInitializer`, the `if-else` chain checked for `ParenListExpr` and `InitListExpr`, but omitted `CXXParenListInitExpr`. Consequently, Clang fell through to `else { Args = Init; }`, treating the entire `CXXParenListInitExpr` object as a single untyped initializer expression rather than extracting its inner member initializer expressions (`CXXList->getInitExprs()`).

This caused aggregate member matching during template instantiation to fail, leading to integer argument truncation (`store i32` instead of `store i64`) in #213284 and a segfault in `AggExprEmitter::VisitCXXParenListOrInitListExpr` in #189005.

### Solution
Added `else-if` block checking for `CXXParenListInitExpr` in `clang/lib/Sema/SemaDeclCXX.cpp` to extract inner initialization expressions.

### Test Plan
- Added two regression tests, one (`clang/test/CodeGen/gh189005.cpp`) fixing #189005, and another (`clang/test/CodeGen/gh213284.cpp`) fixing #213284.
- Verified tests pass cleanly across `clang/test/Sema` and `clang/test/CodeGen`.
- Added two release notes to `clang/docs/ReleaseNotes.md` under *Bug Fixes to C++ Support*.

### Notes
- I believe the testing suite `clang/test/CodeGen/gh213284.cpp` may be better suited to live in `clang/test/Sema`, but I am unsure.

>From ae2110d956bd0575a80d96ef6bea3e7b6152ab6c Mon Sep 17 00:00:00 2001
From: Baba Dan Constantin <babadany2999 at gmail.com>
Date: Sun, 2 Aug 2026 21:14:49 +0300
Subject: [PATCH] [Clang] Fix a bug and a miscompilation codegen for
 parenthesized aggregate initialization

Fixes #GH213284

Fixes #GH189005
---
 clang/docs/ReleaseNotes.md      |  6 ++
 clang/lib/Sema/SemaDeclCXX.cpp  |  2 +
 clang/test/CodeGen/gh189005.cpp | 99 +++++++++++++++++++++++++++++++++
 clang/test/CodeGen/gh213284.cpp | 17 ++++++
 4 files changed, 124 insertions(+)
 create mode 100644 clang/test/CodeGen/gh189005.cpp
 create mode 100644 clang/test/CodeGen/gh213284.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a38b99ff8e075..ba95d6aff619b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -424,6 +424,12 @@ features cannot lower the translation-unit ABI level;
   copy so the union's object representation is copied, matching the defaulted
   union copy constructor.
 
+- Fixed a miscompile where C++20 parenthesized aggregate initialization generated
+  invalid LLVM IR. (GH#213284)
+
+- Fixed a crash when compiling C++20 parenthesized aggregate initialization in
+  template constructor member initializers. (GH#189005)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 47b01b913b428..6202470cb13c6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4657,6 +4657,8 @@ 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 (CXXParenListInitExpr *CXXInitList = dyn_cast<CXXParenListInitExpr>(Init)) {
+    Args = CXXInitList->getInitExprs();
   } else {
     // Template instantiation doesn't reconstruct ParenListExprs for us.
     Args = Init;
diff --git a/clang/test/CodeGen/gh189005.cpp b/clang/test/CodeGen/gh189005.cpp
new file mode 100644
index 0000000000000..1252e803ad394
--- /dev/null
+++ b/clang/test/CodeGen/gh189005.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o -
+
+namespace std {
+
+template <typename T1, typename T2>
+struct pair {
+	T1 first;
+	T2 second;
+
+	// Constructor needed so this reproduces the std::array<std::pair>
+	// initialization from the original report.
+	constexpr
+	pair(const T1& a, const T2& b)
+	: first(a), second(b)
+	{}
+};
+
+template <typename T, unsigned long N>
+struct array {
+	T elems[N];
+};
+} // namespace std
+
+// Nested aggregate containing an array of aggregates.
+struct Inner {
+  int x;
+};
+
+struct Outer {
+	Inner arr[2];
+};
+
+template <typename T>
+struct S {
+	S() : m({{1}, {2}}) {}
+	Outer m;
+};
+
+template struct S<int>;
+
+// std::array<std::pair>-style initialization.
+template <typename T>
+struct S2 {
+	S2() : a({{1, 2}}) {}
+	std::array<std::pair<int, int>, 1> a;
+};
+
+template struct S2<int>;
+
+// Designated initializer.
+struct Point {
+	int x;
+	int y;
+};
+
+struct Config {
+	Point x;
+};
+
+template <typename T>
+struct Designated {
+	Designated() : cfg({.x = 10, .y = 5}) {}
+	Config cfg;
+};
+
+template struct Designated<int>;
+
+// String literal initializer.
+// Not affected by this fix, but kept as a regression
+// for another aggregate initialization path.
+struct Buffer {
+	char data[10];
+};
+
+template <typename T>
+struct String {
+	String() : buf("hello") {}
+	Buffer buf;
+};
+
+template struct String<int>;
+
+// Parenthesized aggregate with multiple arguments.
+struct First {
+	int x;
+};
+
+struct Second {
+	First a;
+	int y;
+};
+
+template <typename T>
+struct Nested {
+	Nested() : sec({1}, 2) {}
+	Second sec;
+};
+
+template struct Nested<int>;
diff --git a/clang/test/CodeGen/gh213284.cpp b/clang/test/CodeGen/gh213284.cpp
new file mode 100644
index 0000000000000..7e875bb9d616e
--- /dev/null
+++ b/clang/test/CodeGen/gh213284.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+
+struct Ref {
+  unsigned long long bits;
+};
+
+template <typename>
+struct Result {
+  Result() : thing(0) {}
+  Ref thing;
+};
+
+Result<void> construct() {
+  return Result<void>();
+}
+// CHECK-LABEL: define {{.*}}construct
+// CHECK: store i64 0



More information about the cfe-commits mailing list