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

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