1 | // RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s |
2 | |
3 | namespace basic { |
4 | struct C { |
5 | static void foo2() {} |
6 | }; |
7 | template <typename T> |
8 | struct A { |
9 | typedef C D; |
10 | }; |
11 | |
12 | template <typename T> |
13 | struct B : A<T> { |
14 | void foo() { |
15 | D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} |
16 | } |
17 | }; |
18 | |
19 | template struct B<int>; // Instantiation has no warnings. |
20 | } |
21 | |
22 | namespace nested_nodep_base { |
23 | // There are limits to our hacks, MSVC accepts this, but we don't. |
24 | struct A { |
25 | struct D { static void foo2(); }; |
26 | }; |
27 | template <typename T> |
28 | struct B : T { |
29 | struct C { |
30 | void foo() { |
31 | D::foo2(); // expected-error {{use of undeclared identifier 'D'}} |
32 | } |
33 | }; |
34 | }; |
35 | |
36 | template struct B<A>; // Instantiation has no warnings. |
37 | } |
38 | |
39 | namespace nested_dep_base { |
40 | // We actually accept this because the inner class has a dependent base even |
41 | // though it isn't a template. |
42 | struct A { |
43 | struct D { static void foo2(); }; |
44 | }; |
45 | template <typename T> |
46 | struct B { |
47 | struct C : T { |
48 | void foo() { |
49 | D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'C' is a Microsoft extension}} |
50 | } |
51 | }; |
52 | }; |
53 | |
54 | template struct B<A>; // Instantiation has no warnings. |
55 | } |
56 | |