xref: /llvm-project/clang/test/SemaTemplate/instantiation-dependence.cpp (revision ba15d186e5cef2620d562c6c9d9a6d570382cd0a)
1*ba15d186SMark de Wever // RUN: %clang_cc1 -std=c++23 -verify %s
2fbb83f18SRichard Smith 
3fbb83f18SRichard Smith // Ensure we substitute into instantiation-dependent but non-dependent
4fbb83f18SRichard Smith // constructs. The poster-child for this is...
5fbb83f18SRichard Smith template<class ...> using void_t = void;
6fbb83f18SRichard Smith 
7fbb83f18SRichard Smith namespace PR24076 {
8fbb83f18SRichard Smith   template<class T> T declval();
9fbb83f18SRichard Smith   struct s {};
10fbb83f18SRichard Smith 
11fbb83f18SRichard Smith   template<class T,
12fbb83f18SRichard Smith            class = void_t<decltype(declval<T>() + 1)>>
foo(T)13fbb83f18SRichard Smith     void foo(T) {} // expected-note {{invalid operands to binary expression}}
14fbb83f18SRichard Smith 
f()15fbb83f18SRichard Smith   void f() {
16fbb83f18SRichard Smith     foo(s{}); // expected-error {{no matching function}}
17fbb83f18SRichard Smith   }
18fbb83f18SRichard Smith 
19fbb83f18SRichard Smith   template<class T,
20fbb83f18SRichard Smith            class = void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}}
21fbb83f18SRichard Smith   struct bar {};
22fbb83f18SRichard Smith 
23fbb83f18SRichard Smith   bar<s> bar; // expected-note {{in instantiation of}}
24fbb83f18SRichard Smith }
25fbb83f18SRichard Smith 
26fbb83f18SRichard Smith namespace PR33655 {
27fbb83f18SRichard Smith   struct One { using x = int; };
28fbb83f18SRichard Smith   struct Two { using y = int; };
29fbb83f18SRichard Smith 
func()30fbb83f18SRichard Smith   template<typename T, void_t<typename T::x> * = nullptr> int &func() {}
func()31fbb83f18SRichard Smith   template<typename T, void_t<typename T::y> * = nullptr> float &func() {}
32fbb83f18SRichard Smith 
33fbb83f18SRichard Smith   int &test1 = func<One>();
34fbb83f18SRichard Smith   float &test2 = func<Two>();
35fbb83f18SRichard Smith 
36fbb83f18SRichard Smith   template<class ...Args> struct indirect_void_t_imp { using type = void; };
37fbb83f18SRichard Smith   template<class ...Args> using indirect_void_t = typename indirect_void_t_imp<Args...>::type;
38fbb83f18SRichard Smith 
foo()39fbb83f18SRichard Smith   template<class T> void foo() {
4000e2098bSCorentin Jabot     int check1[__is_void(indirect_void_t<T>) == 0 ? 1 : -1]; // "ok", dependent
4100e2098bSCorentin Jabot     int check2[__is_void(void_t<T>) == 0 ? 1 : -1]; // expected-error {{array with a negative size}}
42fbb83f18SRichard Smith   }
43fbb83f18SRichard Smith }
44fbb83f18SRichard Smith 
45fbb83f18SRichard Smith namespace PR46791 { // also PR45782
46fbb83f18SRichard Smith   template<typename T, typename = void>
47fbb83f18SRichard Smith   struct trait {
48fbb83f18SRichard Smith     static constexpr int specialization = 0;
49fbb83f18SRichard Smith   };
50fbb83f18SRichard Smith 
51fbb83f18SRichard Smith   // FIXME: Per a strict interpretation of the C++ rules, the two void_t<...>
52fbb83f18SRichard Smith   // types below are equivalent -- we only (effectively) do token-by-token
53fbb83f18SRichard Smith   // comparison for *expressions* appearing within types. But all other
54fbb83f18SRichard Smith   // implementations accept this, using rules that are unclear.
55fbb83f18SRichard Smith   template<typename T>
56fbb83f18SRichard Smith   struct trait<T, void_t<typename T::value_type>> { // expected-note {{previous}} FIXME-note {{matches}}
57fbb83f18SRichard Smith     static constexpr int specialization = 1;
58fbb83f18SRichard Smith   };
59fbb83f18SRichard Smith 
60fbb83f18SRichard Smith   template<typename T>
61fbb83f18SRichard Smith   struct trait<T, void_t<typename T::element_type>> { // expected-error {{redefinition}} FIXME-note {{matches}}
62fbb83f18SRichard Smith     static constexpr int specialization = 2;
63fbb83f18SRichard Smith   };
64fbb83f18SRichard Smith 
65fbb83f18SRichard Smith   struct A {};
66fbb83f18SRichard Smith   struct B { typedef int value_type; };
67fbb83f18SRichard Smith   struct C { typedef int element_type; };
68fbb83f18SRichard Smith   struct D : B, C {};
69fbb83f18SRichard Smith 
70fbb83f18SRichard Smith   static_assert(trait<A>::specialization == 0);
7109117b21STimm Bäder   static_assert(trait<B>::specialization == 1); // FIXME expected-error {{failed}} \
7209117b21STimm Bäder                                                 // expected-note {{evaluates to '0 == 1'}}
7309117b21STimm Bäder   static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}} \
7409117b21STimm Bäder                                                 // expected-note {{evaluates to '0 == 2'}}
75fbb83f18SRichard Smith   static_assert(trait<D>::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
76fbb83f18SRichard Smith }
77fbb83f18SRichard Smith 
78fbb83f18SRichard Smith namespace TypeQualifier {
79fbb83f18SRichard Smith   // Ensure that we substitute into an instantiation-dependent but
80fbb83f18SRichard Smith   // non-dependent qualifier.
81fbb83f18SRichard Smith   template<int> struct A { using type = int; };
f()82fbb83f18SRichard Smith   template<typename T> A<sizeof(sizeof(T::error))>::type f() {} // expected-note {{'int' cannot be used prior to '::'}}
83fbb83f18SRichard Smith   int k = f<int>(); // expected-error {{no matching}}
84fbb83f18SRichard Smith }
85fcb90cbdSRichard Smith 
86fcb90cbdSRichard Smith namespace MemberOfInstantiationDependentBase {
87fcb90cbdSRichard Smith   template<typename T> struct A { template<int> void f(int); };
88fcb90cbdSRichard Smith   template<typename T> struct B { using X = A<T>; };
89fcb90cbdSRichard Smith   template<typename T> struct C1 : B<int> {
90fcb90cbdSRichard Smith     using X = typename C1::X;
fMemberOfInstantiationDependentBase::C191fcb90cbdSRichard Smith     void f(X *p) {
92fcb90cbdSRichard Smith       p->f<0>(0);
93fcb90cbdSRichard Smith       p->template f<0>(0);
94fcb90cbdSRichard Smith     }
95fcb90cbdSRichard Smith   };
96fcb90cbdSRichard Smith   template<typename T> struct C2 : B<int> {
97fcb90cbdSRichard Smith     using X = typename C2<T>::X;
fMemberOfInstantiationDependentBase::C298fcb90cbdSRichard Smith     void f(X *p) {
99fcb90cbdSRichard Smith       p->f<0>(0);
100fcb90cbdSRichard Smith       p->template f<0>(0);
101fcb90cbdSRichard Smith     }
102fcb90cbdSRichard Smith   };
q(C1<int> * c)103fcb90cbdSRichard Smith   void q(C1<int> *c) { c->f(0); }
q(C2<int> * c)104fcb90cbdSRichard Smith   void q(C2<int> *c) { c->f(0); }
105fcb90cbdSRichard Smith }
106