1 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
3 template <typename
> constexpr bool True
= true;
4 template <typename T
> concept C
= True
<T
>;
5 template <typename T
> concept D
= C
<T
> && sizeof(T
) > 2;
6 template <typename T
> concept E
= D
<T
> && alignof(T
) > 1;
9 template <typename
, auto, int, A
, typename
...> struct S
{};
10 template <typename
, auto, int, A
, auto...> struct S2
{};
11 template <typename T
, typename U
> struct X
{};
17 void f(C
auto &, auto &) = delete;
18 template <C Q
> void f(Q
&, C
auto &);
20 void g(struct A
*ap
, struct B
*bp
) {
25 // FIXME: [temp.func.order]p6.2.1 is not implemented, matching GCC.
26 template <typename T
, C U
, typename V
> bool operator==(X
<T
, U
>, V
) = delete;
27 template <C T
, C U
, C V
> bool operator==(T
, X
<U
, V
>);
30 return X
<void *, int>{} == 0;
34 template<C T
, C
auto M
, int W
, A S
,
35 template<typename
, auto, int, A
, typename
...> class U
,
37 void foo(T
, U
<T
, M
, W
, S
, Z
...>) = delete;
38 template<C T
, D
auto M
, int W
, A S
,
39 template<typename
, auto, int, A
, typename
...> class U
,
41 void foo(T
, U
<T
, M
, W
, S
, Z
...>) = delete;
42 template<C T
, E
auto M
, int W
, A S
,
43 template<typename
, auto, int, A
, typename
...> class U
,
45 void foo(T
, U
<T
, M
, W
, S
, Z
...>);
47 void bar(S
<int, 1, 1, A
{}, int> s
, S2
<int, 1, 1, A
{}, 0, 0u> s2
) {
51 template<C
auto... T
> void bar2();
52 template<D
auto... T
> void bar2() = delete;
56 namespace TestConversionFunction
{
58 template<C T
, typename U
> operator X
<T
, U
>(); // expected-note {{candidate function [with T = int, U = int]}}
59 template<typename T
, typename U
> operator X
<U
, T
>(); // expected-note {{candidate function [with T = int, U = int]}}
63 return Y
{}; // expected-error {{conversion from 'Y' to 'X<int, int>' is ambiguous}}
67 namespace ClassPartialSpecPartialOrdering
{
68 template<D T
> struct Y
{ Y()=delete; }; // expected-note {{template is declared here}}
69 template<C T
> struct Y
<T
> {}; // expected-error {{class template partial specialization is not more specialized than the primary template}}
71 template<C T
, int I
> struct Y1
{ Y1()=delete; };
72 template<D T
> struct Y1
<T
, 2> { Y1()=delete; };
73 template<E T
> struct Y1
<T
, 1+1> {};
75 template<class T
, int I
, int U
> struct Y2
{};
76 template<class T
, int I
> struct Y2
<T
*, I
, I
+2> {}; // expected-note {{partial specialization matches}}
77 template<C T
, int I
> struct Y2
<T
*, I
, I
+1+1> {}; // expected-note {{partial specialization matches}}
79 template<C T
, C
auto I
, int W
, A S
, template<typename
, auto, int, A
, typename
...> class U
, typename
... Z
>
80 struct Y3
{ Y3()=delete; };
81 template<C T
, D
auto I
, int W
, A S
, template<typename
, auto, int, A
, typename
...> class U
, typename
... Z
>
82 struct Y3
<T
, I
, W
, S
, U
, Z
...> { Y3()=delete; };
83 template<C T
, E
auto I
, int W
, A S
, template<typename
, auto, int, A
, typename
...> class U
, typename
... Z
>
84 struct Y3
<T
, I
, W
, S
, U
, Z
...> {};
88 Y2
<char*, 1, 3> b
; // expected-error {{ambiguous partial specializations}}
89 Y3
<int, 1, 1, A
{}, S
, int> c
;
92 // Per [temp.func.order]p6.2.2, specifically "if the function parameters that
93 // positionally correspond between the two templates are not of the same type",
94 // this partial specialization does not work.
95 // See https://github.com/llvm/llvm-project/issues/58896
96 template<C T
, C V
> struct Y4
; // expected-note {{template is declared here}}
97 template<D T
, C V
> struct Y4
<V
, T
>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
99 template<C
auto T
> struct W1
;
100 template<D
auto T
> struct W1
<T
> {};
102 // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
103 // template<C auto... T> struct W2;
104 // template<D auto... T> struct W2<T...> {};
106 template<class T
, class U
>
107 concept C1
= C
<T
> && C
<U
>;
108 template<class T
, class U
>
109 concept D1
= D
<T
> && C
<U
>;
111 template<C1
<A
> auto T
> struct W3
;
112 template<D1
<A
> auto T
> struct W3
<T
> {};
114 // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
115 // template<C1<A> auto... T> struct W4;
116 // template<D1<A> auto... T> struct W4<T...> {};
118 // FIXME: enable once Clang support non-trivial auto on NTTP.
119 // template<C auto* T> struct W5;
120 // template<D auto* T> struct W5<T> {};
122 // FIXME: enable once Clang support non-trivial auto on NTTP.
123 // template<C auto& T> struct W6;
124 // template<D auto& T> struct W6<T> {};
130 // FIXME: enable once Clang support non-trivial auto on NTTP.
131 // struct W5<(int*)nullptr> w5;
137 template <typename T
>
141 void f(T t
) {} // expected-note {{candidate function [with T = int]}}
143 template <typename T
>
144 void f(const T
&t
) {} // expected-note {{candidate function [with T = int]}}
147 f(0); // expected-error {{call to 'f' is ambiguous}}
151 template <typename T
> explicit S(T
) noexcept requires C
<T
> {} // expected-note {{candidate constructor}}
152 template <typename T
> explicit S(const T
&) noexcept
{} // expected-note {{candidate constructor}}
156 S
s(4); // expected-error-re {{call to constructor of {{.*}} is ambiguous}}
161 namespace NestedConstraintsDiffer
{
162 template<typename T
> concept A
= true;
163 template<typename T
> concept B
= A
<T
> && true;
165 // This is valid: we can compare the constraints of the two overloads of `f`
166 // because the template-parameters are equivalent, despite having different
168 template<typename T
> struct Z
{};
169 template<template<typename T
> typename
> struct X
{};
170 template<A U
, template<A T
> typename TT
> void f(U
, X
<TT
>) {}
171 template<B U
, template<B T
> typename TT
> void f(U
, X
<TT
>) {}
172 void g(X
<Z
> x
) { f(0, x
); }
174 // Same thing with a constrained non-type parameter.
175 template<auto N
> struct W
{};
176 template<template<auto> typename
> struct Y
{};
177 template<A U
, template<A
auto> typename TT
> void h(U
, Y
<TT
>) {}
178 template<B U
, template<B
auto> typename TT
> void h(U
, Y
<TT
>) {}
179 void i(Y
<W
> x
) { h(0, x
); }