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>();