Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -3662,9 +3662,13 @@ def err_unexpected_namespace : Error< "unexpected namespace name %0: expected expression">; def err_undeclared_var_use : Error<"use of undeclared identifier %0">; -def warn_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " - "found via unqualified lookup into dependent bases of class templates is a " - "Microsoft extension">, InGroup; +def ext_undeclared_unqual_id_with_dependent_base : ExtWarn< + "use of undeclared identifier %0; " + "unqualified lookup into dependent bases of class template %1 is a Microsoft extension">, + InGroup; +def ext_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " + "found via unqualified lookup into dependent bases of class templates is a " + "Microsoft extension">, InGroup; def note_dependent_var_use : Note<"must qualify identifier to find this " "declaration in dependent base class">; def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -1762,7 +1762,7 @@ // TODO: fixit for inserting 'Base::' in the other cases. // Actually quite difficult! if (getLangOpts().MSVCCompat) - diagnostic = diag::warn_found_via_dependent_bases_lookup; + diagnostic = diag::ext_found_via_dependent_bases_lookup; if (isInstance) { Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); @@ -1927,6 +1927,54 @@ return true; } +/// In Microsoft mode, if we are inside a template class whose parent class has +/// dependent base classes, and we can't resolve an unqualified identifier, then +/// assume the identifier is a member of a dependent base class. We can only +/// recover successfully in static methods, instance methods, and other contexts +/// where 'this' is available. This doesn't precisely match MSVC's +/// instantiation model, but it's close enough. +static Expr * +recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, + DeclarationNameInfo &NameInfo, + SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo *TemplateArgs) { + // Only try to recover from lookup into dependent bases in static methods or + // contexts where 'this' is available. + QualType ThisType = S.getCurrentThisType(); + const CXXRecordDecl *RD = nullptr; + if (!ThisType.isNull()) + RD = ThisType->getPointeeType()->getAsCXXRecordDecl(); + else if (auto *MD = dyn_cast(S.CurContext)) + RD = MD->getParent(); + if (!RD || !RD->hasAnyDependentBases()) + return nullptr; + + // Diagnose this as unqualified lookup into a dependent base class. If 'this' + // is available, suggest inserting 'this->' as a fixit. + SourceLocation Loc = NameInfo.getLoc(); + DiagnosticBuilder DB = + S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base) + << NameInfo.getName() << RD; + + if (!ThisType.isNull()) { + DB << FixItHint::CreateInsertion(Loc, "this->"); + return CXXDependentScopeMemberExpr::Create( + Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, + /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc, + /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs); + } + + // Synthesize a fake NNS that points to the derived class. This will + // perform name lookup during template instantiation. + CXXScopeSpec SS; + auto *NNS = + NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl()); + SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc)); + return DependentScopeDeclRefExpr::Create( + Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, + TemplateArgs); +} + ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -2034,28 +2082,10 @@ bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { - // In Microsoft mode, if we are inside a template class member function - // whose parent class has dependent base classes, and we can't resolve - // an unqualified identifier, then assume the identifier is a member of a - // dependent base class. The goal is to postpone name lookup to - // instantiation time to be able to search into the type dependent base - // classes. - // FIXME: If we want 100% compatibility with MSVC, we will have delay all - // unqualified name lookup. Any name lookup during template parsing means - // clang might find something that MSVC doesn't. For now, we only handle - // the common case of members of a dependent base class. if (SS.isEmpty() && getLangOpts().MSVCCompat) { - CXXMethodDecl *MD = dyn_cast(CurContext); - if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) { - QualType ThisType = MD->getThisType(Context); - // Since the 'this' expression is synthesized, we don't need to - // perform the double-lookup check. - NamedDecl *FirstQualifierInScope = nullptr; - return CXXDependentScopeMemberExpr::Create( - Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, - /*Op=*/SourceLocation(), SS.getWithLocInContext(Context), - TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); - } + if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo, + TemplateKWLoc, TemplateArgs)) + return E; } // Don't diagnose an empty lookup for inline assmebly. 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 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -verify %s template @@ -64,7 +64,7 @@ class B : public A { public: void f() { - var = 3; + var = 3; // expected-warning {{use of undeclared identifier 'var'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} } }; @@ -160,7 +160,7 @@ class A : public T { public: void f(int hWnd) { - m_hWnd = 1; + m_hWnd = 1; // expected-warning {{use of undeclared identifier 'm_hWnd'; unqualified lookup into dependent bases of class template 'A' is a Microsoft extension}} } }; @@ -204,18 +204,20 @@ static int sa; }; template struct B : T { - int foo() { return a; } - int *bar() { return &a; } + int foo() { return a; } // expected-warning {{lookup into dependent bases}} + int *bar() { return &a; } // expected-warning {{lookup into dependent bases}} int baz() { return T::a; } int T::*qux() { return &T::a; } static int T::*stuff() { return &T::a; } static int stuff1() { return T::sa; } static int *stuff2() { return &T::sa; } + static int stuff3() { return sa; } // expected-warning {{lookup into dependent bases}} + static int *stuff4() { return &sa; } // expected-warning {{lookup into dependent bases}} }; template struct C : T { - int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C'}} - int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C'}} + int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C'}} expected-warning {{lookup into dependent bases}} + 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'}} @@ -259,3 +261,17 @@ template struct A; // expected-note {{in instantiation of member function 'PR19233::A::baz' requested here}} } + +namespace nonmethod_missing_this { +template struct Base { int y = 42; }; +template struct Derived : Base { + int x = y; // expected-warning {{lookup into dependent bases}} + auto foo(int j) -> decltype(y * j) { // expected-warning {{lookup into dependent bases}} + return y * j; // expected-warning {{lookup into dependent bases}} + } + int bar() { + return [&] { return y; }(); // expected-warning {{lookup into dependent bases}} + } +}; +template struct Derived; +}