Skip to content

[Clang] Diagnose defaulted assignment operator with incompatible object parameter #70176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get an example where move assignment fails as well.

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

}