aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2024-07-25 19:05:19 -0400
committerPatrick Palka <ppalka@redhat.com>2024-07-25 19:05:19 -0400
commit523836716137d0f7f4088c85752a980f5f971b36 (patch)
treed23dc2a57c10495d0554d31d6eebe0e7a911adf7
parent9bcad238837e2100978cd839c343c488f72e1d4a (diff)
downloadgcc-523836716137d0f7f4088c85752a980f5f971b36.zip
gcc-523836716137d0f7f4088c85752a980f5f971b36.tar.gz
gcc-523836716137d0f7f4088c85752a980f5f971b36.tar.bz2
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 <jason@redhat.com>
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/pt.cc55
-rw-r--r--gcc/cp/tree.cc7
-rw-r--r--gcc/cp/typeck.cc17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C41
6 files changed, 106 insertions, 31 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7d50aac..238d786 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 e102e3e..39f7e8a 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 f2001ac..31ecbb1 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 8df8b87..f26b5b2 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 e0f0747..58436f9 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 0000000..151b848
--- /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>();