-- >8 --
Subject: [PATCH 2/1] c++: non-template alias with dependent attributes
[PR115897]
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.
* pt.cc (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): Add comment mentioning similar
behavior in push_template_decl above.
(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 argument.
(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.
---
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(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-79a.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7d50aac4b6b..0de181ae84d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7619,6 +7619,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 dependent_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/pt.cc b/gcc/cp/pt.cc
index e102e3ea490..4da3bb49ccf 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 check these predicates. */
+ 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)
@@ -6513,6 +6525,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. Checking this predicate is usually
+ done in tandem with 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))));
+}
+
/* If T is a specialization of an alias template, return it; otherwise return
NULL_TREE. If TRANSPARENT_TYPEDEFS is true, look through other aliases.
*/
@@ -6530,7 +6555,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 +6660,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 +6711,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. Checking this predicate is usually done in tandem
+ with 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 +6750,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);
@@ -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 f2001ace6db..31ecbb1ac79 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 8df8b871676..f26b5b2a1f4 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 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
};
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 00000000000..151b8487e1f
--- /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>();