| // RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s |
| |
| namespace basic { |
| struct C { |
| static void foo2() {} |
| }; |
| template <typename T> |
| struct A { |
| typedef C D; |
| }; |
| |
| template <typename T> |
| struct B : A<T> { |
| void foo() { |
| D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} |
| } |
| }; |
| |
| template struct B<int>; // Instantiation has no warnings. |
| } |
| |
| namespace nested_nodep_base { |
| // There are limits to our hacks, MSVC accepts this, but we don't. |
| struct A { |
| struct D { static void foo2(); }; |
| }; |
| template <typename T> |
| struct B : T { |
| struct C { |
| void foo() { |
| D::foo2(); // expected-error {{use of undeclared identifier 'D'}} |
| } |
| }; |
| }; |
| |
| template struct B<A>; // Instantiation has no warnings. |
| } |
| |
| namespace nested_dep_base { |
| // We actually accept this because the inner class has a dependent base even |
| // though it isn't a template. |
| struct A { |
| struct D { static void foo2(); }; |
| }; |
| template <typename T> |
| struct B { |
| struct C : T { |
| void foo() { |
| D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'C' is a Microsoft extension}} |
| } |
| }; |
| }; |
| |
| template struct B<A>; // Instantiation has no warnings. |
| } |