1// RUN: %clang_cc1 -fsyntax-only -verify %s
2template<typename T>
3void call_f0(T x) {
4  x.Base::f0();
5}
6
7struct Base {
8  void f0();
9};
10
11struct X0 : Base {
12  typedef Base CrazyBase;
13};
14
15void test_f0(X0 x0) {
16  call_f0(x0);
17}
18
19template<typename TheBase, typename T>
20void call_f0_through_typedef(T x) {
21  typedef TheBase Base2;
22  x.Base2::f0();
23}
24
25void test_f0_through_typedef(X0 x0) {
26  call_f0_through_typedef<Base>(x0);
27}
28
29template<typename TheBase, typename T>
30void call_f0_through_typedef2(T x) {
31  typedef TheBase CrazyBase; // expected-note{{current scope}}
32  x.CrazyBase::f0(); // expected-error{{ambiguous}} \
33                     // expected-error 2{{no member named}}
34}
35
36struct OtherBase { };
37
38struct X1 : Base, OtherBase {
39  typedef OtherBase CrazyBase; // expected-note{{object type}}
40};
41
42void test_f0_through_typedef2(X0 x0, X1 x1) {
43  call_f0_through_typedef2<Base>(x0);
44  call_f0_through_typedef2<OtherBase>(x1); // expected-note{{instantiation}}
45  call_f0_through_typedef2<Base>(x1); // expected-note{{instantiation}}
46}
47
48
49struct X2 {
50  operator int() const;
51};
52
53template<typename T, typename U>
54T convert(const U& value) {
55  return value.operator T(); // expected-error{{operator long}}
56}
57
58void test_convert(X2 x2) {
59  convert<int>(x2);
60  convert<long>(x2); // expected-note{{instantiation}}
61}
62
63template<typename T>
64void destruct(T* ptr) {
65  ptr->~T();
66  ptr->T::~T();
67}
68
69template<typename T>
70void destruct_intptr(int *ip) {
71  ip->~T();
72  ip->T::~T();
73}
74
75void test_destruct(X2 *x2p, int *ip) {
76  destruct(x2p);
77  destruct(ip);
78  destruct_intptr<int>(ip);
79}
80
81// PR5220
82class X3 {
83protected:
84  template <int> float* &f0();
85  template <int> const float* &f0() const;
86  void f1() {
87    (void)static_cast<float*>(f0<0>());
88  }
89  void f1() const{
90    (void)f0<0>();
91  }
92};
93
94// Fun with template instantiation and conversions
95struct X4 {
96  int& member();
97  float& member() const;
98};
99
100template<typename T>
101struct X5 {
102  void f(T* ptr) { int& ir = ptr->member(); }
103  void g(T* ptr) { float& fr = ptr->member(); }
104};
105
106void test_X5(X5<X4> x5, X5<const X4> x5c, X4 *xp, const X4 *cxp) {
107  x5.f(xp);
108  x5c.g(cxp);
109}
110
111// In theory we can do overload resolution at template-definition time on this.
112// We should at least not assert.
113namespace test4 {
114  struct Base {
115    template <class T> void foo() {}
116  };
117
118  template <class T> struct Foo : Base {
119    void test() {
120      foo<int>();
121    }
122  };
123}
124
125namespace test5 {
126  template<typename T>
127  struct X {
128    using T::value;
129
130    T &getValue() {
131      return &value;
132    }
133  };
134}
135
136// PR8739
137namespace test6 {
138  struct A {};
139  struct B {};
140  template <class T> class Base;
141  template <class T> class Derived : public Base<T> {
142    A *field;
143    void get(B **ptr) {
144      // It's okay if at some point we figure out how to diagnose this
145      // at instantiation time.
146      *ptr = field;
147    }
148  };
149}
150