227 lines · cpp
1// RUN: %clang_cc1 -std=c++2a -verify %s2// RUN: %clang_cc1 -std=c++2a -verify %s -DDEFINE_FIRST3 4// As modified by P2002R0:5// The exception specification for a comparison operator function (12.6.2)6// without a noexcept-specifier that is defaulted on its first declaration is7// potentially-throwing if and only if any expression in the implicit8// definition is potentially-throwing.9 10#define CAT2(a, b) a ## b11#define CAT(a, b) CAT2(a, b)12 13#ifdef DEFINE_FIRST14#define DEF(x) auto CAT(a, __LINE__) = x15#else16#define DEF(x)17#endif18 19namespace std {20 struct strong_ordering {21 int n;22 static const strong_ordering equal, less, greater;23 };24 constexpr strong_ordering strong_ordering::equal{0},25 strong_ordering::less{-1}, strong_ordering::greater{1};26 bool operator!=(std::strong_ordering o, int n) noexcept;27}28 29namespace Eq {30 struct A {31 bool operator==(const A&) const = default;32 };33 DEF(A() == A());34 static_assert(noexcept(A() == A()));35 36 struct B {37 bool operator==(const B&) const;38 };39 struct C {40 B b;41 bool operator==(const C&) const = default;42 };43 DEF(C() == C());44 static_assert(!noexcept(C() == C()));45 46 // Ensure we do not trigger odr-use from exception specification computation.47 template<typename T> struct D {48 bool operator==(const D &) const {49 typename T::error error; // expected-error {{no type}}50 }51 };52 struct E {53 D<E> d;54 bool operator==(const E&) const = default;55 };56 static_assert(!noexcept(E() == E()));57 58 // (but we do when defining the function).59 struct F {60 D<F> d;61 bool operator==(const F&) const = default; // expected-note {{in instantiation}}62 };63 bool equal = F() == F();64 static_assert(!noexcept(F() == F()));65}66 67namespace Spaceship {68 struct X {69 friend std::strong_ordering operator<=>(X, X);70 };71 struct Y : X {72 friend std::strong_ordering operator<=>(Y, Y) = default;73 };74 DEF(Y() <=> Y());75 static_assert(!noexcept(Y() <=> Y()));76 77 struct ThrowingCmpCat {78 ThrowingCmpCat(std::strong_ordering);79 operator std::strong_ordering();80 };81 bool operator!=(ThrowingCmpCat o, int n) noexcept;82 83 struct A {84 friend ThrowingCmpCat operator<=>(A, A) noexcept;85 };86 87 struct B {88 A a;89 std::strong_ordering operator<=>(const B&) const = default;90 };91 DEF(B() <=> B());92 static_assert(!noexcept(B() <=> B()));93 94 struct C {95 int n;96 ThrowingCmpCat operator<=>(const C&) const = default;97 };98 DEF(C() <=> C());99 static_assert(!noexcept(C() <=> C()));100 101 struct D {102 int n;103 std::strong_ordering operator<=>(const D&) const = default;104 };105 DEF(D() <=> D());106 static_assert(noexcept(D() <=> D()));107 108 109 struct ThrowingCmpCat2 {110 ThrowingCmpCat2(std::strong_ordering) noexcept;111 operator std::strong_ordering() noexcept;112 };113 bool operator!=(ThrowingCmpCat2 o, int n);114 115 struct E {116 friend ThrowingCmpCat2 operator<=>(E, E) noexcept;117 };118 119 struct F {120 E e;121 std::strong_ordering operator<=>(const F&) const = default;122 };123 DEF(F() <=> F());124 static_assert(noexcept(F() <=> F()));125 126 struct G {127 int n;128 ThrowingCmpCat2 operator<=>(const G&) const = default;129 };130 DEF(G() <=> G());131 static_assert(!noexcept(G() <=> G()));132}133 134namespace Synth {135 struct A {136 friend bool operator==(A, A) noexcept;137 friend bool operator<(A, A) noexcept;138 };139 struct B {140 A a;141 friend std::strong_ordering operator<=>(B, B) = default;142 };143 std::strong_ordering operator<=>(B, B) noexcept;144 145 struct C {146 friend bool operator==(C, C);147 friend bool operator<(C, C) noexcept;148 };149 struct D {150 C c;151 friend std::strong_ordering operator<=>(D, D) = default; // expected-note {{previous}}152 };153 std::strong_ordering operator<=>(D, D) noexcept; // expected-error {{does not match}}154 155 struct E {156 friend bool operator==(E, E) noexcept;157 friend bool operator<(E, E);158 };159 struct F {160 E e;161 friend std::strong_ordering operator<=>(F, F) = default; // expected-note {{previous}}162 };163 std::strong_ordering operator<=>(F, F) noexcept; // expected-error {{does not match}}164}165 166namespace Secondary {167 struct A {168 friend bool operator==(A, A);169 friend bool operator!=(A, A) = default; // expected-note {{previous}}170 171 friend int operator<=>(A, A);172 friend bool operator<(A, A) = default; // expected-note {{previous}}173 friend bool operator<=(A, A) = default; // expected-note {{previous}}174 friend bool operator>(A, A) = default; // expected-note {{previous}}175 friend bool operator>=(A, A) = default; // expected-note {{previous}}176 };177 bool operator!=(A, A) noexcept; // expected-error {{does not match}}178 bool operator<(A, A) noexcept; // expected-error {{does not match}}179 bool operator<=(A, A) noexcept; // expected-error {{does not match}}180 bool operator>(A, A) noexcept; // expected-error {{does not match}}181 bool operator>=(A, A) noexcept; // expected-error {{does not match}}182 183 struct B {184 friend bool operator==(B, B) noexcept;185 friend bool operator!=(B, B) = default;186 187 friend int operator<=>(B, B) noexcept;188 friend bool operator<(B, B) = default;189 friend bool operator<=(B, B) = default;190 friend bool operator>(B, B) = default;191 friend bool operator>=(B, B) = default;192 };193 bool operator!=(B, B) noexcept;194 bool operator<(B, B) noexcept;195 bool operator<=(B, B) noexcept;196 bool operator>(B, B) noexcept;197 bool operator>=(B, B) noexcept;198}199 200// Check that we attempt to define a defaulted comparison before trying to201// compute its exception specification.202namespace DefineBeforeComputingExceptionSpec {203 template<int> struct A {204 A();205 A(const A&) = delete; // expected-note 3{{here}}206 friend bool operator==(A, A); // expected-note 3{{passing}}207 friend bool operator!=(const A&, const A&) = default; // expected-error 3{{call to deleted constructor}}208 };209 210 bool a0 = A<0>() != A<0>(); // expected-note {{in defaulted equality comparison operator}}211 bool a1 = operator!=(A<1>(), A<1>()); // expected-note {{in defaulted equality comparison operator}}212 213 template struct A<2>;214 bool operator!=(const A<2>&, const A<2>&) noexcept; // expected-note {{in evaluation of exception specification}}215 216 template<int> struct B {217 B();218 B(const B&) = delete; // expected-note 3{{here}}219 friend bool operator==(B, B); // expected-note 3{{passing}}220 bool operator!=(const B&) const = default; // expected-error 3{{call to deleted constructor}}221 };222 223 bool b0 = B<0>() != B<0>(); // expected-note {{in defaulted equality comparison operator}}224 bool b1 = B<1>().operator!=(B<1>()); // expected-note {{in defaulted equality comparison operator}}225 int b2 = sizeof(&B<2>::operator!=); // expected-note {{in evaluation of exception specification}}226}227