232 lines · cpp
1// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions2 3namespace std {4 struct strong_ordering { // expected-note 6{{candidate}}5 int n;6 constexpr operator int() const { return n; }7 static const strong_ordering less, equal, greater;8 };9 constexpr strong_ordering strong_ordering::less{-1},10 strong_ordering::equal{0}, strong_ordering::greater{1};11 12 struct weak_ordering {13 int n;14 constexpr weak_ordering(int n) : n(n) {}15 constexpr weak_ordering(strong_ordering o) : n(o.n) {}16 constexpr operator int() const { return n; }17 static const weak_ordering less, equivalent, greater;18 };19 constexpr weak_ordering weak_ordering::less{-1},20 weak_ordering::equivalent{0}, weak_ordering::greater{1};21 22 struct partial_ordering {23 double d;24 constexpr partial_ordering(double d) : d(d) {}25 constexpr partial_ordering(strong_ordering o) : d(o.n) {}26 constexpr partial_ordering(weak_ordering o) : d(o.n) {}27 constexpr operator double() const { return d; }28 static const partial_ordering less, equivalent, greater, unordered;29 };30 constexpr partial_ordering partial_ordering::less{-1},31 partial_ordering::equivalent{0}, partial_ordering::greater{1},32 partial_ordering::unordered{__builtin_nan("")};33 34 static_assert(!(partial_ordering::unordered < 0));35 static_assert(!(partial_ordering::unordered == 0));36 static_assert(!(partial_ordering::unordered > 0));37}38 39namespace Deletedness {40 struct A {41 std::strong_ordering operator<=>(const A&) const;42 };43 struct B {44 bool operator==(const B&) const;45 bool operator<(const B&) const;46 };47 struct C {48 std::strong_ordering operator<=>(const C&) const = delete; // expected-note 2{{deleted}}49 };50 struct D1 {51 bool operator==(const D1&) const;52 std::strong_ordering operator<=>(int) const; // expected-note 2{{function not viable}} expected-note 2{{function (with reversed parameter order) not viable}}53 bool operator<(int) const; // expected-note 2{{function not viable}}54 };55 struct D2 {56 bool operator<(const D2&) const;57 std::strong_ordering operator<=>(int) const; // expected-note 2{{function not viable}} expected-note 2{{function (with reversed parameter order) not viable}}58 bool operator==(int) const; // expected-note 2{{function not viable}}59 };60 struct E {61 bool operator==(const E&) const;62 bool operator<(const E&) const = delete; // expected-note 2{{deleted}}63 };64 struct F {65 std::strong_ordering operator<=>(const F&) const; // expected-note 2{{candidate}}66 std::strong_ordering operator<=>(F) const; // expected-note 2{{candidate}}67 };68 struct G1 {69 bool operator==(const G1&) const;70 void operator<(const G1&) const;71 };72 struct G2 {73 void operator==(const G2&) const;74 bool operator<(const G2&) const;75 };76 struct H {77 void operator<=>(const H&) const;78 };79 80 // expected-note@#base {{deleted comparison function for base class 'C'}}81 // expected-note@#base {{no viable three-way comparison function for base class 'D1'}}82 // expected-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}83 // expected-note@#base {{no viable 'operator==' for base class 'D2'}}84 // expected-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}85 // expected-note@#base {{deleted comparison function for base class 'E'}}86 // expected-note@#base {{implied comparison for base class 'F' is ambiguous}}87 template<typename T> struct Cmp : T { // #base88 std::strong_ordering operator<=>(const Cmp&) const = default; // #cmp expected-note 5{{here}}89 };90 91 void use(...);92 void f() {93 use(94 Cmp<A>() <=> Cmp<A>(),95 Cmp<B>() <=> Cmp<B>(),96 Cmp<C>() <=> Cmp<C>(), // expected-error {{deleted}}97 Cmp<D1>() <=> Cmp<D1>(), // expected-error {{deleted}}98 Cmp<D2>() <=> Cmp<D2>(), // expected-error {{deleted}}99 Cmp<E>() <=> Cmp<E>(), // expected-error {{deleted}}100 Cmp<F>() <=> Cmp<F>(), // expected-error {{deleted}}101 // FIXME: The following three errors are not very good.102 // expected-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}103 Cmp<G1>() <=> Cmp<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G1>' first required here}}j104 // expected-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}105 Cmp<G2>() <=> Cmp<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G2>' first required here}}j106 // expected-error@#cmp {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}107 Cmp<H>() <=> Cmp<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}H>' first required here}}j108 0109 );110 }111 112 // expected-note@#arr {{deleted comparison function for member 'arr'}}113 // expected-note@#arr {{no viable three-way comparison function for member 'arr'}}114 // expected-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}115 // expected-note@#arr {{no viable 'operator==' for member 'arr'}}116 // expected-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}117 // expected-note@#arr {{deleted comparison function for member 'arr'}}118 // expected-note@#arr {{implied comparison for member 'arr' is ambiguous}}119 template<typename T> struct CmpArray {120 T arr[3]; // #arr121 std::strong_ordering operator<=>(const CmpArray&) const = default; // #cmparray expected-note 5{{here}}122 };123 void g() {124 use(125 CmpArray<A>() <=> CmpArray<A>(),126 CmpArray<B>() <=> CmpArray<B>(),127 CmpArray<C>() <=> CmpArray<C>(), // expected-error {{deleted}}128 CmpArray<D1>() <=> CmpArray<D1>(), // expected-error {{deleted}}129 CmpArray<D2>() <=> CmpArray<D2>(), // expected-error {{deleted}}130 CmpArray<E>() <=> CmpArray<E>(), // expected-error {{deleted}}131 CmpArray<F>() <=> CmpArray<F>(), // expected-error {{deleted}}132 // FIXME: The following three errors are not very good.133 // expected-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}134 CmpArray<G1>() <=> CmpArray<G1>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G1>' first required here}}j135 // expected-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}136 CmpArray<G2>() <=> CmpArray<G2>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G2>' first required here}}j137 // expected-error@#cmparray {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}138 CmpArray<H>() <=> CmpArray<H>(), // expected-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}H>' first required here}}j139 0140 );141 }142}143 144namespace Access {145 class A {146 std::strong_ordering operator<=>(const A &) const; // expected-note {{here}}147 public:148 bool operator==(const A &) const;149 bool operator<(const A &) const;150 };151 struct B {152 A a; // expected-note {{would invoke a private 'operator<=>'}}153 friend std::strong_ordering operator<=>(const B &, const B &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}154 };155 156 class C {157 std::strong_ordering operator<=>(const C &); // not viable (not const)158 bool operator==(const C &) const; // expected-note {{here}}159 bool operator<(const C &) const;160 };161 struct D {162 C c; // expected-note {{would invoke a private 'operator=='}}163 friend std::strong_ordering operator<=>(const D &, const D &) = default; // expected-warning {{deleted}} expected-note{{replace 'default'}}164 };165}166 167namespace Synthesis {168 enum Result { False, True, Mu };169 170 constexpr bool toBool(Result R) {171 if (R == Mu) throw "should not ask this question";172 return R == True;173 }174 175 struct Val {176 Result equal, less;177 constexpr bool operator==(const Val&) const { return toBool(equal); }178 constexpr bool operator<(const Val&) const { return toBool(less); }179 };180 181 template<typename T> struct Cmp {182 Val val;183 friend T operator<=>(const Cmp&, const Cmp&) = default; // expected-note {{deleted}}184 };185 186 template<typename T> constexpr auto cmp(Result equal, Result less = Mu, Result reverse_less = Mu) {187 return Cmp<T>{equal, less} <=> Cmp<T>{Mu, reverse_less};188 }189 190 static_assert(cmp<std::strong_ordering>(True) == 0);191 static_assert(cmp<std::strong_ordering>(False, True) < 0);192 static_assert(cmp<std::strong_ordering>(False, False) > 0);193 194 static_assert(cmp<std::weak_ordering>(True) == 0);195 static_assert(cmp<std::weak_ordering>(False, True) < 0);196 static_assert(cmp<std::weak_ordering>(False, False) > 0);197 198 static_assert(cmp<std::partial_ordering>(True) == 0);199 static_assert(cmp<std::partial_ordering>(False, True) < 0);200 static_assert(cmp<std::partial_ordering>(False, False, True) > 0);201 static_assert(!(cmp<std::partial_ordering>(False, False, False) > 0));202 static_assert(!(cmp<std::partial_ordering>(False, False, False) == 0));203 static_assert(!(cmp<std::partial_ordering>(False, False, False) < 0));204 205 // No synthesis is performed for a custom return type, even if it can be206 // converted from a standard ordering.207 struct custom_ordering {208 custom_ordering(std::strong_ordering o);209 };210 void f(Cmp<custom_ordering> c) {211 c <=> c; // expected-error {{deleted}}212 }213}214 215namespace Preference {216 struct A {217 A(const A&) = delete; // expected-note {{deleted}}218 // "usable" candidate that can't actually be called219 friend void operator<=>(A, A); // expected-note {{passing}}220 // Callable candidates for synthesis not considered.221 friend bool operator==(A, A);222 friend bool operator<(A, A);223 };224 225 struct B {226 B();227 A a;228 std::strong_ordering operator<=>(const B&) const = default; // expected-error {{call to deleted constructor of 'A'}}229 };230 bool x = B() < B(); // expected-note {{in defaulted three-way comparison operator for 'B' first required here}}231}232