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
