+2019-11-12 Jason Merrill <jason@redhat.com>
+
+ 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 <asutton@lock3software.com>
PR c++/92236
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);
&& !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
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))
? 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;
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)
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
// 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))
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;
}
|| 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
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. */
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;
{
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. */
/* 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
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;
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)));
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
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+template <typename T> struct A { };
+template <typename T, int = sizeof(typename T::type)> using AA = A<T>; // { dg-error "char" }
+template <typename T> using AAA = AA<T>;
+
+template <class T> struct C { };
+template <class T> struct B {
+ C<AAA<T>> a;
+};
+B<char> b; // { dg-message "" }