[clang] [clang] Fix C++20 list initialization of const references to arrays of unknown bound (PR #218225)
Ahmed Zihan Hossain via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 30 09:38:56 PDT 2026
https://github.com/zihan001 updated https://github.com/llvm/llvm-project/pull/218225
>From 6ecd1ceff6a64d60bbe296ee1f079690b15a4778 Mon Sep 17 00:00:00 2001
From: Zihan <zihanhossain99 at gmail.com>
Date: Sun, 23 Aug 2026 03:50:18 -0600
Subject: [PATCH] [clang] Fix C++20 list initialization of const references to
arrays of unknown bound
The existing C++20 handling for arrays of unknown bound only covered
rvalue references. Const lvalue references could reach CodeGen with a
mismatched argument type and hit an assertion.
Handle both reference kinds and preserve the correct value category.
Fixes #215501.
Assisted-by: Claude Code
Assisted-by: ChatGPT
---
clang/docs/ReleaseNotes.md | 3 +++
clang/lib/Sema/SemaInit.cpp | 13 ++++++++-----
.../CodeGenCXX/cxx20-p0388-unbound-ary.cpp | 18 ++++++++++++++++++
clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp | 15 +++++++++++++++
4 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bdbabf2cd98d0..896c5dce9ece5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -551,6 +551,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 when passing a braced initializer list to a const reference
+ to an array of unknown bound in C++20. (#GH215501)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 48ce51863c2c0..e66d75419d2be 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5004,8 +5004,7 @@ static void TryReferenceListInitialization(Sema &S,
Sequence.AddReferenceBindingStep(cv1T1IgnoreAS,
/*BindingTemporary=*/true);
if (S.getLangOpts().CPlusPlus20 &&
- isa<IncompleteArrayType>(T1->getUnqualifiedDesugaredType()) &&
- DestType->isRValueReferenceType()) {
+ isa<IncompleteArrayType>(T1->getUnqualifiedDesugaredType())) {
// C++20 [dcl.init.list]p3.10:
// List-initialization of an object or reference of type T is defined as
// follows:
@@ -5013,9 +5012,13 @@ static void TryReferenceListInitialization(Sema &S,
// case the type of the prvalue is the type of x in the declaration U
// x[] H, where H is the initializer list.
- // The call to AddReferenceBindingStep above converts the rvalue to an
- // xvalue. Convert that xvalue to the incomplete array type.
- Sequence.AddQualificationConversionStep(cv1T1, clang::VK_XValue);
+ // The prvalue described above is the initializer-list result and
+ // already has the deduced bound. The preceding reference-binding
+ // step materializes it, so this conversion operates on a glvalue.
+ // Convert it to the incomplete array type while preserving its
+ // value category.
+ Sequence.AddQualificationConversionStep(
+ cv1T1, DestType->isRValueReferenceType() ? VK_XValue : VK_LValue);
}
if (T1Quals.hasAddressSpace())
Sequence.AddQualificationConversionStep(
diff --git a/clang/test/CodeGenCXX/cxx20-p0388-unbound-ary.cpp b/clang/test/CodeGenCXX/cxx20-p0388-unbound-ary.cpp
index 007b47c441b2f..ac39e1b6d2e13 100644
--- a/clang/test/CodeGenCXX/cxx20-p0388-unbound-ary.cpp
+++ b/clang/test/CodeGenCXX/cxx20-p0388-unbound-ary.cpp
@@ -48,3 +48,21 @@ void gh151716_f() {
}
} // namespace One
+
+namespace Two {
+
+void unknownBoundArrayRef(const int (&)[]);
+
+// CHECK-LABEL: @_ZN3Two8gh215501Ev
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %ref.tmp = alloca [3 x i32], align 4
+// CHECK: store i32 1, ptr %ref.tmp, align 4
+// CHECK: store i32 2, ptr %arrayinit.element, align 4
+// CHECK: store i32 3, ptr %arrayinit.element1, align 4
+// CHECK: call void @_ZN3Two20unknownBoundArrayRefERA_Ki(ptr noundef nonnull align 4 %ref.tmp)
+// CHECK: ret void
+void gh215501() {
+ unknownBoundArrayRef({1, 2, 3});
+}
+
+} // namespace Two
diff --git a/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp b/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
index f2d5cabad235d..5ab71db861c71 100644
--- a/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
+++ b/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
@@ -170,4 +170,19 @@ void g3() {
} // namespace Eight
+namespace Nine {
+// A const lvalue reference binds to the materialized temporary, a non-const
+// lvalue reference does not.
+void f(const int (&)[]);
+void g() {
+ f({1, 2, 3});
+}
+
+void h() {
+ int(&r)[] = {1, 2, 3};
+ // expected-error at -1{{cannot bind to an initializer list temporary}}
+}
+
+} // namespace Nine
+
#endif
More information about the cfe-commits
mailing list