Index: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp +++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp @@ -703,8 +703,13 @@ if (getLangOpts().MSVCCompat) { DeclContext *DC = LookupCtx ? LookupCtx : CurContext; if (DC->isDependentContext() && DC->isFunctionOrMethod()) { - SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); - return false; + CXXRecordDecl *ContainingClass = dyn_cast(DC->getParent()); + if (ContainingClass && ContainingClass->hasAnyDependentBases()) { + Diag(IdentifierLoc, diag::ext_undeclared_unqual_id_with_dependent_base) + << &Identifier << ContainingClass; + SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + return false; + } } } Index: cfe/trunk/test/SemaTemplate/lookup-dependent-bases.cpp =================================================================== --- cfe/trunk/test/SemaTemplate/lookup-dependent-bases.cpp +++ cfe/trunk/test/SemaTemplate/lookup-dependent-bases.cpp @@ -1,20 +1,55 @@ // RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s -// expected-no-diagnostics -class C { -public: - static void foo2() { } -}; -template -class A { -public: - typedef C D; -}; - -template -class B : public A { -public: - void foo() { - D::foo2(); - } +namespace basic { +struct C { + static void foo2() {} }; +template +struct A { + typedef C D; +}; + +template +struct B : A { + 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; // 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 +struct B : T { + struct C { + void foo() { + D::foo2(); // expected-error {{use of undeclared identifier 'D'}} + } + }; +}; + +template struct B; // 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 +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; // Instantiation has no warnings. +} Index: cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp =================================================================== --- cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -220,7 +220,8 @@ int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C'}} expected-warning {{lookup into dependent bases}} int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} - int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} + int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} \ + // expected-warning {{unqualified lookup into dependent bases of class template 'C'}} }; template struct B; @@ -249,7 +250,8 @@ ::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}} } void baz() { - B::qux(); // expected-error {{use of undeclared identifier 'B'}} + B::qux(); // expected-error {{use of undeclared identifier 'B'}} \ + // expected-warning {{unqualified lookup into dependent bases of class template 'A'}} } }; @@ -460,3 +462,11 @@ int x = f(); }; } + +namespace function_template_undef_impl { +template +void f() { + Undef::staticMethod(); // expected-error {{use of undeclared identifier 'Undef'}} + UndefVar.method(); // expected-error {{use of undeclared identifier 'UndefVar'}} +} +}