[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