// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
template <typename> constexpr bool True = true;
template <typename T> concept C = True<T>;
template <typename T> concept D = C<T> && sizeof(T) > 2;
template <typename T> concept E = D<T> && alignof(T) > 1;
struct A {};
template <typename, auto, int, A, typename...> struct S {};
template <typename, auto, int, A, auto...> struct S2 {};
template <typename T, typename U> struct X {};
namespace p6 {
struct B;
void f(C auto &, auto &) = delete;
template <C Q> void f(Q &, C auto &);
void g(struct A *ap, struct B *bp) {
f(*ap, *bp);
}
#if 0
// FIXME: [temp.func.order]p6.2.1 is not implemented, matching GCC.
template <typename T, C U, typename V> bool operator==(X<T, U>, V) = delete;
template <C T, C U, C V> bool operator==(T, X<U, V>);
bool h() {
return X<void *, int>{} == 0;
}
#endif
template<C T, C auto M, int W, A S,
template<typename, auto, int, A, typename...> class U,
typename... Z>
void foo(T, U<T, M, W, S, Z...>) = delete;
template<C T, D auto M, int W, A S,
template<typename, auto, int, A, typename...> class U,
typename... Z>
void foo(T, U<T, M, W, S, Z...>) = delete;
template<C T, E auto M, int W, A S,
template<typename, auto, int, A, typename...> class U,
typename... Z>
void foo(T, U<T, M, W, S, Z...>);
void bar(S<int, 1, 1, A{}, int> s, S2<int, 1, 1, A{}, 0, 0u> s2) {
foo(0, s);
}
template<C auto... T> void bar2();
template<D auto... T> void bar2() = delete;
} // namespace p6
namespace TestConversionFunction {
struct Y {
template<C T, typename U> operator X<T, U>(); // expected-note {{candidate function [with T = int, U = int]}}
template<typename T, typename U> operator X<U, T>(); // expected-note {{candidate function [with T = int, U = int]}}
};
X<int,int> f() {
return Y{}; // expected-error {{conversion from 'Y' to 'X<int, int>' is ambiguous}}
}
}
namespace ClassPartialSpecPartialOrdering {
template<D T> struct Y { Y()=delete; }; // expected-note {{template is declared here}}
template<C T> struct Y<T> {}; // expected-error {{class template partial specialization is not more specialized than the primary template}}
template<C T, int I> struct Y1 { Y1()=delete; };
template<D T> struct Y1<T, 2> { Y1()=delete; };
template<E T> struct Y1<T, 1+1> {};
template<class T, int I, int U> struct Y2 {};
template<class T, int I> struct Y2<T*, I, I+2> {}; // expected-note {{partial specialization matches}}
template<C T, int I> struct Y2<T*, I, I+1+1> {}; // expected-note {{partial specialization matches}}
template<C T, C auto I, int W, A S, template<typename, auto, int, A, typename...> class U, typename... Z>
struct Y3 { Y3()=delete; };
template<C T, D auto I, int W, A S, template<typename, auto, int, A, typename...> class U, typename... Z>
struct Y3<T, I, W, S, U, Z...> { Y3()=delete; };
template<C T, E auto I, int W, A S, template<typename, auto, int, A, typename...> class U, typename... Z>
struct Y3<T, I, W, S, U, Z...> {};
void f() {
Y1<int, 2> a;
Y2<char*, 1, 3> b; // expected-error {{ambiguous partial specializations}}
Y3<int, 1, 1, A{}, S, int> c;
}
// Per [temp.func.order]p6.2.2, specifically "if the function parameters that
// positionally correspond between the two templates are not of the same type",
// this partial specialization does not work.
// See https://github.com/llvm/llvm-project/issues/58896
template<C T, C V> struct Y4; // expected-note {{template is declared here}}
template<D T, C V> struct Y4<V, T>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
template<C auto T> struct W1;
template<D auto T> struct W1<T> {};
// See http://cplusplus.github.io/concepts-ts/ts-active.html#28
// template<C auto... T> struct W2;
// template<D auto... T> struct W2<T...> {};
template<class T, class U>
concept C1 = C<T> && C<U>;
template<class T, class U>
concept D1 = D<T> && C<U>;
template<C1<A> auto T> struct W3;
template<D1<A> auto T> struct W3<T> {};
// See http://cplusplus.github.io/concepts-ts/ts-active.html#28
// template<C1<A> auto... T> struct W4;
// template<D1<A> auto... T> struct W4<T...> {};
// FIXME: enable once Clang support non-trivial auto on NTTP.
// template<C auto* T> struct W5;
// template<D auto* T> struct W5<T> {};
// FIXME: enable once Clang support non-trivial auto on NTTP.
// template<C auto& T> struct W6;
// template<D auto& T> struct W6<T> {};
struct W1<0> w1;
// struct W2<0> w2;
struct W3<0> w3;
// struct W4<0> w4;
// FIXME: enable once Clang support non-trivial auto on NTTP.
// struct W5<(int*)nullptr> w5;
// struct W6<w5> w6;
}
namespace PR53640 {
template <typename T>
concept C = true;
template <C T>
void f(T t) {} // expected-note {{candidate function [with T = int]}}
template <typename T>
void f(const T &t) {} // expected-note {{candidate function [with T = int]}}
int g() {
f(0); // expected-error {{call to 'f' is ambiguous}}
}
struct S {
template <typename T> explicit S(T) noexcept requires C<T> {} // expected-note {{candidate constructor}}
template <typename T> explicit S(const T &) noexcept {} // expected-note {{candidate constructor}}
};
int h() {
S s(4); // expected-error-re {{call to constructor of {{.*}} is ambiguous}}
}
}
namespace NestedConstraintsDiffer {
template<typename T> concept A = true;
template<typename T> concept B = A<T> && true;
// This is valid: we can compare the constraints of the two overloads of `f`
// because the template-parameters are equivalent, despite having different
// constraints.
template<typename T> struct Z {};
template<template<typename T> typename> struct X {};
template<A U, template<A T> typename TT> void f(U, X<TT>) {}
template<B U, template<B T> typename TT> void f(U, X<TT>) {}
void g(X<Z> x) { f(0, x); }
// Same thing with a constrained non-type parameter.
template<auto N> struct W {};
template<template<auto> typename> struct Y {};
template<A U, template<A auto> typename TT> void h(U, Y<TT>) {}
template<B U, template<B auto> typename TT> void h(U, Y<TT>) {}
void i(Y<W> x) { h(0, x); }
}