[clang] ffe6129 - [c++20] Implement P1946R0: allow defaulted comparisons to take their

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 10 19:55:12 PST 2019


Author: Richard Smith
Date: 2019-12-10T19:54:35-08:00
New Revision: ffe612922cb5aa2767c79d47a1b162811a08583f

URL: https://github.com/llvm/llvm-project/commit/ffe612922cb5aa2767c79d47a1b162811a08583f
DIFF: https://github.com/llvm/llvm-project/commit/ffe612922cb5aa2767c79d47a1b162811a08583f.diff

LOG: [c++20] Implement P1946R0: allow defaulted comparisons to take their
arguments by value.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
    clang/test/CXX/class/class.compare/class.eq/p3.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4eec4b066ae5..423ccbd293d2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8194,7 +8194,10 @@ def err_defaulted_comparison_out_of_class : Error<
   "definition">;
 def err_defaulted_comparison_param : Error<
   "invalid parameter type for defaulted %sub{select_defaulted_comparison_kind}0"
-  "%
diff {; found $, expected $|}1,2">;
+  "; found %1, expected %2%select{| or %4}3">;
+def err_defaulted_comparison_param_mismatch : Error<
+  "parameters for defaulted %sub{select_defaulted_comparison_kind}0 "
+  "must have the same type%
diff { (found $ vs $)|}1,2">;
 def err_defaulted_comparison_non_const : Error<
   "defaulted member %sub{select_defaulted_comparison_kind}0 must be "
   "const-qualified">;

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 365286097699..5373bb422ad6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7921,22 +7921,41 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
   //   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 friend of C having two parameters of type const C&.
-  QualType ExpectedParmType =
-      Context.getLValueReferenceType(Context.getRecordType(RD).withConst());
+  //    -- a friend of C having two parameters of type const C& or two
+  //       parameters of type C.
+  QualType ExpectedParmType1 = Context.getRecordType(RD);
+  QualType ExpectedParmType2 =
+      Context.getLValueReferenceType(ExpectedParmType1.withConst());
+  if (isa<CXXMethodDecl>(FD))
+    ExpectedParmType1 = ExpectedParmType2;
   for (const ParmVarDecl *Param : FD->parameters()) {
     if (!Param->getType()->isDependentType() &&
-        !Context.hasSameType(Param->getType(), ExpectedParmType)) {
+        !Context.hasSameType(Param->getType(), ExpectedParmType1) &&
+        !Context.hasSameType(Param->getType(), ExpectedParmType2)) {
       // Don't diagnose an implicit 'operator=='; we will have diagnosed the
       // corresponding defaulted 'operator<=>' already.
       if (!FD->isImplicit()) {
         Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
-            << (int)DCK << Param->getType() << ExpectedParmType
-            << Param->getSourceRange();
+            << (int)DCK << Param->getType() << ExpectedParmType1
+            << !isa<CXXMethodDecl>(FD)
+            << ExpectedParmType2 << Param->getSourceRange();
       }
       return true;
     }
   }
+  if (FD->getNumParams() == 2 &&
+      !Context.hasSameType(FD->getParamDecl(0)->getType(),
+                           FD->getParamDecl(1)->getType())) {
+    if (!FD->isImplicit()) {
+      Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch)
+          << (int)DCK
+          << FD->getParamDecl(0)->getType()
+          << FD->getParamDecl(0)->getSourceRange()
+          << FD->getParamDecl(1)->getType()
+          << FD->getParamDecl(1)->getSourceRange();
+    }
+    return true;
+  }
 
   // ... non-static const member ...
   if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {

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 a73b34870769..1a0ccc91741b 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
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++2a -verify %s
 
 struct B {};
-bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}}
+bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}} expected-note {{candidate}}
 bool operator<=>(const B&, const B&) = default; // expected-error {{three-way comparison operator can only be defaulted in a class definition}}
 
 template<typename T = void>
@@ -9,18 +9,19 @@ template<typename T = void>
 
 struct A {
   friend bool operator==(const A&, const A&) = default;
-  friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
+  friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison operator; found 'const B &', expected 'A' or 'const A &'}}
   friend bool operator!=(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
   friend bool operator<(const A&, const A&);
   friend bool operator<(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
-  friend bool operator>(A, A) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
+  friend bool operator>(A, A) = default; // expected-warning {{implicitly deleted}}
 
   bool operator<(const A&) const;
   bool operator<=(const A&) const = default;
   bool operator==(const A&) const volatile && = default; // surprisingly, OK
   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 {{invalid parameter type for defaulted relational comparison}}
+  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}}
+  friend bool operator>(A, const A&) = default; // expected-error {{must have the same type}} expected-note {{would be the best match}}
 
   template<typename T = void>
     friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}}
@@ -120,3 +121,14 @@ namespace LookupContext {
     }
   }
 }
+
+namespace P1946 {
+  struct A {
+    friend bool operator==(A &, A &); // expected-note {{would lose const qualifier}}
+  };
+  struct B {
+    A a; // expected-note {{no viable comparison}}
+    friend bool operator==(B, B) = default; // ok
+    friend bool operator==(const B&, const B&) = default; // expected-warning {{deleted}}
+  };
+}

diff  --git a/clang/test/CXX/class/class.compare/class.eq/p3.cpp b/clang/test/CXX/class/class.compare/class.eq/p3.cpp
index a7356b5381cd..04db022fe730 100644
--- a/clang/test/CXX/class/class.compare/class.eq/p3.cpp
+++ b/clang/test/CXX/class/class.compare/class.eq/p3.cpp
@@ -11,3 +11,15 @@ static_assert(A{1, 2, 3, 4, 5} == A{1, 0, 3, 4, 5}); // expected-error {{failed}
 static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 0, 4, 5}); // expected-error {{failed}}
 static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 3, 0, 5}); // expected-error {{failed}}
 static_assert(A{1, 2, 3, 4, 5} == A{1, 2, 3, 4, 0}); // expected-error {{failed}}
+
+struct B {
+  int a, b[3], c;
+  friend bool operator==(B, B) = default;
+};
+
+static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 4, 5});
+static_assert(B{1, 2, 3, 4, 5} == B{0, 2, 3, 4, 5}); // expected-error {{failed}}
+static_assert(B{1, 2, 3, 4, 5} == B{1, 0, 3, 4, 5}); // expected-error {{failed}}
+static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 0, 4, 5}); // expected-error {{failed}}
+static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 0, 5}); // expected-error {{failed}}
+static_assert(B{1, 2, 3, 4, 5} == B{1, 2, 3, 4, 0}); // expected-error {{failed}}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index f8dbc840763c..2d5a7a32f4a3 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -938,7 +938,7 @@ <h2 id="cxx20">C++2a implementation status</h2>
       </tr>
       <tr> <!-- from Kona 2019 -->
         <td><a href="https://wg21.link/p1185r2">P1185R2</a></td>
-        <td rowspan="3" class="svn" align="center">SVN</td>
+        <td rowspan="4" class="svn" align="center">SVN</td>
       </tr>
       <tr> <!-- from Cologne -->
         <td><a href="https://wg21.link/p1186r3">P1186R3</a></td>
@@ -948,7 +948,6 @@ <h2 id="cxx20">C++2a implementation status</h2>
       </tr>
       <tr> <!-- from Belfast -->
         <td><a href="https://wg21.link/p1946r0">P1946R0</a></td>
-        <td rowspan="2" class="none" align="center">No</td>
       </tr>
       <tr>
         <td><a href="https://wg21.link/p1959r0">P1959R0</a></td>


        


More information about the cfe-commits mailing list