https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/70176
>From 9b559ac5504593ab7aa21539b49ece7eea944eb5 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 25 Oct 2023 10:08:24 +0200 Subject: [PATCH 1/3] [Clang] Diagnose defaulted assignment operator with incompatible object parameter. Per https://eel.is/c++draft/dcl.fct.def.default#2.2, the explicit object parameter of a defaulted special member function must be of the same type as the one of an equivalent implicitly defaulted function, ignoring references. Fixes #69233 --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Sema/SemaDeclCXX.cpp | 19 ++++++++++++ clang/test/SemaCXX/cxx2b-deducing-this.cpp | 31 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a673ce726d6c220..6e138683334c2c3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9481,6 +9481,9 @@ def err_defaulted_special_member_return_type : Error< def err_defaulted_special_member_quals : Error< "an explicitly-defaulted %select{copy|move}0 assignment operator may not " "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; +def err_defaulted_special_member_explicit_object_mismatch : Error< + "the type of the explicit object parameter of an explicitly-defaulted " + "%select{copy|move}0 assignment operator should match the type of the class %1">; def err_defaulted_special_member_volatile_param : Error< "the parameter for an explicitly-defaulted %sub{select_special_member_kind}0 " "may not be volatile">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a3f68d4ffc0f6ec..957171b75ba4958 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7748,6 +7748,25 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, HadError = true; } } + // [C++23][dcl.fct.def.default]/p2.2 + // if F2 has an implicit object parameter of type “reference to C”, + // F1 may be an explicit object member function whose explicit object + // parameter is of (possibly different) type “reference to C”, + // in which case the type of F1 would differ from the type of F2 + // in that the type of F1 has an additional parameter; + if (!Context.hasSameType( + ThisType.getNonReferenceType().getUnqualifiedType(), + Context.getRecordType(RD))) { + if (DeleteOnTypeMismatch) + ShouldDeleteForTypeMismatch = true; + else { + Diag(MD->getLocation(), + diag::err_defaulted_special_member_explicit_object_mismatch) + << (CSM == CXXMoveAssignment) << RD + << MD->getSourceRange(); + HadError = true; + } + } } // Check for parameter type matching. diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 535381e876da9c7..f9e73b41e2c330f 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -585,3 +585,34 @@ class Server : public Thing { S name_; }; } + +namespace GH69233 { +struct Base {}; +struct S : Base { + int j; + S& operator=(this Base& self, const S&) = default; + // expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} + // expected-note@-2 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}} + // expected-note@-3 {{explicitly defaulted function was implicitly deleted here}} +}; + +struct S2 { + S2& operator=(this int&& self, const S2&); + S2& operator=(this int&& self, S2&&); + operator int(); +}; + +S2& S2::operator=(this int&& self, const S2&) = default; +// expected-error@-1 {{the type of the explicit object parameter of an explicitly-defaulted copy assignment operator should match the type of the class 'S2'}} + +S2& S2::operator=(this int&& self, S2&&) = default; +// expected-error@-1 {{the type of the explicit object parameter of an explicitly-defaulted move assignment operator should match the type of the class 'S2'}} + +void test() { + S s; + s = s; // expected-error {{object of type 'S' cannot be assigned because its copy assignment operator is implicitly deleted}} + S2 s2; + s2 = s2; +} + +} >From e5f681590232af81edddc764b749ad644e1ef0b4 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 26 Oct 2023 15:48:15 +0200 Subject: [PATCH 2/3] add source range --- clang/lib/Sema/SemaDeclCXX.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 957171b75ba4958..beb7e5b177c6e9a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7762,8 +7762,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, else { Diag(MD->getLocation(), diag::err_defaulted_special_member_explicit_object_mismatch) - << (CSM == CXXMoveAssignment) << RD - << MD->getSourceRange(); + << (CSM == CXXMoveAssignment) << RD << MD->getSourceRange(); HadError = true; } } >From 77049d5a6fff1b9529850f1ac5a3ab651004896b Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Sat, 28 Oct 2023 15:02:46 +0200 Subject: [PATCH 3/3] Add tests for move. Note that if there is an invalid move constructor, overload resolution will try to pick a copy constructor instead. --- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index f9e73b41e2c330f..0033541fa322dc4 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -608,11 +608,21 @@ S2& S2::operator=(this int&& self, const S2&) = default; S2& S2::operator=(this int&& self, S2&&) = default; // expected-error@-1 {{the type of the explicit object parameter of an explicitly-defaulted move assignment operator should match the type of the class 'S2'}} +struct Move { + Move& operator=(this int&, Move&&) = default; + // expected-warning@-1 {{explicitly defaulted move assignment operator is implicitly deleted}} + // expected-note@-2 {{function is implicitly deleted because its declared type does not match the type of an implicit move assignment operator}} + // expected-note@-3 {{copy assignment operator is implicitly deleted because 'Move' has a user-declared move assignment operator}} +}; + void test() { S s; s = s; // expected-error {{object of type 'S' cannot be assigned because its copy assignment operator is implicitly deleted}} S2 s2; s2 = s2; + + Move m; + m = Move{}; // expected-error {{object of type 'Move' cannot be assigned because its copy assignment operator is implicitly deleted}} } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits