// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu #include "Inputs/std-compare.h" namespace std { struct type_info; }; namespace ThreeWayComparison { struct A { int n; constexpr friend int operator<=>(const A &a, const A &b) { return a.n < b.n ? -1 : a.n > b.n ? 1 : 0; } }; static_assert(A{1} <=> A{2} < 0); static_assert(A{2} <=> A{1} > 0); static_assert(A{2} <=> A{2} == 0); static_assert(1 <=> 2 < 0); static_assert(2 <=> 1 > 0); static_assert(1 <=> 1 == 0); constexpr int k = (1 <=> 1, 0); // expected-warning@-1 {{three-way comparison result unused}} static_assert(std::strong_ordering::equal == 0); constexpr void f() { void(1 <=> 1); } struct MemPtr { void foo() {} void bar() {} int data; int data2; long data3; }; struct MemPtr2 { void foo() {} void bar() {} int data; int data2; long data3; }; using MemPtrT = void (MemPtr::*)(); using FnPtrT = void (*)(); void FnPtr1() {} void FnPtr2() {} #define CHECK(...) ((__VA_ARGS__) ? void() : throw "error") #define CHECK_TYPE(...) static_assert(__is_same(__VA_ARGS__)); constexpr bool test_constexpr_success = [] { { auto &EQ = std::strong_ordering::equal; auto &LESS = std::strong_ordering::less; auto &GREATER = std::strong_ordering::greater; using SO = std::strong_ordering; auto eq = (42 <=> 42); CHECK_TYPE(decltype(eq), SO); CHECK(eq.test_eq(EQ)); auto less = (-1 <=> 0); CHECK_TYPE(decltype(less), SO); CHECK(less.test_eq(LESS)); auto greater = (42l <=> 1u); CHECK_TYPE(decltype(greater), SO); CHECK(greater.test_eq(GREATER)); } { using PO = std::partial_ordering; auto EQUIV = PO::equivalent; auto LESS = PO::less; auto GREATER = PO::greater; auto eq = (42.0 <=> 42.0); CHECK_TYPE(decltype(eq), PO); CHECK(eq.test_eq(EQUIV)); auto less = (39.0 <=> 42.0); CHECK_TYPE(decltype(less), PO); CHECK(less.test_eq(LESS)); auto greater = (-10.123 <=> -101.1); CHECK_TYPE(decltype(greater), PO); CHECK(greater.test_eq(GREATER)); } { using SE = std::strong_equality; auto EQ = SE::equal; auto NEQ = SE::nonequal; MemPtrT P1 = &MemPtr::foo; MemPtrT P12 = &MemPtr::foo; MemPtrT P2 = &MemPtr::bar; MemPtrT P3 = nullptr; auto eq = (P1 <=> P12); CHECK_TYPE(decltype(eq), SE); CHECK(eq.test_eq(EQ)); auto neq = (P1 <=> P2); CHECK_TYPE(decltype(eq), SE); CHECK(neq.test_eq(NEQ)); auto eq2 = (P3 <=> nullptr); CHECK_TYPE(decltype(eq2), SE); CHECK(eq2.test_eq(EQ)); } { using SE = std::strong_equality; auto EQ = SE::equal; auto NEQ = SE::nonequal; FnPtrT F1 = &FnPtr1; FnPtrT F12 = &FnPtr1; FnPtrT F2 = &FnPtr2; FnPtrT F3 = nullptr; auto eq = (F1 <=> F12); CHECK_TYPE(decltype(eq), SE); CHECK(eq.test_eq(EQ)); auto neq = (F1 <=> F2); CHECK_TYPE(decltype(neq), SE); CHECK(neq.test_eq(NEQ)); } { // mixed nullptr tests using SO = std::strong_ordering; using SE = std::strong_equality; int x = 42; int *xp = &x; MemPtrT mf = nullptr; MemPtrT mf2 = &MemPtr::foo; auto r3 = (mf <=> nullptr); CHECK_TYPE(decltype(r3), std::strong_equality); CHECK(r3.test_eq(SE::equal)); } return true; }(); template constexpr bool test_constexpr() { using nullptr_t = decltype(nullptr); using LHSTy = decltype(LHS); using RHSTy = decltype(RHS); // expected-note@+1 {{subexpression not valid in a constant expression}} auto Res = (LHS <=> RHS); if constexpr (__is_same(LHSTy, nullptr_t) || __is_same(RHSTy, nullptr_t)) { CHECK_TYPE(decltype(Res), std::strong_equality); } if (ExpectTrue) return Res == 0; return Res != 0; } int dummy = 42; int dummy2 = 101; constexpr bool tc1 = test_constexpr(); constexpr bool tc2 = test_constexpr<&dummy, nullptr>(); // OK, equality comparison only constexpr bool tc3 = test_constexpr<&MemPtr::foo, nullptr>(); constexpr bool tc4 = test_constexpr(); constexpr bool tc5 = test_constexpr<&MemPtr::foo, &MemPtr::bar>(); constexpr bool tc6 = test_constexpr<&MemPtr::data, nullptr>(); constexpr bool tc7 = test_constexpr(); constexpr bool tc8 = test_constexpr<&MemPtr::data, &MemPtr::data2>(); // expected-error@+1 {{must be initialized by a constant expression}} constexpr bool tc9 = test_constexpr<&dummy, &dummy2>(); // expected-note {{in call}} template constexpr T makeComplex(R r, I i) { T res{r, i}; return res; }; template constexpr bool complex_test(T x, T y, ResultT Expect) { auto res = x <=> y; CHECK_TYPE(decltype(res), ResultT); return res.test_eq(Expect); } static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), makeComplex<_Complex double>(0.0, 0.0), std::weak_equality::equivalent)); static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), makeComplex<_Complex double>(1.0, 0.0), std::weak_equality::nonequivalent)); static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0), makeComplex<_Complex double>(0.0, 1.0), std::weak_equality::nonequivalent)); static_assert(complex_test(makeComplex<_Complex int>(0, 0), makeComplex<_Complex int>(0, 0), std::strong_equality::equal)); static_assert(complex_test(makeComplex<_Complex int>(0, 0), makeComplex<_Complex int>(1, 0), std::strong_equality::nonequal)); // TODO: defaulted operator <=> } // namespace ThreeWayComparison constexpr bool for_range_init() { int k = 0; for (int arr[3] = {1, 2, 3}; int n : arr) k += n; return k == 6; } static_assert(for_range_init()); namespace Virtual { struct NonZeroOffset { int padding = 123; }; // Ensure that we pick the right final overrider during construction. struct A { virtual constexpr char f() const { return 'A'; } char a = f(); }; struct NoOverrideA : A {}; struct B : NonZeroOffset, NoOverrideA { virtual constexpr char f() const { return 'B'; } char b = f(); }; struct NoOverrideB : B {}; struct C : NonZeroOffset, A { virtual constexpr char f() const { return 'C'; } A *pba; char c = ((A*)this)->f(); char ba = pba->f(); constexpr C(A *pba) : pba(pba) {} }; struct D : NonZeroOffset, NoOverrideB, C { // expected-warning {{inaccessible}} virtual constexpr char f() const { return 'D'; } char d = f(); constexpr D() : C((B*)this) {} }; constexpr D d; static_assert(((B&)d).a == 'A'); static_assert(((C&)d).a == 'A'); static_assert(d.b == 'B'); static_assert(d.c == 'C'); // During the construction of C, the dynamic type of B's A is B. static_assert(d.ba == 'B'); static_assert(d.d == 'D'); static_assert(d.f() == 'D'); constexpr const A &a = (B&)d; constexpr const B &b = d; static_assert(a.f() == 'D'); static_assert(b.f() == 'D'); // FIXME: It is unclear whether this should be permitted. D d_not_constexpr; static_assert(d_not_constexpr.f() == 'D'); // expected-error {{constant expression}} expected-note {{virtual function called on object 'd_not_constexpr' whose dynamic type is not constant}} // Check that we apply a proper adjustment for a covariant return type. struct Covariant1 { D d; virtual const A *f() const; }; template struct Covariant2 : Covariant1 { virtual const T *f() const; }; template struct Covariant3 : Covariant2 { constexpr virtual const D *f() const { return &this->d; } }; constexpr Covariant3 cb; constexpr Covariant3 cc; constexpr const Covariant1 *cb1 = &cb; constexpr const Covariant2 *cb2 = &cb; static_assert(cb1->f()->a == 'A'); static_assert(cb1->f() == (B*)&cb.d); static_assert(cb1->f()->f() == 'D'); static_assert(cb2->f()->b == 'B'); static_assert(cb2->f() == &cb.d); static_assert(cb2->f()->f() == 'D'); constexpr const Covariant1 *cc1 = &cc; constexpr const Covariant2 *cc2 = &cc; static_assert(cc1->f()->a == 'A'); static_assert(cc1->f() == (C*)&cc.d); static_assert(cc1->f()->f() == 'D'); static_assert(cc2->f()->c == 'C'); static_assert(cc2->f() == &cc.d); static_assert(cc2->f()->f() == 'D'); static_assert(cb.f()->d == 'D'); static_assert(cc.f()->d == 'D'); struct Abstract { constexpr virtual void f() = 0; // expected-note {{declared here}} constexpr Abstract() { do_it(); } // expected-note {{in call to}} constexpr void do_it() { f(); } // expected-note {{pure virtual function 'Virtual::Abstract::f' called}} }; struct PureVirtualCall : Abstract { void f(); }; // expected-note {{in call to 'Abstract}} constexpr PureVirtualCall pure_virtual_call; // expected-error {{constant expression}} expected-note {{in call to 'PureVirtualCall}} } namespace DynamicCast { struct A2 { virtual void a2(); }; struct A : A2 { virtual void a(); }; struct B : A {}; struct C2 { virtual void c2(); }; struct C : A, C2 { A *c = dynamic_cast(static_cast(this)); }; struct D { virtual void d(); }; struct E { virtual void e(); }; struct F : B, C, D, private E { void *f = dynamic_cast(static_cast(this)); }; struct Padding { virtual void padding(); }; struct G : Padding, F {}; constexpr G g; // During construction of C, A is unambiguous subobject of dynamic type C. static_assert(g.c == (C*)&g); // ... but in the complete object, the same is not true, so the runtime fails. static_assert(dynamic_cast(static_cast(&g)) == nullptr); // dynamic_cast produces a pointer to the object of the dynamic type. static_assert(g.f == (void*)(F*)&g); static_assert(dynamic_cast(static_cast(&g)) == &g); // expected-note@+1 {{reference dynamic_cast failed: 'DynamicCast::A' is an ambiguous base class of dynamic type 'DynamicCast::G' of operand}} constexpr int d_a = (dynamic_cast(static_cast(g)), 0); // expected-error {{}} // Can navigate from A2 to its A... static_assert(&dynamic_cast((A2&)(B&)g) == &(A&)(B&)g); // ... and from B to its A ... static_assert(&dynamic_cast((B&)g) == &(A&)(B&)g); // ... but not from D. // expected-note@+1 {{reference dynamic_cast failed: 'DynamicCast::A' is an ambiguous base class of dynamic type 'DynamicCast::G' of operand}} static_assert(&dynamic_cast((D&)g) == &(A&)(B&)g); // expected-error {{}} // Can cast from A2 to sibling class D. static_assert(&dynamic_cast((A2&)(B&)g) == &(D&)g); // Cannot cast from private base E to derived class F. // expected-note@+1 {{reference dynamic_cast failed: static type 'DynamicCast::E' of operand is a non-public base class of dynamic type 'DynamicCast::G'}} constexpr int e_f = (dynamic_cast((E&)g), 0); // expected-error {{}} // Cannot cast from B to private sibling E. // expected-note@+1 {{reference dynamic_cast failed: 'DynamicCast::E' is a non-public base class of dynamic type 'DynamicCast::G' of operand}} constexpr int b_e = (dynamic_cast((B&)g), 0); // expected-error {{}} struct Unrelated { virtual void unrelated(); }; // expected-note@+1 {{reference dynamic_cast failed: dynamic type 'DynamicCast::G' of operand does not have a base class of type 'DynamicCast::Unrelated'}} constexpr int b_unrelated = (dynamic_cast((B&)g), 0); // expected-error {{}} // expected-note@+1 {{reference dynamic_cast failed: dynamic type 'DynamicCast::G' of operand does not have a base class of type 'DynamicCast::Unrelated'}} constexpr int e_unrelated = (dynamic_cast((E&)g), 0); // expected-error {{}} } namespace TypeId { struct A { const std::type_info &ti = typeid(*this); }; struct A2 : A {}; static_assert(&A().ti == &typeid(A)); static_assert(&typeid((A2())) == &typeid(A2)); extern A2 extern_a2; static_assert(&typeid(extern_a2) == &typeid(A2)); constexpr A2 a2; constexpr const A &a1 = a2; static_assert(&typeid(a1) == &typeid(A)); struct B { virtual void f(); const std::type_info &ti1 = typeid(*this); }; struct B2 : B { const std::type_info &ti2 = typeid(*this); }; static_assert(&B2().ti1 == &typeid(B)); static_assert(&B2().ti2 == &typeid(B2)); extern B2 extern_b2; // expected-note@+1 {{typeid applied to object 'extern_b2' whose dynamic type is not constant}} static_assert(&typeid(extern_b2) == &typeid(B2)); // expected-error {{constant expression}} constexpr B2 b2; constexpr const B &b1 = b2; static_assert(&typeid(b1) == &typeid(B2)); constexpr bool side_effects() { // Not polymorphic nor a glvalue. bool OK = true; (void)typeid(OK = false, A2()); // expected-warning {{has no effect}} if (!OK) return false; // Not polymorphic. A2 a2; (void)typeid(OK = false, a2); // expected-warning {{has no effect}} if (!OK) return false; // Not a glvalue. (void)typeid(OK = false, B2()); // expected-warning {{has no effect}} if (!OK) return false; // Polymorphic glvalue: operand evaluated. OK = false; B2 b2; (void)typeid(OK = true, b2); // expected-warning {{will be evaluated}} return OK; } static_assert(side_effects()); } namespace TwosComplementShifts { using uint32 = __UINT32_TYPE__; using int32 = __INT32_TYPE__; static_assert(uint32(int32(0x1234) << 16) == 0x12340000); static_assert(uint32(int32(0x1234) << 19) == 0x91a00000); static_assert(uint32(int32(0x1234) << 20) == 0x23400000); // expected-warning {{requires 34 bits}} static_assert(uint32(int32(0x1234) << 24) == 0x34000000); // expected-warning {{requires 38 bits}} static_assert(uint32(int32(-1) << 31) == 0x80000000); static_assert(-1 >> 1 == -1); static_assert(-1 >> 31 == -1); static_assert(-2 >> 1 == -1); static_assert(-3 >> 1 == -2); static_assert(-4 >> 1 == -2); }