diff options
Diffstat (limited to 'clang/test')
10 files changed, 1128 insertions, 0 deletions
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp new file mode 100644 index 00000000000..578efb5b24e --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp @@ -0,0 +1,175 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -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]}} +}
\ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp new file mode 100644 index 00000000000..ea345320190 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +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> struct identity { using type = T; }; +template<typename T> using identity_t = T; + +// Type requirements +template<typename T> requires requires { typename identity_t<T>; } +struct r1; +template<typename U> requires requires { typename identity_t<U>; } // expected-note{{previous template declaration is here}} +struct r1; +template<typename T> requires requires { typename identity_t<T*>; } // expected-error{{requires clause differs in template redeclaration}} +struct r1; +template<typename T> requires requires { typename ::identity_t<T>; } +struct r1; + +template<typename Y> requires requires { typename identity<Y>::type; } +struct r2; +template<typename U> requires requires { typename identity<U>::type; } +struct r2; +template<typename T> requires requires { typename ::identity<T>::type; } // expected-note 2{{previous template declaration is here}} +struct r2; +template<typename T> requires requires { typename identity<T>::typr; } // expected-error{{requires clause differs in template redeclaration}} +struct r2; +namespace ns { + template<typename T> struct identity { using type = T; }; +} +template<typename T> requires requires { typename ns::identity<T>::type; } // expected-error{{requires clause differs in template redeclaration}} +struct r2; + +template<typename T> requires requires { typename T::template identity<T>::type; } +struct r3; +template<typename U> requires requires { typename U::template identity<U>::type; } // expected-note{{previous template declaration is here}} +struct r3; +template<typename T> requires requires { typename T::template identitr<T>::type; } // expected-error{{requires clause differs in template redeclaration}} +struct r3; + +template<typename T> requires requires { typename T::template temp<>; } +struct r4; +template<typename U> requires requires { typename U::template temp<>; } +struct r4; + +// Expr requirements +template<typename T> requires requires { 0; } // expected-note{{previous template declaration is here}} +struct r5; +template<typename T> requires requires { 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r5; + +template<typename T> +concept C1 = true; + +template<typename T> requires requires { sizeof(T); } +struct r6; +template<typename U> requires requires { sizeof(U); } // expected-note{{previous template declaration is here}} +struct r6; +template<typename U> requires requires { sizeof(U) - 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; +template<typename T> requires requires { { sizeof(T) }; } // expected-note 2{{previous template declaration is here}} +struct r6; +template<typename T> requires requires { { sizeof(T) } noexcept; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; +template<typename T> requires requires { { sizeof(T) } -> C1; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; + +template<typename T> requires requires { { sizeof(T) } -> C1; } +struct r7; +template<typename U> requires requires { { sizeof(U) } -> C1; } +struct r7; +template<typename T> requires requires { { sizeof(T) } -> C1<>; } // expected-note {{previous template declaration is here}} +struct r7; +template<typename U> requires requires { { sizeof(U) }; } // expected-error{{requires clause differs in template redeclaration}} +struct r7; + +template<typename T, typename U> +concept C2 = true; + +template<typename T> requires requires { { sizeof(T) } -> C2<T>; } +struct r8; +template<typename U> requires requires { { sizeof(U) } -> C2<U>; } // expected-note{{previous template declaration is here}} +struct r8; +template<typename T> requires requires { { sizeof(T) } -> C2<T*>; } // expected-error{{requires clause differs in template redeclaration}} +struct r8; + +// Nested requirements +template<typename T> requires requires { requires sizeof(T) == 0; } +struct r9; +template<typename U> requires requires { requires sizeof(U) == 0; } // expected-note{{previous template declaration is here}} +struct r9; +template<typename T> requires requires { requires sizeof(T) == 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r9; + +// Parameter list +template<typename T> requires requires { requires true; } +struct r10; +template<typename T> requires requires() { requires true; } // expected-note{{previous template declaration is here}} +struct r10; +template<typename T> requires requires(T i) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r10; + +template<typename T> requires requires(T i, T *j) { requires true; } // expected-note 2{{previous template declaration is here}} +struct r11; +template<typename T> requires requires(T i) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r11; +template<typename T> requires requires(T i, T *j, T &k) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r11; + +// Parameter names +template<typename T> requires requires(int i) { requires sizeof(i) == 1; } +struct r12; +template<typename T> requires requires(int j) { requires sizeof(j) == 1; } // expected-note 2{{previous template declaration is here}} +struct r12; +template<typename T> requires requires(int k) { requires sizeof(k) == 2; } // expected-error{{requires clause differs in template redeclaration}} +struct r12; +template<typename T> requires requires(const int k) { requires sizeof(k) == 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r12; + +// Order of requirements +template<typename T> requires requires { requires true; 0; } +struct r13; +template<typename T> requires requires { requires true; 0; } // expected-note{{previous template declaration is here}} +struct r13; +template<typename T> requires requires { 0; requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r13; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp new file mode 100644 index 00000000000..f8776832d33 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +static_assert(requires { requires true; }); + +template<typename T> requires requires { requires false; } // expected-note{{because 'false' evaluated to false}} +struct r1 {}; + +using r1i = r1<int>; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} + +template<typename T> requires requires { requires sizeof(T) == 0; } // expected-note{{because 'sizeof(int) == 0' (4 == 0) evaluated to false}} +struct r2 {}; + +using r2i = r2<int>; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}} + +template<typename T> requires requires (T t) { requires sizeof(t) == 0; } // expected-note{{because 'sizeof (t) == 0' (4 == 0) evaluated to false}} +struct r3 {}; + +using r3i = r3<int>; // expected-error{{constraints not satisfied for class template 'r3' [with T = int]}} + +template<typename T> +struct X { + template<typename U> requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} + struct r4 {}; +}; + +using r4i = X<void>::r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with U = int]}} + +// C++ [expr.prim.req.nested] Examples +namespace std_example { + template<typename U> concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}} + template<typename T> concept D = + requires (T t) { + requires C1<decltype (+t)>; // expected-note{{because 'decltype(+t)' (aka 'int') does not satisfy 'C1'}} + }; + + struct T1 { char operator+() { return 'a'; } }; + static_assert(D<T1>); + template<D T> struct D_check {}; // expected-note{{because 'short' does not satisfy 'D'}} + using dc1 = D_check<short>; // expected-error{{constraints not satisfied for class template 'D_check' [with T = short]}} + + template<typename T> + concept C2 = requires (T a) { // expected-note{{'a' declared here}} + requires sizeof(a) == 4; // OK + requires a == 0; // expected-error{{constraint variable 'a' cannot be used in an evaluated context}} + }; +}
\ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp new file mode 100644 index 00000000000..a1a745253dd --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +// Examples from standard + +template<typename T, typename U> +concept convertible_to = requires(T t) { U(t); }; + +template<typename T> +concept R = requires (T i) { + typename T::type; + {*i} -> convertible_to<const typename T::type&>; +}; + +template<typename T> requires R<T> struct S {}; + +struct T { + using type = int; + type i; + const type &operator*() { return i; } +}; + +using si = S<T>; + +template<typename T> +requires requires (T x) { x + x; } // expected-note{{because 'x + x' would be invalid: invalid operands to binary expression ('T' and 'T')}} +T add(T a, T b) { return a + b; } // expected-note{{candidate template ignored: constraints not satisfied [with T = T]}} + +int x = add(1, 2); +int y = add(T{}, T{}); // expected-error{{no matching function for call to 'add'}} + +template<typename T> +concept C = requires (T x) { x + x; }; // expected-note{{because 'x + x' would be invalid: invalid operands to binary expression ('T' and 'T')}} +template<typename T> requires C<T> // expected-note{{because 'T' does not satisfy 'C'}} +T add2(T a, T b) { return a + b; } // expected-note{{candidate template ignored: constraints not satisfied [with T = T]}} + +int z = add2(1, 2); +int w = add2(T{}, T{}); // expected-error{{no matching function for call to 'add2'}}
\ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp new file mode 100644 index 00000000000..f9d8c3eed11 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +using A = int; + +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>; + +static_assert(requires { requires true; 0; typename A; + { 0 } -> same_as<int>; }); +static_assert(is_same_v<bool, decltype(requires { requires false; })>); + +// Check that requires expr is an unevaluated context. +struct Y { + int i; + static constexpr bool r = requires { i; }; +}; + +template<typename T> requires requires (T t) { + requires false; // expected-note{{because 'false' evaluated to false}} + requires false; + requires requires { + requires false; + }; +} +struct r1 { }; + +using r1i = r1<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = int]}} + +template<typename T> requires requires (T t) { + requires requires { + requires false; // expected-note{{because 'false' evaluated to false}} + }; +} +struct r2 { }; + +using r2i = r2<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r2' [with T = int]}} + +template<typename T> requires requires (T t) { + requires requires { + requires true; + }; + requires true; + requires requires { + requires false; // expected-note{{because 'false' evaluated to false}} + }; +} +struct r3 { }; + +using r3i = r3<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r3' [with T = int]}} + +template<typename T> +struct S { static const int s = T::value; }; + +template<typename T> requires requires { T::value; S<T>::s; } +// expected-note@-1 {{because 'T::value' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +struct r4 { }; + +using r4i = r4<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}}
\ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp new file mode 100644 index 00000000000..a5e6c3057fe --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 %s -I%S -std=c++2a -fconcepts-ts -verify + +namespace std { struct type_info; } + +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}} + +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@-1{{because 'a + b' would be invalid: invalid operands to binary expression ('A' and 'const A')}} +// expected-note@-2{{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@-1{{because 'a.foo()' would be invalid: no member named 'foo' in 'A'}} +// expected-note@-2{{because 'a.foo()' would be invalid: member reference base type 'int' is not a structure or union}} +// expected-note@-3{{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@-1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} +// expected-note@-2{{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]}} + +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)>; + +template<class T> void f(T) = delete; +template<class T> requires (sizeof(T) == 1) void f(T) { } + +template<typename T> requires requires(T t) { f(t); } +// expected-note@-1{{because 'f(t)' would be invalid: call to deleted function 'f'}} +struct r5 {}; + +using r5i1 = r5<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r5' [with T = int]}} +using r5i2 = r5<char>; + +template<typename T> +struct E { + struct non_default_constructible { non_default_constructible(T t) { } }; +}; + +template<typename T> requires requires(T t) { typename E<T>::non_default_constructible{}; } +// expected-note@-1 {{because 'typename E<T>::non_default_constructible({})' would be invalid: no matching constructor for initialization of 'typename E<int>::non_default_constructible'}} +struct r6 {}; + +using r6i1 = r6<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r6' [with T = int]}} + +template<typename T> requires requires(T t) { typename E<T>::non_default_constructible(); } +// expected-note@-1 {{because 'typename E<T>::non_default_constructible()' would be invalid: no matching constructor for initialization of 'typename E<int>::non_default_constructible'}} +struct r7 {}; + +using r7i1 = r7<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r7' [with T = int]}} + +// C++ [expr.prim.req.simple] Example +namespace std_example { + template<typename T> concept C = + requires (T a, T b) { // expected-note{{because substituted constraint expression is ill-formed: argument may not have 'void' type}} + a + b; // expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('int *' and 'int *')}} + }; + + static_assert(C<int>); + template<C T> struct C_check {}; // expected-note{{because 'void' does not satisfy 'C'}} expected-note{{because 'int *' does not satisfy 'C'}} + using c1c1 = C_check<void>; // expected-error{{constraints not satisfied for class template 'C_check' [with T = void]}} + using c1c2 = C_check<int *>; // expected-error{{constraints not satisfied for class template 'C_check' [with T = int *]}} +} + +// typeid() of an expression becomes potentially evaluated if the expression is +// of a polymorphic type. +class X { virtual ~X(); }; +constexpr bool b = requires (X &x) { static_cast<int(*)[(typeid(x), 0)]>(nullptr); }; +// expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}} +// expected-note@-2{{'x' declared here}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp new file mode 100644 index 00000000000..8e402a88c40 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp @@ -0,0 +1,194 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +using A = int; + +template<typename T> using identity_t = T; // expected-note 4{{template is declared here}}} + +template<typename T> struct identity { using type = T; }; +// expected-note@-1 2{{template is declared here}} + +struct C {}; + +struct D { static int type; }; // expected-note{{referenced member 'type' is declared here}} + +// Basic unqualified and global-qualified lookups + +static_assert(requires { typename A; typename ::A; }); +static_assert(requires { typename identity_t<A>; typename ::identity_t<A>; }); +static_assert(!requires { typename identity_t<A, A>; }); // expected-error{{too many template arguments for alias template 'identity_t'}} +static_assert(!requires { typename ::identity_t<A, A>; }); // expected-error{{too many template arguments for alias template 'identity_t'}} +static_assert(requires { typename identity<A>; }); +static_assert(!requires { typename identity; }); +// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}} +static_assert(!requires { typename ::identity; }); +// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}} +static_assert(!requires { typename identity_t; }); +// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}} +static_assert(!requires { typename ::identity_t; }); +// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}} + +namespace ns { + using B = int; + int C = 0; + // expected-note@-1 {{referenced 'C' is declared here}} + static_assert(requires { typename A; typename B; typename ::A; }); + static_assert(!requires { typename ns::A; }); // expected-error{{no type named 'A' in namespace 'ns'}} + static_assert(!requires { typename ::B; }); // expected-error{{no type named 'B' in the global namespace}} + static_assert(requires { typename C; }); + // expected-error@-1 {{typename specifier refers to non-type 'C'}} +} + +// member type lookups + +static_assert(requires { typename identity<int>::type; typename ::identity<int>::type; }); +static_assert(!requires { typename identity<int>::typr; }); // expected-error{{no type named 'typr' in 'identity<int>'}} +static_assert(!requires { typename ::identity<int>::typr; }); // expected-error{{no type named 'typr' in 'identity<int>'}} + +template<typename T> requires requires { typename T::type; } +// expected-note@-1 {{because 'typename T::type' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +// expected-note@-2 {{because 'typename T::type' would be invalid: no type named 'type' in 'C'}} +// expected-note@-3 {{because 'typename T::type' would be invalid: typename specifier refers to non-type member 'type' in 'D'}} +// expected-note@-4 {{in instantiation of template class 'invalid<D>' requested here}} +// expected-note@-5 {{in instantiation of requirement here}} +// expected-note@-6 {{while substituting template arguments into constraint expression here}} +// expected-note@-7 {{because 'typename T::type' would be invalid}} +struct r1 {}; + +using r1i1 = r1<identity<int>>; +using r1i2 = r1<int>; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} +using r1i3 = r1<C>; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}} +using r1i4 = r1<D>; // expected-error{{constraints not satisfied for class template 'r1' [with T = D]}} + +template<typename T> struct invalid { typename T::type x; }; +// expected-error@-1 {{typename specifier refers to non-type member 'type' in 'D'}} +using r1i5 = r1<invalid<D>>; +// expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = invalid<D>]}} +// expected-note@-2 {{while checking constraint satisfaction for template 'r1<invalid<D> >' required here}} + +// mismatching template arguments + +template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note{{because 'typename identity<Ts...>' would be invalid: too many template arguments for class template 'identity'}} +struct r2 {}; + +using r2i1 = r2<int>; +using r2i2 = r2<void>; +using r2i3 = r2<int, int>; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = <int, int>]}} + +namespace ns2 { + template<typename T, typename U> struct identity {}; + + template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note 2{{because 'typename identity<Ts...>' would be invalid: too few template arguments for class template 'identity'}} + struct r4 {}; + + using r4i1 = r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int>]}} +} + +using r4i2 = ns2::r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int>]}} + +using E = int; +template<typename T> requires requires { typename E<T>; } // expected-error{{expected ';' at end of requirement}} +struct r5v1 {}; +template<typename T> requires requires { typename ::E<T>; } // expected-error{{expected ';' at end of requirement}} +struct r5v2 {}; + +template<typename T> requires (sizeof(T) == 1) +struct chars_only {}; + +template<typename T> requires requires { typename chars_only<T>; } // expected-note{{because 'typename chars_only<T>' would be invalid: constraints not satisfied for class template 'chars_only' [with T = int]}} +struct r6 {}; + +using r6i = r6<int>; // expected-error{{constraints not satisfied for class template 'r6' [with T = int]}} + +template<typename T> int F = 0; // expected-note 2{{variable template 'F' declared here}} + +static_assert(!requires { typename F<int>; }); +// expected-error@-1{{template name refers to non-type template 'F'}} +static_assert(!requires { typename ::F<int>; }); +// expected-error@-1{{template name refers to non-type template '::F'}} + +struct G { template<typename T> static T temp; }; + +template<typename T> requires requires { typename T::template temp<int>; } +// expected-note@-1{{because 'typename T::temp<int>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +// expected-note@-2{{because 'typename T::temp<int>' would be invalid: no member named 'temp' in 'D'}} +// expected-note@-3{{because 'typename T::temp<int>' would be invalid: template name refers to non-type template 'G::template temp'}} +struct r7 {}; + +using r7i1 = r7<int>; // expected-error{{constraints not satisfied for class template 'r7' [with T = int]}} +using r7i2 = r7<D>; // expected-error{{constraints not satisfied for class template 'r7' [with T = D]}} +using r7i3 = r7<G>; // expected-error{{constraints not satisfied for class template 'r7' [with T = G]}} + +template<typename T> struct H; + +template<typename T> requires requires { typename H<T>; } +struct r8 {}; + +using r8i = r8<int>; + +template<typename T> struct I { struct incomplete; }; // expected-note{{member is declared here}} + +static_assert(!requires { I<int>::incomplete::inner; }); // expected-error{{implicit instantiation of undefined member 'I<int>::incomplete'}} + +template<typename T> requires requires { typename I<T>::incomplete::inner; } // expected-note{{because 'typename I<T>::incomplete::inner' would be invalid: implicit instantiation of undefined member 'I<int>::incomplete'}} +struct r9 {}; + +using r9i = r9<int>; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}} + +namespace ns3 { + struct X { }; // expected-note 2{{candidate found by name lookup is 'ns3::X'}} +} + +struct X { using inner = int; }; // expected-note 2{{candidate found by name lookup is 'X'}} + +using namespace ns3; +static_assert(requires { typename X; }); // expected-error{{reference to 'X' is ambiguous}} +static_assert(requires { typename X::inner; }); // expected-error{{reference to 'X' is ambiguous}} +// expected-error@-1{{unknown type name 'inner'}} + +// naming a type template specialization in a type requirement does not require +// it to be complete and should not care about partial specializations. + +template<typename T> +struct Z; + +template<typename T> requires (sizeof(T) >= 1) +struct Z<T> {}; // expected-note{{partial specialization matches [with T = int]}} + +template<typename T> requires (sizeof(T) <= 4) +struct Z<T> {}; // expected-note{{partial specialization matches [with T = int]}} + +Z<int> x; // expected-error{{ambiguous partial specializations of 'Z<int>'}} + +static_assert(requires { typename Z<int>; }); + +// C++ [expr.prim.req.type] Example +namespace std_example { + template<typename T, typename T::type = 0> struct S; + // expected-note@-1 {{because 'typename S<T>' would be invalid: no type named 'type' in 'std_example::has_inner}} + template<typename T> using Ref = T&; // expected-note{{because 'typename Ref<T>' would be invalid: cannot form a reference to 'void'}} + template<typename T> concept C1 = + requires { + typename T::inner; + // expected-note@-1 {{because 'typename T::inner' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} + // expected-note@-2 {{because 'typename T::inner' would be invalid: no type named 'inner' in 'std_example::has_type'}} + }; + template<typename T> concept C2 = requires { typename S<T>; }; + template<typename T> concept C3 = requires { typename Ref<T>; }; + + struct has_inner { using inner = int;}; + struct has_type { using type = int; }; + struct has_inner_and_type { using inner = int; using type = int; }; + + static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>); + template<C1 T> struct C1_check {}; + // expected-note@-1 {{because 'int' does not satisfy 'C1'}} + // expected-note@-2 {{because 'std_example::has_type' does not satisfy 'C1'}} + template<C2 T> struct C2_check {}; + // expected-note@-1 {{because 'std_example::has_inner' does not satisfy 'C2'}} + template<C3 T> struct C3_check {}; + // expected-note@-1 {{because 'void' does not satisfy 'C3'}} + using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}} + using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}} + using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}} + using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}} +}
\ No newline at end of file diff --git a/clang/test/PCH/cxx2a-requires-expr.cpp b/clang/test/PCH/cxx2a-requires-expr.cpp new file mode 100644 index 00000000000..d52d451c2d6 --- /dev/null +++ b/clang/test/PCH/cxx2a-requires-expr.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-pch -std=c++2a -fconcepts-ts -o %t %s +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x ast -ast-print %t | FileCheck %s + +template<typename T> +concept C = true; + +template<typename T, typename U> +concept C2 = true; + +template<typename T> +bool f() { + // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2<int>; typename T::a; requires T::val; }; + return requires (T t) { + t++; + { t++ } noexcept -> C; + { t++ } -> C2<int>; + typename T::a; + requires T::val; + }; +} diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp new file mode 100644 index 00000000000..a53189caa5f --- /dev/null +++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp @@ -0,0 +1,141 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify + +bool r1 = requires () {}; +// expected-error@-1 {{a requires expression must contain at least one requirement}} + +bool r2 = requires { requires true; }; + +bool r3 = requires (int a, ...) { requires true; }; +// expected-error@-1 {{varargs not allowed in requires expression}} + +template<typename... T> +bool r4 = requires (T... ts) { requires true; }; + +bool r5 = requires (bool c, int d) { c; d; }; + +bool r6 = requires (bool c, int d) { c; d; } && decltype(d){}; +// expected-error@-1 {{use of undeclared identifier 'd'}} + +bool r7 = requires (bool c) { c; (requires (int d) { c; d; }); d; } && decltype(c){} && decltype(d){}; +// expected-error@-1 2{{use of undeclared identifier 'd'}} +// expected-error@-2 {{use of undeclared identifier 'c'}} + +bool r8 = requires (bool, int) { requires true; }; + +bool r9 = requires (bool a, int a) { requires true; }; +// expected-error@-1 {{redefinition of parameter 'a'}} +// expected-note@-2 {{previous declaration is here}} + +bool r10 = requires (struct new_struct { int x; } s) { requires true; }; +// expected-error@-1 {{'new_struct' cannot be defined in a parameter type}} + +bool r11 = requires (int x(1)) { requires true; }; +// expected-error@-1 {{expected parameter declarator}} +// expected-error@-2 {{expected ')'}} +// expected-note@-3 {{to match this '('}} + +bool r12 = requires (int x = 10) { requires true; }; +// expected-error@-1 {{default arguments not allowed for parameters of a requires expression}} + +bool r13 = requires (int f(int)) { requires true; }; + +bool r14 = requires (int (*f)(int)) { requires true; }; + +bool r15 = requires (10) { requires true; }; +// expected-error@-1 {{expected parameter declarator}} + +bool r16 = requires (auto x) { requires true; }; +// expected-error@-1 {{'auto' not allowed in requires expression parameter}} + +bool r17 = requires (auto [x, y]) { requires true; }; +// expected-error@-1 {{'auto' not allowed in requires expression parameter}} +// expected-error@-2 {{use of undeclared identifier 'x'}} + +using a = int; + +bool r18 = requires { typename a; }; + +bool r19 = requires { typename ::a; }; + +template<typename T> struct identity { using type = T; }; + +template<typename T> using identity_t = T; + +bool r20 = requires { + typename identity<int>::type; + typename identity<int>; + typename ::identity_t<int>; +}; + +struct s { bool operator==(const s&); ~s(); }; + +bool r21 = requires { typename s::operator==; }; +// expected-error@-1 {{expected an identifier or template-id after '::'}} + +bool r22 = requires { typename s::~s; }; +// expected-error@-1 {{expected an identifier or template-id after '::'}} + +template<typename T> +bool r23 = requires { typename identity<T>::temp<T>; }; +// expected-error@-1 {{use 'template' keyword to treat 'temp' as a dependent template name}} + +template<typename T> +bool r24 = requires { + typename identity<T>::template temp<T>; + typename identity<T>::template temp; // expected-error{{expected an identifier or template-id after '::'}} +}; + +bool r25 = requires { ; }; +// expected-error@-1 {{expected expression}} + +bool r26 = requires { {}; }; +// expected-error@-1 {{expected expression}} + +bool r27 = requires { { 0 } noexcept; }; + +bool r28 = requires { { 0 } noexcept noexcept; }; +// expected-error@-1 {{expected '->' before expression type requirement}} +// expected-error@-2 {{expected concept name with optional arguments}} + +template<typename T> +concept C1 = true; + +template<typename T, typename U> +concept C2 = true; + +bool r29 = requires { { 0 } noexcept C1; }; +// expected-error@-1 {{expected '->' before expression type requirement}} + +bool r30 = requires { { 0 } noexcept -> C2<int>; }; + +template<typename T> +T i1 = 0; + +bool r31 = requires { requires false, 1; }; +// expected-error@-1 {{expected ';' at end of requirement}} + +bool r32 = requires { 0 noexcept; }; +// expected-error@-1 {{'noexcept' can only be used in a compound requirement (with '{' '}' around the expression)}} + +bool r33 = requires { 0 int; }; +// expected-error@-1 {{expected ';' at end of requirement}} + +bool r34 = requires { requires true }; +// expected-error@-1 {{expected ';' at end of requirement}} + +bool r35 = requires (bool b) { requires sizeof(b) == 1; }; + +void r36(bool b) requires requires { 1 } {} +// expected-error@-1 {{expected ';' at end of requirement}} + +bool r37 = requires { requires { 1; }; }; +// expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} + +bool r38 = requires { requires () { 1; }; }; +// expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} + +bool r39 = requires { requires (int i) { i; }; }; +// expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} + +bool r40 = requires { requires (); }; +// expected-error@-1 {{expected expression}} diff --git a/clang/test/SemaTemplate/instantiate-requires-expr.cpp b/clang/test/SemaTemplate/instantiate-requires-expr.cpp new file mode 100644 index 00000000000..3304fd25cdc --- /dev/null +++ b/clang/test/SemaTemplate/instantiate-requires-expr.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify -Wno-unused-value + +template<typename T, typename U> +constexpr bool is_same_v = false; + +template<typename T> +constexpr bool is_same_v<T, T> = true; + +// We use a hack in this file to make the compiler print out the requires +// expression after it has been instantiated - we put false_v<requires {...}> as +// the requires clause of a class template, then instantiate the template. +// The requirement will not be satisfied, and the explaining diagnostic will +// print out false_v<requires {...}> in its raw form (the false_v serves to +// prevent the diagnostic from elaborating on why the requires expr wasn't +// satisfied). + +template<bool v> +constexpr bool false_v = false; + +template<typename... Ts> +using void_t = void; + +// Check that requires parameters are instantiated correctly. + +template<typename T> requires +false_v<requires (T t) { requires is_same_v<decltype(t), int>; }> +// expected-note@-1 {{because 'false_v<requires (int t) { requires is_same_v<decltype(t), int>; }>' evaluated to false}} +// expected-note@-2 {{because 'false_v<requires (char t) { requires is_same_v<decltype(t), int>; }>' evaluated to false}} +struct r1 {}; + +using r1i1 = r1<int>; // expected-error {{constraints not satisfied for class template 'r1' [with T = int]}} +using r1i2 = r1<char>; // expected-error {{constraints not satisfied for class template 'r1' [with T = char]}} + +// Check that parameter packs work. + +template<typename... Ts> requires +false_v<requires (Ts... ts) {requires ((sizeof(ts) == 2) && ...);}> +// expected-note@-1 {{because 'false_v<requires (short ts, unsigned short ts) { requires (sizeof (ts) == 2) && (sizeof (ts) == 2); }>'}} +// expected-note@-2 {{because 'false_v<requires (short ts) { requires (sizeof (ts) == 2); }>' evaluated to false}} +struct r2 {}; + +using r2i1 = r2<short, unsigned short>; // expected-error {{constraints not satisfied for class template 'r2' [with Ts = <short, unsigned short>]}} +using r2i2 = r2<short>; // expected-error {{constraints not satisfied for class template 'r2' [with Ts = <short>]}} + +template<typename... Ts> requires +false_v<(requires (Ts ts) {requires sizeof(ts) != 0;} && ...)> +// expected-note@-1 {{because 'false_v<requires (short ts) { requires sizeof (ts) != 0; } && requires (unsigned short ts) { requires sizeof (ts) != 0; }>' evaluated to false}} +// expected-note@-2 {{because 'false_v<requires (short ts) { requires sizeof (ts) != 0; }>' evaluated to false}} +struct r3 {}; + +using r3i1 = r3<short, unsigned short>; // expected-error {{constraints not satisfied for class template 'r3' [with Ts = <short, unsigned short>]}} +using r3i2 = r3<short>; // expected-error {{constraints not satisfied for class template 'r3' [with Ts = <short>]}} + +template<typename T> +struct identity { using type = T; }; + +namespace type_requirement { + struct A {}; + + // check that nested name specifier is instantiated correctly. + template<typename T> requires false_v<requires { typename T::type; }> // expected-note{{because 'false_v<requires { typename identity<int>::type; }>' evaluated to false}} + struct r1 {}; + + using r1i = r1<identity<int>>; // expected-error{{constraints not satisfied for class template 'r1' [with T = identity<int>]}} + + // check that template argument list is instantiated correctly. + template<typename T> + struct contains_template { + template<typename U> requires is_same_v<contains_template<T>, U> + using temp = int; + }; + + template<typename T> requires + false_v<requires { typename T::template temp<T>; }> + // expected-note@-1 {{because 'false_v<requires { typename contains_template<int>::temp<contains_template<int> >; }>' evaluated to false}} + // expected-note@-2 {{because 'false_v<requires { typename contains_template<short>::temp<contains_template<short> >; }>' evaluated to false}} + struct r2 {}; + + using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}} + using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<short>]}} + + // substitution error occurs, then requires expr is instantiated again + + template<typename T> + struct a { + template<typename U> requires (requires { typename T::a::a; }, false) + // expected-note@-1{{because 'requires { <<error-type>>; } , false' evaluated to false}} + struct r {}; + }; + + using ari = a<int>::r<short>; // expected-error{{constraints not satisfied for class template 'r' [with U = short]}} + + // Parameter pack inside expr + template<typename... Ts> requires + false_v<(requires { typename Ts::type; } && ...)> + // expected-note@-1 {{because 'false_v<requires { typename identity<short>::type; } && requires { typename identity<int>::type; } && requires { <<error-type>>; }>' evaluated to false}} + struct r5 {}; + + using r5i = r5<identity<short>, identity<int>, short>; // expected-error{{constraints not satisfied for class template 'r5' [with Ts = <identity<short>, identity<int>, short>]}} + template<typename... Ts> requires + false_v<(requires { typename void_t<Ts>; } && ...)> // expected-note{{because 'false_v<requires { typename void_t<int>; } && requires { typename void_t<short>; }>' evaluated to false}} + struct r6 {}; + + using r6i = r6<int, short>; // expected-error{{constraints not satisfied for class template 'r6' [with Ts = <int, short>]}} + + template<typename... Ts> requires + false_v<(requires { typename Ts::template aaa<Ts>; } && ...)> + // expected-note@-1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}} + struct r7 {}; + + using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}} +} + +namespace expr_requirement { + // check that compound/simple requirements are instantiated correctly. + + template<typename T> requires false_v<requires { sizeof(T); { sizeof(T) }; }> + // expected-note@-1 {{because 'false_v<requires { sizeof(int); { sizeof(int) }; }>' evaluated to false}} + // expected-note@-2 {{because 'false_v<requires { <<error-expression>>; { sizeof(T) }; }>' evaluated to false}} + struct r1 {}; + + using r1i1 = r1<int>; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} + using r1i2 = r1<void>; // expected-error{{constraints not satisfied for class template 'r1' [with T = void]}} + + // substitution error occurs in expr, then expr is instantiated again. + + template<typename T> + struct a { + template<typename U> requires (requires { sizeof(T::a); }, false) // expected-note{{because 'requires { <<error-expression>>; } , false' evaluated to false}} + struct r {}; + }; + + using ari = a<int>::r<short>; // expected-error{{constraints not satisfied for class template 'r' [with U = short]}} + + // check that the return-type-requirement is instantiated correctly. + + template<typename T, typename U = int> + concept C1 = is_same_v<T, U>; + + template<typename T> requires false_v<requires(T t) { { t } -> C1<T>; }> + // expected-note@-1 {{because 'false_v<requires (int t) { { t } -> C1<int>; }>' evaluated to false}} + // expected-note@-2 {{because 'false_v<requires (double t) { { t } -> C1<double>; }>' evaluated to false}} + struct r2 {}; + + using r2i1 = r2<int>; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}} + using r2i2 = r2<double>; // expected-error{{constraints not satisfied for class template 'r2' [with T = double]}} + + + // substitution error occurs in return type requirement, then requires expr is + // instantiated again. + + template<typename T> + struct b { + template<typename U> requires (requires { { 0 } -> C1<typename T::a>; }, false) // expected-note{{because 'requires { { 0 } -> <<error-type>>; } , false' evaluated to false}} + struct r {}; + }; + + using bri = b<int>::r<short>; // expected-error{{constraints not satisfied for class template 'r' [with U = short]}} + + + template<typename... Ts> requires + false_v<(requires { { 0 } noexcept -> C1<Ts>; } && ...)> + // expected-note@-1 {{because 'false_v<requires { { 0 } noexcept -> C1<int>; } && requires { { 0 } noexcept -> C1<unsigned int>; }>' evaluated to false}} + struct r3 {}; + + using r3i = r3<int, unsigned int>; // expected-error{{constraints not satisfied for class template 'r3' [with Ts = <int, unsigned int>]}} +} + +namespace nested_requirement { + // check that constraint expression is instantiated correctly + template<typename T> requires false_v<requires { requires sizeof(T) == 2; }> // expected-note{{because 'false_v<requires { requires sizeof(int) == 2; }>' evaluated to false}} + struct r1 {}; + + using r1i = r1<int>; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} + + // substitution error occurs in expr, then expr is instantiated again. + template<typename T> + struct a { + template<typename U> requires + (requires { requires sizeof(T::a) == 0; }, false) // expected-note{{because 'requires { requires <<error-expression>>; } , false' evaluated to false}} + struct r {}; + }; + + using ari = a<int>::r<short>; // expected-error{{constraints not satisfied for class template 'r' [with U = short]}} + + // Parameter pack inside expr + template<typename... Ts> requires + false_v<(requires { requires sizeof(Ts) == 0; } && ...)> + // expected-note@-1 {{because 'false_v<requires { requires sizeof(int) == 0; } && requires { requires sizeof(short) == 0; }>' evaluated to false}} + struct r2 {}; + + using r2i = r2<int, short>; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = <int, short>]}} +} + +// Parameter pack inside multiple requirements +template<typename... Ts> requires +false_v<(requires { requires sizeof(Ts) == 0; sizeof(Ts); } && ...)> +// expected-note@-1 {{because 'false_v<requires { requires sizeof(int) == 0; sizeof(Ts); } && requires { requires sizeof(short) == 0; sizeof(Ts); }>' evaluated to false}} +struct r4 {}; + +using r4i = r4<int, short>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int, short>]}} + +template<typename... Ts> requires +false_v<(requires(Ts t) { requires sizeof(t) == 0; t++; } && ...)> +// expected-note@-1 {{because 'false_v<requires (int t) { requires sizeof (t) == 0; t++; } && requires (short t) { requires sizeof (t) == 0; t++; }>' evaluated to false}} +struct r5 {}; + +using r5i = r5<int, short>; // expected-error{{constraints not satisfied for class template 'r5' [with Ts = <int, short>]}} + +template<typename T> requires +false_v<(requires(T t) { T{t}; })> // T{t} creates an "UnevaluatedList" context. +// expected-note@-1 {{because 'false_v<(requires (int t) { int{t}; })>' evaluated to false}} +struct r6 {}; + +using r6i = r6<int>; +// expected-error@-1 {{constraints not satisfied for class template 'r6' [with T = int]}} |