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 <[email protected]>

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@-1 {{initialization of incomplete type 'MoveOnly'}}
+  // expected-note@-2 {{in implicit initialization of array element 0 with 
omitted initializer}}
+  // expected-note@-3 {{in initialization of temporary of type 'MoveOnly[1]' 
created to list-initialize this reference}}
+}
+} // namespace gh140685


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

Reply via email to