r250856 - Re-land r250592 without rejecting field refs in unevaluated contexts

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 20 14:04:13 PDT 2015


Author: rnk
Date: Tue Oct 20 16:04:13 2015
New Revision: 250856

URL: http://llvm.org/viewvc/llvm-project?rev=250856&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaTemplate/instantiate-using-decl.cpp

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=250856&r1=250855&r2=250856&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 20 16:04:13 2015
@@ -9127,9 +9127,20 @@ TreeTransform<Derived>::TransformUnresol
   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.

Modified: cfe/trunk/test/SemaTemplate/instantiate-using-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-using-decl.cpp?rev=250856&r1=250855&r2=250856&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-using-decl.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-using-decl.cpp Tue Oct 20 16:04:13 2015
@@ -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 at +1 {{invalid use of member 'field' in static member function}}
+    (void)field;
+    // expected-error at +1 {{invalid use of member 'field' in static member function}}
+    (void)&field;
+    // expected-error at +1 {{call to non-static member function without an object argument}}
+    (void)method;
+    // expected-error at +1 {{call to non-static member function without an object argument}}
+    (void)&method;
+    // expected-error at +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 at +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 at +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 at +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 at +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




More information about the cfe-commits mailing list