On Thu, 7 Jan 2021, Jason Merrill wrote:

> On 1/7/21 5:47 PM, Patrick Palka wrote:
> > On Thu, 7 Jan 2021, Jason Merrill wrote:
> > 
> > > On 1/6/21 1:19 PM, Patrick Palka wrote:
> > > > In the first testcase below, we incorrectly reject the use of the
> > > > protected non-static member A::var0 from C<int>::g() because
> > > > check_accessibility_of_qualified_id, at template parse time, determines
> > > > that the access doesn't go through 'this'.  (This happens because the
> > > > dependent base B<T> of C<T> doesn't have a binfo object, so it appears
> > > > to DERIVED_FROM_P that A is not an indirect base of C<T>.)  From there
> > > > we create the corresponding deferred access check, which we then
> > > > perform at instantiation time and which (unsurprisingly) fails.
> > > > 
> > > > The problem ultimately seems to be that we can't, in general, know
> > > > whether a use of a scoped non-static member goes through 'this' until
> > > > instantiation time, as the second testcase below demonstrates.  So this
> > > > patch makes check_accessibility_of_qualified_id punt in this situation.
> > > > 
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
> > > > commit?
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > >         PR c++/98515
> > > >         * semantics.c (check_accessibility_of_qualified_id): Punt if
> > > >         we're checking the access of a scoped non-static member at
> > > >         class template parse time.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > >         PR c++/98515
> > > >         * g++.dg/template/access32.C: New test.
> > > >         * g++.dg/template/access33.C: New test.
> > > > ---
> > > >    gcc/cp/semantics.c                       | 20 +++++++++++++++-----
> > > >    gcc/testsuite/g++.dg/template/access32.C |  8 ++++++++
> > > >    gcc/testsuite/g++.dg/template/access33.C |  9 +++++++++
> > > >    3 files changed, 32 insertions(+), 5 deletions(-)
> > > >    create mode 100644 gcc/testsuite/g++.dg/template/access32.C
> > > >    create mode 100644 gcc/testsuite/g++.dg/template/access33.C
> > > > 
> > > > diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> > > > index b448efe024a..f52b2e4d1e7 100644
> > > > --- a/gcc/cp/semantics.c
> > > > +++ b/gcc/cp/semantics.c
> > > > @@ -2107,14 +2107,24 @@ check_accessibility_of_qualified_id (tree decl,
> > > >          /* If the reference is to a non-static member of the
> > > >          current class, treat it as if it were referenced through
> > > >          `this'.  */
> > > > -      tree ct;
> > > >          if (DECL_NONSTATIC_MEMBER_P (decl)
> > > > -         && current_class_ptr
> > > > -         && DERIVED_FROM_P (scope, ct = current_nonlambda_class_type 
> > > > ()))
> > > > -       qualifying_type = ct;
> > > > +         && current_class_ptr)
> > > > +       {
> > > > +         if (dependent_type_p (TREE_TYPE (current_class_ptr)))
> > > 
> > > This should also look at current_nonlambda_class_type.
> > 
> > Ah, ack.  But it seems to me we really only need to be checking
> > dependence of current_nonlambda_class_type here.
> 
> Yes, that's what I meant, sorry about the ambiguous use of "also".  :)

Oops, I see what you had meant now, sorry about the confusion :)

> 
> >  IIUC, dependence of
> > these two types should coincide except in the case where we're inside a
> > generic lambda within a non-template class (in which case
> > current_class_ptr will dependent and current_nonlambda_class_type won't).
> > But in this case we have enough information to be able to resolve the
> > access check at parse time, I think (and so we shouldn't punt).
> > 
> > The below patch, which seems to pass 'make check-c++', checks the
> > dependence of current_nonlambda_class_type instead of that of
> > current_class_ptr.  Does this approach seem right?
> 
> OK.

Thanks.

> 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: Fix access checking of scoped non-static member
> >   [PR98515]
> > 
> > In the first testcase below, we incorrectly reject the use of the
> > protected non-static member A::var0 from C<int>::g() because
> > check_accessibility_of_qualified_id, at template parse time, determines
> > that the access doesn't go through 'this'.  (This happens because the
> > dependent base B<T> of C<T> doesn't have a binfo object, so it appears
> > to DERIVED_FROM_P that A is not an indirect base of C<T>.)  From there
> > we create the corresponding deferred access check, which we then
> > perform at instantiation time and which (unsurprisingly) fails.
> > 
> > The problem ultimately seems to be that we can't in general determine
> > whether a use of a scoped non-static member goes through 'this' until
> > instantiation time, as the second testcase below illustrates.  So this
> > patch makes check_accessibility_of_qualified_id punt in such situations
> > to avoid creating a bogus deferred access check.
> > 
> > gcc/cp/ChangeLog:
> > 
> >     PR c++/98515
> >     * semantics.c (check_accessibility_of_qualified_id): Punt if
> >     we're checking access of a scoped non-static member inside a
> >     class template.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     PR c++/98515
> >     * g++.dg/template/access32.C: New test.
> >     * g++.dg/template/access33.C: New test.
> > ---
> >   gcc/cp/semantics.c                       | 22 +++++++++++++++++-----
> >   gcc/testsuite/g++.dg/template/access32.C |  8 ++++++++
> >   gcc/testsuite/g++.dg/template/access33.C |  9 +++++++++
> >   3 files changed, 34 insertions(+), 5 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/access32.C
> >   create mode 100644 gcc/testsuite/g++.dg/template/access33.C
> > 
> > diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> > index b448efe024a..51f7c114b03 100644
> > --- a/gcc/cp/semantics.c
> > +++ b/gcc/cp/semantics.c
> > @@ -2107,14 +2107,26 @@ check_accessibility_of_qualified_id (tree decl,
> >         /* If the reference is to a non-static member of the
> >      current class, treat it as if it were referenced through
> >      `this'.  */
> > -      tree ct;
> >         if (DECL_NONSTATIC_MEMBER_P (decl)
> > -     && current_class_ptr
> > -     && DERIVED_FROM_P (scope, ct = current_nonlambda_class_type ()))
> > -   qualifying_type = ct;
> > +     && current_class_ptr)
> > +   {
> > +     if (tree current = current_nonlambda_class_type ())
> > +       {
> > +         if (dependent_type_p (current))
> > +         /* In general we can't know whether this access goes through
> > +            `this' until instantiation time.  Punt now, or else we might
> > +            create a deferred access check that's not relative to 'this'
> > +            when it ought to be.  We'll check this access again after
> > +            substitution, e.g. from tsubst_qualified_id.  */
> > +           return true;
> > +
> > +         if (DERIVED_FROM_P (scope, current))
> > +           qualifying_type = current;
> > +       }
> > +   }
> >         /* Otherwise, use the type indicated by the
> >      nested-name-specifier.  */
> > -      else
> > +      if (!qualifying_type)
> >     qualifying_type = nested_name_specifier;
> >       }
> >     else
> > diff --git a/gcc/testsuite/g++.dg/template/access32.C
> > b/gcc/testsuite/g++.dg/template/access32.C
> > new file mode 100644
> > index 00000000000..08faa9f0f97
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/access32.C
> > @@ -0,0 +1,8 @@
> > +// PR c++/98515
> > +// { dg-do compile }
> > +
> > +struct A { protected: int var0; };
> > +template <class> struct B : public A { };
> > +template <class T> struct C : public B<T> { void g(); };
> > +template <class T> void C<T>::g() { A::var0++; }
> > +template class C<int>;
> > diff --git a/gcc/testsuite/g++.dg/template/access33.C
> > b/gcc/testsuite/g++.dg/template/access33.C
> > new file mode 100644
> > index 00000000000..9fb9b9a1236
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/access33.C
> > @@ -0,0 +1,9 @@
> > +// PR c++/98515
> > +// { dg-do compile }
> > +
> > +struct A { protected: int var0; };
> > +template <class> struct B : public A { };
> > +template <class T> struct C : public B<T> { void g(); };
> > +template <class T> void C<T>::g() { A::var0++; } // { dg-error
> > "protected|invalid" }
> > +template <> struct B<char> { };
> > +template class C<char>;
> > 
> 
> 

Reply via email to