llvm/clang/test/SemaCXX/cxx2c-fold-exprs.cpp

// 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));

}