| // RUN: %clang_cc1 -std=c++2a -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::template temp<int>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} |
| // expected-note@-2{{because 'typename T::template temp<int>' would be invalid: no member named 'temp' in 'D'}} |
| // expected-note@-3{{because 'typename T::template 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]}} |
| } |
| |
| namespace PR48656 { |
| |
| template <typename T> concept C = requires { requires requires { T::a; }; }; |
| // expected-note@-1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}} |
| |
| template <C...> struct A {}; |
| // expected-note@-1 {{because 'PR48656::T1' does not satisfy 'C'}} |
| |
| struct T1 {}; |
| template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}} |
| |
| struct T2 { static constexpr bool a = false; }; |
| template struct A<T2>; |
| |
| template <typename T> struct T3 { |
| static void m(auto) requires requires { T::fail; } {} |
| // expected-note@-1 {{constraints not satisfied}} |
| // expected-note@-2 {{type 'int' cannot be used prior to '::'}} |
| }; |
| template <typename... Args> void t3(Args... args) { (..., T3<int>::m(args)); } |
| // expected-error@-1 {{no matching function for call to 'm'}} |
| |
| template void t3<int>(int); // expected-note {{requested here}} |
| |
| } // namespace PR48656 |