1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
// 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); }
}
|