1 // RUN: %clang_cc1 -std=c++23 -verify %s
3 // Ensure we substitute into instantiation-dependent but non-dependent
4 // constructs. The poster-child for this is...
5 template<class ...> using void_t
= void;
8 template<class T
> T
declval();
12 class = void_t
<decltype(declval
<T
>() + 1)>>
13 void foo(T
) {} // expected-note {{invalid operands to binary expression}}
16 foo(s
{}); // expected-error {{no matching function}}
20 class = void_t
<decltype(declval
<T
>() + 1)>> // expected-error {{invalid operands to binary expression}}
23 bar
<s
> bar
; // expected-note {{in instantiation of}}
27 struct One
{ using x
= int; };
28 struct Two
{ using y
= int; };
30 template<typename T
, void_t
<typename
T::x
> * = nullptr> int &func() {}
31 template<typename T
, void_t
<typename
T::y
> * = nullptr> float &func() {}
33 int &test1
= func
<One
>();
34 float &test2
= func
<Two
>();
36 template<class ...Args
> struct indirect_void_t_imp
{ using type
= void; };
37 template<class ...Args
> using indirect_void_t
= typename indirect_void_t_imp
<Args
...>::type
;
39 template<class T
> void foo() {
40 int check1
[__is_void(indirect_void_t
<T
>) == 0 ? 1 : -1]; // "ok", dependent
41 int check2
[__is_void(void_t
<T
>) == 0 ? 1 : -1]; // expected-error {{array with a negative size}}
45 namespace PR46791
{ // also PR45782
46 template<typename T
, typename
= void>
48 static constexpr int specialization
= 0;
51 // FIXME: Per a strict interpretation of the C++ rules, the two void_t<...>
52 // types below are equivalent -- we only (effectively) do token-by-token
53 // comparison for *expressions* appearing within types. But all other
54 // implementations accept this, using rules that are unclear.
56 struct trait
<T
, void_t
<typename
T::value_type
>> { // expected-note {{previous}} FIXME-note {{matches}}
57 static constexpr int specialization
= 1;
61 struct trait
<T
, void_t
<typename
T::element_type
>> { // expected-error {{redefinition}} FIXME-note {{matches}}
62 static constexpr int specialization
= 2;
66 struct B
{ typedef int value_type
; };
67 struct C
{ typedef int element_type
; };
70 static_assert(trait
<A
>::specialization
== 0);
71 static_assert(trait
<B
>::specialization
== 1); // FIXME expected-error {{failed}} \
72 // expected-note {{evaluates to '0 == 1'}}
73 static_assert(trait
<C
>::specialization
== 2); // FIXME expected-error {{failed}} \
74 // expected-note {{evaluates to '0 == 2'}}
75 static_assert(trait
<D
>::specialization
== 0); // FIXME-error {{ambiguous partial specialization}}
78 namespace TypeQualifier
{
79 // Ensure that we substitute into an instantiation-dependent but
80 // non-dependent qualifier.
81 template<int> struct A
{ using type
= int; };
82 template<typename T
> A
<sizeof(sizeof(T::error
))>::type
f() {} // expected-note {{'int' cannot be used prior to '::'}}
83 int k
= f
<int>(); // expected-error {{no matching}}
86 namespace MemberOfInstantiationDependentBase
{
87 template<typename T
> struct A
{ template<int> void f(int); };
88 template<typename T
> struct B
{ using X
= A
<T
>; };
89 template<typename T
> struct C1
: B
<int> {
90 using X
= typename
C1::X
;
96 template<typename T
> struct C2
: B
<int> {
97 using X
= typename C2
<T
>::X
;
103 void q(C1
<int> *c
) { c
->f(0); }
104 void q(C2
<int> *c
) { c
->f(0); }