[clang] 699da98 - PR51874: Fix diagnostics for defaulted, implicitly deleted 'operator!='.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 15 15:43:16 PDT 2021


Author: Richard Smith
Date: 2021-09-15T15:43:02-07:00
New Revision: 699da98739b0f88c27f75adbe8295c7e1dfd0188

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

LOG: PR51874: Fix diagnostics for defaulted, implicitly deleted 'operator!='.

Don't say we couldn't find an 'operator<=>' when we were actually
looking for an 'operator=='. Also fix a crash when attempting to
diagnose if we select a built-in 'operator!=' in this lookup.

Added: 
    clang/test/CXX/class/class.compare/class.compare.secondary/p2.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 824d9bf469360..cef82aba6c2f1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9156,14 +9156,18 @@ def note_defaulted_comparison_calls_deleted : Note<
   "defaulted %0 is implicitly deleted because it would invoke a deleted "
   "comparison function%select{| for member %2| for base class %2}1">;
 def note_defaulted_comparison_no_viable_function : Note<
-  "defaulted %0 is implicitly deleted because there is no viable three-way "
-  "comparison function for%select{| member| base class}1 %2">;
+  "defaulted %0 is implicitly deleted because there is no viable "
+  "%select{three-way comparison function|'operator=='}1 for "
+  "%select{|member |base class }2%3">;
 def note_defaulted_comparison_no_viable_function_synthesized : Note<
   "three-way comparison cannot be synthesized because there is no viable "
   "function for %select{'=='|'<'}0 comparison">;
 def note_defaulted_comparison_not_rewritten_callee : Note<
   "defaulted %0 is implicitly deleted because this non-rewritten comparison "
   "function would be the best match for the comparison">;
+def note_defaulted_comparison_not_rewritten_conversion : Note<
+  "defaulted %0 is implicitly deleted because a builtin comparison function "
+  "using this conversion would be the best match for the comparison">;
 def note_defaulted_comparison_cannot_deduce : Note<
   "return type of defaulted 'operator<=>' cannot be deduced because "
   "return type %2 of three-way comparison for %select{|member|base class}0 %1 "

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d980869a3b067..ecafab99424fc 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7804,9 +7804,21 @@ class DefaultedComparisonAnalyzer
            DCK == DefaultedComparisonKind::Relational) &&
           !Best->RewriteKind) {
         if (Diagnose == ExplainDeleted) {
-          S.Diag(Best->Function->getLocation(),
-                 diag::note_defaulted_comparison_not_rewritten_callee)
-              << FD;
+          if (Best->Function) {
+            S.Diag(Best->Function->getLocation(),
+                   diag::note_defaulted_comparison_not_rewritten_callee)
+                << FD;
+          } else {
+            assert(Best->Conversions.size() == 2 &&
+                   Best->Conversions[0].isUserDefined() &&
+                   "non-user-defined conversion from class to built-in "
+                   "comparison");
+            S.Diag(Best->Conversions[0]
+                       .UserDefined.FoundConversionFunction.getDecl()
+                       ->getLocation(),
+                   diag::note_defaulted_comparison_not_rewritten_conversion)
+                << FD;
+          }
         }
         return Result::deleted();
       }
@@ -7962,7 +7974,7 @@ class DefaultedComparisonAnalyzer
 
       if (Diagnose == ExplainDeleted) {
         S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function)
-            << FD << Subobj.Kind << Subobj.Decl;
+            << FD << (OO == OO_ExclaimEqual) << Subobj.Kind << Subobj.Decl;
 
         // For a three-way comparison, list both the candidates for the
         // original operator and the candidates for the synthesized operator.

diff  --git a/clang/test/CXX/class/class.compare/class.compare.secondary/p2.cpp b/clang/test/CXX/class/class.compare/class.compare.secondary/p2.cpp
new file mode 100644
index 0000000000000..7226d565b6c3e
--- /dev/null
+++ b/clang/test/CXX/class/class.compare/class.compare.secondary/p2.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+struct A {
+  bool operator!=(const A&) const = default; // expected-warning {{explicitly defaulted equality comparison operator is implicitly deleted}}
+  // expected-note at -1 {{defaulted 'operator!=' is implicitly deleted because there is no viable 'operator==' for 'A'}}
+};
+
+struct Q {};
+bool operator!=(Q, Q); // expected-note {{defaulted 'operator!=' is implicitly deleted because this non-rewritten comparison function would be the best match for the comparison}}
+struct B {
+  operator Q() const;
+  bool operator!=(const B&) const = default; // expected-warning {{explicitly defaulted equality comparison operator is implicitly deleted}}
+};
+
+struct R {};
+bool operator==(R, R);
+struct B2 {
+  operator R() const;
+  bool operator!=(const B2&) const = default; // OK! Converts to use rewritten R comparison.
+};
+
+struct C {
+  operator int() const; // expected-note {{defaulted 'operator!=' is implicitly deleted because a builtin comparison function using this conversion would be the best match for the comparison}}
+  bool operator!=(const C&) const = default; // expected-warning {{explicitly defaulted equality comparison operator is implicitly deleted}}
+};
+
+struct D {
+  bool operator<(const D&) const = default; // expected-warning {{explicitly defaulted relational comparison operator is implicitly deleted}}
+  // expected-note at -1 {{defaulted 'operator<' is implicitly deleted because there is no viable three-way comparison function for 'D'}}
+};
+
+bool operator<(Q, Q); // expected-note {{defaulted 'operator<' is implicitly deleted because this non-rewritten comparison function would be the best match for the comparison}}
+struct E {
+  operator Q() const;
+  bool operator<(const E&) const = default; // expected-warning {{explicitly defaulted relational comparison operator is implicitly deleted}}
+};
+
+int operator<=>(R, R);
+struct E2 {
+  operator R() const;
+  bool operator<(const E2&) const = default;
+};
+
+struct F {
+  operator int() const; // expected-note {{defaulted 'operator<' is implicitly deleted because a builtin comparison function using this conversion would be the best match for the comparison}}
+  bool operator<(const F&) const = default; // expected-warning {{explicitly defaulted relational comparison operator is implicitly deleted}}
+};


        


More information about the cfe-commits mailing list