Author: Jens Massberg Date: 2023-06-07T12:56:35+02:00 New Revision: 593a2740f7a499e35f19e64d180d0b8246b52ba3
URL: https://github.com/llvm/llvm-project/commit/593a2740f7a499e35f19e64d180d0b8246b52ba3 DIFF: https://github.com/llvm/llvm-project/commit/593a2740f7a499e35f19e64d180d0b8246b52ba3.diff LOG: [clang] Show error if defaulted comparions operator function is volatile or has ref-qualifier &&. This patch implemed the change proposed in [P2002R1] to 11.11.1 [class.compare.default] paragraph 1. A defaulted compariosn operator function must be non-volatile and must either have no ref-qualifier or the ref-qualifier &. Differential Revision: https://reviews.llvm.org/D148924 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaDeclCXX.cpp clang/test/CXX/class/class.compare/class.compare.default/p1.cpp clang/test/CodeGenCXX/virtual-compare.cpp clang/www/cxx_status.html Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7ec9b3911ad5d..733a003f5321b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -110,6 +110,7 @@ C++20 Feature Support unevaluated contexts will be surfaced as errors. They were previously handled as SFINAE. - Clang now supports `requires cplusplus20` for module maps. +- Implemented missing parts of `P2002R1: Consistent comparison operators <https://wg21.link/P2002R1>`_ C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5895888c175fa..e03e27d196731 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9462,6 +9462,10 @@ def note_defaulted_comparison_not_constexpr_here : Note< def note_in_declaration_of_implicit_equality_comparison : Note< "while declaring the corresponding implicit 'operator==' " "for this defaulted 'operator<=>'">; +def err_volatile_comparison_operator : Error< + "defaulted comparison function must not be volatile">; +def err_ref_qualifier_comparison_operator : Error< + "ref-qualifier '&&' is not allowed on a defaulted comparison operator">; def ext_implicit_exception_spec_mismatch : ExtWarn< "function previously declared with an %select{explicit|implicit}0 exception " diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3169b381071bb..9b3bcc296ddb7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -8582,8 +8582,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // non-template function declared in the member-specification of C that is - // -- a non-static const member of C having one parameter of type - // const C&, or + // -- a non-static const non-volatile member of C having one parameter of + // type const C& and either no ref-qualifier or the ref-qualifier &, or // -- a friend of C having two parameters of type const C& or two // parameters of type C. @@ -8593,6 +8593,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, auto *MD = cast<CXXMethodDecl>(FD); assert(!MD->isStatic() && "comparison function cannot be a static member"); + if (MD->getRefQualifier() == RQ_RValue) { + Diag(MD->getLocation(), diag::err_ref_qualifier_comparison_operator); + + // Remove the ref qualifier to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.RefQualifier = RQ_None; + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + // If we're out-of-class, this is the class we're comparing. if (!RD) RD = MD->getParent(); @@ -8615,6 +8626,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, MD->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); } + + if (MD->isVolatile()) { + Diag(MD->getLocation(), diag::err_volatile_comparison_operator); + + // Remove the 'volatile' from the type to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals.removeVolatile(); + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } } if (FD->getNumParams() != (IsMethod ? 1 : 2)) { diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp index e469e31e1f696..9094d400fd546 100644 --- a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp +++ b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp @@ -15,7 +15,8 @@ struct A { bool operator<(const A&) const; bool operator<=(const A&) const = default; - bool operator==(const A&) const volatile && = default; // surprisingly, OK + bool operator==(const A&) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on a defaulted comparison operator}} + bool operator>=(const A&) const volatile = default; // expected-error {{defaulted comparison function must not be volatile}} bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}} bool operator>=(const B&) const = default; // expected-error-re {{invalid parameter type for defaulted relational comparison operator; found 'const B &', expected 'const A &'{{$}}}} static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}} @@ -195,6 +196,11 @@ struct S6 { friend bool operator==(const S6&, const S6&) = default; // expected-error {{because it was already declared outside}} }; +struct S7 { + bool operator==(S7 const &) const &&; +}; +bool S7::operator==(S7 const &) const && = default; // expected-error {{ref-qualifier '&&' is not allowed on a defaulted comparison operator}} + enum e {}; bool operator==(e, int) = default; // expected-error{{expected class or reference to a constant class}} diff --git a/clang/test/CodeGenCXX/virtual-compare.cpp b/clang/test/CodeGenCXX/virtual-compare.cpp index ef75513ec0fe9..cbb06da3c1492 100644 --- a/clang/test/CodeGenCXX/virtual-compare.cpp +++ b/clang/test/CodeGenCXX/virtual-compare.cpp @@ -21,8 +21,6 @@ struct A : X, Y { virtual std::strong_ordering operator<=>(const A &) const & = default; // CHECK-SAME: @_ZN1A1gEv virtual void g(); - // CHECK-SAME: @_ZNKO1AssERKS_ - virtual std::strong_ordering operator<=>(const A &) const && = default; // CHECK-SAME: @_ZN1A1hEv virtual void h(); @@ -35,9 +33,6 @@ struct A : X, Y { // CHECK-SAME: @_ZNKR1AeqERKS_ // implicit virtual A &operator==(const A&) const & = default; - - // CHECK-SAME: @_ZNKO1AeqERKS_ - // implicit virtual A &operator==(const A&) const && = default; }; // For Y: diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 585b09bcb3751..7300da521da0c 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -532,7 +532,7 @@ <h2 id="cxx20">C++20 implementation status</h2> </tr> <tr> <!-- from Prague --> <td><a href="https://wg21.link/p2002r1">P2002R1</a></td> - <td class="partial" align="center">Partial</td> + <td class="unreleased" align="center">Clang 17</td> </tr> <tr> <td><a href="https://wg21.link/p2085r0">P2085R0</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits