<div dir="ltr"><div><br></div><div class="gmail_extra"><div class="gmail_quote">On Tue, Dec 16, 2014 at 4:07 PM, Reid Kleckner <span dir="ltr"><<a href="mailto:rnk@google.com" target="_blank">rnk@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Hi rsmith,<br>
<br>
During the initial template parse for this code, 'member' is unresolved<br>
and we don't know anything about it:<br>
<br>
  struct A { int member };<br>
  template <typename T><br>
  struct B : public T {<br>
    using T::member;<br>
    static void f() {<br>
      (void)member; // Could be static or non-static.<br>
    }<br>
  };<br>
  template class B<A>;<br>
<br>
The pattern declaration contains an UnresolvedLookupExpr rather than an<br>
UnresolvedMemberExpr.</blockquote><div><br></div><div>The documentation for UnresolvedLookupExpr suggests that this is a bug when parsing the template:</div><div><br></div><div><div>  /// These never include UnresolvedUsingValueDecls, which are always class</div><div>  /// members and therefore appear only in UnresolvedMemberLookupExprs.</div></div><div><br></div><div>(The comment presumably means UnresolvedMemberExpr.)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Later we have to notice that the decl resolved to<br>
an instance member and form a MemberExpr if so.<br>
<br>
<a href="http://reviews.llvm.org/D6700" target="_blank">http://reviews.llvm.org/D6700</a><br>
<br>
Files:<br>
  lib/Sema/SemaExprMember.cpp<br>
  lib/Sema/TreeTransform.h<br>
  test/SemaTemplate/instantiate-using-decl.cpp<br>
<br>
Index: lib/Sema/SemaExprMember.cpp<br>
===================================================================<br>
--- lib/Sema/SemaExprMember.cpp<br>
+++ lib/Sema/SemaExprMember.cpp<br>
@@ -90,7 +90,6 @@<br>
 /// conservatively answer "yes", in which case some errors will simply<br>
 /// not be caught until template-instantiation.<br>
 static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,<br>
-                                            Scope *CurScope,<br>
                                             const LookupResult &R) {<br>
   assert(!R.empty() && (*R.begin())->isCXXClassMember());<br>
<br>
@@ -205,6 +204,9 @@<br>
   SourceRange Range(Loc);<br>
   if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());<br>
<br>
+  // Look through using shadow decls and aliases.<br>
+  Rep = Rep->getUnderlyingDecl();<br></blockquote><div><br></div><div>You can test this change in isolation with:</div><div><br></div><div>struct A { int n; }; struct B : A { using A::n; static int f() { return n; } };<br></div><div><br></div><div>... which currently produces this bogus diagnostic:</div><div><br></div><div><div><stdin>:1:73: error: call to non-static member function without an object argument</div><div>struct A { int n; }; struct B : A { using A::n; static int f() { return n; } };</div><div>                                                                        ^</div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+<br>
   DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();<br>
   CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);<br>
   CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr;<br>
@@ -237,7 +239,7 @@<br>
                                       SourceLocation TemplateKWLoc,<br>
                                       LookupResult &R,<br>
                                 const TemplateArgumentListInfo *TemplateArgs) {<br>
-  switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {<br>
+  switch (ClassifyImplicitMemberAccess(*this, R)) {<br>
   case IMA_Instance:<br>
     return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true);<br>
<br>
Index: lib/Sema/TreeTransform.h<br>
===================================================================<br>
--- lib/Sema/TreeTransform.h<br>
+++ lib/Sema/TreeTransform.h<br>
@@ -8705,8 +8705,18 @@<br>
<br>
   // If we have neither explicit template arguments, nor the template keyword,<br>
   // it's a normal declaration name.<br>
-  if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())<br>
+  if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {<br>
+    // If this resolved to a data member, do member reference semantic analysis<br>
+    // and possibly form a MemberExpr.<br>
+    if (NamedDecl *D = R.getAsSingle<NamedDecl>()) {<br>
+      D = D->getUnderlyingDecl();<br>
+      if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) ||<br>
+          isa<MSPropertyDecl>(D))<br></blockquote><div><br></div><div>Per the comment on UnresolvedLookupExpr, I'm not sure this is the right place for this fix. In any case, we have somewhat more complex logic for this in ActOnIdExpression:</div><div><br></div><div><div>  if (!R.empty() && (*R.begin())->isCXXClassMember()) {</div><div>    bool MightBeImplicitMember;</div><div>    if (!IsAddressOfOperand)</div><div>      MightBeImplicitMember = true;</div><div>    else if (!SS.isEmpty())</div><div>      MightBeImplicitMember = false;</div><div>    else if (R.isOverloadedResult())</div><div>      MightBeImplicitMember = false;</div><div>    else if (R.isUnresolvableResult())</div><div>      MightBeImplicitMember = true;</div><div>    else</div><div>      MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||</div><div>                              isa<IndirectFieldDecl>(R.getFoundDecl()) ||</div><div>                              isa<MSPropertyDecl>(R.getFoundDecl());</div><div><br></div><div>    if (MightBeImplicitMember)</div><div>      return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,</div><div>                                             R, TemplateArgs);</div><div>  }</div></div><div><br></div><div>At least some of those checks seem like they would be relevant here.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+        return getSema().BuildPossibleImplicitMemberExpr(<br>
+            SS, SourceLocation(), R, /*TemplateArgs=*/nullptr);<br>
+    }<br>
     return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());<br>
+  }<br>
<br>
   // If we have template arguments, rebuild them, then rebuild the<br>
   // templateid expression.<br>
Index: test/SemaTemplate/instantiate-using-decl.cpp<br>
===================================================================<br>
--- test/SemaTemplate/instantiate-using-decl.cpp<br>
+++ test/SemaTemplate/instantiate-using-decl.cpp<br>
@@ -104,3 +104,26 @@<br>
     x.f();<br>
   }<br>
 }<br>
+<br>
+namespace PR21923 {<br>
+struct A {<br>
+  int member;<br>
+  void method();<br>
+};<br>
+template <typename T><br>
+struct B : public T {<br>
+  using T::member;<br>
+  using T::method;<br>
+  static void StaticFun() {<br>
+    (void)member; // expected-error {{invalid use of member 'member' in static member function}}<br>
+    (void)B<T>::member; // expected-error {{invalid use of member 'member' in static member function}}<br>
+    method(); // expected-error {{call to non-static member function without an object argument}}<br>
+  }<br>
+  void InstanceFun() {<br>
+    (void)member;<br>
+    (void)B<T>::member;<br>
+    method();<br>
+  }<br>
+};<br>
+template class B<A>; // expected-note 1 {{requested here}}<br>
+}<br>
<br>
EMAIL PREFERENCES<br>
  <a href="http://reviews.llvm.org/settings/panel/emailpreferences/" target="_blank">http://reviews.llvm.org/settings/panel/emailpreferences/</a><br>
</blockquote></div><br></div></div>