124 lines
2.3 KiB
C++
124 lines
2.3 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
|
template<typename T>
|
|
void call_f0(T x) {
|
|
x.Base::f0();
|
|
}
|
|
|
|
struct Base {
|
|
void f0();
|
|
};
|
|
|
|
struct X0 : Base {
|
|
typedef Base CrazyBase;
|
|
};
|
|
|
|
void test_f0(X0 x0) {
|
|
call_f0(x0);
|
|
}
|
|
|
|
template<typename TheBase, typename T>
|
|
void call_f0_through_typedef(T x) {
|
|
typedef TheBase Base2;
|
|
x.Base2::f0();
|
|
}
|
|
|
|
void test_f0_through_typedef(X0 x0) {
|
|
call_f0_through_typedef<Base>(x0);
|
|
}
|
|
|
|
template<typename TheBase, typename T>
|
|
void call_f0_through_typedef2(T x) {
|
|
typedef TheBase CrazyBase; // expected-note{{current scope}}
|
|
x.CrazyBase::f0(); // expected-error{{ambiguous}} \
|
|
// expected-error 2{{no member named}}
|
|
}
|
|
|
|
struct OtherBase { };
|
|
|
|
struct X1 : Base, OtherBase {
|
|
typedef OtherBase CrazyBase; // expected-note{{object type}}
|
|
};
|
|
|
|
void test_f0_through_typedef2(X0 x0, X1 x1) {
|
|
call_f0_through_typedef2<Base>(x0);
|
|
call_f0_through_typedef2<OtherBase>(x1); // expected-note{{instantiation}}
|
|
call_f0_through_typedef2<Base>(x1); // expected-note{{instantiation}}
|
|
}
|
|
|
|
|
|
struct X2 {
|
|
operator int() const;
|
|
};
|
|
|
|
template<typename T, typename U>
|
|
T convert(const U& value) {
|
|
return value.operator T(); // expected-error{{operator long}}
|
|
}
|
|
|
|
void test_convert(X2 x2) {
|
|
convert<int>(x2);
|
|
convert<long>(x2); // expected-note{{instantiation}}
|
|
}
|
|
|
|
template<typename T>
|
|
void destruct(T* ptr) {
|
|
ptr->~T();
|
|
ptr->T::~T();
|
|
}
|
|
|
|
template<typename T>
|
|
void destruct_intptr(int *ip) {
|
|
ip->~T();
|
|
ip->T::~T();
|
|
}
|
|
|
|
void test_destruct(X2 *x2p, int *ip) {
|
|
destruct(x2p);
|
|
destruct(ip);
|
|
destruct_intptr<int>(ip);
|
|
}
|
|
|
|
// PR5220
|
|
class X3 {
|
|
protected:
|
|
template <int> float* &f0();
|
|
template <int> const float* &f0() const;
|
|
void f1() {
|
|
(void)static_cast<float*>(f0<0>());
|
|
}
|
|
void f1() const{
|
|
(void)f0<0>();
|
|
}
|
|
};
|
|
|
|
// Fun with template instantiation and conversions
|
|
struct X4 {
|
|
int& member();
|
|
float& member() const;
|
|
};
|
|
|
|
template<typename T>
|
|
struct X5 {
|
|
void f(T* ptr) { int& ir = ptr->member(); }
|
|
void g(T* ptr) { float& fr = ptr->member(); }
|
|
};
|
|
|
|
void test_X5(X5<X4> x5, X5<const X4> x5c, X4 *xp, const X4 *cxp) {
|
|
x5.f(xp);
|
|
x5c.g(cxp);
|
|
}
|
|
|
|
// In theory we can do overload resolution at template-definition time on this.
|
|
// We should at least not assert.
|
|
namespace test4 {
|
|
struct Base {
|
|
template <class T> void foo() {}
|
|
};
|
|
|
|
template <class T> struct Foo : Base {
|
|
void test() {
|
|
foo<int>();
|
|
}
|
|
};
|
|
}
|