aboutsummaryrefslogtreecommitdiff
path: root/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
blob: 30ec2a3ab70f7dd2bce433fce886ef95897715e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// RUN:  %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s

template<typename T> concept C1 = true; // expected-note{{template is declared here}}
static_assert(C1<int>);
static_assert(C1);
// expected-error@-1{{use of concept 'C1' requires template arguments}}

template<typename T> concept C2 = sizeof(T) == 4;
static_assert(C2<int>);
static_assert(!C2<long long int>);
static_assert(C2<char[4]>);
static_assert(!C2<char[5]>);

template<typename T> concept C3 = sizeof(*T{}) == 4;
static_assert(C3<int*>);
static_assert(!C3<long long int>);

struct A {
  static constexpr int add(int a, int b) {
    return a + b;
  }
};
struct B {
  static int add(int a, int b) { // expected-note{{declared here}}
    return a + b;
  }
};
template<typename U>
concept C4 = U::add(1, 2) == 3;
// expected-error@-1{{substitution into constraint expression resulted in a non-constant expression}}
// expected-note@-2{{non-constexpr function 'add' cannot be used in a constant expression}}
static_assert(C4<A>);
static_assert(!C4<B>); // expected-note {{while checking the satisfaction of concept 'C4<B>' requested here}}

template<typename T, typename U>
constexpr bool is_same_v = false;

template<typename T>
constexpr bool is_same_v<T, T> = true;

template<typename T, typename U>
concept Same = is_same_v<T, U>;

static_assert(Same<int, int>);
static_assert(Same<int, decltype(1)>);
static_assert(!Same<int, unsigned int>);
static_assert(!Same<A, B>);
static_assert(Same<A, A>);

static_assert(Same<bool, decltype(C1<int>)>);
static_assert(Same<bool, decltype(C2<int>)>);
static_assert(Same<bool, decltype(C3<int*>)>);
static_assert(Same<bool, decltype(C4<A>)>);

template<typename T> concept C5 = T{}; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
constexpr bool x = C5<int>; // expected-note {{while checking the satisfaction of concept 'C5<int>' requested here}}

template<int x>
concept IsEven = (x % 2) == 0;

static_assert(IsEven<20>);
static_assert(!IsEven<11>);

template<template<typename T> typename P>
concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool>
                          && is_same_v<decltype(P<int>::value), const bool>
                          && is_same_v<decltype(P<long long>::value), const bool>;

template<typename T> struct T1 {};
template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; };

static_assert(IsTypePredicate<T2>);
static_assert(!IsTypePredicate<T1>);

template<typename T, typename U, typename... Ts>
concept OneOf = (Same<T, Ts> || ...);

static_assert(OneOf<int, long, int>);
static_assert(!OneOf<long, int, char, char>);

namespace piecewise_substitution {
  template <typename T>
  concept True = true;

  template <typename T>
  concept A = True<T> || T::value;

  template <typename T>
  concept B = (True<T> || T::value);

  template <typename T>
  concept C = !True<T> && T::value || true;

  template <typename T>
  concept D = (!True<T> && T::value) || true;

  template <typename T>
  concept E = T::value || True<T>;

  template <typename T>
  concept F = (T::value || True<T>);

  template <typename T>
  concept G = T::value && !True<T> || true;

  template <typename T>
  concept H = (T::value && !True<T>) || true;

  template <typename T>
  concept I = T::value;

  static_assert(A<int>);
  static_assert(B<int>);
  static_assert(C<int>);
  static_assert(D<int>);
  static_assert(E<int>);
  static_assert(F<int>);
  static_assert(G<int>);
  static_assert(H<int>);
  static_assert(!I<int>);
}

// Short ciruiting

template<typename T> struct T3 { using type = typename T::type; };
// expected-error@-1{{type 'char' cannot be used prior to '::' because it has no members}}
// expected-error@-2{{type 'short' cannot be used prior to '::' because it has no members}}

template<typename T>
concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1;
// expected-note@-1{{while substituting template arguments into constraint expression here}}
// expected-note@-2{{in instantiation of template class 'T3<char>' requested here}}

template<typename T>
concept C7 = sizeof(T) == 1 || sizeof(
// expected-note@-1{{while substituting template arguments into constraint expression here}}
    typename
      T3<T>
// expected-note@-1{{in instantiation of template class 'T3<short>' requested here}}
        ::type) == 1;

static_assert(!C6<short>);
static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
static_assert(C7<char>);
static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}

// Make sure argument list is converted when instantiating a CSE.

template<typename T, typename U = int>
concept SameSize = sizeof(T) == sizeof(U);

template<typename T>
struct X { static constexpr bool a = SameSize<T>; };

static_assert(X<unsigned>::a);

// static_assert concept diagnostics
template<typename T>
concept Large = sizeof(T) > 100;
// expected-note@-1 2{{because 'sizeof(small) > 100' (1 > 100) evaluated to false}}

struct small { };
static_assert(Large<small>);
// expected-error@-1 {{static_assert failed}}
// expected-note@-2 {{because 'small' does not satisfy 'Large'}}
static_assert(Large<small>, "small isn't large");
// expected-error@-1 {{static_assert failed "small isn't large"}}
// expected-note@-2 {{because 'small' does not satisfy 'Large'}}

// Make sure access-checking can fail a concept specialization

class T4 { static constexpr bool f = true; };
template<typename T> concept AccessPrivate = T{}.f;
// expected-note@-1{{because substituted constraint expression is ill-formed: 'f' is a private member of 'T4'}}
static_assert(AccessPrivate<T4>);
// expected-error@-1{{static_assert failed}}
// expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}}

template<typename T, typename U>
// expected-note@-1{{template parameter is declared here}}
concept C8 = sizeof(T) > sizeof(U);

template<typename... T>
constexpr bool B8 = C8<T...>;
// expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}}


// Make sure we correctly check for containsUnexpandedParameterPack

template<typename T>
concept C9 = true;

template <typename Fn, typename... Args>
using invoke = typename Fn::template invoke<Args...>;

template <typename C, typename... L>
// The converted argument here will not containsUnexpandedParameterPack, but the
// as-written one will.
requires (C9<invoke<C, L>> &&...)
struct S { };