forked from OSchip/llvm-project
104 lines
3.4 KiB
C++
104 lines
3.4 KiB
C++
// RUN: %clang_cc1 -std=c++2b -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() {
|
|
static_assert(!__is_void(indirect_void_t<T>)); // "ok", dependent
|
|
static_assert(!__is_void(void_t<T>)); // expected-error {{failed}}
|
|
}
|
|
}
|
|
|
|
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}}
|
|
static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}}
|
|
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); }
|
|
}
|