diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 25 | ||||
-rw-r--r-- | clang/test/CXX/class/class.compare/class.spaceship/p2.cpp | 33 |
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 { |