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