| // RUN: %clang_cc1 -std=c++23 -verify %s | 
 |  | 
 | // Ensure we substitute into instantiation-dependent but non-dependent | 
 | // constructs. The poster-child for this is... | 
 | template<class ...> using void_t = void; | 
 |  | 
 | namespace PR24076 { | 
 |   template<class T> T declval(); | 
 |   struct s {}; | 
 |  | 
 |   template<class T, | 
 |            class = void_t<decltype(declval<T>() + 1)>> | 
 |     void foo(T) {} // expected-note {{invalid operands to binary expression}} | 
 |  | 
 |   void f() { | 
 |     foo(s{}); // expected-error {{no matching function}} | 
 |   } | 
 |  | 
 |   template<class T, | 
 |            class = void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}} | 
 |   struct bar {}; | 
 |  | 
 |   bar<s> bar; // expected-note {{in instantiation of}} | 
 | } | 
 |  | 
 | namespace PR33655 { | 
 |   struct One { using x = int; }; | 
 |   struct Two { using y = int; }; | 
 |  | 
 |   template<typename T, void_t<typename T::x> * = nullptr> int &func() {} | 
 |   template<typename T, void_t<typename T::y> * = nullptr> float &func() {} | 
 |  | 
 |   int &test1 = func<One>(); | 
 |   float &test2 = func<Two>(); | 
 |  | 
 |   template<class ...Args> struct indirect_void_t_imp { using type = void; }; | 
 |   template<class ...Args> using indirect_void_t = typename indirect_void_t_imp<Args...>::type; | 
 |  | 
 |   template<class T> void foo() { | 
 |     int check1[__is_void(indirect_void_t<T>) == 0 ? 1 : -1]; // "ok", dependent | 
 |     int check2[__is_void(void_t<T>) == 0 ? 1 : -1]; // expected-error {{array with a negative size}} | 
 |   } | 
 | } | 
 |  | 
 | namespace PR46791 { // also PR45782 | 
 |   template<typename T, typename = void> | 
 |   struct trait { | 
 |     static constexpr int specialization = 0; | 
 |   }; | 
 |  | 
 |   // FIXME: Per a strict interpretation of the C++ rules, the two void_t<...> | 
 |   // types below are equivalent -- we only (effectively) do token-by-token | 
 |   // comparison for *expressions* appearing within types. But all other | 
 |   // implementations accept this, using rules that are unclear. | 
 |   template<typename T> | 
 |   struct trait<T, void_t<typename T::value_type>> { // expected-note {{previous}} FIXME-note {{matches}} | 
 |     static constexpr int specialization = 1; | 
 |   }; | 
 |  | 
 |   template<typename T> | 
 |   struct trait<T, void_t<typename T::element_type>> { // expected-error {{redefinition}} FIXME-note {{matches}} | 
 |     static constexpr int specialization = 2; | 
 |   }; | 
 |  | 
 |   struct A {}; | 
 |   struct B { typedef int value_type; }; | 
 |   struct C { typedef int element_type; }; | 
 |   struct D : B, C {}; | 
 |  | 
 |   static_assert(trait<A>::specialization == 0); | 
 |   static_assert(trait<B>::specialization == 1); // FIXME expected-error {{failed}} \ | 
 |                                                 // expected-note {{evaluates to '0 == 1'}} | 
 |   static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}} \ | 
 |                                                 // expected-note {{evaluates to '0 == 2'}} | 
 |   static_assert(trait<D>::specialization == 0); // FIXME-error {{ambiguous partial specialization}} | 
 | } | 
 |  | 
 | namespace TypeQualifier { | 
 |   // Ensure that we substitute into an instantiation-dependent but | 
 |   // non-dependent qualifier. | 
 |   template<int> struct A { using type = int; }; | 
 |   template<typename T> A<sizeof(sizeof(T::error))>::type f() {} // expected-note {{'int' cannot be used prior to '::'}} | 
 |   int k = f<int>(); // expected-error {{no matching}} | 
 | } | 
 |  | 
 | namespace MemberOfInstantiationDependentBase { | 
 |   template<typename T> struct A { template<int> void f(int); }; | 
 |   template<typename T> struct B { using X = A<T>; }; | 
 |   template<typename T> struct C1 : B<int> { | 
 |     using X = typename C1::X; | 
 |     void f(X *p) { | 
 |       p->f<0>(0); | 
 |       p->template f<0>(0); | 
 |     } | 
 |   }; | 
 |   template<typename T> struct C2 : B<int> { | 
 |     using X = typename C2<T>::X; | 
 |     void f(X *p) { | 
 |       p->f<0>(0); | 
 |       p->template f<0>(0); | 
 |     } | 
 |   }; | 
 |   void q(C1<int> *c) { c->f(0); } | 
 |   void q(C2<int> *c) { c->f(0); } | 
 | } |