241 lines
7.7 KiB
C++
241 lines
7.7 KiB
C++
// RUN: %clang_cc1 %s -I%S -std=c++2a -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 'a' would be invalid: 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}}
|
|
|
|
namespace access_checks {
|
|
namespace in_requires_expression {
|
|
template<auto>
|
|
struct A {
|
|
static constexpr bool foo();
|
|
static constexpr bool bar();
|
|
static constexpr bool baz();
|
|
static constexpr bool faz();
|
|
};
|
|
|
|
class C{};
|
|
|
|
class B {
|
|
void p() {}
|
|
bool data_member = true;
|
|
static const bool static_member = true;
|
|
friend struct A<0>;
|
|
};
|
|
|
|
template<auto x>
|
|
constexpr bool A<x>::foo() {
|
|
return requires(B b) { b.p(); };
|
|
}
|
|
static_assert(!A<1>::foo());
|
|
static_assert(A<0>::foo());
|
|
|
|
template<auto x>
|
|
constexpr bool A<x>::bar() {
|
|
return requires() { B::static_member; };
|
|
}
|
|
static_assert(!A<1>::bar());
|
|
static_assert(A<0>::bar());
|
|
|
|
template<auto x>
|
|
constexpr bool A<x>::baz() {
|
|
return requires(B b) { b.data_member; };
|
|
}
|
|
static_assert(!A<1>::baz());
|
|
static_assert(A<0>::baz());
|
|
|
|
template<auto x>
|
|
constexpr bool A<x>::faz() {
|
|
return requires(B a, B b) {
|
|
a.p();
|
|
b.data_member;
|
|
B::static_member;
|
|
};
|
|
}
|
|
static_assert(!A<1>::faz());
|
|
static_assert(A<0>::faz());
|
|
} // namespace in_requires_expression
|
|
|
|
namespace in_concepts {
|
|
// Dependent access does not cause hard errors.
|
|
template<int N> class A;
|
|
|
|
template <> class A<0> {
|
|
static void f() {}
|
|
};
|
|
template<int N>
|
|
concept C1 = requires() { A<N>::f(); };
|
|
static_assert(!C1<0>);
|
|
|
|
template <> class A<1> {
|
|
public:
|
|
static void f() {}
|
|
};
|
|
static_assert(C1<1>);
|
|
|
|
// Non-dependent access to private member is a hard error.
|
|
class B{
|
|
static void f() {} // expected-note 2{{implicitly declared private here}}
|
|
};
|
|
template<class T>
|
|
concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
|
|
|
|
constexpr bool non_template_func() {
|
|
return requires() {
|
|
B::f(); // expected-error {{'f' is a private member}}
|
|
};
|
|
}
|
|
template<int x>
|
|
constexpr bool template_func() {
|
|
return requires() {
|
|
A<x>::f();
|
|
};
|
|
}
|
|
static_assert(!template_func<0>());
|
|
static_assert(template_func<1>());
|
|
} // namespace in_concepts
|
|
|
|
namespace in_trailing_requires {
|
|
template <class> struct B;
|
|
class A {
|
|
static void f();
|
|
friend struct B<short>;
|
|
};
|
|
|
|
template <class T> struct B {
|
|
static constexpr int index() requires requires{ A::f(); } {
|
|
return 1;
|
|
}
|
|
static constexpr int index() {
|
|
return 2;
|
|
}
|
|
};
|
|
|
|
static_assert(B<short>::index() == 1);
|
|
static_assert(B<int>::index() == 2);
|
|
|
|
namespace missing_member_function {
|
|
template <class T> struct Use;
|
|
class X {
|
|
int a;
|
|
static int B;
|
|
friend struct Use<short>;
|
|
};
|
|
template <class T> struct Use {
|
|
constexpr static int foo() requires requires(X x) { x.a; } {
|
|
return 1;
|
|
}
|
|
constexpr static int bar() requires requires { X::B; } {
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
void test() {
|
|
// FIXME: Propagate diagnostic.
|
|
Use<int>::foo(); //expected-error {{invalid reference to function 'foo': constraints not satisfied}}
|
|
static_assert(Use<short>::foo() == 1);
|
|
}
|
|
} // namespace missing_member_function
|
|
} // namespace in_trailing_requires
|
|
} // namespace access_check
|