Re-land r250592 without rejecting field refs in unevaluated contexts

This time, I went with the first approach from
http://reviews.llvm.org/D6700, where clang actually attempts to form an
implicit member reference from an UnresolvedLookupExpr. We know that
there are only two possible outcomes at this point, a DeclRefExpr of the
FieldDecl or an error, but its safer to reuse the existing machinery for
this.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@250856 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner 2015-10-20 21:04:13 +00:00
parent 5552f5c7ce
commit d903d33591
2 changed files with 77 additions and 3 deletions

View File

@ -9127,9 +9127,20 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();
// If we have neither explicit template arguments, nor the template keyword,
// it's a normal declaration name.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
// it's a normal declaration name or member reference.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {
NamedDecl *D = R.getAsSingle<NamedDecl>();
// In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an
// instance member. In other contexts, BuildPossibleImplicitMemberExpr will
// give a good diagnostic.
if (D && D->isCXXInstanceMember()) {
return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R,
/*TemplateArgs=*/nullptr,
/*Scope=*/nullptr);
}
return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
}
// If we have template arguments, rebuild them, then rebuild the
// templateid expression.

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
namespace test0 {
namespace N { }
@ -104,3 +105,65 @@ namespace PR16936 {
x.f();
}
}
namespace pr21923 {
template <typename> struct Base {
int field;
void method();
};
template <typename Scalar> struct Derived : Base<Scalar> {
using Base<Scalar>::field;
using Base<Scalar>::method;
static void m_fn1() {
// expected-error@+1 {{invalid use of member 'field' in static member function}}
(void)field;
// expected-error@+1 {{invalid use of member 'field' in static member function}}
(void)&field;
// expected-error@+1 {{call to non-static member function without an object argument}}
(void)method;
// expected-error@+1 {{call to non-static member function without an object argument}}
(void)&method;
// expected-error@+1 {{call to non-static member function without an object argument}}
method();
(void)&Base<Scalar>::field;
(void)&Base<Scalar>::method;
}
#if __cplusplus >= 201103L
// These usages are OK in C++11 due to the unevaluated context.
enum { TheSize = sizeof(field) };
typedef decltype(field) U;
#else
// expected-error@+1 {{invalid use of non-static data member 'field'}}
enum { TheSize = sizeof(field) };
#endif
};
#if __cplusplus < 201103L
// C++98 has an extra note for TheSize.
// expected-note@+2 {{requested here}}
#endif
template class Derived<int>; // expected-note {{requested here}}
// This is interesting because we form an UnresolvedLookupExpr in the static
// function template and an UnresolvedMemberExpr in the instance function
// template. As a result, we get slightly different behavior.
struct UnresolvedTemplateNames {
template <typename> void maybe_static();
#if __cplusplus < 201103L
// expected-warning@+2 {{default template arguments for a function template are a C++11 extension}}
#endif
template <typename T, typename T::type = 0> static void maybe_static();
template <typename T>
void instance_method() { (void)maybe_static<T>(); }
template <typename T>
static void static_method() {
// expected-error@+1 {{call to non-static member function without an object argument}}
(void)maybe_static<T>();
}
};
void force_instantiation(UnresolvedTemplateNames x) {
x.instance_method<int>();
UnresolvedTemplateNames::static_method<int>(); // expected-note {{requested here}}
}
} // pr21923