Clang Project

clang_source_code/test/SemaCXX/constant-expression-cxx2a.cpp
1// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
2
3#include "Inputs/std-compare.h"
4
5namespace ThreeWayComparison {
6  struct A {
7    int n;
8    constexpr friend int operator<=>(const A &a, const A &b) {
9      return a.n < b.n ? -1 : a.n > b.n ? 1 : 0;
10    }
11  };
12  static_assert(A{1} <=> A{2} < 0);
13  static_assert(A{2} <=> A{1} > 0);
14  static_assert(A{2} <=> A{2} == 0);
15
16  static_assert(1 <=> 2 < 0);
17  static_assert(2 <=> 1 > 0);
18  static_assert(1 <=> 1 == 0);
19  constexpr int k = (1 <=> 1, 0);
20  // expected-warning@-1 {{three-way comparison result unused}}
21
22  static_assert(std::strong_ordering::equal == 0);
23
24  constexpr void f() {
25    void(1 <=> 1);
26  }
27
28  struct MemPtr {
29    void foo() {}
30    void bar() {}
31    int data;
32    int data2;
33    long data3;
34  };
35
36  struct MemPtr2 {
37    void foo() {}
38    void bar() {}
39    int data;
40    int data2;
41    long data3;
42  };
43  using MemPtrT = void (MemPtr::*)();
44
45  using FnPtrT = void (*)();
46
47  void FnPtr1() {}
48  void FnPtr2() {}
49
50#define CHECK(...) ((__VA_ARGS__) ? void() : throw "error")
51#define CHECK_TYPE(...) static_assert(__is_same(__VA_ARGS__));
52
53constexpr bool test_constexpr_success = [] {
54  {
55    auto &EQ = std::strong_ordering::equal;
56    auto &LESS = std::strong_ordering::less;
57    auto &GREATER = std::strong_ordering::greater;
58    using SO = std::strong_ordering;
59    auto eq = (42 <=> 42);
60    CHECK_TYPE(decltype(eq), SO);
61    CHECK(eq.test_eq(EQ));
62
63    auto less = (-1 <=> 0);
64    CHECK_TYPE(decltype(less), SO);
65    CHECK(less.test_eq(LESS));
66
67    auto greater = (42l <=> 1u);
68    CHECK_TYPE(decltype(greater), SO);
69    CHECK(greater.test_eq(GREATER));
70  }
71  {
72    using PO = std::partial_ordering;
73    auto EQUIV = PO::equivalent;
74    auto LESS = PO::less;
75    auto GREATER = PO::greater;
76
77    auto eq = (42.0 <=> 42.0);
78    CHECK_TYPE(decltype(eq), PO);
79    CHECK(eq.test_eq(EQUIV));
80
81    auto less = (39.0 <=> 42.0);
82    CHECK_TYPE(decltype(less), PO);
83    CHECK(less.test_eq(LESS));
84
85    auto greater = (-10.123 <=> -101.1);
86    CHECK_TYPE(decltype(greater), PO);
87    CHECK(greater.test_eq(GREATER));
88  }
89  {
90    using SE = std::strong_equality;
91    auto EQ = SE::equal;
92    auto NEQ = SE::nonequal;
93
94    MemPtrT P1 = &MemPtr::foo;
95    MemPtrT P12 = &MemPtr::foo;
96    MemPtrT P2 = &MemPtr::bar;
97    MemPtrT P3 = nullptr;
98
99    auto eq = (P1 <=> P12);
100    CHECK_TYPE(decltype(eq), SE);
101    CHECK(eq.test_eq(EQ));
102
103    auto neq = (P1 <=> P2);
104    CHECK_TYPE(decltype(eq), SE);
105    CHECK(neq.test_eq(NEQ));
106
107    auto eq2 = (P3 <=> nullptr);
108    CHECK_TYPE(decltype(eq2), SE);
109    CHECK(eq2.test_eq(EQ));
110  }
111  {
112    using SE = std::strong_equality;
113    auto EQ = SE::equal;
114    auto NEQ = SE::nonequal;
115
116    FnPtrT F1 = &FnPtr1;
117    FnPtrT F12 = &FnPtr1;
118    FnPtrT F2 = &FnPtr2;
119    FnPtrT F3 = nullptr;
120
121    auto eq = (F1 <=> F12);
122    CHECK_TYPE(decltype(eq), SE);
123    CHECK(eq.test_eq(EQ));
124
125    auto neq = (F1 <=> F2);
126    CHECK_TYPE(decltype(neq), SE);
127    CHECK(neq.test_eq(NEQ));
128  }
129  { // mixed nullptr tests
130    using SO = std::strong_ordering;
131    using SE = std::strong_equality;
132
133    int x = 42;
134    int *xp = &x;
135
136    MemPtrT mf = nullptr;
137    MemPtrT mf2 = &MemPtr::foo;
138    auto r3 = (mf <=> nullptr);
139    CHECK_TYPE(decltype(r3), std::strong_equality);
140    CHECK(r3.test_eq(SE::equal));
141  }
142
143  return true;
144}();
145
146template <auto LHS, auto RHS, bool ExpectTrue = false>
147constexpr bool test_constexpr() {
148  using nullptr_t = decltype(nullptr);
149  using LHSTy = decltype(LHS);
150  using RHSTy = decltype(RHS);
151  // expected-note@+1 {{subexpression not valid in a constant expression}}
152  auto Res = (LHS <=> RHS);
153  if constexpr (__is_same(LHSTy, nullptr_t) || __is_same(RHSTy, nullptr_t)) {
154    CHECK_TYPE(decltype(Res), std::strong_equality);
155  }
156  if (ExpectTrue)
157    return Res == 0;
158  return Res != 0;
159}
160int dummy = 42;
161int dummy2 = 101;
162
163constexpr bool tc1 = test_constexpr<nullptr, &dummy>();
164constexpr bool tc2 = test_constexpr<&dummy, nullptr>();
165
166// OK, equality comparison only
167constexpr bool tc3 = test_constexpr<&MemPtr::foo, nullptr>();
168constexpr bool tc4 = test_constexpr<nullptr, &MemPtr::foo>();
169constexpr bool tc5 = test_constexpr<&MemPtr::foo, &MemPtr::bar>();
170
171constexpr bool tc6 = test_constexpr<&MemPtr::data, nullptr>();
172constexpr bool tc7 = test_constexpr<nullptr, &MemPtr::data>();
173constexpr bool tc8 = test_constexpr<&MemPtr::data, &MemPtr::data2>();
174
175// expected-error@+1 {{must be initialized by a constant expression}}
176constexpr bool tc9 = test_constexpr<&dummy, &dummy2>(); // expected-note {{in call}}
177
178template <class T, class R, class I>
179constexpr T makeComplex(R r, I i) {
180  T res{r, i};
181  return res;
182};
183
184template <class T, class ResultT>
185constexpr bool complex_test(T x, T y, ResultT Expect) {
186  auto res = x <=> y;
187  CHECK_TYPE(decltype(res), ResultT);
188  return res.test_eq(Expect);
189}
190static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0),
191                           makeComplex<_Complex double>(0.0, 0.0),
192                           std::weak_equality::equivalent));
193static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0),
194                           makeComplex<_Complex double>(1.0, 0.0),
195                           std::weak_equality::nonequivalent));
196static_assert(complex_test(makeComplex<_Complex double>(0.0, 0.0),
197                           makeComplex<_Complex double>(0.0, 1.0),
198                           std::weak_equality::nonequivalent));
199static_assert(complex_test(makeComplex<_Complex int>(0, 0),
200                           makeComplex<_Complex int>(0, 0),
201                           std::strong_equality::equal));
202static_assert(complex_test(makeComplex<_Complex int>(0, 0),
203                           makeComplex<_Complex int>(1, 0),
204                           std::strong_equality::nonequal));
205// TODO: defaulted operator <=>
206} // namespace ThreeWayComparison
207
208constexpr bool for_range_init() {
209  int k = 0;
210  for (int arr[3] = {1, 2, 3}; int n : arr) k += n;
211  return k == 6;
212}
213static_assert(for_range_init());
214