[clang] [Clang] Fix assertion on delegating initializer when the class is an aggregate (PR #220830)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 3 03:56:06 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->186650

`struct a { a() && : a{} {} };` trips an assertion in `BuildDelegatingInitializer`. The ref-qualifier makes the constructor invalid, and `CXXRecordDecl::addedMember` ignores invalid declarations, so as far as the class is concerned it has no user-declared constructor and is still an aggregate. The delegating initializer therefore goes through plain aggregate initialization and comes back as an `InitListExpr`, which the `cast<CXXConstructExpr>` in the assert rejects. The same happens with C++20 parenthesized aggregate init, where `C() & : C(1) {}` produces a `CXXParenListInitExpr`. Nothing to do with the truncated file in the report, by the way; the complete one-liner crashes just the same.

A delegating initializer has to resolve to a constructor call, and aggregate initialization is only possible here when the class has no valid user-provided constructor, which means the one being defined was already diagnosed. So if the initialization succeeds without producing a `CXXConstructExpr`, treat it as a failed delegation and let the existing recovery path wrap the arguments in a `RecoveryExpr`. No new diagnostic, there is already one on the constructor. The test covers the braced and the parenthesized forms in C++11 and C++20 mode.

---
Full diff: https://github.com/llvm/llvm-project/pull/220830.diff


3 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+4) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+7) 
- (added) clang/test/SemaCXX/GH186650.cpp (+20) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4c2bf55f6ebdd..492aa0bd37159 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -610,6 +610,10 @@ features cannot lower the translation-unit ABI level;
   in a token that was lexed and cached before the first occurrence was parsed.
   (#GH214128)
 
+- Fixed an assertion when an invalid constructor (e.g. one declared with a
+  ref-qualifier) delegated to its own class and the class had no other
+  constructors, as in `struct A { A() && : A{} {} };`. (#GH186650)
+
 #### 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 4e90c496de342..7c03684d930fd 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4775,6 +4775,13 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
   InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args);
   ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
                                               Args, nullptr);
+
+  // Aggregate initialization here means the class has no valid user-provided
+  // constructor, so the one being defined has already been diagnosed.
+  if (DelegationInit.isUsable() && !DelegationInit.get()->containsErrors() &&
+      !isa<CXXConstructExpr>(DelegationInit.get()))
+    DelegationInit = ExprError();
+
   if (!DelegationInit.isInvalid()) {
     assert((DelegationInit.get()->containsErrors() ||
             cast<CXXConstructExpr>(DelegationInit.get())->getConstructor()) &&
diff --git a/clang/test/SemaCXX/GH186650.cpp b/clang/test/SemaCXX/GH186650.cpp
new file mode 100644
index 0000000000000..24f6b8fb83a14
--- /dev/null
+++ b/clang/test/SemaCXX/GH186650.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+// The constructors are invalid, so the classes are still aggregates.
+
+struct A {
+  A() && : A{} {} // expected-error{{ref-qualifier '&&' is not allowed on a constructor}}
+};
+
+struct B {
+  int x;
+  B() const : B{1} {} // expected-error{{'const' qualifier is not allowed on a constructor}}
+};
+
+#if __cplusplus >= 202002L
+struct C {
+  int x;
+  C() & : C(1) {} // expected-error{{ref-qualifier '&' is not allowed on a constructor}}
+};
+#endif

``````````

</details>


https://github.com/llvm/llvm-project/pull/220830


More information about the cfe-commits mailing list