[PATCH] Instantiate UnresolvedLookupExpr to MemberExpr when appropriate

Richard Smith richard at metafoo.co.uk
Tue Dec 16 16:33:21 PST 2014


On Tue, Dec 16, 2014 at 4:07 PM, Reid Kleckner <rnk at google.com> wrote:

> Hi rsmith,
>
> During the initial template parse for this code, 'member' is unresolved
> and we don't know anything about it:
>
>   struct A { int member };
>   template <typename T>
>   struct B : public T {
>     using T::member;
>     static void f() {
>       (void)member; // Could be static or non-static.
>     }
>   };
>   template class B<A>;
>
> The pattern declaration contains an UnresolvedLookupExpr rather than an
> UnresolvedMemberExpr.


The documentation for UnresolvedLookupExpr suggests that this is a bug when
parsing the template:

  /// These never include UnresolvedUsingValueDecls, which are always class
  /// members and therefore appear only in UnresolvedMemberLookupExprs.

(The comment presumably means UnresolvedMemberExpr.)

Later we have to notice that the decl resolved to
> an instance member and form a MemberExpr if so.
>
> http://reviews.llvm.org/D6700
>
> Files:
>   lib/Sema/SemaExprMember.cpp
>   lib/Sema/TreeTransform.h
>   test/SemaTemplate/instantiate-using-decl.cpp
>
> Index: lib/Sema/SemaExprMember.cpp
> ===================================================================
> --- lib/Sema/SemaExprMember.cpp
> +++ lib/Sema/SemaExprMember.cpp
> @@ -90,7 +90,6 @@
>  /// conservatively answer "yes", in which case some errors will simply
>  /// not be caught until template-instantiation.
>  static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
> -                                            Scope *CurScope,
>                                              const LookupResult &R) {
>    assert(!R.empty() && (*R.begin())->isCXXClassMember());
>
> @@ -205,6 +204,9 @@
>    SourceRange Range(Loc);
>    if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
>
> +  // Look through using shadow decls and aliases.
> +  Rep = Rep->getUnderlyingDecl();
>

You can test this change in isolation with:

struct A { int n; }; struct B : A { using A::n; static int f() { return n;
} };

... which currently produces this bogus diagnostic:

<stdin>:1:73: error: call to non-static member function without an object
argument
struct A { int n; }; struct B : A { using A::n; static int f() { return n;
} };
                                                                        ^

+
>    DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();
>    CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);
>    CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr;
> @@ -237,7 +239,7 @@
>                                        SourceLocation TemplateKWLoc,
>                                        LookupResult &R,
>                                  const TemplateArgumentListInfo
> *TemplateArgs) {
> -  switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
> +  switch (ClassifyImplicitMemberAccess(*this, R)) {
>    case IMA_Instance:
>      return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
> true);
>
> Index: lib/Sema/TreeTransform.h
> ===================================================================
> --- lib/Sema/TreeTransform.h
> +++ lib/Sema/TreeTransform.h
> @@ -8705,8 +8705,18 @@
>
>    // If we have neither explicit template arguments, nor the template
> keyword,
>    // it's a normal declaration name.
> -  if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
> +  if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {
> +    // If this resolved to a data member, do member reference semantic
> analysis
> +    // and possibly form a MemberExpr.
> +    if (NamedDecl *D = R.getAsSingle<NamedDecl>()) {
> +      D = D->getUnderlyingDecl();
> +      if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) ||
> +          isa<MSPropertyDecl>(D))
>

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:

  if (!R.empty() && (*R.begin())->isCXXClassMember()) {
    bool MightBeImplicitMember;
    if (!IsAddressOfOperand)
      MightBeImplicitMember = true;
    else if (!SS.isEmpty())
      MightBeImplicitMember = false;
    else if (R.isOverloadedResult())
      MightBeImplicitMember = false;
    else if (R.isUnresolvableResult())
      MightBeImplicitMember = true;
    else
      MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
                              isa<IndirectFieldDecl>(R.getFoundDecl()) ||
                              isa<MSPropertyDecl>(R.getFoundDecl());

    if (MightBeImplicitMember)
      return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
                                             R, TemplateArgs);
  }

At least some of those checks seem like they would be relevant here.

+        return getSema().BuildPossibleImplicitMemberExpr(
> +            SS, SourceLocation(), R, /*TemplateArgs=*/nullptr);
> +    }
>      return getDerived().RebuildDeclarationNameExpr(SS, R,
> Old->requiresADL());
> +  }
>
>    // If we have template arguments, rebuild them, then rebuild the
>    // templateid expression.
> Index: test/SemaTemplate/instantiate-using-decl.cpp
> ===================================================================
> --- test/SemaTemplate/instantiate-using-decl.cpp
> +++ test/SemaTemplate/instantiate-using-decl.cpp
> @@ -104,3 +104,26 @@
>      x.f();
>    }
>  }
> +
> +namespace PR21923 {
> +struct A {
> +  int member;
> +  void method();
> +};
> +template <typename T>
> +struct B : public T {
> +  using T::member;
> +  using T::method;
> +  static void StaticFun() {
> +    (void)member; // expected-error {{invalid use of member 'member' in
> static member function}}
> +    (void)B<T>::member; // expected-error {{invalid use of member
> 'member' in static member function}}
> +    method(); // expected-error {{call to non-static member function
> without an object argument}}
> +  }
> +  void InstanceFun() {
> +    (void)member;
> +    (void)B<T>::member;
> +    method();
> +  }
> +};
> +template class B<A>; // expected-note 1 {{requested here}}
> +}
>
> EMAIL PREFERENCES
>   http://reviews.llvm.org/settings/panel/emailpreferences/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141216/0c1f3ec0/attachment.html>


More information about the cfe-commits mailing list