1 | // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s |
2 | |
3 | |
4 | template <class T> |
5 | class A { |
6 | public: |
7 | void f(T a) { }// expected-note 2{{must qualify identifier to find this declaration in dependent base class}} |
8 | void g();// expected-note 2{{must qualify identifier to find this declaration in dependent base class}} |
9 | }; |
10 | |
11 | template <class T> |
12 | class B : public A<T> { |
13 | public: |
14 | void z(T a) |
15 | { |
16 | f(a); // expected-warning 2{{use of identifier 'f' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
17 | g(); // expected-warning 2{{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
18 | } |
19 | }; |
20 | |
21 | template class B<int>; // expected-note {{requested here}} |
22 | template class B<char>; // expected-note {{requested here}} |
23 | |
24 | void test() |
25 | { |
26 | B<int> b; |
27 | b.z(3); |
28 | } |
29 | |
30 | struct A2 { |
31 | template<class T> void f(T) { |
32 | XX; //expected-error {{use of undeclared identifier 'XX'}} |
33 | A2::XX; //expected-error {{no member named 'XX' in 'A2'}} |
34 | } |
35 | }; |
36 | template void A2::f(int); |
37 | |
38 | template<class T0> |
39 | struct A3 { |
40 | template<class T1> void f(T1) { |
41 | XX; //expected-error {{use of undeclared identifier 'XX'}} |
42 | } |
43 | }; |
44 | template void A3<int>::f(int); |
45 | |
46 | template<class T0> |
47 | struct A4 { |
48 | void f(char) { |
49 | XX; //expected-error {{use of undeclared identifier 'XX'}} |
50 | } |
51 | }; |
52 | template class A4<int>; |
53 | |
54 | |
55 | namespace lookup_dependent_bases_id_expr { |
56 | |
57 | template<class T> class A { |
58 | public: |
59 | int var; |
60 | }; |
61 | |
62 | |
63 | template<class T> |
64 | class B : public A<T> { |
65 | public: |
66 | void f() { |
67 | var = 3; // expected-warning {{use of undeclared identifier 'var'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} |
68 | } |
69 | }; |
70 | |
71 | template class B<int>; |
72 | |
73 | } |
74 | |
75 | |
76 | |
77 | namespace lookup_dependent_base_class_static_function { |
78 | |
79 | template <class T> |
80 | class A { |
81 | public: |
82 | static void static_func();// expected-note {{must qualify identifier to find this declaration in dependent base class}} |
83 | void func();// expected-note {{must qualify identifier to find this declaration in dependent base class}} |
84 | }; |
85 | |
86 | |
87 | template <class T> |
88 | class B : public A<T> { |
89 | public: |
90 | static void z2(){ |
91 | static_func(); // expected-warning {{use of identifier 'static_func' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
92 | func(); // expected-warning {{use of identifier 'func' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-error {{call to non-static member function without an object argument}} |
93 | } |
94 | }; |
95 | template class B<int>; // expected-note {{requested here}} |
96 | |
97 | } |
98 | |
99 | |
100 | |
101 | namespace lookup_dependent_base_class_default_argument { |
102 | |
103 | template<class T> |
104 | class A { |
105 | public: |
106 | static int f1(); // expected-note {{must qualify identifier to find this declaration in dependent base class}} |
107 | int f2(); // expected-note {{must qualify identifier to find this declaration in dependent base class}} |
108 | }; |
109 | |
110 | template<class T> |
111 | class B : public A<T> { |
112 | public: |
113 | void g1(int p = f1());// expected-warning {{use of identifier 'f1' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
114 | void g2(int p = f2());// expected-warning {{use of identifier 'f2' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-error {{call to non-static member function without an object argument}} |
115 | }; |
116 | |
117 | void foo() |
118 | { |
119 | B<int> b; |
120 | b.g1(); // expected-note {{required here}} |
121 | b.g2(); // expected-note {{required here}} |
122 | } |
123 | |
124 | } |
125 | |
126 | |
127 | namespace lookup_dependent_base_class_friend { |
128 | |
129 | template <class T> |
130 | class B { |
131 | public: |
132 | static void g(); // expected-note {{must qualify identifier to find this declaration in dependent base class}} |
133 | }; |
134 | |
135 | template <class T> |
136 | class A : public B<T> { |
137 | public: |
138 | friend void foo(A<T> p){ |
139 | g(); // expected-warning {{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
140 | } |
141 | }; |
142 | |
143 | int main2() |
144 | { |
145 | A<int> a; |
146 | foo(a); // expected-note {{requested here}} |
147 | } |
148 | |
149 | } |
150 | |
151 | |
152 | namespace lookup_dependent_base_no_typo_correction { |
153 | |
154 | class C { |
155 | public: |
156 | int m_hWnd; |
157 | }; |
158 | |
159 | template <class T> |
160 | class A : public T { |
161 | public: |
162 | void f(int hWnd) { |
163 | m_hWnd = 1; // expected-warning {{use of undeclared identifier 'm_hWnd'; unqualified lookup into dependent bases of class template 'A' is a Microsoft extension}} |
164 | } |
165 | }; |
166 | |
167 | template class A<C>; |
168 | |
169 | } |
170 | |
171 | namespace PR12701 { |
172 | |
173 | class A {}; |
174 | class B {}; |
175 | |
176 | template <class T> |
177 | class Base { |
178 | public: |
179 | bool base_fun(void* p) { return false; } // expected-note {{must qualify identifier to find this declaration in dependent base class}} |
180 | operator T*() const { return 0; } |
181 | }; |
182 | |
183 | template <class T> |
184 | class Container : public Base<T> { |
185 | public: |
186 | template <typename S> |
187 | bool operator=(const Container<S>& rhs) { |
188 | return base_fun(rhs); // expected-warning {{use of identifier 'base_fun' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
189 | } |
190 | }; |
191 | |
192 | void f() { |
193 | Container<A> text_provider; |
194 | Container<B> text_provider2; |
195 | text_provider2 = text_provider; // expected-note {{in instantiation of function template specialization}} |
196 | } |
197 | |
198 | } // namespace PR12701 |
199 | |
200 | namespace PR16014 { |
201 | |
202 | struct A { |
203 | int a; |
204 | static int sa; |
205 | }; |
206 | template <typename T> struct B : T { |
207 | int foo() { return a; } // expected-warning {{lookup into dependent bases}} |
208 | int *bar() { return &a; } // expected-warning {{lookup into dependent bases}} |
209 | int baz() { return T::a; } |
210 | int T::*qux() { return &T::a; } |
211 | static int T::*stuff() { return &T::a; } |
212 | static int stuff1() { return T::sa; } |
213 | static int *stuff2() { return &T::sa; } |
214 | static int stuff3() { return sa; } // expected-warning {{lookup into dependent bases}} |
215 | static int *stuff4() { return &sa; } // expected-warning {{lookup into dependent bases}} |
216 | }; |
217 | |
218 | template <typename T> struct C : T { |
219 | int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}} |
220 | int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}} |
221 | int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} |
222 | int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} |
223 | int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} \ |
224 | // expected-warning {{unqualified lookup into dependent bases of class template 'C'}} |
225 | }; |
226 | |
227 | template struct B<A>; |
228 | template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::{{.*}}' requested here}} |
229 | |
230 | template <typename T> struct D : T { |
231 | struct Inner { |
232 | int foo() { |
233 | // FIXME: MSVC can find this in D's base T! Even worse, if ::sa exists, |
234 | // clang will use it instead. |
235 | return sa; // expected-error {{use of undeclared identifier 'sa'}} |
236 | } |
237 | }; |
238 | }; |
239 | template struct D<A>; |
240 | |
241 | } |
242 | |
243 | namespace PR19233 { |
244 | template <class T> |
245 | struct A : T { |
246 | void foo() { |
247 | ::undef(); // expected-error {{no member named 'undef' in the global namespace}} |
248 | } |
249 | void bar() { |
250 | ::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}} |
251 | } |
252 | void baz() { |
253 | B::qux(); // expected-error {{use of undeclared identifier 'B'}} \ |
254 | // expected-warning {{unqualified lookup into dependent bases of class template 'A'}} |
255 | } |
256 | }; |
257 | |
258 | struct B { void qux(); }; |
259 | struct C : B { }; |
260 | template struct A<C>; // No error! B is a base of A<C>, and qux is available. |
261 | |
262 | struct D { }; |
263 | template struct A<D>; // expected-note {{in instantiation of member function 'PR19233::A<PR19233::D>::baz' requested here}} |
264 | |
265 | } |
266 | |
267 | namespace nonmethod_missing_this { |
268 | template <typename T> struct Base { int y = 42; }; |
269 | template <typename T> struct Derived : Base<T> { |
270 | int x = y; // expected-warning {{lookup into dependent bases}} |
271 | auto foo(int j) -> decltype(y * j) { // expected-warning {{lookup into dependent bases}} |
272 | return y * j; // expected-warning {{lookup into dependent bases}} |
273 | } |
274 | int bar() { |
275 | return [&] { return y; }(); // expected-warning {{lookup into dependent bases}} |
276 | } |
277 | }; |
278 | template struct Derived<int>; |
279 | } |
280 | |
281 | namespace typedef_in_base { |
282 | template <typename T> struct A { typedef T NameFromBase; }; |
283 | template <typename T> struct B : A<T> { |
284 | NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} |
285 | }; |
286 | static_assert(sizeof(B<int>) == 4, ""); |
287 | } |
288 | |
289 | namespace struct_in_base { |
290 | template <typename T> struct A { struct NameFromBase {}; }; |
291 | template <typename T> struct B : A<T> { |
292 | NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} |
293 | }; |
294 | static_assert(sizeof(B<int>) == 1, ""); |
295 | } |
296 | |
297 | namespace enum_in_base { |
298 | template <typename T> struct A { enum NameFromBase { X }; }; |
299 | template <typename T> struct B : A<T> { |
300 | NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} |
301 | }; |
302 | static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), ""); |
303 | } |
304 | |
305 | namespace two_types_in_base { |
306 | template <typename T> struct A { typedef T NameFromBase; }; // expected-note {{member found by ambiguous name lookup}} |
307 | template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-note {{member found by ambiguous name lookup}} |
308 | template <typename T> struct C : A<T>, B<T> { |
309 | NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
310 | }; |
311 | static_assert(sizeof(C<int>) != 0, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}} |
312 | } |
313 | |
314 | namespace type_and_decl_in_base { |
315 | template <typename T> struct A { typedef T NameFromBase; }; |
316 | template <typename T> struct B { static const T NameFromBase = 42; }; |
317 | template <typename T> struct C : A<T>, B<T> { |
318 | NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} |
319 | }; |
320 | } |
321 | |
322 | namespace classify_type_from_base { |
323 | template <typename T> struct A { struct NameFromBase {}; }; |
324 | template <typename T> struct B : A<T> { |
325 | A<NameFromBase> m; // expected-warning {{found via unqualified lookup into dependent bases}} |
326 | }; |
327 | } |
328 | |
329 | namespace classify_nontype_from_base { |
330 | // MSVC does not do lookup of non-type declarations from dependent template base |
331 | // classes. The extra lookup only applies to types. |
332 | template <typename T> struct A { void NameFromBase() {} }; |
333 | template <void (*F)()> struct B { }; |
334 | template <typename T> struct C : A<T> { |
335 | B<C::NameFromBase> a; // correct |
336 | B<NameFromBase> b; // expected-error {{use of undeclared identifier 'NameFromBase'}} |
337 | }; |
338 | } |
339 | |
340 | namespace template_in_base { |
341 | template <typename T> struct A { |
342 | template <typename U> struct NameFromBase { U x; }; |
343 | }; |
344 | template <typename T> struct B : A<T> { |
345 | // Correct form. |
346 | typename B::template NameFromBase<T> m; |
347 | }; |
348 | template <typename T> struct C : A<T> { |
349 | // Incorrect form. |
350 | NameFromBase<T> m; // expected-error {{no template named 'NameFromBase'}} |
351 | }; |
352 | } |
353 | |
354 | namespace type_in_inner_class_in_base { |
355 | template <typename T> |
356 | struct A { |
357 | struct B { typedef T NameFromBase; }; |
358 | }; |
359 | template <typename T> |
360 | struct C : A<T>::B { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}} |
361 | } |
362 | |
363 | namespace type_in_inner_template_class_in_base { |
364 | template <typename T> |
365 | struct A { |
366 | template <typename U> struct B { typedef U InnerType; }; |
367 | }; |
368 | template <typename T> |
369 | struct C : A<T>::template B<T> { |
370 | NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} |
371 | }; |
372 | } |
373 | |
374 | namespace have_nondependent_base { |
375 | template <typename T> |
376 | struct A { |
377 | // Nothing, lookup should fail. |
378 | }; |
379 | template <typename T> |
380 | struct B : A<T> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}} |
381 | struct C : A<int> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}} |
382 | } |
383 | |
384 | namespace type_in_base_of_dependent_base { |
385 | struct A { typedef int NameFromBase; }; |
386 | template <typename T> |
387 | struct B : A {}; |
388 | template <typename T> |
389 | struct C : B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
390 | } |
391 | |
392 | namespace type_in_second_dependent_base { |
393 | template <typename T> |
394 | struct A {}; |
395 | template<typename T> |
396 | struct B { typedef T NameFromBase; }; |
397 | template <typename T> |
398 | struct D : A<T>, B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
399 | } |
400 | |
401 | namespace type_in_second_non_dependent_base { |
402 | struct A {}; |
403 | struct B { typedef int NameFromBase; }; |
404 | template<typename T> |
405 | struct C : A, B {}; |
406 | template <typename T> |
407 | struct D : C<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
408 | } |
409 | |
410 | namespace type_in_virtual_base_of_dependent_base { |
411 | template <typename T> |
412 | struct A { typedef T NameFromBase; }; |
413 | template <typename T> |
414 | struct B : virtual A<T> {}; |
415 | template <typename T> |
416 | struct C : B<T>, virtual A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
417 | C<int> c; |
418 | } |
419 | |
420 | namespace type_in_base_of_multiple_dependent_bases { |
421 | template <typename T> |
422 | struct A { typedef T NameFromBase; }; |
423 | template <typename T> |
424 | struct B : public A<T> {}; |
425 | template <typename T> |
426 | struct C : B<T>, public A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-warning {{direct base 'A<int>' is inaccessible due to ambiguity:}} |
427 | C<int> c; // expected-note {{in instantiation of template class 'type_in_base_of_multiple_dependent_bases::C<int>' requested here}} |
428 | } |
429 | |
430 | namespace type_in_dependent_base_of_non_dependent_type { |
431 | template<typename T> struct A { typedef int NameFromBase; }; |
432 | template<typename T> struct B : A<T> { |
433 | struct C; |
434 | template<typename TT> |
435 | struct D : C { |
436 | NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
437 | }; |
438 | struct E : C { |
439 | NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
440 | }; |
441 | }; |
442 | template<typename T> struct B<T>::C : B { |
443 | NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} |
444 | }; |
445 | template<typename T> struct F : B<T>::C { |
446 | NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} |
447 | }; |
448 | } |
449 | |
450 | namespace lookup_in_function_contexts { |
451 | template <typename T> struct A { typedef T NameFromBase; }; |
452 | template <typename T> |
453 | struct B : A<T> { |
454 | // expected-warning@+1 {{lookup into dependent bases}} |
455 | static auto lateSpecifiedFunc() -> decltype(NameFromBase()) { |
456 | return {}; |
457 | } |
458 | |
459 | static void memberFunc() { |
460 | NameFromBase x; // expected-warning {{lookup into dependent bases}} |
461 | } |
462 | |
463 | static void funcLocalClass() { |
464 | struct X { |
465 | NameFromBase x; // expected-warning {{lookup into dependent bases}} |
466 | } y; |
467 | } |
468 | |
469 | void localClassMethod() { |
470 | struct X { |
471 | void bar() { |
472 | NameFromBase m; // expected-warning {{lookup into dependent bases}} |
473 | } |
474 | } x; |
475 | x.bar(); |
476 | } |
477 | |
478 | static void funcLambda() { |
479 | auto l = []() { |
480 | NameFromBase x; // expected-warning {{lookup into dependent bases}} |
481 | }; |
482 | l(); |
483 | } |
484 | |
485 | static constexpr int constexprFunc() { |
486 | NameFromBase x = {}; // expected-warning {{lookup into dependent bases}} |
487 | return sizeof(x); |
488 | } |
489 | |
490 | static auto autoFunc() { |
491 | NameFromBase x; // expected-warning {{lookup into dependent bases}} |
492 | return x; |
493 | } |
494 | }; |
495 | |
496 | // Force us to parse the methods. |
497 | template struct B<int>; |
498 | } |
499 | |
500 | namespace function_template_deduction { |
501 | // Overloaded function templates. |
502 | template <int N> int f() { return N; } |
503 | template <typename T> int f() { return sizeof(T); } |
504 | |
505 | // Dependent base class with type. |
506 | template <typename T> |
507 | struct A { typedef T NameFromBase; }; |
508 | template <typename T> |
509 | struct B : A<T> { |
510 | // expected-warning@+1 {{found via unqualified lookup into dependent bases}} |
511 | int x = f<NameFromBase>(); |
512 | }; |
513 | |
514 | // Dependent base class with enum. |
515 | template <typename T> struct C { enum { NameFromBase = 4 }; }; |
516 | template <typename T> struct D : C<T> { |
517 | // expected-warning@+1 {{use of undeclared identifier 'NameFromBase'; unqualified lookup into dependent bases}} |
518 | int x = f<NameFromBase>(); |
519 | }; |
520 | } |
521 | |
522 | namespace function_template_undef_impl { |
523 | template<class T> |
524 | void f() { |
525 | Undef::staticMethod(); // expected-error {{use of undeclared identifier 'Undef'}} |
526 | UndefVar.method(); // expected-error {{use of undeclared identifier 'UndefVar'}} |
527 | } |
528 | } |
529 | |
530 | namespace PR20716 { |
531 | template <template <typename T> class A> |
532 | struct B : A<int> |
533 | { |
534 | XXX x; // expected-error {{unknown type name}} |
535 | }; |
536 | |
537 | template <typename T> |
538 | struct C {}; |
539 | |
540 | template <typename T> |
541 | using D = C<T>; |
542 | |
543 | template <typename T> |
544 | struct E : D<T> |
545 | { |
546 | XXX x; // expected-error {{unknown type name}} |
547 | }; |
548 | } |
549 | |
550 | namespace PR23810 { |
551 | void f(int); |
552 | struct Base { |
553 | void f(); // expected-note{{must qualify identifier to find this declaration in dependent base class}} |
554 | }; |
555 | template <typename T> struct Template : T { |
556 | void member() { |
557 | f(); // expected-warning {{found via unqualified lookup into dependent bases}} |
558 | } |
559 | }; |
560 | void test() { |
561 | Template<Base> x; |
562 | x.member(); // expected-note{{requested here}} |
563 | }; |
564 | } |
565 | |
566 | namespace PR23823 { |
567 | // Don't delay lookup in SFINAE context. |
568 | template <typename T> decltype(g(T())) check(); // expected-note{{candidate template ignored: substitution failure [with T = int]: use of undeclared identifier 'g'}} |
569 | decltype(check<int>()) x; // expected-error{{no matching function for call to 'check'}} |
570 | |
571 | void h(); |
572 | template <typename T> decltype(h(T())) check2(); // expected-note{{candidate template ignored: substitution failure [with T = int]: no matching function for call to 'h'}} |
573 | decltype(check2<int>()) y; // expected-error{{no matching function for call to 'check2'}} |
574 | } |
575 | |
576 | // We also allow unqualified lookup into bases in contexts where the we know the |
577 | // undeclared identifier *must* be a type, such as a new expression or catch |
578 | // parameter type. |
579 | template <typename T> |
580 | struct UseUnqualifiedTypeNames : T { |
581 | void foo() { |
582 | void *P = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}} |
583 | size_t x = __builtin_offsetof(TheType, f2); // expected-warning {{unqualified lookup}} expected-error {{no type}} |
584 | try { |
585 | } catch (TheType) { // expected-warning {{unqualified lookup}} expected-error {{no type}} |
586 | } |
587 | enum E : IntegerType { E0 = 42 }; // expected-warning {{unqualified lookup}} expected-error {{no type}} |
588 | _Atomic(TheType) a; // expected-warning {{unqualified lookup}} expected-error {{no type}} |
589 | } |
590 | void out_of_line(); |
591 | }; |
592 | template <typename T> |
593 | void UseUnqualifiedTypeNames<T>::out_of_line() { |
594 | void *p = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}} |
595 | } |
596 | struct Base { |
597 | typedef int IntegerType; |
598 | struct TheType { |
599 | int f1, f2; |
600 | }; |
601 | }; |
602 | template struct UseUnqualifiedTypeNames<Base>; |
603 | struct BadBase { }; |
604 | template struct UseUnqualifiedTypeNames<BadBase>; // expected-note-re 2 {{in instantiation {{.*}} requested here}} |
605 | |
606 | namespace partial_template_lookup { |
607 | |
608 | class Bar; |
609 | class Spare; |
610 | |
611 | template <class T, class X = Bar> |
612 | class FooTemplated; |
613 | |
614 | class FooBase { |
615 | public: |
616 | typedef int BaseTypedef; |
617 | }; |
618 | |
619 | // Partial template spec (unused) |
620 | template <class T> |
621 | class FooTemplated<T, Spare> {}; |
622 | |
623 | // Partial template spec (used) |
624 | template <class T> |
625 | class FooTemplated<T, Bar> : public FooBase {}; |
626 | |
627 | // Full template spec |
628 | template <class T, class X> |
629 | class FooTemplated : public FooTemplated<T, Bar> { |
630 | public: |
631 | BaseTypedef Member; // expected-warning {{unqualified lookup}} |
632 | }; |
633 | } |
634 | |