diff mbox

[C++,Patch/RFC] PR 72764

Message ID 56a2b869-84be-2fd5-1254-9b27544fbecb@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Jan. 23, 2017, 4:15 p.m. UTC
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.

/////////////////////////////

Comments

Jason Merrill Jan. 23, 2017, 8:28 p.m. UTC | #1
On Mon, Jan 23, 2017 at 11:15 AM, Paolo Carlini
<paolo.carlini@oracle.com> wrote:
> 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?

Hmm.  How did we get the typedef in the first place to a type that we
can't reconstruct?  I would think that instantiating C<int> should
give an error before we get to strip_typedefs.

Jason
diff mbox

Patch

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;