[clang] 593a274 - [clang] Show error if defaulted comparions operator function is volatile or has ref-qualifier &&.

Jens Massberg via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 7 03:57:38 PDT 2023


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>


        


More information about the cfe-commits mailing list