If a fold expanded constraint would expand packs of different size, it is not a valid pack expansion and it is not satisfied. This should not produce an error. Fixes #99430
308 lines
11 KiB
C++
308 lines
11 KiB
C++
// RUN: %clang_cc1 -std=c++2c -verify %s
|
|
|
|
template <class T> concept A = true;
|
|
template <class T> concept C = A<T> && true;
|
|
template <class T> concept D = A<T> && __is_same(T, int);
|
|
|
|
|
|
template <class T> requires (A<T>)
|
|
constexpr int f(T) { return 0; };
|
|
template <class... T> requires (C<T> && ...)
|
|
constexpr int f(T...) { return 1; };
|
|
|
|
static_assert(f(0) == 0);
|
|
static_assert(f(1) == 0);
|
|
|
|
|
|
template <class... T> requires (A<T> && ...)
|
|
constexpr int g(T...) { return 0; };
|
|
template <class... T> requires (C<T> && ...)
|
|
constexpr int g(T...) { return 1; };
|
|
|
|
static_assert(g(0) == 1);
|
|
static_assert(g() == 1);
|
|
static_assert(g(1, 2) == 1);
|
|
|
|
|
|
|
|
template <class... T> requires (A<T> && ...)
|
|
constexpr int h(T...) { return 0; }; // expected-note {{candidate}}
|
|
template <class... T> requires (C<T> || ...)
|
|
constexpr int h(T...) { return 1; }; // expected-note {{candidate}}
|
|
|
|
static_assert(h(0) == 1); // expected-error {{call to 'h' is ambiguous}}
|
|
|
|
template <class... T> requires (A<T> || ...)
|
|
constexpr int i(T...) { return 0; }; // expected-note {{candidate}}
|
|
template <class... T> requires (C<T> && ...)
|
|
constexpr int i(T...) { return 1; }; // expected-note {{candidate}}
|
|
|
|
static_assert(i(0) == 1); // expected-error {{call to 'i' is ambiguous}}
|
|
|
|
|
|
template <class... T> requires (A<T> || ... || true)
|
|
constexpr int j(T...) { return 0; };
|
|
template <class... T> requires (C<T> && ... && true)
|
|
constexpr int j(T...) { return 1; };
|
|
|
|
static_assert(j(0) == 1);
|
|
static_assert(j() == 1);
|
|
|
|
|
|
|
|
template <class... T> requires (A<T> || ...)
|
|
constexpr int k(T...) { return 0; }; // expected-note {{candidate template ignored: constraints not satisfied [with T = <>]}}
|
|
template <class... T> requires (C<T> || ...)
|
|
constexpr int k(T...) { return 1; }; // expected-note {{candidate template ignored: constraints not satisfied [with T = <>]}}
|
|
|
|
static_assert(k(0) == 1);
|
|
static_assert(k() == 0); // expected-error {{no matching function for call to 'k'}}
|
|
static_assert(k(1, 2) == 1);
|
|
|
|
|
|
consteval int terse(A auto...) {return 1;}
|
|
consteval int terse(D auto...) {return 2;}
|
|
|
|
static_assert(terse() == 2);
|
|
static_assert(terse(0, 0) == 2);
|
|
static_assert(terse(0L, 0) == 1);
|
|
|
|
template <A... T>
|
|
consteval int tpl_head(A auto...) {return 1;}
|
|
template <D... T>
|
|
consteval int tpl_head(D auto...) {return 2;}
|
|
|
|
static_assert(tpl_head() == 2);
|
|
static_assert(tpl_head(0, 0) == 2);
|
|
static_assert(tpl_head(0L, 0) == 1);
|
|
|
|
|
|
namespace equivalence {
|
|
|
|
template <typename... T>
|
|
struct S {
|
|
template <typename... U>
|
|
void f() requires (A<U> && ...);
|
|
template <typename... U>
|
|
void f() requires (C<U> && ...);
|
|
|
|
template <typename... U>
|
|
void g() requires (A<T> && ...);
|
|
template <typename... U>
|
|
void g() requires (C<T> && ...);
|
|
|
|
template <typename... U>
|
|
void h() requires (A<U> && ...); // expected-note {{candidate}}
|
|
template <typename... U>
|
|
void h() requires (C<T> && ...); // expected-note {{candidate}}
|
|
};
|
|
|
|
void test() {
|
|
S<int>{}.f<int>();
|
|
S<int>{}.g<int>();
|
|
S<int>{}.h<int>(); // expected-error {{call to member function 'h' is ambiguous}}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
namespace substitution {
|
|
struct S {
|
|
using type = int;
|
|
};
|
|
|
|
template <typename... T>
|
|
consteval int And1() requires (C<typename T::type> && ...) { // #and1
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename... U>
|
|
consteval int And2() requires (C<typename U::type> && ... && C<typename T::type>) { // #and2
|
|
return 2;
|
|
}
|
|
|
|
template <typename T, typename... U>
|
|
consteval int And3() requires (C<typename T::type> && ... && C<typename U::type>) { // #and3
|
|
return 3;
|
|
}
|
|
|
|
template <typename... T>
|
|
consteval int Or1() requires (C<typename T::type> || ...) { // #or1
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename... U>
|
|
consteval int Or2() requires (C<typename U::type> || ... || C<typename T::type>) { // #or2
|
|
return 2;
|
|
}
|
|
|
|
template <typename T, typename... U>
|
|
consteval int Or3() requires (C<typename T::type> || ... || C<typename U::type>) { // #or3
|
|
return 3;
|
|
}
|
|
|
|
static_assert(And1<>() == 1);
|
|
static_assert(And1<S>() == 1);
|
|
static_assert(And1<S, S>() == 1);
|
|
static_assert(And1<int>() == 1); // expected-error {{no matching function for call to 'And1'}}
|
|
// expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and1 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And1<S, int>() == 1); // expected-error {{no matching function for call to 'And1'}}
|
|
// expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and1 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And1<int, S>() == 1); // expected-error {{no matching function for call to 'And1'}}
|
|
// expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and1 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And2<S>() == 2);
|
|
static_assert(And2<S, S>() == 2);
|
|
static_assert(And2<int>() == 2);
|
|
|
|
static_assert(And2<int, int>() == 2); // expected-error {{no matching function for call to 'And2'}}
|
|
// expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and2 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And2<S, int>() == 2); // expected-error {{no matching function for call to 'And2'}}
|
|
// expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and2 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And2<int, S>() == 2); // expected-error {{no matching function for call to 'And2'}}
|
|
// expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and2 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And3<S>() == 3);
|
|
static_assert(And3<S, S>() == 3);
|
|
static_assert(And3<int>() == 3); // expected-error {{no matching function for call to 'And3'}}
|
|
// expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and3 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And3<int, int>() == 3); // expected-error {{no matching function for call to 'And3'}}
|
|
// expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and3 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And3<S, int>() == 3); // expected-error {{no matching function for call to 'And3'}}
|
|
// expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and3 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(And3<int, S>() == 3); // expected-error {{no matching function for call to 'And3'}}
|
|
// expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
|
|
// expected-note@#and3 {{because substituted constraint expression is ill-formed}}
|
|
|
|
|
|
static_assert(Or1<>() == 1); // expected-error {{no matching function for call to 'Or1'}}
|
|
// expected-note@#or1 {{candidate template ignored: constraints not satisfied}}
|
|
static_assert(Or1<S>() == 1);
|
|
static_assert(Or1<int, S>() == 1);
|
|
static_assert(Or1<S, int>() == 1);
|
|
static_assert(Or1<S, S>() == 1);
|
|
static_assert(Or1<int>() == 1); // expected-error {{no matching function for call to 'Or1'}}
|
|
// expected-note@#or1 {{candidate template ignored: constraints not satisfied}} \
|
|
// expected-note@#or1 {{because substituted constraint expression is ill-formed}}
|
|
|
|
|
|
static_assert(Or2<S>() == 2);
|
|
static_assert(Or2<int, S>() == 2);
|
|
static_assert(Or2<S, int>() == 2);
|
|
static_assert(Or2<S, S>() == 2);
|
|
static_assert(Or2<int>() == 2); // expected-error {{no matching function for call to 'Or2'}}
|
|
// expected-note@#or2 {{candidate template ignored: constraints not satisfied}} \
|
|
// expected-note@#or2 {{because substituted constraint expression is ill-formed}}
|
|
|
|
static_assert(Or3<S>() == 3);
|
|
static_assert(Or3<int, S>() == 3);
|
|
static_assert(Or3<S, int>() == 3);
|
|
static_assert(Or3<S, S>() == 3);
|
|
static_assert(Or3<int>() == 3); // expected-error {{no matching function for call to 'Or3'}}
|
|
// expected-note@#or3 {{candidate template ignored: constraints not satisfied}} \
|
|
// expected-note@#or3 {{because substituted constraint expression is ill-formed}}
|
|
}
|
|
|
|
namespace bool_conversion_break {
|
|
|
|
template <typename ...V> struct A;
|
|
struct Thingy {
|
|
static constexpr int compare(const Thingy&) {return 1;}
|
|
};
|
|
template <typename ...T, typename ...U>
|
|
void f(A<T ...> *, A<U ...> *) // expected-note {{candidate template ignored: failed template argument deduction}}
|
|
requires (T::compare(U{}) && ...); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
|
|
|
|
void g() {
|
|
A<Thingy, Thingy> *ap;
|
|
f(ap, ap); // expected-error{{no matching function for call to 'f'}} \
|
|
// expected-note {{while checking constraint satisfaction}} \
|
|
// expected-note {{in instantiation of function template specialization}}
|
|
}
|
|
|
|
}
|
|
|
|
namespace nested {
|
|
|
|
template <typename... T>
|
|
struct S {
|
|
template <typename... U>
|
|
consteval static int f()
|
|
requires ((A<T> && ...) && ... && A<U> ) {
|
|
return 1;
|
|
}
|
|
|
|
template <typename... U>
|
|
consteval static int f()
|
|
requires ((C<T> && ...) && ... && C<U> ) {
|
|
return 2;
|
|
}
|
|
|
|
template <typename... U>
|
|
consteval static int g() // #nested-ambiguous-g1
|
|
requires ((A<T> && ...) && ... && A<U> ) {
|
|
return 1;
|
|
}
|
|
|
|
template <typename... U>
|
|
consteval static int g() // #nested-ambiguous-g2
|
|
requires ((C<U> && ...) && ... && C<T> ) {
|
|
return 2;
|
|
}
|
|
};
|
|
|
|
static_assert(S<int>::f<int>() == 2);
|
|
|
|
static_assert(S<int>::g<int>() == 2); // expected-error {{call to 'g' is ambiguous}}
|
|
// expected-note@#nested-ambiguous-g1 {{candidate}}
|
|
// expected-note@#nested-ambiguous-g2 {{candidate}}
|
|
|
|
|
|
}
|
|
|
|
namespace GH99430 {
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
using _Synth_three_way_result = int;
|
|
|
|
template <class... _Types>
|
|
class tuple;
|
|
|
|
template <int _Index>
|
|
struct tuple_element;
|
|
|
|
template <class, int...>
|
|
struct _Three_way_comparison_result_with_tuple_like {
|
|
using type = int;
|
|
};
|
|
|
|
template <class... _TTypes, int... _Indices>
|
|
requires(requires {
|
|
typename _Synth_three_way_result<_TTypes, tuple_element<_Indices>>;
|
|
} && ...)
|
|
|
|
struct _Three_way_comparison_result_with_tuple_like<tuple<_TTypes...>, _Indices...>{
|
|
using type = long;
|
|
};
|
|
|
|
static_assert(__is_same_as(_Three_way_comparison_result_with_tuple_like<tuple<int>, 0, 1>::type, int));
|
|
static_assert(__is_same_as(_Three_way_comparison_result_with_tuple_like<tuple<int>, 0>::type, long));
|
|
|
|
}
|