Hi rsmith,
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 also emit a diagnostic in both cases.
http://reviews.llvm.org/D4079
Files:
lib/Sema/SemaExpr.cpp
test/SemaTemplate/ms-lookup-template-base-classes.cpp
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1927,6 +1927,52 @@
return true;
}
+/// 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.
+/// This doesn't precisely match MSVC's instantiation model, but it's close
+/// enough.
+static Expr *
+recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
+ DeclContext *DC, DeclarationNameInfo &NameInfo,
+ SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
+
+ // Only try to recover from lookup into dependent bases inside methods.
+ if (!MD || !MD->getParent()->hasAnyDependentBases())
+ return nullptr;
+
+ // Diagnose this as unqualified lookup into a dependent base class. If this
+ // is an instance method, we suggest inserting this-> as a fixit.
+ SourceLocation Loc = NameInfo.getLoc();
+ unsigned DI = diag::warn_found_via_dependent_bases_lookup;
+ DiagnosticBuilder DB = S.Diag(Loc, DI) << NameInfo.getName();
+
+ if (MD->isInstance()) {
+ DB << FixItHint::CreateInsertion(Loc, "this->");
+
+ // Since the 'this' expression is synthesized, we don't need to
+ // perform the double-lookup check.
+ QualType ThisType = MD->getThisType(Context);
+ NamedDecl *FirstQualifierInScope = nullptr;
+ return CXXDependentScopeMemberExpr::Create(
+ Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,
+ /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
+ FirstQualifierInScope, 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,
+ MD->getParent()->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 +2080,11 @@
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, CurContext,
+ NameInfo, TemplateKWLoc,
+ TemplateArgs))
+ return E;
}
// Don't diagnose an empty lookup for inline assmebly.
Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp
===================================================================
--- test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -64,7 +64,7 @@
class B : public A<T> {
public:
void f() {
- var = 3;
+ var = 3; // expected-warning {{use of identifier 'var' found via unqualified lookup into dependent bases of class templates 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 identifier 'm_hWnd' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
}
};
@@ -204,18 +204,20 @@
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'}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits