xref: /llvm-project/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp (revision 76476efd68951907a94def92b2bb6ba6e32ca5b4)
15d98ba60SSaar Raz // RUN:  %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s
25d98ba60SSaar Raz 
35d98ba60SSaar Raz template<typename T> concept C1 = true; // expected-note{{template is declared here}}
45d98ba60SSaar Raz static_assert(C1<int>);
55d98ba60SSaar Raz static_assert(C1);
65d98ba60SSaar Raz // expected-error@-1{{use of concept 'C1' requires template arguments}}
75d98ba60SSaar Raz 
85d98ba60SSaar Raz template<typename T> concept C2 = sizeof(T) == 4;
95d98ba60SSaar Raz static_assert(C2<int>);
105d98ba60SSaar Raz static_assert(!C2<long long int>);
115d98ba60SSaar Raz static_assert(C2<char[4]>);
125d98ba60SSaar Raz static_assert(!C2<char[5]>);
135d98ba60SSaar Raz 
145d98ba60SSaar Raz template<typename T> concept C3 = sizeof(*T{}) == 4;
155d98ba60SSaar Raz static_assert(C3<int*>);
165d98ba60SSaar Raz static_assert(!C3<long long int>);
175d98ba60SSaar Raz 
185d98ba60SSaar Raz struct A {
addA195d98ba60SSaar Raz   static constexpr int add(int a, int b) {
205d98ba60SSaar Raz     return a + b;
215d98ba60SSaar Raz   }
225d98ba60SSaar Raz };
235d98ba60SSaar Raz struct B {
addB245d98ba60SSaar Raz   static int add(int a, int b) { // expected-note{{declared here}}
255d98ba60SSaar Raz     return a + b;
265d98ba60SSaar Raz   }
275d98ba60SSaar Raz };
285d98ba60SSaar Raz template<typename U>
295d98ba60SSaar Raz concept C4 = U::add(1, 2) == 3;
305d98ba60SSaar Raz // expected-error@-1{{substitution into constraint expression resulted in a non-constant expression}}
315d98ba60SSaar Raz // expected-note@-2{{non-constexpr function 'add' cannot be used in a constant expression}}
325d98ba60SSaar Raz static_assert(C4<A>);
335d98ba60SSaar Raz static_assert(!C4<B>); // expected-note {{while checking the satisfaction of concept 'C4<B>' requested here}}
345d98ba60SSaar Raz 
355d98ba60SSaar Raz template<typename T, typename U>
365d98ba60SSaar Raz constexpr bool is_same_v = false;
375d98ba60SSaar Raz 
385d98ba60SSaar Raz template<typename T>
395d98ba60SSaar Raz constexpr bool is_same_v<T, T> = true;
405d98ba60SSaar Raz 
415d98ba60SSaar Raz template<typename T, typename U>
425d98ba60SSaar Raz concept Same = is_same_v<T, U>;
435d98ba60SSaar Raz 
445d98ba60SSaar Raz static_assert(Same<int, int>);
455d98ba60SSaar Raz static_assert(Same<int, decltype(1)>);
465d98ba60SSaar Raz static_assert(!Same<int, unsigned int>);
475d98ba60SSaar Raz static_assert(!Same<A, B>);
485d98ba60SSaar Raz static_assert(Same<A, A>);
495d98ba60SSaar Raz 
505d98ba60SSaar Raz static_assert(Same<bool, decltype(C1<int>)>);
515d98ba60SSaar Raz static_assert(Same<bool, decltype(C2<int>)>);
525d98ba60SSaar Raz static_assert(Same<bool, decltype(C3<int*>)>);
535d98ba60SSaar Raz static_assert(Same<bool, decltype(C4<A>)>);
545d98ba60SSaar Raz 
555d98ba60SSaar Raz template<typename T> concept C5 = T{}; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
565d98ba60SSaar Raz constexpr bool x = C5<int>; // expected-note {{while checking the satisfaction of concept 'C5<int>' requested here}}
575d98ba60SSaar Raz 
585d98ba60SSaar Raz template<int x>
595d98ba60SSaar Raz concept IsEven = (x % 2) == 0;
605d98ba60SSaar Raz 
615d98ba60SSaar Raz static_assert(IsEven<20>);
625d98ba60SSaar Raz static_assert(!IsEven<11>);
635d98ba60SSaar Raz 
645d98ba60SSaar Raz template<template<typename T> typename P>
655d98ba60SSaar Raz concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool>
665d98ba60SSaar Raz                           && is_same_v<decltype(P<int>::value), const bool>
675d98ba60SSaar Raz                           && is_same_v<decltype(P<long long>::value), const bool>;
685d98ba60SSaar Raz 
695d98ba60SSaar Raz template<typename T> struct T1 {};
705d98ba60SSaar Raz template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; };
715d98ba60SSaar Raz 
725d98ba60SSaar Raz static_assert(IsTypePredicate<T2>);
735d98ba60SSaar Raz static_assert(!IsTypePredicate<T1>);
745d98ba60SSaar Raz 
75fdf80e86SSaar Raz template<typename T, typename U, typename... Ts>
76fdf80e86SSaar Raz concept OneOf = (Same<T, Ts> || ...);
77fdf80e86SSaar Raz 
78df061c3eSSaar Raz static_assert(OneOf<int, long, int>);
79df061c3eSSaar Raz static_assert(!OneOf<long, int, char, char>);
80fdf80e86SSaar Raz 
815d98ba60SSaar Raz namespace piecewise_substitution {
825d98ba60SSaar Raz   template <typename T>
835d98ba60SSaar Raz   concept True = true;
845d98ba60SSaar Raz 
855d98ba60SSaar Raz   template <typename T>
865d98ba60SSaar Raz   concept A = True<T> || T::value;
875d98ba60SSaar Raz 
885d98ba60SSaar Raz   template <typename T>
895d98ba60SSaar Raz   concept B = (True<T> || T::value);
905d98ba60SSaar Raz 
915d98ba60SSaar Raz   template <typename T>
925d98ba60SSaar Raz   concept C = !True<T> && T::value || true;
935d98ba60SSaar Raz 
945d98ba60SSaar Raz   template <typename T>
955d98ba60SSaar Raz   concept D = (!True<T> && T::value) || true;
965d98ba60SSaar Raz 
975d98ba60SSaar Raz   template <typename T>
985d98ba60SSaar Raz   concept E = T::value || True<T>;
995d98ba60SSaar Raz 
1005d98ba60SSaar Raz   template <typename T>
1015d98ba60SSaar Raz   concept F = (T::value || True<T>);
1025d98ba60SSaar Raz 
1035d98ba60SSaar Raz   template <typename T>
1045d98ba60SSaar Raz   concept G = T::value && !True<T> || true;
1055d98ba60SSaar Raz 
1065d98ba60SSaar Raz   template <typename T>
1075d98ba60SSaar Raz   concept H = (T::value && !True<T>) || true;
1085d98ba60SSaar Raz 
1095d98ba60SSaar Raz   template <typename T>
1105d98ba60SSaar Raz   concept I = T::value;
1115d98ba60SSaar Raz 
1125d98ba60SSaar Raz   static_assert(A<int>);
1135d98ba60SSaar Raz   static_assert(B<int>);
1145d98ba60SSaar Raz   static_assert(C<int>);
1155d98ba60SSaar Raz   static_assert(D<int>);
1165d98ba60SSaar Raz   static_assert(E<int>);
1175d98ba60SSaar Raz   static_assert(F<int>);
1185d98ba60SSaar Raz   static_assert(G<int>);
1195d98ba60SSaar Raz   static_assert(H<int>);
1205d98ba60SSaar Raz   static_assert(!I<int>);
1215d98ba60SSaar Raz }
1225d98ba60SSaar Raz 
1235d98ba60SSaar Raz // Short ciruiting
1245d98ba60SSaar Raz 
1255d98ba60SSaar Raz template<typename T> struct T3 { using type = typename T::type; };
1265d98ba60SSaar Raz // expected-error@-1{{type 'char' cannot be used prior to '::' because it has no members}}
1275d98ba60SSaar Raz // expected-error@-2{{type 'short' cannot be used prior to '::' because it has no members}}
1285d98ba60SSaar Raz 
1295d98ba60SSaar Raz template<typename T>
1305d98ba60SSaar Raz concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1;
1315d98ba60SSaar Raz // expected-note@-1{{while substituting template arguments into constraint expression here}}
1325d98ba60SSaar Raz // expected-note@-2{{in instantiation of template class 'T3<char>' requested here}}
1335d98ba60SSaar Raz 
1345d98ba60SSaar Raz template<typename T>
1355d98ba60SSaar Raz concept C7 = sizeof(T) == 1 || sizeof(
1365d98ba60SSaar Raz // expected-note@-1{{while substituting template arguments into constraint expression here}}
1375d98ba60SSaar Raz     typename
1385d98ba60SSaar Raz       T3<T>
1395d98ba60SSaar Raz // expected-note@-1{{in instantiation of template class 'T3<short>' requested here}}
1405d98ba60SSaar Raz         ::type) == 1;
1415d98ba60SSaar Raz 
1425d98ba60SSaar Raz static_assert(!C6<short>);
1435d98ba60SSaar Raz static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
1445d98ba60SSaar Raz static_assert(C7<char>);
1455d98ba60SSaar Raz static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}
1465d98ba60SSaar Raz 
1475d98ba60SSaar Raz // Make sure argument list is converted when instantiating a CSE.
1485d98ba60SSaar Raz 
1495d98ba60SSaar Raz template<typename T, typename U = int>
1505d98ba60SSaar Raz concept SameSize = sizeof(T) == sizeof(U);
1515d98ba60SSaar Raz 
1525d98ba60SSaar Raz template<typename T>
1535d98ba60SSaar Raz struct X { static constexpr bool a = SameSize<T>; };
1545d98ba60SSaar Raz 
1555d98ba60SSaar Raz static_assert(X<unsigned>::a);
156fdf80e86SSaar Raz 
157fdf80e86SSaar Raz // static_assert concept diagnostics
158fdf80e86SSaar Raz template<typename T>
159fdf80e86SSaar Raz concept Large = sizeof(T) > 100;
160fdf80e86SSaar Raz // expected-note@-1 2{{because 'sizeof(small) > 100' (1 > 100) evaluated to false}}
161fdf80e86SSaar Raz 
162fdf80e86SSaar Raz struct small { };
163fdf80e86SSaar Raz static_assert(Large<small>);
164*76476efdSMuhammad Usman Shahid // expected-error@-1 {{static assertion failed}}
165fdf80e86SSaar Raz // expected-note@-2 {{because 'small' does not satisfy 'Large'}}
166fdf80e86SSaar Raz static_assert(Large<small>, "small isn't large");
167*76476efdSMuhammad Usman Shahid // expected-error@-1 {{static assertion failed: small isn't large}}
168fdf80e86SSaar Raz // expected-note@-2 {{because 'small' does not satisfy 'Large'}}
169fdf80e86SSaar Raz 
170fdf80e86SSaar Raz // Make sure access-checking can fail a concept specialization
171fdf80e86SSaar Raz 
172fdf80e86SSaar Raz class T4 { static constexpr bool f = true; };
173fdf80e86SSaar Raz template<typename T> concept AccessPrivate = T{}.f;
174fdf80e86SSaar Raz // expected-note@-1{{because substituted constraint expression is ill-formed: 'f' is a private member of 'T4'}}
175fdf80e86SSaar Raz static_assert(AccessPrivate<T4>);
176*76476efdSMuhammad Usman Shahid // expected-error@-1{{static assertion failed}}
177fdf80e86SSaar Raz // expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}}
178df061c3eSSaar Raz 
179df061c3eSSaar Raz template<typename T, typename U>
180df061c3eSSaar Raz // expected-note@-1{{template parameter is declared here}}
181df061c3eSSaar Raz concept C8 = sizeof(T) > sizeof(U);
182df061c3eSSaar Raz 
183df061c3eSSaar Raz template<typename... T>
184df061c3eSSaar Raz constexpr bool B8 = C8<T...>;
185df061c3eSSaar Raz // expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}}
186c83d9bedSSaar Raz 
187c83d9bedSSaar Raz 
188c83d9bedSSaar Raz // Make sure we correctly check for containsUnexpandedParameterPack
189c83d9bedSSaar Raz 
190c83d9bedSSaar Raz template<typename T>
191c83d9bedSSaar Raz concept C9 = true;
192c83d9bedSSaar Raz 
193c83d9bedSSaar Raz template <typename Fn, typename... Args>
194c83d9bedSSaar Raz using invoke = typename Fn::template invoke<Args...>;
195c83d9bedSSaar Raz 
196c83d9bedSSaar Raz template <typename C, typename... L>
197c83d9bedSSaar Raz // The converted argument here will not containsUnexpandedParameterPack, but the
198c83d9bedSSaar Raz // as-written one will.
199c83d9bedSSaar Raz requires (C9<invoke<C, L>> &&...)
200c83d9bedSSaar Raz struct S { };
201