https://github.com/kodlan updated 
https://github.com/llvm/llvm-project/pull/221488

>From c7b363325cff0c485db311cbb9eeeaab5c120c36 Mon Sep 17 00:00:00 2001
From: Stanislav Bardyuk <[email protected]>
Date: Sat, 5 Sep 2026 19:46:42 +0000
Subject: [PATCH 1/3] [Clang] Complete the element type when list-initializing
 an array of unknown bound

List-initializing a temporary array of unknown bound from an empty
initializer list creates a zero-length array whose elements are never
initialized, so nothing ever completes the element type. If that type is
a class template specialization that has not been instantiated yet (or a
forward-declared class), the destructor lookup for the temporary in
MaybeBindToTemporary runs on a record without a definition and trips the
CanDeclareSpecialMemberFunction assertion in LookupSpecialMember.

TryListInitialization already requires a record destination type to be
complete. Extend that check to the base element type of an incomplete
array destination, mirroring what TryListConversion does in overload
resolution. The specialization gets instantiated and the program is
accepted (as with GCC); a forward-declared element type is now diagnosed
as an incomplete type instead of crashing.

Fixes #217883
---
 clang/docs/ReleaseNotes.md                    |  4 +++
 clang/lib/Sema/SemaInit.cpp                   | 12 +++++--
 ...-list-unbound-array-incomplete-element.cpp | 35 +++++++++++++++++++
 3 files changed, 48 insertions(+), 3 deletions(-)
 create mode 100644 
clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a43ed2b924622..06830897083e2 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -641,6 +641,10 @@ features cannot lower the translation-unit ABI level;
   (#GH214128)
 - Fixed a crash when a coroutine keyword appeared inside a mem-initializer on a
   function that is not a constructor. (#GH194298)
+- Fixed a crash when list-initializing an array of unknown bound from an empty
+  initializer list whose element type is an uninstantiated class template
+  specialization or an incomplete class; the element type is now completed
+  first. (#GH217883)
 
 #### Bug Fixes to AST Handling
 
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 48ce51863c2c0..064f3080a6915 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5053,9 +5053,15 @@ static void TryListInitialization(Sema &S,
     return;
   }
 
-  if (DestType->isRecordType() &&
-      !S.isCompleteType(InitList->getBeginLoc(), DestType)) {
-    Sequence.setIncompleteTypeFailure(DestType);
+  // For an array of unknown bound (C++20), the base element type must be
+  // complete: an empty list creates a zero-length array whose elements are
+  // never initialized, so nothing else would complete it.
+  QualType InitTy = DestType;
+  if (const auto *IAT = S.Context.getAsIncompleteArrayType(DestType))
+    InitTy = S.Context.getBaseElementType(IAT);
+  if (InitTy->isRecordType() &&
+      !S.isCompleteType(InitList->getBeginLoc(), InitTy)) {
+    Sequence.setIncompleteTypeFailure(InitTy);
     return;
   }
 
diff --git a/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp 
b/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp
new file mode 100644
index 0000000000000..7970570c5eea2
--- /dev/null
+++ b/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+// List-initializing a temporary array of unknown bound from an empty list
+// creates a zero-length array whose element type was never completed, and
+// destructor lookup on the uninstantiated (or forward-declared) element type
+// crashed. https://github.com/llvm/llvm-project/issues/217883
+
+namespace gh217883 {
+template <typename> struct Q {};
+
+const Q<int> (&r1)[] = {};
+Q<int> (&&r2)[] = {};
+const Q<int> (&r3)[][2] = {};
+
+void call(void (*f)(const Q<int> (&)[])) { f({}); }
+void call_rvalue(void (*f)(Q<int> (&&)[])) { f({}); }
+void call_nested(void (*f)(const Q<int> (&)[][2])) { f({}); }
+
+#if __cplusplus >= 202002L
+static_assert(requires(void f(const Q<int> (&)[])) { f({}); });
+#endif
+
+template <typename> struct DeletedDtor { ~DeletedDtor() = delete; }; // 
expected-note {{marked deleted here}}
+void call_deleted(void (*f)(const DeletedDtor<int> (&)[])) {
+  f({}); // expected-error {{attempt to use a deleted function}}
+}
+
+struct Incomplete; // expected-note 3 {{forward declaration of 
'gh217883::Incomplete'}}
+const Incomplete (&r4)[] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
+const Incomplete (&r5)[][2] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
+void call_incomplete(void (*f)(const Incomplete (&)[])) {
+  f({}); // expected-error {{initialization of incomplete type 'const 
Incomplete'}}
+}
+} // namespace gh217883

>From 52364996ba37eda2ecbda2fe66253f6261607d84 Mon Sep 17 00:00:00 2001
From: Stanislav Bardyuk <[email protected]>
Date: Mon, 7 Sep 2026 20:40:08 +0200
Subject: [PATCH 2/3] Update clang/docs/ReleaseNotes.md

Co-authored-by: Shengxin Pei <[email protected]>
---
 clang/docs/ReleaseNotes.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 06830897083e2..5bc1fdb124d30 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -643,8 +643,7 @@ features cannot lower the translation-unit ABI level;
   function that is not a constructor. (#GH194298)
 - Fixed a crash when list-initializing an array of unknown bound from an empty
   initializer list whose element type is an uninstantiated class template
-  specialization or an incomplete class; the element type is now completed
-  first. (#GH217883)
+  specialization or an incomplete class. (#GH217883)
 
 #### Bug Fixes to AST Handling
 

>From a99bb2dde9ad29c89939c08e753d245c9f0af3c5 Mon Sep 17 00:00:00 2001
From: Stanislav Bardyuk <[email protected]>
Date: Mon, 7 Sep 2026 19:00:29 +0000
Subject: [PATCH 3/3] [Clang] Move the GH217883 tests into
 cxx20-p0388-unbound-ary.cpp

---
 .../test/SemaCXX/cxx20-p0388-unbound-ary.cpp  | 28 +++++++++++++++
 ...-list-unbound-array-incomplete-element.cpp | 35 -------------------
 2 files changed, 28 insertions(+), 35 deletions(-)
 delete mode 100644 
clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp

diff --git a/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp 
b/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
index f2d5cabad235d..7ac0204e612b0 100644
--- a/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
+++ b/clang/test/SemaCXX/cxx20-p0388-unbound-ary.cpp
@@ -171,3 +171,31 @@ void g3() {
 } // namespace Eight
 
 #endif
+
+namespace gh217883 {
+template <typename> struct Q {};
+
+const Q<int> (&r1)[] = {};
+Q<int> (&&r2)[] = {};
+const Q<int> (&r3)[][2] = {};
+
+void call(void (*f)(const Q<int> (&)[])) { f({}); }
+void call_rvalue(void (*f)(Q<int> (&&)[])) { f({}); }
+void call_nested(void (*f)(const Q<int> (&)[][2])) { f({}); }
+
+#if __cplusplus >= 202002
+static_assert(requires(void f(const Q<int> (&)[])) { f({}); });
+#endif
+
+template <typename> struct DeletedDtor { ~DeletedDtor() = delete; }; // 
expected-note {{marked deleted here}}
+void call_deleted(void (*f)(const DeletedDtor<int> (&)[])) {
+  f({}); // expected-error {{attempt to use a deleted function}}
+}
+
+struct Incomplete; // expected-note 3 {{forward declaration of 
'gh217883::Incomplete'}}
+const Incomplete (&r4)[] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
+const Incomplete (&r5)[][2] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
+void call_incomplete(void (*f)(const Incomplete (&)[])) {
+  f({}); // expected-error {{initialization of incomplete type 'const 
Incomplete'}}
+}
+} // namespace gh217883
diff --git a/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp 
b/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp
deleted file mode 100644
index 7970570c5eea2..0000000000000
--- a/clang/test/SemaCXX/init-list-unbound-array-incomplete-element.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-
-// List-initializing a temporary array of unknown bound from an empty list
-// creates a zero-length array whose element type was never completed, and
-// destructor lookup on the uninstantiated (or forward-declared) element type
-// crashed. https://github.com/llvm/llvm-project/issues/217883
-
-namespace gh217883 {
-template <typename> struct Q {};
-
-const Q<int> (&r1)[] = {};
-Q<int> (&&r2)[] = {};
-const Q<int> (&r3)[][2] = {};
-
-void call(void (*f)(const Q<int> (&)[])) { f({}); }
-void call_rvalue(void (*f)(Q<int> (&&)[])) { f({}); }
-void call_nested(void (*f)(const Q<int> (&)[][2])) { f({}); }
-
-#if __cplusplus >= 202002L
-static_assert(requires(void f(const Q<int> (&)[])) { f({}); });
-#endif
-
-template <typename> struct DeletedDtor { ~DeletedDtor() = delete; }; // 
expected-note {{marked deleted here}}
-void call_deleted(void (*f)(const DeletedDtor<int> (&)[])) {
-  f({}); // expected-error {{attempt to use a deleted function}}
-}
-
-struct Incomplete; // expected-note 3 {{forward declaration of 
'gh217883::Incomplete'}}
-const Incomplete (&r4)[] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
-const Incomplete (&r5)[][2] = {}; // expected-error {{initialization of 
incomplete type 'const Incomplete'}}
-void call_incomplete(void (*f)(const Incomplete (&)[])) {
-  f({}); // expected-error {{initialization of incomplete type 'const 
Incomplete'}}
-}
-} // namespace gh217883

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to