-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesPer 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 Full diff: https://github.com/llvm/llvm-project/pull/70176.diff 3 Files Affected:
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..35554fca5776f2c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7748,6 +7748,21 @@ 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;
+ 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;
+}
+
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
441f247
to
6fd05ad
Compare
clang/lib/Sema/SemaDeclCXX.cpp
Outdated
else { | ||
Diag(MD->getLocation(), | ||
diag::err_defaulted_special_member_explicit_object_mismatch) | ||
<< (CSM == CXXMoveAssignment) << RD; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a useful source range we can supply here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you have in mind? the first parameter? I am not sure how useful it is though - we certainly don't do it for other warnings here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing specific. In line 7709 above, we pass MD->getSourceRange()
.
9277312
to
e5f6815
Compare
|
||
void test() { | ||
S s; | ||
s = s; // expected-error {{object of type 'S' cannot be assigned because its copy assignment operator is implicitly deleted}} |
There was a problem hiding this comment.
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.
I could use an explanation as to how they must be the same type when 2.2 says "...may be an explicit object member function whose explicit object parameter is of (possibly different) type “reference to C”, in which case..." |
That wording is terrible, but it's hard to phrase it better. Ie it can be either I had a chat with core on mattermost and there is agreement that the wording could be made clearer editorially. |
Thank you for the explanation! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM though something seems to be amiss with precommit CI and so it might be nice to get a clean run of that before landing (I don't insist).
…ct 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 llvm#69233
Note that if there is an invalid move constructor, overload resolution will try to pick a copy constructor instead.
77049d5
to
a4a51f2
Compare
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