[clang] [Clang] Diagnose defaulted assignment operator with incompatible object parameter (PR #70176)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 28 06:06:14 PDT 2023
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 <corentinjabot at 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 at -1 {{explicitly defaulted copy assignment operator is implicitly deleted}}
+ // expected-note at -2 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}}
+ // expected-note at -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 at -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 at -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 <corentinjabot at 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 <corentinjabot at 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 at -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 at -1 {{explicitly defaulted move assignment operator is implicitly deleted}}
+ // expected-note at -2 {{function is implicitly deleted because its declared type does not match the type of an implicit move assignment operator}}
+ // expected-note at -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}}
}
}
More information about the cfe-commits
mailing list