summaryrefslogtreecommitdiff
path: root/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
blob: dd3f0c0e3d6cb2e646242a591b278c4db5fe4911 (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
// 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>);

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);