forked from OSchip/llvm-project
Allow lookup into dependent bases in more places under -fms-compatibility
We currently allow unqualified lookup for instance methods but not static methods because we can't recover with a semantic 'this->' insertion. ATL headers have static methods that do unqualified lookup into dependent base classes. The pattern looks like: template <typename T> struct Foo : T { static int *getBarFromT() { return Bar; } }; Now we recover as if the user had written: template <typename T> struct Foo : T { static int *getBarFromT() { return Foo::Bar; } }; ... which will eventually look up Bar in T at instantiation time. Now we emit a diagnostic in both cases, and delay lookup in other contexts where 'this' is available and refers to a class with dependent bases. Reviewed by: rsmith Differential Revision: http://reviews.llvm.org/D4079 llvm-svn: 210611
This commit is contained in:
parent
2dace6e54b
commit
10ca24c631
|
@ -3662,9 +3662,13 @@ def err_unexpected_typedef : Error<
|
|||
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<Microsoft>;
|
||||
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<Microsoft>;
|
||||
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<Microsoft>;
|
||||
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 "
|
||||
|
|
|
@ -1762,7 +1762,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
|||
// TODO: fixit for inserting 'Base<T>::' 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 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
|||
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<CXXMethodDecl>(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 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
|
|||
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<CXXMethodDecl>(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.
|
||||
|
|
|
@ -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 <class T>
|
||||
|
@ -64,7 +64,7 @@ template<class T>
|
|||
class B : public A<T> {
|
||||
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 @@ template <class T>
|
|||
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 @@ struct A {
|
|||
static int sa;
|
||||
};
|
||||
template <typename T> 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 <typename T> struct C : T {
|
||||
int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}}
|
||||
int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}}
|
||||
int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}}
|
||||
int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} 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 @@ struct D { };
|
|||
template struct A<D>; // expected-note {{in instantiation of member function 'PR19233::A<PR19233::D>::baz' requested here}}
|
||||
|
||||
}
|
||||
|
||||
namespace nonmethod_missing_this {
|
||||
template <typename T> struct Base { int y = 42; };
|
||||
template <typename T> struct Derived : Base<T> {
|
||||
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<int>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue