summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp25
-rw-r--r--clang/test/CXX/class/class.compare/class.spaceship/p2.cpp33
3 files changed, 64 insertions, 0 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b7b8c5f17c4..5608e2064b2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8392,6 +8392,12 @@ 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 "
"is not a standard comparison category type">;
+def err_defaulted_comparison_cannot_deduce_undeduced_auto : Error<
+ "return type of defaulted 'operator<=>' cannot be deduced because "
+ "three-way comparison for %select{|member|base class}0 %1 "
+ "has a deduced return type and is not yet defined">;
+def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
+ "%select{|member|base class}0 %1 declared here">;
def note_defaulted_comparison_cannot_deduce_callee : Note<
"selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
def err_incorrect_defaulted_comparison_constexpr : Error<
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 9fa5691983a..19403e05085 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7438,6 +7438,31 @@ private:
if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
if (auto *BestFD = Best->Function) {
+ // If any callee has an undeduced return type, deduce it now.
+ // FIXME: It's not clear how a failure here should be handled. For
+ // now, we produce an eager diagnostic, because that is forward
+ // compatible with most (all?) other reasonable options.
+ if (BestFD->getReturnType()->isUndeducedType() &&
+ S.DeduceReturnType(BestFD, FD->getLocation(),
+ /*Diagnose=*/false)) {
+ // Don't produce a duplicate error when asked to explain why the
+ // comparison is deleted: we diagnosed that when initially checking
+ // the defaulted operator.
+ if (Diagnose == NoDiagnostics) {
+ S.Diag(
+ FD->getLocation(),
+ diag::err_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(
+ Subobj.Loc,
+ diag::note_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_cannot_deduce_callee)
+ << Subobj.Kind << Subobj.Decl;
+ }
+ return Result::deleted();
+ }
if (auto *Info = S.Context.CompCategories.lookupInfoForType(
BestFD->getCallResultType())) {
R.Category = Info->Kind;
diff --git a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
index a912384ccf7..dae31e925ba 100644
--- a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
+++ b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp
@@ -97,6 +97,39 @@ namespace Deduction {
// Check that the above mechanism works.
template void f<std::strong_ordering, weak>(); // expected-note {{instantiation of}}
+
+ std::strong_ordering x = A<strong>() <=> A<strong>();
+}
+
+namespace PR44723 {
+ // Make sure we trigger return type deduction for a callee 'operator<=>'
+ // before inspecting its return type.
+ template<int> struct a {
+ friend constexpr auto operator<=>(a const &lhs, a const &rhs) {
+ return std::strong_ordering::equal;
+ }
+ };
+ struct b {
+ friend constexpr auto operator<=>(b const &, b const &) = default;
+ a<0> m_value;
+ };
+ std::strong_ordering cmp_b = b() <=> b();
+
+ struct c {
+ auto operator<=>(const c&) const&; // expected-note {{selected 'operator<=>' for base class 'c' declared here}}
+ };
+ struct d : c { // expected-note {{base class 'c' declared here}}
+ friend auto operator<=>(const d&, const d&) = default; // #d
+ // expected-error@#d {{return type of defaulted 'operator<=>' cannot be deduced because three-way comparison for base class 'c' has a deduced return type and is not yet defined}}
+ // expected-warning@#d {{implicitly deleted}}
+ };
+ auto c::operator<=>(const c&) const& { // #c
+ return std::strong_ordering::equal;
+ }
+ // expected-error@+1 {{overload resolution selected deleted operator '<=>'}}
+ std::strong_ordering cmp_d = d() <=> d();
+ // expected-note@#c 2{{candidate}}
+ // expected-note@#d {{candidate function has been implicitly deleted}}
}
namespace BadDeducedType {
OpenPOWER on IntegriCloud