On Fri, 25 Jun 2021, Jason Merrill wrote:

> On 6/25/21 11:03 AM, Patrick Palka wrote:
> > Here, when determining whether the partial specialization matches the
> > specialization has_set_attr_method<Child>, we do so from the scope of
> > where the template-id appears rather than from the scope of the
> > specialization, and this causes us to select the partial specialization
> > (since Child::type is accessible from Parent).  When we later
> > instantiate this partial specialization, we've entered the scope of the
> > specialization and so substitution into e.g. the DECL_CONTEXT for
> > 'value' yields access errors for Child::type since the friend
> > declaration no longer applies.
> > 
> > It seems the appropriate access scope from which to perform partial
> > specialization matching is the specialization itself (similar to how
> > we check access of base-clauses), which is what this patch implements.
> 
> > There's implementation divergence however: Clang accepts both testcases
> > below whereas MSVC and ICC reject both (indicating that Clang performs
> > partial spec matching from the scope of the specialization and MSVC/ICC
> > performs it from whatever scope the template-id appears).
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> >     PR c++/96204
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * pt.c (instantiate_class_template_1): Enter the scope of the
> >     type before calling most_specialized_partial_spec.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/template/access40.C: New test.
> >     * g++.dg/template/access40a.C: New test.
> > ---
> >   gcc/cp/pt.c                               |  6 ++++-
> >   gcc/testsuite/g++.dg/template/access40.C  | 30 +++++++++++++++++++++++
> >   gcc/testsuite/g++.dg/template/access40a.C | 30 +++++++++++++++++++++++
> >   3 files changed, 65 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/access40.C
> >   create mode 100644 gcc/testsuite/g++.dg/template/access40a.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index f4e0abe5c1e..5107bfbf9d1 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -11774,8 +11774,12 @@ instantiate_class_template_1 (tree type)
> >     deferring_access_check_sentinel acs (dk_no_deferred);
> >       /* Determine what specialization of the original template to
> > -     instantiate.  */
> > +     instantiate; do this relative to the scope of the type.  */
> > +  push_access_scope (TYPE_NAME (type));
> > +  pushclass (type);
> 
> How about replacing these two calls with push_nested_class (type), like we use
> later in the function?

That works nicely.  Would the patch be OK with that change?
Bootstrapped and regtested on x86_64-pc-linux-gnu.

> 
> >     t = most_specialized_partial_spec (type, tf_warning_or_error);
> > +  popclass ();
> > +  pop_access_scope (TYPE_NAME (type));
> >     if (t == error_mark_node)
> >       return error_mark_node;
> >     else if (t)
> > diff --git a/gcc/testsuite/g++.dg/template/access40.C
> > b/gcc/testsuite/g++.dg/template/access40.C
> > new file mode 100644
> > index 00000000000..e0d30779377
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/access40.C
> > @@ -0,0 +1,30 @@
> > +// PR c++/96204
> > +
> > +template<bool> struct bool_constant;
> > +
> > +template<class, class = void>
> > +struct has_type_member {
> > +  static const bool value = false;
> > +};
> > +
> > +template<class T>
> > +struct has_type_member<T, typename T::type> {
> > +  static const bool value = true;
> > +};
> > +
> > +struct Parent;
> > +
> > +struct Child {
> > +private:
> > +  friend struct Parent;
> > +  typedef void type;
> > +};
> > +
> > +struct Parent {
> > +  static void f() {
> > +    // The partial specialization of has_type_member does not match
> > +    // despite Child::type being accessible from the current scope.
> > +    typedef bool_constant<has_type_member<Child>::value> type;
> > +    typedef bool_constant<false> type;
> > +  }
> > +};
> > diff --git a/gcc/testsuite/g++.dg/template/access40a.C
> > b/gcc/testsuite/g++.dg/template/access40a.C
> > new file mode 100644
> > index 00000000000..85138c9e570
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/access40a.C
> > @@ -0,0 +1,30 @@
> > +// PR c++/96204
> > +
> > +template<bool> struct bool_constant;
> > +
> > +template<class, class = void>
> > +struct has_type_member {
> > +  static const bool value = false;
> > +};
> > +
> > +template<class T>
> > +struct has_type_member<T, typename T::type> {
> > +  static const bool value = true;
> > +};
> > +
> > +struct Parent;
> > +
> > +struct Child {
> > +private:
> > +  friend struct has_type_member<Child>;
> > +  typedef void type;
> > +};
> > +
> > +struct Parent {
> > +  static void f() {
> > +    // The partial specialization matches because Child::type is
> > +    // accessible from has_type_member<Child>.
> > +    typedef bool_constant<has_type_member<Child>::value> type;
> > +    typedef bool_constant<true> type;
> > +  }
> > +};
> > 
> 
> 

Reply via email to