<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>