Skip to content

Commit

Permalink
[Clang] Diagnose defaulted assignment operator with incompatible obje…
Browse files Browse the repository at this point in the history
…ct parameter (#70176)

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
  • Loading branch information
cor3ntin committed Oct 30, 2023
1 parent 6a62707 commit 273ceb1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -9483,6 +9483,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">;
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7748,6 +7748,24 @@ 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.
Expand Down
41 changes: 41 additions & 0 deletions clang/test/SemaCXX/cxx2b-deducing-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,44 @@ 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'}}

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}}
}

}

0 comments on commit 273ceb1

Please sign in to comment.