On Fri, 19 Jul 2024, Patrick Palka wrote:

> On Thu, 18 Jul 2024, Jason Merrill wrote:
> 
> > On 7/18/24 12:45 PM, Patrick Palka wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does thi look
> > > OK for trunk/14?
> > > 
> > > -- >8 --
> > > 
> > > As a followup of r15-2047-g7954bb4fcb6fa8, we also need to consider
> > > dependent attributes when recursing into a non-template alias that names
> > > a dependent alias template specialization (and so STF_STRIP_DEPENDENT
> > > is set), otherwise in the first testcase below we undesirably strip B
> > > all the way to T instead of to A<T>.
> > > 
> > > We also need to move the typedef recursion case of strip_typedefs up to
> > > get checked before the compound type recursion cases.  Otherwise for C
> > > below (which ultimately aliases T*) we end up stripping it to T* instead
> > > of to A<T*> because the POINTER_TYPE recursion dominates the typedef
> > > recursion.  It also means we issue an unexpected extra error in the
> > > third testcase below.
> > > 
> > > Ideally we would also want to consider dependent attributes on
> > > non-template aliases, so that we accept the second testcase below, but
> > > making that work correctly would require broader changes to e.g.
> > > spec_hasher which currently assumes all non-template aliases are
> > > stripped and hence it'd conflate the dependent specializations A<T>
> > > and A<B> even if we didn't strip B.
> > 
> > Wouldn't that just be a matter of changing structural_comptypes to consider
> > dependent attributes as well as dependent specializations?
> 
> Pretty much, it seems.  ISTM we should check dependent attributes even
> when !comparing_dependent_aliases since they affect type identity rather
> than just SFINAE behavior.
> 
> > 
> > Or better, adding attributes to dependent_alias_template_spec_p (and 
> > changing
> > its name)?  It seems like other callers would also benefit from that change.
> 
> I ended up adding a new predicate opaque_alias_p separate from
> dependent_alias_template_spec_p since ISTM we need to call it from
> there and from alias_template_specialization_p to avoid looking through
> such aliases.
> 
> So opaque_alias_p checks for type identity of an alias, whereas
> dependent_alias_template_spec_p more broadly checks for SFINAE identity.
> 
> Something like the following (as an incremental patch on top of the
> previous one, to consider separately for backportings since it's riskier):
> 

IMHO extending dependent attr support to non-template aliases doesn't
seem that important though because it can always(?) be worked around by
introducing an intermediate alias template, e.g. instead of

  using B [[gnu::vector_size(16)]] = T;

one can do

  template<class T> using A [[gnu::vector_size(16)]] = T;
  using B = A<T>;

So making sure depedent attrs work on alias templates should be
sufficient in practice AFAICT.

> -- >8 --
> 
> Subject: [PATCH 2/1] c++: non-template alias with dependent attributes 
> [PR115897]
> 
>       PR c++/115897
> 
> gcc/cp/ChangeLog:
> 
>       * cp-tree.h (opaque_alias_p): Declare.
>       * decl.cc (start_decl): Use structural equality for an
>       opaque alias.
>       * pt.cc (opaque_alias_p): Define.
>       (alias_template_specialization_p): Don't look through an
>       opaque alias.
>       (complex_alias_template_p): Use opaque_alias_p instead of
>       any_dependent_template_arguments_p directly.
>       (dependent_alias_template_spec_p): Don't look through an
>       opaque alias.
>       (get_underlying_template): Use opaque_alias_p instead of
>       any_dependent_template_arguments_p.
>       * tree.cc (strip_typedefs): Don't strip an opaque alias.
>       * typeck.cc (structural_comptypes): Compare declaration
>       attributes for an opaque alias.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp0x/alias-decl-79.C: Remove xfails.
> ---
>  gcc/cp/cp-tree.h                           |  1 +
>  gcc/cp/decl.cc                             |  3 ++
>  gcc/cp/pt.cc                               | 23 ++++++++----
>  gcc/cp/tree.cc                             |  7 ++--
>  gcc/cp/typeck.cc                           | 42 ++++++++++++++--------
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C | 16 ++++-----
>  6 files changed, 61 insertions(+), 31 deletions(-)
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index c6f102564ce..f2a64b63133 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7622,6 +7622,7 @@ extern tree instantiate_non_dependent_or_null   (tree);
>  extern bool variable_template_specialization_p  (tree);
>  extern bool alias_type_or_template_p            (tree);
>  enum { nt_opaque = false, nt_transparent = true };
> +extern bool opaque_alias_p                   (const_tree);
>  extern tree alias_template_specialization_p     (const_tree, bool);
>  extern tree dependent_alias_template_spec_p     (const_tree, bool);
>  extern tree get_template_parm_object         (tree expr, tree mangle);
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 66e8a973cce..755701fd8aa 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -6144,6 +6144,9 @@ start_decl (const cp_declarator *declarator,
>    if (decl == error_mark_node)
>      return error_mark_node;
>  
> +  if (opaque_alias_p (TREE_TYPE (decl)))
> +    SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (decl));
> +
>    if (VAR_P (decl)
>        && DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) && !was_public
>        && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 0620c8c023a..4d4a5cef92c 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -6508,6 +6508,19 @@ alias_type_or_template_p (tree t)
>         || DECL_ALIAS_TEMPLATE_P (t));
>  }
>  
> +/* Return true if substituting into T would yield a different type than
> +   substituting into its expansion.  */
> +
> +bool
> +opaque_alias_p (const_tree t)
> +{
> +  return (TYPE_P (t)
> +       && typedef_variant_p (t)
> +       && uses_template_parms (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
> +       && any_dependent_type_attributes_p (DECL_ATTRIBUTES
> +                                           (TYPE_NAME (t))));
> +}
> +
>  /* If T is a specialization of an alias template, return it; otherwise return
>     NULL_TREE.  If TRANSPARENT_TYPEDEFS is true, look through other aliases.  
> */
>  
> @@ -6525,7 +6538,7 @@ alias_template_specialization_p (const_tree t,
>        if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t))
>       if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)))
>         return CONST_CAST_TREE (t);
> -      if (transparent_typedefs)
> +      if (transparent_typedefs && !opaque_alias_p (t))
>       return alias_template_specialization_p (DECL_ORIGINAL_TYPE
>                                               (TYPE_NAME (t)),
>                                               transparent_typedefs);
> @@ -6630,8 +6643,7 @@ complex_alias_template_p (const_tree tmpl, tree 
> *seen_out)
>      return true;
>  
>    /* An alias with dependent type attributes is complex.  */
> -  if (any_dependent_type_attributes_p (DECL_ATTRIBUTES
> -                                    (DECL_TEMPLATE_RESULT (tmpl))))
> +  if (opaque_alias_p (TREE_TYPE (tmpl)))
>      return true;
>  
>    if (!complex_alias_tmpl_info)
> @@ -6718,7 +6730,7 @@ dependent_alias_template_spec_p (const_tree t, bool 
> transparent_typedefs)
>       }
>      }
>  
> -  if (transparent_typedefs)
> +  if (transparent_typedefs && !opaque_alias_p (t))
>      {
>        tree utype = DECL_ORIGINAL_TYPE (TYPE_NAME (t));
>        return dependent_alias_template_spec_p (utype, transparent_typedefs);
> @@ -6787,8 +6799,7 @@ get_underlying_template (tree tmpl)
>       break;
>  
>        /* If TMPL adds dependent type attributes, it isn't equivalent.  */
> -      if (any_dependent_type_attributes_p (DECL_ATTRIBUTES
> -                                        (DECL_TEMPLATE_RESULT (tmpl))))
> +      if (opaque_alias_p (TREE_TYPE (tmpl)))
>       break;
>  
>        /* Alias is equivalent.  Strip it and repeat.  */
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index 0e6be8de59a..3a2283b4d65 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -1613,12 +1613,13 @@ strip_typedefs (tree t, bool *remove_attributes /* = 
> NULL */,
>         && !user_facing_original_type_p (t))
>       return t;
>  
> +      if (opaque_alias_p (t))
> +     return t;
> +
>        if (alias_template_specialization_p (t, nt_opaque))
>       {
>         if (dependent_alias_template_spec_p (t, nt_opaque)
> -           && (!(flags & STF_STRIP_DEPENDENT)
> -               || any_dependent_type_attributes_p (DECL_ATTRIBUTES
> -                                                   (TYPE_NAME (t)))))
> +           && !(flags & STF_STRIP_DEPENDENT))
>           /* DR 1558: However, if the template-id is dependent, subsequent
>              template argument substitution still applies to the template-id. 
>  */
>           return t;
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 15e5577f670..e966bcd9d03 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -1658,20 +1658,34 @@ structural_comptypes (tree t1, tree t2, int strict)
>      return false;
>  
>   check_alias:
> -  if (comparing_dependent_aliases)
> -    {
> -      /* Don't treat an alias template specialization with dependent
> -      arguments as equivalent to its underlying type when used as a
> -      template argument; we need them to be distinct so that we
> -      substitute into the specialization arguments at instantiation
> -      time.  And aliases can't be equivalent without being ==, so
> -      we don't need to look any deeper.  */
> -      ++processing_template_decl;
> -      tree dep1 = dependent_alias_template_spec_p (t1, nt_transparent);
> -      tree dep2 = dependent_alias_template_spec_p (t2, nt_transparent);
> -      --processing_template_decl;
> -      if ((dep1 || dep2) && dep1 != dep2)
> -     return false;
> +  if (typedef_variant_p (t1) || typedef_variant_p (t2))
> +    {
> +      tree o1 = opaque_alias_p (t1) ? t1 : NULL_TREE;
> +      tree o2 = opaque_alias_p (t2) ? t2 : NULL_TREE;
> +      if (o1 || o2)
> +     {
> +       if (!o1 || !o2)
> +         return false;
> +       if (!comp_type_attributes (DECL_ATTRIBUTES (TYPE_NAME (o1)),
> +                                  DECL_ATTRIBUTES (TYPE_NAME (o2))))
> +         return false;
> +     }
> +
> +      if (comparing_dependent_aliases)
> +     {
> +       /* Don't treat an alias template specialization with dependent
> +          arguments as equivalent to its underlying type when used as a
> +          template argument; we need them to be distinct so that we
> +          substitute into the specialization arguments at instantiation
> +          time.  And aliases can't be equivalent without being ==, so
> +          we don't need to look any deeper.  */
> +       ++processing_template_decl;
> +       tree dep1 = dependent_alias_template_spec_p (t1, nt_transparent);
> +       tree dep2 = dependent_alias_template_spec_p (t2, nt_transparent);
> +       --processing_template_decl;
> +       if ((dep1 || dep2) && dep1 != dep2)
> +         return false;
> +     }
>      }
>  
>    return true;
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C 
> b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
> index e0f07475cc1..58436f907ef 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
> @@ -14,22 +14,22 @@ template<class T> struct A;
>  template<class T>
>  void f() {
>    using B [[gnu::vector_size(16)]] = T;
> -  static_assert(!is_same<T, B>::value, "");        // { dg-bogus "" "" { 
> xfail *-*-* } }
> -  static_assert(!is_same<A<T>, A<B>>::value, "");  // { dg-bogus "" "" { 
> xfail *-*-* } }
> +  static_assert(!is_same<T, B>::value, "");
> +  static_assert(!is_same<A<T>, A<B>>::value, "");
>  #if __cpp_variable_templates
> -  static_assert(!is_same_v<T, B>, "");             // { dg-bogus "" "" { 
> xfail c++14 } }
> -  static_assert(!is_same_v<A<T>, A<B>>, "");       // { dg-bogus "" "" { 
> xfail c++14 } }
> +  static_assert(!is_same_v<T, B>, "");
> +  static_assert(!is_same_v<A<T>, A<B>>, "");
>  #endif
>  };
>  
>  template<class T>
>  void g() {
>    using C [[gnu::vector_size(16)]] = T*;
> -  static_assert(!is_same<T*, C>::value, "");       // { dg-bogus "" "" { 
> xfail *-*-* } }
> -  static_assert(!is_same<A<T*>, A<C>>::value, ""); // { dg-bogus "" "" { 
> xfail *-*-* } }
> +  static_assert(!is_same<T*, C>::value, "");
> +  static_assert(!is_same<A<T*>, A<C>>::value, "");
>  #if __cpp_variable_templates
> -  static_assert(!is_same_v<T*, C>, "");            // { dg-bogus "" "" { 
> xfail c++14 } }
> -  static_assert(!is_same_v<A<T*>, A<C>>, "");      // { dg-bogus "" "" { 
> xfail c++14 } }
> +  static_assert(!is_same_v<T*, C>, "");
> +  static_assert(!is_same_v<A<T*>, A<C>>, "");
>  #endif
>  };
>  
> -- 
> 2.46.0.rc0.106.g1c4a234a1c
> 
> 

Reply via email to