1 // RUN: %clang_cc1 -std=c++23 -verify %s 2 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; 6 7 namespace PR24076 { 8 template<class T> T declval(); 9 struct s {}; 10 11 template<class T, 12 class = void_t<decltype(declval<T>() + 1)>> foo(T)13 void foo(T) {} // expected-note {{invalid operands to binary expression}} 14 f()15 void f() { 16 foo(s{}); // expected-error {{no matching function}} 17 } 18 19 template<class T, 20 class = void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}} 21 struct bar {}; 22 23 bar<s> bar; // expected-note {{in instantiation of}} 24 } 25 26 namespace PR33655 { 27 struct One { using x = int; }; 28 struct Two { using y = int; }; 29 func()30 template<typename T, void_t<typename T::x> * = nullptr> int &func() {} func()31 template<typename T, void_t<typename T::y> * = nullptr> float &func() {} 32 33 int &test1 = func<One>(); 34 float &test2 = func<Two>(); 35 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; 38 foo()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}} 42 } 43 } 44 45 namespace PR46791 { // also PR45782 46 template<typename T, typename = void> 47 struct trait { 48 static constexpr int specialization = 0; 49 }; 50 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. 55 template<typename T> 56 struct trait<T, void_t<typename T::value_type>> { // expected-note {{previous}} FIXME-note {{matches}} 57 static constexpr int specialization = 1; 58 }; 59 60 template<typename T> 61 struct trait<T, void_t<typename T::element_type>> { // expected-error {{redefinition}} FIXME-note {{matches}} 62 static constexpr int specialization = 2; 63 }; 64 65 struct A {}; 66 struct B { typedef int value_type; }; 67 struct C { typedef int element_type; }; 68 struct D : B, C {}; 69 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}} 76 } 77 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; }; f()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}} 84 } 85 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; fMemberOfInstantiationDependentBase::C191 void f(X *p) { 92 p->f<0>(0); 93 p->template f<0>(0); 94 } 95 }; 96 template<typename T> struct C2 : B<int> { 97 using X = typename C2<T>::X; fMemberOfInstantiationDependentBase::C298 void f(X *p) { 99 p->f<0>(0); 100 p->template f<0>(0); 101 } 102 }; q(C1<int> * c)103 void q(C1<int> *c) { c->f(0); } q(C2<int> * c)104 void q(C2<int> *c) { c->f(0); } 105 } 106