r210611 - Allow lookup into dependent bases in more places under -fms-compatibility
Reid Kleckner
reid at kleckner.net
Tue Jun 10 17:01:28 PDT 2014
Author: rnk
Date: Tue Jun 10 19:01:28 2014
New Revision: 210611
URL: http://llvm.org/viewvc/llvm-project?rev=210611&view=rev
Log:
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
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=210611&r1=210610&r2=210611&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jun 10 19:01:28 2014
@@ -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 "
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=210611&r1=210610&r2=210611&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 10 19:01:28 2014
@@ -1762,7 +1762,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S,
// 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,
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
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.
Modified: cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp?rev=210611&r1=210610&r2=210611&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp (original)
+++ cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp Tue Jun 10 19:01:28 2014
@@ -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>;
+}
More information about the cfe-commits
mailing list