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@-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@-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}} +}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits