1 // RUN:  %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s
2 
3 template<typename T> concept C1 = true; // expected-note{{template is declared here}}
4 static_assert(C1<int>);
5 static_assert(C1);
6 // expected-error@-1{{use of concept 'C1' requires template arguments}}
7 
8 template<typename T> concept C2 = sizeof(T) == 4;
9 static_assert(C2<int>);
10 static_assert(!C2<long long int>);
11 static_assert(C2<char[4]>);
12 static_assert(!C2<char[5]>);
13 
14 template<typename T> concept C3 = sizeof(*T{}) == 4;
15 static_assert(C3<int*>);
16 static_assert(!C3<long long int>);
17 
18 struct A {
19   static constexpr int add(int a, int b) {
20     return a + b;
21   }
22 };
23 struct B {
24   static int add(int a, int b) { // expected-note{{declared here}}
25     return a + b;
26   }
27 };
28 template<typename U>
29 concept C4 = U::add(1, 2) == 3;
30 // expected-error@-1{{substitution into constraint expression resulted in a non-constant expression}}
31 // expected-note@-2{{non-constexpr function 'add' cannot be used in a constant expression}}
32 static_assert(C4<A>);
33 static_assert(!C4<B>); // expected-note {{while checking the satisfaction of concept 'C4<B>' requested here}}
34 
35 template<typename T, typename U>
36 constexpr bool is_same_v = false;
37 
38 template<typename T>
39 constexpr bool is_same_v<T, T> = true;
40 
41 template<typename T, typename U>
42 concept Same = is_same_v<T, U>;
43 
44 static_assert(Same<int, int>);
45 static_assert(Same<int, decltype(1)>);
46 static_assert(!Same<int, unsigned int>);
47 static_assert(!Same<A, B>);
48 static_assert(Same<A, A>);
49 
50 static_assert(Same<bool, decltype(C1<int>)>);
51 static_assert(Same<bool, decltype(C2<int>)>);
52 static_assert(Same<bool, decltype(C3<int*>)>);
53 static_assert(Same<bool, decltype(C4<A>)>);
54 
55 template<typename T> concept C5 = T{}; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
56 constexpr bool x = C5<int>; // expected-note {{while checking the satisfaction of concept 'C5<int>' requested here}}
57 
58 template<int x>
59 concept IsEven = (x % 2) == 0;
60 
61 static_assert(IsEven<20>);
62 static_assert(!IsEven<11>);
63 
64 template<template<typename T> typename P>
65 concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool>
66                           && is_same_v<decltype(P<int>::value), const bool>
67                           && is_same_v<decltype(P<long long>::value), const bool>;
68 
69 template<typename T> struct T1 {};
70 template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; };
71 
72 static_assert(IsTypePredicate<T2>);
73 static_assert(!IsTypePredicate<T1>);
74 
75 template<typename T, typename U, typename... Ts>
76 concept OneOf = (Same<T, Ts> || ...);
77 
78 template<typename... X>
79 constexpr bool S = OneOf<X..., int, int>;
80 
81 static_assert(S<int, long, int>);
82 static_assert(!S<long, int, char, char>);
83 
84 namespace piecewise_substitution {
85   template <typename T>
86   concept True = true;
87 
88   template <typename T>
89   concept A = True<T> || T::value;
90 
91   template <typename T>
92   concept B = (True<T> || T::value);
93 
94   template <typename T>
95   concept C = !True<T> && T::value || true;
96 
97   template <typename T>
98   concept D = (!True<T> && T::value) || true;
99 
100   template <typename T>
101   concept E = T::value || True<T>;
102 
103   template <typename T>
104   concept F = (T::value || True<T>);
105 
106   template <typename T>
107   concept G = T::value && !True<T> || true;
108 
109   template <typename T>
110   concept H = (T::value && !True<T>) || true;
111 
112   template <typename T>
113   concept I = T::value;
114 
115   static_assert(A<int>);
116   static_assert(B<int>);
117   static_assert(C<int>);
118   static_assert(D<int>);
119   static_assert(E<int>);
120   static_assert(F<int>);
121   static_assert(G<int>);
122   static_assert(H<int>);
123   static_assert(!I<int>);
124 }
125 
126 // Short ciruiting
127 
128 template<typename T> struct T3 { using type = typename T::type; };
129 // expected-error@-1{{type 'char' cannot be used prior to '::' because it has no members}}
130 // expected-error@-2{{type 'short' cannot be used prior to '::' because it has no members}}
131 
132 template<typename T>
133 concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1;
134 // expected-note@-1{{while substituting template arguments into constraint expression here}}
135 // expected-note@-2{{in instantiation of template class 'T3<char>' requested here}}
136 
137 template<typename T>
138 concept C7 = sizeof(T) == 1 || sizeof(
139 // expected-note@-1{{while substituting template arguments into constraint expression here}}
140     typename
141       T3<T>
142 // expected-note@-1{{in instantiation of template class 'T3<short>' requested here}}
143         ::type) == 1;
144 
145 static_assert(!C6<short>);
146 static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
147 static_assert(C7<char>);
148 static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}
149 
150 // Make sure argument list is converted when instantiating a CSE.
151 
152 template<typename T, typename U = int>
153 concept SameSize = sizeof(T) == sizeof(U);
154 
155 template<typename T>
156 struct X { static constexpr bool a = SameSize<T>; };
157 
158 static_assert(X<unsigned>::a);
159 
160 // static_assert concept diagnostics
161 template<typename T>
162 concept Large = sizeof(T) > 100;
163 // expected-note@-1 2{{because 'sizeof(small) > 100' (1 > 100) evaluated to false}}
164 
165 struct small { };
166 static_assert(Large<small>);
167 // expected-error@-1 {{static_assert failed}}
168 // expected-note@-2 {{because 'small' does not satisfy 'Large'}}
169 static_assert(Large<small>, "small isn't large");
170 // expected-error@-1 {{static_assert failed "small isn't large"}}
171 // expected-note@-2 {{because 'small' does not satisfy 'Large'}}
172 
173 // Make sure access-checking can fail a concept specialization
174 
175 class T4 { static constexpr bool f = true; };
176 template<typename T> concept AccessPrivate = T{}.f;
177 // expected-note@-1{{because substituted constraint expression is ill-formed: 'f' is a private member of 'T4'}}
178 static_assert(AccessPrivate<T4>);
179 // expected-error@-1{{static_assert failed}}
180 // expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}}
181