https://gcc.gnu.org/g:523836716137d0f7f4088c85752a980f5f971b36

commit r15-2331-g523836716137d0f7f4088c85752a980f5f971b36
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu Jul 25 19:05:19 2024 -0400

    c++: non-template alias with dependent attributes [PR115897]
    
    This patch generalizes our support for dependent attributes on alias
    templates to also support them on non-template aliases.  The main
    addition is a new predicate dependent_opaque_alias_p controlling whether
    we can treat an alias (template or non-template) as type-equivalent to
    its expansion.
    
            PR c++/115897
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (dependent_opaque_alias_p): Declare.
            * pt.cc (push_template_decl): Manually mark a dependent opaque
            alias or dependent alias template specialization as dependent,
            and use structural equality for them.
            (dependent_opaque_alias_p): Define.
            (alias_template_specialization_p): Don't look through an
            opaque alias.
            (complex_alias_template_p): Use dependent_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 dependent_opaque_alias_p instead of
            any_dependent_template_arguments_p.
            (instantiate_alias_template): Mention same logic in
            push_template_decl.
            (dependent_type_p_r): Remove dependent_alias_template_spec_p check.
            (any_template_arguments_need_structural_equality_p): Return true
            for a dependent opaque alias.
            (alias_ctad_tweaks): Use template_args_equal instead of same_type_p
            followed by dependent_alias_template_spec_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.
            * g++.dg/cpp0x/alias-decl-79a.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/cp-tree.h                            |  1 +
 gcc/cp/pt.cc                                | 55 ++++++++++++++++++++---------
 gcc/cp/tree.cc                              |  7 ++--
 gcc/cp/typeck.cc                            | 17 ++++++---
 gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C  | 16 ++++-----
 gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C | 41 +++++++++++++++++++++
 6 files changed, 106 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7d50aac4b6b8..238d786b0674 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7621,6 +7621,7 @@ extern bool alias_type_or_template_p            (tree);
 enum { nt_opaque = false, nt_transparent = true };
 extern tree alias_template_specialization_p     (const_tree, bool);
 extern tree dependent_alias_template_spec_p     (const_tree, bool);
+extern bool dependent_opaque_alias_p            (const_tree);
 extern tree get_template_parm_object           (tree expr, tree mangle);
 extern tree tparm_object_argument              (tree);
 extern bool explicit_class_specialization_p     (tree);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e102e3ea490f..39f7e8a4e688 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6271,6 +6271,18 @@ push_template_decl (tree decl, bool is_friend)
        }
     }
 
+  if (is_typedef_decl (decl)
+      && (dependent_opaque_alias_p (TREE_TYPE (decl))
+         || dependent_alias_template_spec_p (TREE_TYPE (decl), nt_opaque)))
+    {
+      /* Manually mark such aliases as dependent so that dependent_type_p_r
+        doesn't have to handle them.  */
+      TYPE_DEPENDENT_P_VALID (TREE_TYPE (decl)) = true;
+      TYPE_DEPENDENT_P (TREE_TYPE (decl)) = true;
+      /* The identity of such aliases is hairy; see structural_comptypes.  */
+      SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (decl));
+    }
+
   if (flag_implicit_templates
       && !is_friend
       && TREE_PUBLIC (decl)
@@ -6530,7 +6542,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 && !dependent_opaque_alias_p (t))
        return alias_template_specialization_p (DECL_ORIGINAL_TYPE
                                                (TYPE_NAME (t)),
                                                transparent_typedefs);
@@ -6635,8 +6647,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 (dependent_opaque_alias_p (TREE_TYPE (tmpl)))
     return true;
 
   if (!complex_alias_tmpl_info)
@@ -6687,7 +6698,10 @@ complex_alias_template_p (const_tree tmpl, tree 
*seen_out)
 /* If T is a specialization of a complex alias template with a dependent
    argument for an unused template parameter, return it; otherwise return
    NULL_TREE.  If T is a typedef to such a specialization, return the
-   specialization.  */
+   specialization.  This predicate is usually checked alongside
+   dependent_opaque_alias_p.  Whereas dependent_opaque_alias_p checks
+   type equivalence of an alias vs its expansion, this predicate more
+   broadly checks SFINAE equivalence.  */
 
 tree
 dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs)
@@ -6723,7 +6737,7 @@ dependent_alias_template_spec_p (const_tree t, bool 
transparent_typedefs)
        }
     }
 
-  if (transparent_typedefs)
+  if (transparent_typedefs && !dependent_opaque_alias_p (t))
     {
       tree utype = DECL_ORIGINAL_TYPE (TYPE_NAME (t));
       return dependent_alias_template_spec_p (utype, transparent_typedefs);
@@ -6732,6 +6746,19 @@ dependent_alias_template_spec_p (const_tree t, bool 
transparent_typedefs)
   return NULL_TREE;
 }
 
+/* Return true if substituting into T would yield a different type than
+   substituting into its expansion.  This predicate is usually checked
+   alongside dependent_alias_template_spec_p.  */
+
+bool
+dependent_opaque_alias_p (const_tree t)
+{
+  return (TYPE_P (t)
+         && typedef_variant_p (t)
+         && any_dependent_type_attributes_p (DECL_ATTRIBUTES
+                                             (TYPE_NAME (t))));
+}
+
 /* Return the number of innermost template parameters in TMPL.  */
 
 static int
@@ -6792,8 +6819,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 (dependent_opaque_alias_p (TREE_TYPE (tmpl)))
        break;
 
       /* Alias is equivalent.  Strip it and repeat.  */
@@ -22278,6 +22304,7 @@ instantiate_alias_template (tree tmpl, tree args, 
tsubst_flags_t complain)
 
   if (tree d = dependent_alias_template_spec_p (TREE_TYPE (r), nt_opaque))
     {
+      /* Note this is also done at parse time from push_template_decl.  */
       /* An alias template specialization can be dependent
         even if its underlying type is not.  */
       TYPE_DEPENDENT_P (d) = true;
@@ -27906,11 +27933,6 @@ dependent_type_p_r (tree type)
   if (TREE_CODE (type) == TYPENAME_TYPE)
     return true;
 
-  /* An alias template specialization can be dependent even if the
-     resulting type is not.  */
-  if (dependent_alias_template_spec_p (type, nt_transparent))
-    return true;
-
   /* -- a cv-qualified type where the cv-unqualified type is
        dependent.
      No code is necessary for this bullet; the code below handles
@@ -29018,7 +29040,8 @@ any_template_arguments_need_structural_equality_p (tree 
args)
                return true;
              else if (TYPE_P (arg)
                       && TYPE_STRUCTURAL_EQUALITY_P (arg)
-                      && dependent_alias_template_spec_p (arg, nt_transparent))
+                      && (dependent_alias_template_spec_p (arg, nt_opaque)
+                          || dependent_opaque_alias_p (arg)))
                /* Require structural equality for specializations written
                   in terms of a dependent alias template specialization.  */
                return true;
@@ -30418,9 +30441,9 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
             A with the same template arguments.  */
          ret = TREE_TYPE (TREE_TYPE (fprime));
          if (ctad_kind == alias
-             && (!same_type_p (atype, ret)
-                 /* FIXME this should mean they don't compare as equivalent. */
-                 || dependent_alias_template_spec_p (atype, nt_opaque)))
+             /* Use template_args_equal instead of same_type_p to get the
+                comparing_dependent_aliases behavior.  */
+             && !template_args_equal (atype, ret))
            {
              tree same = finish_trait_expr (loc, CPTK_IS_DEDUCIBLE, tmpl, ret);
              ci = append_constraint (ci, same);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f2001ace6db0..31ecbb1ac79b 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 (dependent_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 8df8b871676b..f26b5b2a1f40 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -1658,8 +1658,17 @@ structural_comptypes (tree t1, tree t2, int strict)
     return false;
 
  check_alias:
-  if (comparing_dependent_aliases)
-    {
+  if (comparing_dependent_aliases
+      && (typedef_variant_p (t1) || typedef_variant_p (t2)))
+    {
+      tree dep1 = dependent_opaque_alias_p (t1) ? t1 : NULL_TREE;
+      tree dep2 = dependent_opaque_alias_p (t2) ? t2 : NULL_TREE;
+      if ((dep1 || dep2)
+         && (!(dep1 && dep2)
+             || !comp_type_attributes (DECL_ATTRIBUTES (TYPE_NAME (dep1)),
+                                       DECL_ATTRIBUTES (TYPE_NAME (dep2)))))
+       return false;
+
       /* 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
@@ -1667,8 +1676,8 @@ structural_comptypes (tree t1, tree t2, int strict)
         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);
+      dep1 = dependent_alias_template_spec_p (t1, nt_transparent);
+      dep2 = dependent_alias_template_spec_p (t2, nt_transparent);
       --processing_template_decl;
       if ((dep1 || dep2) && dep1 != dep2)
        return false;
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
index e0f07475cc12..58436f907efe 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
 };
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C
new file mode 100644
index 000000000000..151b8487e1f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C
@@ -0,0 +1,41 @@
+// A version of alias-decl-79.C where defining-type-id of B and C
+// are not dependent and instead their vector_size attribute is.
+// PR c++/115897
+// { dg-do compile { target c++11 } }
+
+template<class T, class U>
+struct is_same { static constexpr bool value = __is_same(T, U); };
+
+#if __cpp_variable_templates
+template<class T, class U>
+constexpr bool is_same_v = __is_same(T, U);
+#endif
+
+template<class T> struct A;
+
+template<int N>
+void f() {
+  using T = float;
+  using B [[gnu::vector_size(N * sizeof(float))]] = T;
+  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>, "");
+  static_assert(!is_same_v<A<T>, A<B>>, "");
+#endif
+};
+
+template<int N>
+void g() {
+  using T = float*;
+  using C [[gnu::vector_size(N * sizeof(float*))]] = T;
+  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>, "");
+  static_assert(!is_same_v<A<T*>, A<C>>, "");
+#endif
+};
+
+template void f<4>();
+template void g<4>();

Reply via email to