https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/220830

>From 5f5f9975d841542f03a475a0a47cb7a30e5e791c Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Thu, 3 Sep 2026 12:45:48 +0530
Subject: [PATCH 1/4] [Clang] Fix assertion on delegating initializer when the
 class is an aggregate

An invalid constructor (e.g. one declared with a ref-qualifier) is ignored
by CXXRecordDecl::addedMember, so the class stays an aggregate. A delegating
initializer such as `a() && : a{} {}` then performs aggregate initialization
and BuildDelegatingInitializer casts the resulting InitListExpr (or a
CXXParenListInitExpr in C++20) to CXXConstructExpr.

Treat a delegation that did not select a constructor as a failed
initialization and go through the existing RecoveryExpr path. The
constructor has already been diagnosed, so no new diagnostic is needed.

Fixes #186650
---
 clang/docs/ReleaseNotes.md      |  4 ++++
 clang/lib/Sema/SemaDeclCXX.cpp  |  7 +++++++
 clang/test/SemaCXX/GH186650.cpp | 20 ++++++++++++++++++++
 3 files changed, 31 insertions(+)
 create mode 100644 clang/test/SemaCXX/GH186650.cpp

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

>From 0be6c444957187fb8dc48f170e1f03d9ec967929 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Thu, 3 Sep 2026 20:50:38 +0530
Subject: [PATCH 2/4] Keep the aggregate initialization instead of clearing it

Now, store the expression Perform built as the delegating
initializer and only teach the assertion that an aggregate can show
up here.
---
 clang/lib/Sema/SemaDeclCXX.cpp | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 7c03684d930fd..d4dabc9178a94 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4775,15 +4775,11 @@ 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()) {
+    // If all user-provided constructors are invalid the class is still an
+    // aggregate, and the delegation is an aggregate initialization instead.
     assert((DelegationInit.get()->containsErrors() ||
+            ClassDecl->isAggregate() ||
             cast<CXXConstructExpr>(DelegationInit.get())->getConstructor()) &&
            "Delegating constructor with no target?");
 

>From 4e3de2957a3b277f7748bb5319772b372dfcf716 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Fri, 18 Sep 2026 19:07:35 +0530
Subject: [PATCH 3/4] Reposition the release notes to avoid the conflicts

---
 clang/docs/ReleaseNotes.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index da42b4d97f6dd..7343f2fd9f509 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -632,6 +632,10 @@ features cannot lower the translation-unit ABI level;
   parsed where a nested-name-specifier could appear (e.g. ``int decltype = 
0;``).
   Clang now diagnoses the error instead of asserting. (#GH211207)
 
+- 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)
+
 - Fixed an assertion failure when a parenthesized structured binding declarator
   was followed by a function declarator and body (e.g. ``([a, b])() {}``).
   (#GH218144, #GH193687)
@@ -724,10 +728,6 @@ features cannot lower the translation-unit ABI level;
 - Fixed an issue where an explicit specialization of a constexpr variable would
   result in a link error. (#GH219796)
 
-- 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

>From a525a90f691f4f8932e5450b6fae1482b52feeb2 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Thu, 8 Oct 2026 15:59:19 +0530
Subject: [PATCH 4/4] Remove the assertion and extend the tests

The assertion only held because an error-recovery escape hatch let the
state through, so it was not guarding an impossible state. Add tests for
a static constructor, an explicit object parameter, and a class whose
constructors are all invalid.
---
 clang/docs/ReleaseNotes.md      |  5 ++---
 clang/lib/Sema/SemaDeclCXX.cpp  |  7 -------
 clang/test/SemaCXX/GH186650.cpp | 19 ++++++++++++++++++-
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index d25ad137a4228..2c82b2f096df3 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -706,9 +706,8 @@ features cannot lower the translation-unit ABI level;
   parsed where a nested-name-specifier could appear (e.g. ``int decltype = 
0;``).
   Clang now diagnoses the error instead of asserting. (#GH211207)
 
-- 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)
+- Fixed a crash when an invalid constructor delegated to its own class and the
+  class had no valid constructors. (#GH186650)
 
 - Fixed an assertion failure when a parenthesized structured binding declarator
   was followed by a function declarator and body (e.g. ``([a, b])() {}``).
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 97370524eac83..c88657d33548f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4802,13 +4802,6 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, 
Expr *Init,
   ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
                                               Args, nullptr);
   if (!DelegationInit.isInvalid()) {
-    // If all user-provided constructors are invalid the class is still an
-    // aggregate, and the delegation is an aggregate initialization instead.
-    assert((DelegationInit.get()->containsErrors() ||
-            ClassDecl->isAggregate() ||
-            cast<CXXConstructExpr>(DelegationInit.get())->getConstructor()) &&
-           "Delegating constructor with no target?");
-
     // C++11 [class.base.init]p7:
     //   The initialization of each base and member constitutes a
     //   full-expression.
diff --git a/clang/test/SemaCXX/GH186650.cpp b/clang/test/SemaCXX/GH186650.cpp
index 24f6b8fb83a14..dececac1595b4 100644
--- a/clang/test/SemaCXX/GH186650.cpp
+++ b/clang/test/SemaCXX/GH186650.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s
 
 // The constructors are invalid, so the classes are still aggregates.
 
@@ -12,9 +12,26 @@ struct B {
   B() const : B{1} {} // expected-error{{'const' qualifier is not allowed on a 
constructor}}
 };
 
+struct S {
+  static S() : S{} {} // expected-error{{constructor cannot be declared 
'static'}}
+};
+
+struct M {
+  int x;
+  M() const : M{1} {} // expected-error{{'const' qualifier is not allowed on a 
constructor}}
+  M(int) volatile : M{} {} // expected-error{{'volatile' qualifier is not 
allowed on a constructor}}
+  static M(int, int) : M{} {} // expected-error{{constructor cannot be 
declared 'static'}}
+};
+
 #if __cplusplus >= 202002L
 struct C {
   int x;
   C() & : C(1) {} // expected-error{{ref-qualifier '&' is not allowed on a 
constructor}}
 };
 #endif
+
+#if __cplusplus >= 202302L
+struct E {
+  E(this E &) : E{} {} // expected-error{{an explicit object parameter cannot 
appear in a constructor}}
+};
+#endif

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

Reply via email to