From: Jason Merrill Date: Wed, 27 Nov 2019 22:05:41 +0000 (-0500) Subject: PR c++/92206 - ICE with typedef to dependent alias. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=96cbfa7ff8a146febd6af9a53d10468a90706419;p=gcc.git PR c++/92206 - ICE with typedef to dependent alias. rsandifo's patch for 92206 demonstrated a problem with the existing checking for alias template specializations: they were returning false for a typedef to an alias template specialization. Which is sometimes what the caller wants, and sometimes not: Sometimes we're interested in whether the type was written as an alias template-id, and sometimes whether it represents one. The testcase illustrates a case that remained wrong with the earlier patch: if the typedef is itself an alias template specialization, we can't strip an underlying dependent alias. * pt.c (dependent_alias_template_spec_p) (alias_template_specialization_p): Add transparent_typedefs parameter. (iterative_hash_template_arg, any_template_parm_r) (primary_template_specialization_p, tsubst, dependent_type_p_r): Adjust. * decl.c (check_elaborated_type_specifier): Adjust. * error.c (dump_template_bindings, dump_aggr_type): Adjust. From-SVN: r278784 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c3e66d4e40f..0f26009b2be 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2019-11-12 Jason Merrill + + PR c++/92206 - ICE with typedef to dependent alias. + * pt.c (dependent_alias_template_spec_p) + (alias_template_specialization_p): Add transparent_typedefs + parameter. + (iterative_hash_template_arg, any_template_parm_r) + (primary_template_specialization_p, tsubst, dependent_type_p_r): + Adjust. + * decl.c (check_elaborated_type_specifier): Adjust. + * error.c (dump_template_bindings, dump_aggr_type): Adjust. + 2019-11-27 Andrew Sutton PR c++/92236 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4b4bc245d81..d8e12e99ba3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6938,8 +6938,9 @@ extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t); extern tree instantiate_non_dependent_or_null (tree); extern bool variable_template_specialization_p (tree); extern bool alias_type_or_template_p (tree); -extern bool alias_template_specialization_p (const_tree); -extern bool dependent_alias_template_spec_p (const_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 template_parm_object_p (const_tree); extern bool explicit_class_specialization_p (tree); extern bool push_tinst_level (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 26120720f07..7d5bc914d2d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -14548,7 +14548,7 @@ check_elaborated_type_specifier (enum tag_types tag_code, && !DECL_SELF_REFERENCE_P (decl) && tag_code != typename_type) { - if (alias_template_specialization_p (type)) + if (alias_template_specialization_p (type, nt_opaque)) error ("using alias template specialization %qT after %qs", type, tag_name (tag_code)); else diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 4261d3c4cc9..a15230a1f01 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -421,7 +421,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, static void dump_alias_template_specialization (cxx_pretty_printer *pp, tree t, int flags) { - gcc_assert (alias_template_specialization_p (t)); + gcc_assert (alias_template_specialization_p (t, nt_opaque)); tree decl = TYPE_NAME (t); if (!(flags & TFF_UNQUALIFIED_NAME)) @@ -454,7 +454,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) ? STF_USER_VISIBLE : 0); t = strip_typedefs (t, NULL, stf_flags); } - else if (alias_template_specialization_p (t)) + else if (alias_template_specialization_p (t, nt_opaque)) { dump_alias_template_specialization (pp, t, flags); return; @@ -711,7 +711,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) typdef = (!DECL_ARTIFICIAL (name) /* An alias specialization is not considered to be a typedef. */ - && !alias_template_specialization_p (t)); + && !alias_template_specialization_p (t, nt_opaque)); if ((typdef && ((flags & TFF_CHASE_TYPEDEF) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3eed27bb426..244eb7d4ff3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1882,7 +1882,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) switch (tclass) { case tcc_type: - if (alias_template_specialization_p (arg)) + if (tree ats = alias_template_specialization_p (arg, nt_transparent)) { // We want an alias specialization that survived strip_typedefs // to hash differently from its TYPE_CANONICAL, to avoid hash @@ -1891,7 +1891,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) // left alone, or untouched specializations because // coerce_template_parms returns the unconverted template // arguments if it sees incomplete argument packs. - tree ti = TYPE_ALIAS_TEMPLATE_INFO (arg); + tree ti = TYPE_ALIAS_TEMPLATE_INFO (ats); return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti)); } if (TYPE_CANONICAL (arg)) @@ -3575,7 +3575,7 @@ primary_template_specialization_p (const_tree t) return (CLASSTYPE_TEMPLATE_INFO (t) && CLASSTYPE_USE_TEMPLATE (t) && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))); - else if (alias_template_specialization_p (t)) + else if (alias_template_specialization_p (t, nt_transparent)) return true; return false; } @@ -6298,18 +6298,30 @@ alias_type_or_template_p (tree t) || DECL_ALIAS_TEMPLATE_P (t)); } -/* Return TRUE iff T is a specialization of an alias template. */ +/* If T is a specialization of an alias template, return it; otherwise return + NULL_TREE. If TRANSPARENT_TYPEDEFS is true, look through other aliases. */ -bool -alias_template_specialization_p (const_tree t) +tree +alias_template_specialization_p (const_tree t, + bool transparent_typedefs) { + if (!TYPE_P (t)) + return NULL_TREE; + /* It's an alias template specialization if it's an alias and its TYPE_NAME is a specialization of a primary template. */ - if (TYPE_ALIAS_P (t)) - if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t)) - return PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)); + if (typedef_variant_p (t)) + { + if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t)) + if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))) + return CONST_CAST_TREE (t); + if (transparent_typedefs) + return alias_template_specialization_p (DECL_ORIGINAL_TYPE + (TYPE_NAME (t)), + transparent_typedefs); + } - return false; + return NULL_TREE; } /* An alias template is complex from a SFINAE perspective if a template-id @@ -6354,24 +6366,30 @@ complex_alias_template_p (const_tree tmpl) return false; } -/* Return TRUE iff T is a specialization of a complex alias template with - dependent template-arguments. */ +/* If T is a specialization of a complex alias template with dependent + template-arguments, return it; otherwise return NULL_TREE. If T is a + typedef to such a specialization, return the specialization. */ -bool -dependent_alias_template_spec_p (const_tree t) +tree +dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs) { - if (!alias_template_specialization_p (t)) - return false; + if (!TYPE_P (t) || !typedef_variant_p (t)) + return NULL_TREE; tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t); - if (!TEMPLATE_DECL_COMPLEX_ALIAS_P (TI_TEMPLATE (tinfo))) - return false; + if (tinfo + && TEMPLATE_DECL_COMPLEX_ALIAS_P (TI_TEMPLATE (tinfo)) + && (any_dependent_template_arguments_p + (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo))))) + return CONST_CAST_TREE (t); - tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)); - if (!any_dependent_template_arguments_p (args)) - return false; + if (transparent_typedefs) + { + tree utype = DECL_ORIGINAL_TYPE (TYPE_NAME (t)); + return dependent_alias_template_spec_p (utype, transparent_typedefs); + } - return true; + return NULL_TREE; } /* Return the number of innermost template parameters in TMPL. */ @@ -10384,9 +10402,9 @@ any_template_parm_r (tree t, void *data) case UNION_TYPE: case ENUMERAL_TYPE: /* Search for template parameters in type aliases. */ - if (alias_template_specialization_p (t)) + if (tree ats = alias_template_specialization_p (t, nt_opaque)) { - tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t); + tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (ats); WALK_SUBTREE (TI_ARGS (tinfo)); } break; @@ -14896,7 +14914,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) { tree decl = TYPE_NAME (t); - if (alias_template_specialization_p (t)) + if (alias_template_specialization_p (t, nt_opaque)) { /* DECL represents an alias template and we want to instantiate it. */ @@ -25815,7 +25833,7 @@ dependent_type_p_r (tree type) /* An alias template specialization can be dependent even if the resulting type is not. */ - if (dependent_alias_template_spec_p (type)) + if (dependent_alias_template_spec_p (type, nt_transparent)) return true; /* -- a cv-qualified type where the cv-unqualified type is diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d125d60b270..f500ee61442 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1489,7 +1489,7 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) return t; if (!(flags & STF_STRIP_DEPENDENT) - && dependent_alias_template_spec_p (t)) + && dependent_alias_template_spec_p (t, nt_opaque)) /* DR 1558: However, if the template-id is dependent, subsequent template argument substitution still applies to the template-id. */ return t; @@ -1673,14 +1673,19 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) if ((flags & STF_USER_VISIBLE) && !user_facing_original_type_p (t)) return t; + /* If T is a non-template alias or typedef, we can assume that + instantiating its definition will hit any substitution failure, + so we don't need to retain it here as well. */ + if (!alias_template_specialization_p (t, nt_opaque)) + flags |= STF_STRIP_DEPENDENT; result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), - remove_attributes, - flags | STF_STRIP_DEPENDENT); + remove_attributes, flags); } else result = TYPE_MAIN_VARIANT (t); } gcc_assert (!typedef_variant_p (result) + || dependent_alias_template_spec_p (result, nt_opaque) || ((flags & STF_USER_VISIBLE) && !user_facing_original_type_p (result))); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 98c428db52e..a9b87ea8caf 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1463,10 +1463,13 @@ structural_comptypes (tree t1, tree t2, int strict) 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. */ - if (comparing_specializations - && (dependent_alias_template_spec_p (t1) - || dependent_alias_template_spec_p (t2))) - return false; + if (comparing_specializations) + { + tree dep1 = dependent_alias_template_spec_p (t1, nt_transparent); + tree dep2 = dependent_alias_template_spec_p (t2, nt_transparent); + if ((dep1 || dep2) && dep1 != dep2) + return false; + } /* If we get here, we know that from a target independent POV the types are the same. Make sure the target attributes are also diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C new file mode 100644 index 00000000000..4c86d4567ce --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } + +template struct A { }; +template using AA = A; // { dg-error "char" } +template using AAA = AA; + +template struct C { }; +template struct B { + C> a; +}; +B b; // { dg-message "" }