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
|
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
static_assert(requires { { 0 }; });
static_assert(requires { { "aaaa" }; });
static_assert(requires { { (0).da }; }); // expected-error{{member reference base type 'int' is not a structure or union}}
void foo() {}
static_assert(requires { { foo() }; });
// Substitution failure in expression
struct A {};
struct B {
B operator+(const B &other) const { return other; }
};
struct C {
C operator+(C &other) const { return other; }
};
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')}}
struct r1 {};
using r1i1 = r1<int>;
using r1i2 = r1<A>; // expected-error{{constraints not satisfied for class template 'r1' [with T = A]}}
using r1i3 = r1<B>;
using r1i4 = r1<C>; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}}
struct D { void foo() {} };
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}}
struct r2 {};
using r2i1 = r2<int>; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}}
using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class template 'r2' [with T = A]}}
using r2i3 = r2<D>;
using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
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'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
// Non-dependent expressions
template<typename T> requires requires (T t) { { 0 }; { "a" }; { (void)'a' }; }
struct r4 {};
using r4i1 = r4<int>;
using r4i2 = r4<int[10]>;
using r4i3 = r4<int(int)>;
// Noexcept requirement
void maythrow() { }
static_assert(!requires { { maythrow() } noexcept; });
static_assert(requires { { 1 } noexcept; });
struct E { void operator++(int) noexcept; };
struct F { void operator++(int); };
template<typename T> requires requires (T t) { { t++ } noexcept; } // expected-note{{because 't ++' may throw an exception}}
struct r5 {};
using r5i1 = r5<int>;
using r5i2 = r5<E>;
using r5i2 = r5<F>; // expected-error{{constraints not satisfied for class template 'r5' [with T = F]}}
template<typename T> requires requires (T t) { { t.foo() } noexcept; } // expected-note{{because 't.foo()' would be invalid: no member named 'foo' in 'E'}}
struct r6 {};
using r6i = r6<E>; // expected-error{{constraints not satisfied for class template 'r6' [with T = E]}}
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>;
template<typename T>
concept Large = sizeof(T) >= 4; // expected-note{{because 'sizeof(short) >= 4' (2 >= 4) evaluated to false}}
template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'decltype(t)' (aka 'short') does not satisfy 'Large':}}
struct r7 {};
using r7i1 = r7<int>;
using r7i2 = r7<short>; // expected-error{{constraints not satisfied for class template 'r7' [with T = short]}}
template<typename T> requires requires (T t) { { t } -> Same<T>; }
struct r8 {};
using r8i1 = r8<int>;
using r8i2 = r8<short*>;
// Substitution failure in type constraint
template<typename T> requires requires (T t) { { t } -> Same<typename T::type>; } // expected-note{{because 'Same<expr-type, typename T::type>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
struct r9 {};
struct M { using type = M; };
using r9i1 = r9<M>;
using r9i2 = r9<int>; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}}
// Substitution failure in both expression and return type requirement
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}}
struct r10 {};
using r10i = r10<int>; // expected-error{{constraints not satisfied for class template 'r10' [with T = int]}}
// Non-type concept in type constraint
template<int T>
concept IsEven = (T % 2) == 0;
template<typename T> requires requires (T t) { { t } -> IsEven; } // expected-error{{concept named in type constraint is not a type concept}}
struct r11 {};
// C++ [expr.prim.req.compound] Example
namespace std_example {
template<typename T> concept C1 =
requires(T x) {
{x++};
};
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_as = is_same_v<T, U>;
// expected-note@-1 {{because 'is_same_v<int, int *>' evaluated to false}}
static_assert(C1<int>);
static_assert(C1<int*>);
template<C1 T> struct C1_check {};
using c1c1 = C1_check<int>;
using c1c2 = C1_check<int[10]>;
template<typename T> concept C2 =
requires(T x) {
{*x} -> same_as<typename T::inner>;
// expected-note@-1{{because type constraint 'same_as<int, typename T2::inner>' was not satisfied:}}
// expected-note@-2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}}
};
struct T1 {
using inner = int;
inner operator *() { return 0; }
};
struct T2 {
using inner = int *;
int operator *() { return 0; }
};
static_assert(C2<T1>);
template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
template<typename T>
void g(T t) noexcept(sizeof(T) == 1) {}
template<typename T> concept C5 =
requires(T x) {
{g(x)} noexcept; // expected-note{{because 'g(x)' may throw an exception}}
};
static_assert(C5<char>);
template<C5 T> struct C5_check {}; // expected-note{{because 'short' does not satisfy 'C5'}}
using c5 = C5_check<short>; // expected-error{{constraints not satisfied for class template 'C5_check' [with T = short]}}
}
|