Hi,
in this relatively serious ICE on invalid regression (we don't emit any
message before ICEing) make_typename_type, called by strip_typedefs,
returns error_mark_node which then isn't handled by typedef_variant_p.
Indeed, Jakub noticed that the same in principle can happen when
strip_typedefs calls finish_decltype_type. make_typename_type is passed
tf_none therefore cannot emit the diagnostic we want before the ICE
anyway, thus it seems to me that we also have one of those well known
issues about not propagating a tusbst_flags_t flag:
canonicalize_type_argument (and canonicalize_expr_argument) get a
tusbst_flags_t but doesn't propagate it to strip_typedefs (and
strip_typedefs_expr).
Implementing the straightforward set of changes, consistently for
strip_typedefs, strip_typedefs_expr and the related functions plus
checking the return values of make_typename_type and
finish_decltype_type for error_mark_node (only make_typename_type would
be enough for the testcase at issue) appears to solve the problem
without introducing regressions. Does that make sense?
Thanks,
Paolo.
/////////////////////////////
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 244803)
+++ cp/cp-tree.h (working copy)
@@ -6597,8 +6597,10 @@ extern bool class_tmpl_impl_spec_p
(const_tree);
extern int zero_init_p (const_tree);
extern bool check_abi_tag_redeclaration (const_tree,
const_tree, const_tree);
extern bool check_abi_tag_args (tree, tree);
-extern tree strip_typedefs (tree, bool * = NULL);
-extern tree strip_typedefs_expr (tree, bool * = NULL);
+extern tree strip_typedefs (tree, tsubst_flags_t,
+ bool * = NULL);
+extern tree strip_typedefs_expr (tree, tsubst_flags_t,
+ bool * = NULL);
extern tree copy_binfo (tree, tree, tree,
tree *, int);
extern int member_p (const_tree);
Index: cp/error.c
===================================================================
--- cp/error.c (revision 244803)
+++ cp/error.c (working copy)
@@ -354,7 +354,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tr
pop_deferring_access_checks ();
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
pp_simple_type_specifier doesn't know about it. */
- t = strip_typedefs (t);
+ t = strip_typedefs (t, tf_none);
dump_type (pp, t, TFF_PLAIN_IDENTIFIER);
}
}
@@ -393,7 +393,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int fla
|| DECL_SELF_REFERENCE_P (decl)
|| (!flag_pretty_templates
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
- t = strip_typedefs (t);
+ t = strip_typedefs (t, tf_none);
else if (alias_template_specialization_p (t))
{
dump_alias_template_specialization (pp, t, flags);
@@ -3115,7 +3115,7 @@ type_to_string (tree typ, int verbose)
struct obstack *ob = pp_buffer (cxx_pp)->obstack;
/* Remember the end of the initial dump. */
int len = obstack_object_size (ob);
- tree aka = strip_typedefs (typ);
+ tree aka = strip_typedefs (typ, tf_none);
pp_string (cxx_pp, " {aka");
pp_cxx_whitespace (cxx_pp);
/* And remember the start of the aka dump. */
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 244803)
+++ cp/pt.c (working copy)
@@ -1140,12 +1140,13 @@ verify_unstripped_args (tree args)
if (TREE_CODE (arg) == TEMPLATE_DECL)
/* OK */;
else if (TYPE_P (arg))
- gcc_assert (strip_typedefs (arg, NULL) == arg);
- else if (strip_typedefs (TREE_TYPE (arg), NULL) != TREE_TYPE (arg))
+ gcc_assert (strip_typedefs (arg, tf_none, NULL) == arg);
+ else if (strip_typedefs (TREE_TYPE (arg),
+ tf_none, NULL) != TREE_TYPE (arg))
/* Allow typedefs on the type of a non-type argument, since a
parameter can have them. */;
else
- gcc_assert (strip_typedefs_expr (arg, NULL) == arg);
+ gcc_assert (strip_typedefs_expr (arg, tf_none, NULL) == arg);
}
}
--processing_template_decl;
@@ -7312,7 +7313,7 @@ canonicalize_type_argument (tree arg, tsubst_flags
if (!arg || arg == error_mark_node || arg == TYPE_CANONICAL (arg))
return arg;
bool removed_attributes = false;
- tree canon = strip_typedefs (arg, &removed_attributes);
+ tree canon = strip_typedefs (arg, complain, &removed_attributes);
if (removed_attributes
&& (complain & tf_warning))
warning (OPT_Wignored_attributes,
@@ -7328,7 +7329,7 @@ canonicalize_expr_argument (tree arg, tsubst_flags
if (!arg || arg == error_mark_node)
return arg;
bool removed_attributes = false;
- tree canon = strip_typedefs_expr (arg, &removed_attributes);
+ tree canon = strip_typedefs_expr (arg, complain, &removed_attributes);
if (removed_attributes
&& (complain & tf_warning))
warning (OPT_Wignored_attributes,
@@ -20536,7 +20537,7 @@ unify (tree tparms, tree targs, tree parm, tree ar
{
bool removed_attr = false;
- arg = strip_typedefs_expr (arg, &removed_attr);
+ arg = strip_typedefs_expr (arg, complain, &removed_attr);
}
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return unify_success (explain_p);
Index: cp/semantics.c
===================================================================
--- cp/semantics.c (revision 244803)
+++ cp/semantics.c (working copy)
@@ -8991,7 +8991,7 @@ finish_decltype_type (tree expr, bool id_expressio
/* For vector types, pick a non-opaque variant. */
if (VECTOR_TYPE_P (type))
- type = strip_typedefs (type);
+ type = strip_typedefs (type, complain);
if (clk != clk_none && !(clk & clk_class))
type = cp_build_reference_type (type, (clk & clk_rvalueref));
Index: cp/tree.c
===================================================================
--- cp/tree.c (revision 244803)
+++ cp/tree.c (working copy)
@@ -1328,7 +1328,7 @@ apply_identity_attributes (tree result, tree attri
stripped. */
tree
-strip_typedefs (tree t, bool *remove_attributes)
+strip_typedefs (tree t, tsubst_flags_t complain, bool *remove_attributes)
{
tree result = NULL, type = NULL, t0 = NULL;
@@ -1343,7 +1343,8 @@ tree
for (; t; t = TREE_CHAIN (t))
{
gcc_assert (!TREE_PURPOSE (t));
- tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes);
+ tree elt = strip_typedefs (TREE_VALUE (t), complain,
+ remove_attributes);
if (elt != TREE_VALUE (t))
changed = true;
vec_safe_push (vec, elt);
@@ -1367,28 +1368,30 @@ tree
switch (TREE_CODE (t))
{
case POINTER_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
result = build_pointer_type (type);
break;
case REFERENCE_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
break;
case OFFSET_TYPE:
- t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes);
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), complain,
+ remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
result = build_offset_type (t0, type);
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
{
- t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), remove_attributes);
+ t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), complain,
+ remove_attributes);
result = build_ptrmemfunc_type (t0);
}
break;
case ARRAY_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
- t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
+ t0 = strip_typedefs (TYPE_DOMAIN (t), complain, remove_attributes);
result = build_cplus_array_type (type, t0);
break;
case FUNCTION_TYPE:
@@ -1407,7 +1410,7 @@ tree
&& (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t)))
is_variant = true;
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
changed = type != TREE_TYPE (t) || is_variant;
for (arg_node = TYPE_ARG_TYPES (t);
@@ -1417,6 +1420,7 @@ tree
if (arg_node == void_list_node)
break;
arg_type = strip_typedefs (TREE_VALUE (arg_node),
+ complain,
remove_attributes);
gcc_assert (arg_type);
if (arg_type == TREE_VALUE (arg_node) && !changed)
@@ -1488,9 +1492,11 @@ tree
tree arg = TREE_VEC_ELT (args, i);
tree strip_arg;
if (TYPE_P (arg))
- strip_arg = strip_typedefs (arg, remove_attributes);
+ strip_arg = strip_typedefs (arg, complain,
+ remove_attributes);
else
- strip_arg = strip_typedefs_expr (arg, remove_attributes);
+ strip_arg = strip_typedefs_expr (arg, complain,
+ remove_attributes);
TREE_VEC_ELT (new_args, i) = strip_arg;
if (strip_arg != arg)
changed = true;
@@ -1507,8 +1513,11 @@ tree
ggc_free (new_args);
}
result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t),
+ complain,
remove_attributes),
- fullname, typename_type, tf_none);
+ fullname, typename_type, complain);
+ if (result == error_mark_node)
+ return error_mark_node;
/* Handle 'typedef typename A::N N;' */
if (typedef_variant_p (result))
result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (result)));
@@ -1516,14 +1525,19 @@ tree
break;
case DECLTYPE_TYPE:
result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t),
+ complain,
remove_attributes);
if (result == DECLTYPE_TYPE_EXPR (t))
result = NULL_TREE;
else
- result = (finish_decltype_type
- (result,
- DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
- tf_none));
+ {
+ result = (finish_decltype_type
+ (result,
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
+ complain));
+ if (result == error_mark_node)
+ return error_mark_node;
+ }
break;
default:
break;
@@ -1536,7 +1550,7 @@ tree
/* Explicitly get the underlying type, as TYPE_MAIN_VARIANT doesn't
strip typedefs with attributes. */
result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (t)));
- result = strip_typedefs (result);
+ result = strip_typedefs (result, complain);
}
else
result = TYPE_MAIN_VARIANT (t);
@@ -1579,7 +1593,7 @@ tree
sizeof(TT) is replaced by sizeof(T). */
tree
-strip_typedefs_expr (tree t, bool *remove_attributes)
+strip_typedefs_expr (tree t, tsubst_flags_t complain, bool *remove_attributes)
{
unsigned i,n;
tree r, type, *ops;
@@ -1594,7 +1608,7 @@ tree
/* Some expressions have type operands, so let's handle types here rather
than check TYPE_P in multiple places below. */
if (TYPE_P (t))
- return strip_typedefs (t, remove_attributes);
+ return strip_typedefs (t, complain, remove_attributes);
code = TREE_CODE (t);
switch (code)
@@ -1608,8 +1622,10 @@ tree
case TRAIT_EXPR:
{
- tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), remove_attributes);
- tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), remove_attributes);
+ tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), complain,
+ remove_attributes);
+ tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), complain,
+ remove_attributes);
if (type1 == TRAIT_EXPR_TYPE1 (t)
&& type2 == TRAIT_EXPR_TYPE2 (t))
return t;
@@ -1626,7 +1642,8 @@ tree
tree it;
for (it = t; it; it = TREE_CHAIN (it))
{
- tree val = strip_typedefs_expr (TREE_VALUE (t), remove_attributes);
+ tree val = strip_typedefs_expr (TREE_VALUE (t), complain,
+ remove_attributes);
vec_safe_push (vec, val);
if (val != TREE_VALUE (t))
changed = true;
@@ -1652,7 +1669,7 @@ tree
vec_safe_reserve (vec, n);
for (i = 0; i < n; ++i)
{
- tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
+ tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i), complain,
remove_attributes);
vec->quick_push (op);
if (op != TREE_VEC_ELT (t, i))
@@ -1678,11 +1695,12 @@ tree
vec<constructor_elt, va_gc> *vec
= vec_safe_copy (CONSTRUCTOR_ELTS (t));
n = CONSTRUCTOR_NELTS (t);
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
for (i = 0; i < n; ++i)
{
constructor_elt *e = &(*vec)[i];
- tree op = strip_typedefs_expr (e->value, remove_attributes);
+ tree op = strip_typedefs_expr (e->value, complain,
+ remove_attributes);
if (op != e->value)
{
changed = true;
@@ -1689,7 +1707,8 @@ tree
e->value = op;
}
gcc_checking_assert
- (e->index == strip_typedefs_expr (e->index, remove_attributes));
+ (e->index == strip_typedefs_expr (e->index, complain,
+ remove_attributes));
}
if (!changed && type == TREE_TYPE (t))
@@ -1707,7 +1726,8 @@ tree
}
case LAMBDA_EXPR:
- error ("lambda-expression in a constant expression");
+ if (complain & tf_error)
+ error ("lambda-expression in a constant expression");
return error_mark_node;
default:
@@ -1730,12 +1750,13 @@ tree
case REINTERPRET_CAST_EXPR:
case CAST_EXPR:
case NEW_EXPR:
- type = strip_typedefs (type, remove_attributes);
+ type = strip_typedefs (type, complain, remove_attributes);
/* fallthrough */
default:
for (i = 0; i < n; ++i)
- ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), remove_attributes);
+ ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), complain,
+ remove_attributes);
break;
}
Index: testsuite/g++.dg/cpp0x/pr72764.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr72764.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr72764.C (working copy)
@@ -0,0 +1,15 @@
+// PR c++/72764
+// { dg-do compile { target c++11 } }
+
+template < typename > struct A;
+template < typename > struct B {};
+
+template < typename T >
+using C = typename A < T >::template D < T >;
+
+template < typename T > struct A
+{
+ struct D : B < C < T > > {}; // { dg-error "not a class template" }
+};
+
+A < int > a;