2020-01-24 06:43:22 +08:00
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -Wno-unused-value
2020-01-18 15:11:43 +08:00
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]}}