[clang] 4eb7340 - [Clang][Sema] Fix crash on init-list of array with incomplete element type (#205973)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 01:41:29 PDT 2026
Author: Yuli Fiterman
Date: 2026-06-29T10:41:25+02:00
New Revision: 4eb7340fcb8e644883826335955282dff42fa7ef
URL: https://github.com/llvm/llvm-project/commit/4eb7340fcb8e644883826335955282dff42fa7ef
DIFF: https://github.com/llvm/llvm-project/commit/4eb7340fcb8e644883826335955282dff42fa7ef.diff
LOG: [Clang][Sema] Fix crash on init-list of array with incomplete element type (#205973)
## Summary
Fixes #140685.
clangd (and clang itself, with assertions enabled) crashes on:
```cpp
struct MoveOnly;
void test() {
MoveOnly (&&list)[1] = {};
}
```
with
```
Assertion failed: (CanDeclareSpecialMemberFunction(RD) && "doing special member lookup into record that isn't fully complete"), function LookupSpecialMember, file SemaLookup.cpp
```
The path is `InitListChecker::CheckArrayType` →
`checkDestructorReference` → `LookupDestructor` → `LookupSpecialMember`.
`LookupSpecialMember` asserts that the record is fully defined;
`checkDestructorReference` was not guarding against incomplete records
before calling. Error recovery for init-lists of incomplete element
types reaches this point even after the parser has already diagnosed the
incompleteness, so we hit the assert in any `+asserts` build.
## Fix
One-line guard in `checkDestructorReference`: bail when the record has
no definition. This matches the contract `LookupSpecialMember`'s
assertion enforces (via the static `CanDeclareSpecialMemberFunction`)
and is consistent with how other call sites guard their lookups.
```diff
auto *CXXRD = ElementType->getAsCXXRecordDecl();
- if (!CXXRD)
+ if (!CXXRD || !CXXRD->hasDefinition())
return false;
```
## Test
`clang/test/SemaCXX/init-list-incomplete-dtor-crash.cpp` — minimal
`-verify` test that crashed before, now compiles to the expected
diagnostics. Confirmed it fails (assertion crash) without the fix and
passes with it.
No other regressions in `clang/test/SemaCXX`,
`clang/test/CXX/dcl.decl/dcl.init`, `clang/test/CXX/special`
(pre-existing platform-specific failures unchanged).
## Release note
Added under "Bug Fixes to C++ Support" in `clang/docs/ReleaseNotes.rst`.
---------
Co-authored-by: Corentin Jabot <corentinjabot at gmail.com>
Added:
clang/test/SemaCXX/init-list-incomplete-dtor-crash.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaInit.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 05c28aa069d34..837e86d357129 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -820,6 +820,7 @@ Bug Fixes to C++ Support
- Fixed an issue where Clang incorrectly accepted invalid unqualified uses of local nested class names outside their declaring scope. (#GH184622)
- Fixed a crash when parsing invalid friend declaration with storage-class specifier. (#GH186569)
- Fixed a missing vtable for ``dynamic_cast<FinalClass *>(this)`` in a function template. (#GH198511)
+- Fixed an assertion failure during init-list checking of an array whose element type is an incomplete class. (#GH140685)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 8f685feac4beb..dad9c8c972dd9 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2094,7 +2094,12 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
static bool checkDestructorReference(QualType ElementType, SourceLocation Loc,
Sema &SemaRef) {
auto *CXXRD = ElementType->getAsCXXRecordDecl();
- if (!CXXRD)
+ // Bail out on incomplete record types: a forward-declared class has no
+ // destructor to look up, and `LookupDestructor` (via `LookupSpecialMember`)
+ // asserts that the record is fully defined. Error recovery for init lists
+ // of incomplete element types reaches this point even after the parser has
+ // already diagnosed the incompleteness.
+ if (!CXXRD || !CXXRD->hasDefinition())
return false;
CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
diff --git a/clang/test/SemaCXX/init-list-incomplete-dtor-crash.cpp b/clang/test/SemaCXX/init-list-incomplete-dtor-crash.cpp
new file mode 100644
index 0000000000000..f5ea89a3450a7
--- /dev/null
+++ b/clang/test/SemaCXX/init-list-incomplete-dtor-crash.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+
+// Regression test for https://github.com/llvm/llvm-project/issues/140685
+//
+// List-initialization of an array whose element type is an incomplete
+// (forward-declared) class triggered destructor lookup on the incomplete
+// type, hitting an assertion in Sema::LookupSpecialMember.
+
+namespace gh140685 {
+struct MoveOnly; // expected-note {{forward declaration of 'gh140685::MoveOnly'}}
+
+void test() {
+ MoveOnly(&&list)[1] = {};
+ // expected-error at -1 {{initialization of incomplete type 'MoveOnly'}}
+ // expected-note at -2 {{in implicit initialization of array element 0 with omitted initializer}}
+ // expected-note at -3 {{in initialization of temporary of type 'MoveOnly[1]' created to list-initialize this reference}}
+}
+} // namespace gh140685
More information about the cfe-commits
mailing list