xref: /llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp (revision a091bfe71fdde4358dbfc73926f875cb05121c00)
167c608a9SSaar Raz // RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
2a0f50d73SSaar Raz 
3a0f50d73SSaar Raz static_assert(requires { { 0 }; });
4a0f50d73SSaar Raz static_assert(requires { { "aaaa" }; });
5a0f50d73SSaar Raz static_assert(requires { { (0).da }; }); // expected-error{{member reference base type 'int' is not a structure or union}}
6a0f50d73SSaar Raz 
foo()7a0f50d73SSaar Raz void foo() {}
8a0f50d73SSaar Raz static_assert(requires { { foo() }; });
9a0f50d73SSaar Raz 
10a0f50d73SSaar Raz // Substitution failure in expression
11a0f50d73SSaar Raz 
12a0f50d73SSaar Raz struct A {};
13a0f50d73SSaar Raz struct B {
operator +B14a0f50d73SSaar Raz     B operator+(const B &other) const { return other; }
15a0f50d73SSaar Raz };
16a0f50d73SSaar Raz struct C {
operator +C17a0f50d73SSaar Raz     C operator+(C &other) const { return other; }
18a0f50d73SSaar Raz };
19a0f50d73SSaar Raz 
20a0f50d73SSaar Raz template<typename T> requires requires (T a, const T& b) { { a + b }; } // expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('A' and 'const A')}} expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('C' and 'const C')}}
21a0f50d73SSaar Raz struct r1 {};
22a0f50d73SSaar Raz 
23a0f50d73SSaar Raz using r1i1 = r1<int>;
24a0f50d73SSaar Raz using r1i2 = r1<A>; // expected-error{{constraints not satisfied for class template 'r1' [with T = A]}}
25a0f50d73SSaar Raz using r1i3 = r1<B>;
26a0f50d73SSaar Raz using r1i4 = r1<C>; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}}
27a0f50d73SSaar Raz 
fooD28a0f50d73SSaar Raz struct D { void foo() {} };
29a0f50d73SSaar Raz 
30a0f50d73SSaar Raz template<typename T> requires requires (T a) { { a.foo() }; } // expected-note{{because 'a.foo()' would be invalid: no member named 'foo' in 'A'}} expected-note{{because 'a.foo()' would be invalid: member reference base type 'int' is not a structure or union}} expected-note{{because 'a.foo()' would be invalid: 'this' argument to member function 'foo' has type 'const D', but function is not marked const}}
31a0f50d73SSaar Raz struct r2 {};
32a0f50d73SSaar Raz 
33a0f50d73SSaar Raz using r2i1 = r2<int>; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}}
34a0f50d73SSaar Raz using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class template 'r2' [with T = A]}}
35a0f50d73SSaar Raz using r2i3 = r2<D>;
36a0f50d73SSaar Raz using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
37a0f50d73SSaar Raz 
3812cb1cb3SErich Keane template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
39a0f50d73SSaar Raz struct r3 {};
40a0f50d73SSaar Raz 
41a0f50d73SSaar Raz using r3i1 = r3<int>;
42a0f50d73SSaar Raz using r3i2 = r3<A>;
43a0f50d73SSaar Raz using r3i3 = r3<A &>;
44a0f50d73SSaar Raz using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
4512cb1cb3SErich Keane using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
46a0f50d73SSaar Raz 
47a0f50d73SSaar Raz // Non-dependent expressions
48a0f50d73SSaar Raz 
49a0f50d73SSaar Raz template<typename T> requires requires (T t) { { 0 }; { "a" }; { (void)'a' }; }
50a0f50d73SSaar Raz struct r4 {};
51a0f50d73SSaar Raz 
52a0f50d73SSaar Raz using r4i1 = r4<int>;
53a0f50d73SSaar Raz using r4i2 = r4<int[10]>;
54a0f50d73SSaar Raz using r4i3 = r4<int(int)>;
55a0f50d73SSaar Raz 
56a0f50d73SSaar Raz // Noexcept requirement
maythrow()57a0f50d73SSaar Raz void maythrow() { }
58a0f50d73SSaar Raz static_assert(!requires { { maythrow() } noexcept; });
59a0f50d73SSaar Raz static_assert(requires { { 1 } noexcept; });
60a0f50d73SSaar Raz 
61a0f50d73SSaar Raz struct E { void operator++(int) noexcept; };
62a0f50d73SSaar Raz struct F { void operator++(int); };
63a0f50d73SSaar Raz 
64a0f50d73SSaar Raz template<typename T> requires requires (T t) { { t++ } noexcept; } // expected-note{{because 't ++' may throw an exception}}
65a0f50d73SSaar Raz struct r5 {};
66a0f50d73SSaar Raz 
67a0f50d73SSaar Raz using r5i1 = r5<int>;
68a0f50d73SSaar Raz using r5i2 = r5<E>;
69a0f50d73SSaar Raz using r5i2 = r5<F>; // expected-error{{constraints not satisfied for class template 'r5' [with T = F]}}
70a0f50d73SSaar Raz 
71a0f50d73SSaar Raz template<typename T> requires requires (T t) { { t.foo() } noexcept; } // expected-note{{because 't.foo()' would be invalid: no member named 'foo' in 'E'}}
72a0f50d73SSaar Raz struct r6 {};
73a0f50d73SSaar Raz 
74a0f50d73SSaar Raz using r6i = r6<E>; // expected-error{{constraints not satisfied for class template 'r6' [with T = E]}}
75a0f50d73SSaar Raz 
76a0f50d73SSaar Raz template<typename T, typename U>
77a0f50d73SSaar Raz constexpr bool is_same_v = false;
78a0f50d73SSaar Raz 
79a0f50d73SSaar Raz template<typename T>
80a0f50d73SSaar Raz constexpr bool is_same_v<T, T> = true;
81a0f50d73SSaar Raz 
823ad6dd5dSMatheus Izvekov template<typename T> struct remove_reference { using type = T; };
833ad6dd5dSMatheus Izvekov template<typename T> struct remove_reference<T&> { using type = T; };
843ad6dd5dSMatheus Izvekov 
85a0f50d73SSaar Raz template<typename T, typename U>
86a0f50d73SSaar Raz concept Same = is_same_v<T, U>;
87a0f50d73SSaar Raz 
88a0f50d73SSaar Raz template<typename T>
893ad6dd5dSMatheus Izvekov concept Large = sizeof(typename remove_reference<T>::type) >= 4;
903ad6dd5dSMatheus Izvekov // expected-note@-1{{because 'sizeof(typename remove_reference<short &>::type) >= 4' (2 >= 4) evaluated to false}}
91a0f50d73SSaar Raz 
923ad6dd5dSMatheus Izvekov template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'short &' does not satisfy 'Large':}}
93a0f50d73SSaar Raz struct r7 {};
94a0f50d73SSaar Raz 
95a0f50d73SSaar Raz using r7i1 = r7<int>;
96a0f50d73SSaar Raz using r7i2 = r7<short>; // expected-error{{constraints not satisfied for class template 'r7' [with T = short]}}
97a0f50d73SSaar Raz 
983ad6dd5dSMatheus Izvekov template<typename T> requires requires (T t) { { t } -> Same<T&>; }
99a0f50d73SSaar Raz struct r8 {};
100a0f50d73SSaar Raz 
101a0f50d73SSaar Raz using r8i1 = r8<int>;
102a0f50d73SSaar Raz using r8i2 = r8<short*>;
103a0f50d73SSaar Raz 
104a0f50d73SSaar Raz // Substitution failure in type constraint
105a0f50d73SSaar Raz 
1063ad6dd5dSMatheus Izvekov template<typename T> requires requires (T t) { { t } -> Same<typename T::type&>; }
1073ad6dd5dSMatheus Izvekov // expected-note@-1{{because 'Same<expr-type, typename T::type &>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
108a0f50d73SSaar Raz struct r9 {};
109a0f50d73SSaar Raz 
110a0f50d73SSaar Raz struct M { using type = M; };
111a0f50d73SSaar Raz 
112a0f50d73SSaar Raz using r9i1 = r9<M>;
113a0f50d73SSaar Raz using r9i2 = r9<int>; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}}
114a0f50d73SSaar Raz 
115a0f50d73SSaar Raz // Substitution failure in both expression and return type requirement
116a0f50d73SSaar Raz 
117a0f50d73SSaar Raz template<typename T> requires requires (T t) { { t.foo() } -> Same<typename T::type>; } // expected-note{{because 't.foo()' would be invalid: member reference base type 'int' is not a structure or union}}
118a0f50d73SSaar Raz struct r10 {};
119a0f50d73SSaar Raz 
120a0f50d73SSaar Raz using r10i = r10<int>; // expected-error{{constraints not satisfied for class template 'r10' [with T = int]}}
121a0f50d73SSaar Raz 
122a0f50d73SSaar Raz // Non-type concept in type constraint
123a0f50d73SSaar Raz 
124a0f50d73SSaar Raz template<int T>
125a0f50d73SSaar Raz concept IsEven = (T % 2) == 0;
126a0f50d73SSaar Raz 
127a0f50d73SSaar Raz template<typename T> requires requires (T t) { { t } -> IsEven; } // expected-error{{concept named in type constraint is not a type concept}}
128a0f50d73SSaar Raz struct r11 {};
129a0f50d73SSaar Raz 
1303ad6dd5dSMatheus Izvekov // Value categories
1313ad6dd5dSMatheus Izvekov 
1323ad6dd5dSMatheus Izvekov template<auto a = 0>
1333ad6dd5dSMatheus Izvekov requires requires (int b) {
1343ad6dd5dSMatheus Izvekov   { a } -> Same<int>;
1353ad6dd5dSMatheus Izvekov   { b } -> Same<int&>;
1363ad6dd5dSMatheus Izvekov   { 0 } -> Same<int>;
1373ad6dd5dSMatheus Izvekov   { static_cast<int&&>(a) } -> Same<int&&>;
f1()1383ad6dd5dSMatheus Izvekov } void f1() {}
1393ad6dd5dSMatheus Izvekov template void f1<>();
1403ad6dd5dSMatheus Izvekov 
141a0f50d73SSaar Raz // C++ [expr.prim.req.compound] Example
142a0f50d73SSaar Raz namespace std_example {
143a0f50d73SSaar Raz   template<typename T> concept C1 =
144a0f50d73SSaar Raz     requires(T x) {
145a0f50d73SSaar Raz       {x++};
146a0f50d73SSaar Raz     };
147a0f50d73SSaar Raz 
148a0f50d73SSaar Raz   template<typename T, typename U> constexpr bool is_same_v = false;
149a0f50d73SSaar Raz   template<typename T> constexpr bool is_same_v<T, T> = true;
150a0f50d73SSaar Raz 
151a0f50d73SSaar Raz   template<typename T, typename U> concept same_as = is_same_v<T, U>;
15212cb1cb3SErich Keane   // expected-note@-1 {{because 'is_same_v<int, int *>' evaluated to false}}
153a0f50d73SSaar Raz 
154a0f50d73SSaar Raz   static_assert(C1<int>);
155a0f50d73SSaar Raz   static_assert(C1<int*>);
156a0f50d73SSaar Raz   template<C1 T> struct C1_check {};
157a0f50d73SSaar Raz   using c1c1 = C1_check<int>;
158a0f50d73SSaar Raz   using c1c2 = C1_check<int[10]>;
159a0f50d73SSaar Raz 
160a0f50d73SSaar Raz   template<typename T> concept C2 =
161a0f50d73SSaar Raz     requires(T x) {
162a0f50d73SSaar Raz       {*x} -> same_as<typename T::inner>;
163a0f50d73SSaar Raz       // expected-note@-1{{because type constraint 'same_as<int, typename T2::inner>' was not satisfied:}}
164a0f50d73SSaar Raz       // expected-note@-2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}}
165a0f50d73SSaar Raz     };
166a0f50d73SSaar Raz 
167a0f50d73SSaar Raz   struct T1 {
168a0f50d73SSaar Raz     using inner = int;
operator *std_example::T1169a0f50d73SSaar Raz     inner operator *() { return 0; }
170a0f50d73SSaar Raz   };
171a0f50d73SSaar Raz   struct T2 {
172a0f50d73SSaar Raz     using inner = int *;
operator *std_example::T2173a0f50d73SSaar Raz     int operator *() { return 0; }
174a0f50d73SSaar Raz   };
175a0f50d73SSaar Raz   static_assert(C2<T1>);
17612cb1cb3SErich Keane   template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
177a0f50d73SSaar Raz   using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
17812cb1cb3SErich Keane   using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
179a0f50d73SSaar Raz 
180a0f50d73SSaar Raz   template<typename T>
g(T t)181a0f50d73SSaar Raz   void g(T t) noexcept(sizeof(T) == 1) {}
182a0f50d73SSaar Raz 
183a0f50d73SSaar Raz   template<typename T> concept C5 =
184a0f50d73SSaar Raz     requires(T x) {
185a0f50d73SSaar Raz       {g(x)} noexcept; // expected-note{{because 'g(x)' may throw an exception}}
186a0f50d73SSaar Raz     };
187a0f50d73SSaar Raz 
188a0f50d73SSaar Raz   static_assert(C5<char>);
189a0f50d73SSaar Raz   template<C5 T> struct C5_check {}; // expected-note{{because 'short' does not satisfy 'C5'}}
190a0f50d73SSaar Raz   using c5 = C5_check<short>; // expected-error{{constraints not satisfied for class template 'C5_check' [with T = short]}}
191a0f50d73SSaar Raz }
192*a091bfe7SZhikai Zeng 
193*a091bfe7SZhikai Zeng namespace access_checks {
194*a091bfe7SZhikai Zeng namespace in_return_type_requirement {
195*a091bfe7SZhikai Zeng 
196*a091bfe7SZhikai Zeng // https://github.com/llvm/llvm-project/issues/93788
197*a091bfe7SZhikai Zeng template <typename From, typename To>
198*a091bfe7SZhikai Zeng concept is_assignable = requires(From from, To to) {
199*a091bfe7SZhikai Zeng   from = to;
200*a091bfe7SZhikai Zeng };
201*a091bfe7SZhikai Zeng 
202*a091bfe7SZhikai Zeng template <typename T>
203*a091bfe7SZhikai Zeng class trait {
204*a091bfe7SZhikai Zeng  public:
205*a091bfe7SZhikai Zeng   using public_type = int;
206*a091bfe7SZhikai Zeng  private:
207*a091bfe7SZhikai Zeng   using private_type = int;
208*a091bfe7SZhikai Zeng };
209*a091bfe7SZhikai Zeng 
210*a091bfe7SZhikai Zeng template <typename T>
211*a091bfe7SZhikai Zeng concept has_field = requires(T t) {
212*a091bfe7SZhikai Zeng   { t.field } -> is_assignable<typename trait<T>::private_type>;  // expected-note {{'private_type' is a private member}}
213*a091bfe7SZhikai Zeng };
214*a091bfe7SZhikai Zeng template <typename T>
215*a091bfe7SZhikai Zeng concept has_field2 = requires(T t) {
216*a091bfe7SZhikai Zeng   { t.field } -> is_assignable<typename trait<T>::public_type>;
217*a091bfe7SZhikai Zeng };
218*a091bfe7SZhikai Zeng 
219*a091bfe7SZhikai Zeng struct A {
220*a091bfe7SZhikai Zeng   int field;
221*a091bfe7SZhikai Zeng };
222*a091bfe7SZhikai Zeng static_assert(has_field<A>); // expected-error {{static assertion failed}} \
223*a091bfe7SZhikai Zeng                              // expected-note {{because 'A' does not satisfy 'has_field'}}
224*a091bfe7SZhikai Zeng static_assert(has_field2<A>);
225*a091bfe7SZhikai Zeng 
226*a091bfe7SZhikai Zeng }  // namespace access_checks
227*a091bfe7SZhikai Zeng }  // namespace in_return_type_requirement
228