[C++ Patch] PR 81957 ("ICE decltype")

Paolo Carlini paolo.carlini@oracle.com
Tue Oct 31 09:57:00 GMT 2017


Hi,

this ICE on valid seems rather easy to fix, one of those bugs where we 
aren't propagating the tsubst_flags_t argument. In this case, we aren't 
propagating from tsubst_pack_expansion to make_pack_expansion. Doing it, 
fixes the ICE and we actually accept the code as we should. In general, 
make_pack_expansion is also called from many other places, eg, the 
parser, thus I'm using a default tf_warning_or_error for it. Similarly 
to other past fixes, I ended up adding tsubst_flags_t parameters to a 
few other functions in pt.c, eg template_parms_to_args, which eventually 
use make_pack_expansion without propagating.

There are a couple of places where I'm proposing passing a /tf_none/ to 
template_parms_to_args: is_compatible_template_arg, which is currently 
calling template_parms_to_args and passing the result together with a 
tf_none to tsubst_constraint_info; convert_generic_types_to_packs, which 
is currently calling template_parms_to_args and passing the result (via 
add_to_template_args) together with tf_none to tsubst. Of course the 
"conservative" choice would be instead passing tf_warning_or_error.

Tested x86_64-linux.

Thanks, Paolo.

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

-------------- next part --------------
/cp
2017-10-31  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/81957
	* pt.c (make_pack_expansion): Add tsubst_flags_t parameter.
	(template_parm_to_arg): Likewise.
	(template_parms_level_to_args): Likewise.
	(template_parms_to_args): Likewise.
	(current_template_args): Likewise.
	(get_underlying_template): Likewise.
	(expand_integer_pack, template_parm_to_arg,
	template_parms_level_to_args, template_parms_to_args,
	current_template_args, add_inherited_template_parms,
	get_underlying_template, coerce_template_args_for_ttp,
	coerce_template_template_parms, is_compatible_template_arg,
	convert_template_argument, coerce_template_parms,
	lookup_template_class_1, tsubst_pack_expansion, tsubst_template_decl,
	unify, rewrite_template_parm, build_deduction_guide,
	do_auto_deduction, convert_generic_types_to_packs): Adjust calls.
	* tree.c (cp_build_qualified_type_real): Likewise.
	* constraint.cc (finish_shorthand_constraint,
	finish_template_introduction): Likewise.
	* cp-tree.h (make_pack_expansion, template_parm_to_arg): Adjust
	declarations.

/testsuite
2017-10-31  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/81957
	* g++.dg/cpp0x/variadic-crash5.C: New.
-------------- next part --------------
Index: cp/constraint.cc
===================================================================
--- cp/constraint.cc	(revision 254249)
+++ cp/constraint.cc	(working copy)
@@ -1272,7 +1272,8 @@ finish_shorthand_constraint (tree decl, tree const
 
   /* Get the argument and overload used for the requirement
      and adjust it if we're going to expand later.  */
-  tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl));
+  tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl),
+				   tf_warning_or_error);
   if (apply_to_all_p)
     arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0));
 
@@ -1420,7 +1421,8 @@ finish_template_introduction (tree tmpl_decl, tree
   for (; n < TREE_VEC_LENGTH (parm_list); ++n)
     {
       tree parm = TREE_VEC_ELT (parm_list, n);
-      TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm);
+      TREE_VEC_ELT (check_args, n)
+	= template_parm_to_arg (parm, tf_warning_or_error);
     }
   SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (check_args, n);
 
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 254249)
+++ cp/cp-tree.h	(working copy)
@@ -6435,7 +6435,7 @@ extern bool uses_parameter_packs                (t
 extern bool template_parameter_pack_p           (const_tree);
 extern bool function_parameter_pack_p		(const_tree);
 extern bool function_parameter_expanded_from_pack_p (tree, tree);
-extern tree make_pack_expansion                 (tree);
+extern tree make_pack_expansion                 (tree, tsubst_flags_t = tf_warning_or_error);
 extern bool check_for_bare_parameter_packs      (tree);
 extern tree build_template_info			(tree, tree);
 extern tree get_template_info			(const_tree);
@@ -6517,7 +6517,7 @@ extern tree coerce_template_parms               (t
 extern void register_local_specialization       (tree, tree);
 extern tree retrieve_local_specialization       (tree);
 extern tree extract_fnparm_pack                 (tree, tree *);
-extern tree template_parm_to_arg                (tree);
+extern tree template_parm_to_arg                (tree, tsubst_flags_t);
 extern tree dguide_name				(tree);
 extern bool dguide_name_p			(tree);
 extern bool deduction_guide_p			(const_tree);
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 254249)
+++ cp/pt.c	(working copy)
@@ -3435,7 +3435,7 @@ expand_integer_pack (tree call, tree args, tsubst_
 	  call = copy_node (call);
 	  CALL_EXPR_ARG (call, 0) = hi;
 	}
-      tree ex = make_pack_expansion (call);
+      tree ex = make_pack_expansion (call, complain);
       tree vec = make_tree_vec (1);
       TREE_VEC_ELT (vec, 0) = ex;
       return vec;
@@ -3724,7 +3724,7 @@ uses_parameter_packs (tree t)
    EXPR_PACK_EXPANSION, TYPE_PACK_EXPANSION, or TREE_LIST,
    respectively.  */
 tree 
-make_pack_expansion (tree arg)
+make_pack_expansion (tree arg, tsubst_flags_t complain)
 {
   tree result;
   tree parameter_packs = NULL_TREE;
@@ -3770,7 +3770,9 @@ tree
 
       if (parameter_packs == NULL_TREE)
         {
-          error ("base initializer expansion %qT contains no parameter packs", arg);
+	  if (complain & tf_error)
+	    error ("base initializer expansion %qT contains no parameter packs",
+		   arg);
           delete ppd.visited;
           return error_mark_node;
         }
@@ -3834,10 +3836,13 @@ tree
   /* Make sure we found some parameter packs.  */
   if (parameter_packs == NULL_TREE)
     {
-      if (TYPE_P (arg))
-        error ("expansion pattern %qT contains no argument packs", arg);
-      else
-        error ("expansion pattern %qE contains no argument packs", arg);
+      if (complain & tf_error)
+	{
+	  if (TYPE_P (arg))
+	    error ("expansion pattern %qT contains no argument packs", arg);
+	  else
+	    error ("expansion pattern %qE contains no argument packs", arg);
+	}
       return error_mark_node;
     }
   PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs;
@@ -4330,7 +4335,7 @@ end_template_decl (void)
    node, the returned argument is error_mark_node.  */
 
 tree
-template_parm_to_arg (tree t)
+template_parm_to_arg (tree t, tsubst_flags_t complain)
 {
 
   if (t == NULL_TREE
@@ -4355,7 +4360,7 @@ tree
 	  if (CHECKING_P)
 	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
 
-	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t, complain);
 
 	  t = cxx_make_type (TYPE_ARGUMENT_PACK);
 	  SET_ARGUMENT_PACK_ARGS (t, vec);
@@ -4374,7 +4379,7 @@ tree
 	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
 
 	  t = convert_from_reference (t);
-	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t, complain);
 
 	  t  = make_node (NONTYPE_ARGUMENT_PACK);
 	  SET_ARGUMENT_PACK_ARGS (t, vec);
@@ -4389,12 +4394,13 @@ tree
    as a set of template arguments.  */
 
 static tree
-template_parms_level_to_args (tree parms)
+template_parms_level_to_args (tree parms, tsubst_flags_t complain)
 {
   tree a = copy_node (parms);
   TREE_TYPE (a) = NULL_TREE;
   for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
-    TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+    TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i),
+						complain);
 
   if (CHECKING_P)
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
@@ -4407,7 +4413,7 @@ static tree
    the form documented in cp-tree.h for template arguments.  */
 
 static tree
-template_parms_to_args (tree parms)
+template_parms_to_args (tree parms, tsubst_flags_t complain)
 {
   tree header;
   tree args = NULL_TREE;
@@ -4422,7 +4428,8 @@ static tree
 
   for (header = parms; header; header = TREE_CHAIN (header))
     {
-      tree a = template_parms_level_to_args (TREE_VALUE (header));
+      tree a = template_parms_level_to_args (TREE_VALUE (header),
+					     complain);
 
       if (length > 1)
 	TREE_VEC_ELT (args, --l) = a;
@@ -4437,9 +4444,9 @@ static tree
    template parameters as an argument TREE_VEC.  */
 
 static tree
-current_template_args (void)
+current_template_args (tsubst_flags_t complain = tf_warning_or_error)
 {
-  return template_parms_to_args (current_template_parms);
+  return template_parms_to_args (current_template_parms, complain);
 }
 
 /* Update the declared TYPE by doing any lookups which were thought to be
@@ -5670,7 +5677,7 @@ add_inherited_template_parms (tree fn, tree inheri
     = tree_cons (size_int (processing_template_decl + 1),
 		 inner_parms, current_template_parms);
   tree tmpl = build_template_decl (fn, parms, /*member*/true);
-  tree args = template_parms_to_args (parms);
+  tree args = template_parms_to_args (parms, tf_warning_or_error);
   DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
   TREE_TYPE (tmpl) = TREE_TYPE (fn);
   DECL_TEMPLATE_RESULT (tmpl) = fn;
@@ -5995,7 +6002,7 @@ num_innermost_template_parms (tree tmpl)
    the other template.  */
 
 static tree
-get_underlying_template (tree tmpl)
+get_underlying_template (tree tmpl, tsubst_flags_t complain)
 {
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   while (DECL_ALIAS_TEMPLATE_P (tmpl))
@@ -6013,7 +6020,8 @@ static tree
 	break;
 
       tree alias_args = INNERMOST_TEMPLATE_ARGS
-	(template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl)));
+	(template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl),
+				 complain));
       if (!comp_template_args (TI_ARGS (tinfo), alias_args))
 	break;
 
@@ -7006,7 +7014,7 @@ coerce_template_args_for_ttp (tree templ, tree arg
       if (DECL_TEMPLATE_SPECIALIZATION (outer))
 	/* We want arguments for the partial specialization, not arguments for
 	   the primary template.  */
-	outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer));
+	outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer), complain);
       else
 	outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer)));
     }
@@ -7023,7 +7031,7 @@ coerce_template_args_for_ttp (tree templ, tree arg
 	     != TEMPLATE_TYPE_LEVEL (TREE_TYPE (templ)))
 	relevant_template_parms = TREE_CHAIN (relevant_template_parms);
 
-      outer = template_parms_to_args (relevant_template_parms);
+      outer = template_parms_to_args (relevant_template_parms, complain);
     }
 
   if (outer)
@@ -7267,7 +7275,7 @@ coerce_template_template_parms (tree parm_parms,
       /* So coerce P's args to apply to A's parms, and then deduce between A's
 	 args and the converted args.  If that succeeds, A is at least as
 	 specialized as P, so they match.*/
-      tree pargs = template_parms_level_to_args (parm_parms);
+      tree pargs = template_parms_level_to_args (parm_parms, complain);
       ++processing_template_decl;
       pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none,
 				     /*require_all*/true, /*use_default*/true);
@@ -7275,7 +7283,7 @@ coerce_template_template_parms (tree parm_parms,
       if (pargs != error_mark_node)
 	{
 	  tree targs = make_tree_vec (nargs);
-	  tree aargs = template_parms_level_to_args (arg_parms);
+	  tree aargs = template_parms_level_to_args (arg_parms, complain);
 	  if (!unify (arg_parms, targs, aargs, pargs, UNIFY_ALLOW_NONE,
 		      /*explain*/false))
 	    return 1;
@@ -7493,7 +7501,8 @@ is_compatible_template_arg (tree parm, tree arg)
   // words, because coercion is successful, this conversion will be valid.
   if (parm_cons)
     {
-      tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
+      tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg),
+					  tf_none);
       parm_cons = tsubst_constraint_info (parm_cons,
 					  INNERMOST_TEMPLATE_ARGS (args),
 					  tf_none, NULL_TREE);
@@ -7678,7 +7687,7 @@ convert_template_argument (tree parm,
 
 	      /* Strip alias templates that are equivalent to another
 		 template.  */
-	      arg = get_underlying_template (arg);
+	      arg = get_underlying_template (arg, complain);
               argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
 
 	      if (coerce_template_template_parms (parmparm, argparm,
@@ -7694,7 +7703,7 @@ convert_template_argument (tree parm,
                       if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
                         val = TREE_TYPE (val);
 		      if (TREE_CODE (orig_arg) == TYPE_PACK_EXPANSION)
-			val = make_pack_expansion (val);
+			val = make_pack_expansion (val, complain);
                     }
 		}
 	      else
@@ -8188,7 +8197,7 @@ coerce_template_parms (tree parms,
 	      else if (TYPE_P (conv) && !TYPE_P (pattern))
 		/* Recover from missing typename.  */
 		TREE_VEC_ELT (inner_args, arg_idx)
-		  = make_pack_expansion (conv);
+		  = make_pack_expansion (conv, complain);
 
               /* We don't know how many args we have yet, just
                  use the unconverted ones for now.  */
@@ -8697,7 +8706,7 @@ lookup_template_class_1 (tree d1, tree arglist, tr
      the alias to avoid problems with a pack expansion passed to a non-pack
      alias template parameter (DR 1430).  */
   if (pack_expansion_args_count (INNERMOST_TEMPLATE_ARGS (arglist)))
-    templ = get_underlying_template (templ);
+    templ = get_underlying_template (templ, complain);
 
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
     {
@@ -11161,7 +11170,7 @@ gen_elem_of_pack_expansion_instantiation (tree pat
       the Ith element resulting from the substituting is going to
       be a pack expansion as well.  */
   if (ith_elem_is_expansion)
-    t = make_pack_expansion (t);
+    t = make_pack_expansion (t, complain);
 
   return t;
 }
@@ -11573,7 +11582,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_f
       /* We got some full packs, but we can't substitute them in until we
 	 have values for all the packs.  So remember these until then.  */
 
-      t = make_pack_expansion (pattern);
+      t = make_pack_expansion (pattern, complain);
       PACK_EXPANSION_EXTRA_ARGS (t) = args;
       return t;
     }
@@ -11588,7 +11597,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_f
 			 /*integral_constant_expression_p=*/false);
       else
 	t = tsubst (pattern, args, complain, in_decl);
-      t = make_pack_expansion (t);
+      t = make_pack_expansion (t, complain);
       return t;
     }
 
@@ -12551,7 +12560,8 @@ tsubst_template_decl (tree t, tree args, tsubst_fl
       DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
       if (lambda_fntype)
 	{
-	  tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));
+	  tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r),
+					      complain);
 	  DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args);
 	}
       else
@@ -21323,7 +21333,7 @@ unify (tree tparms, tree targs, tree parm, tree ar
 	  if (REFERENCE_REF_P (arg))
 	    arg = TREE_OPERAND (arg, 0);
 	  if (pexp)
-	    arg = make_pack_expansion (arg);
+	    arg = make_pack_expansion (arg, complain);
 	  return unify (tparms, targs, TREE_OPERAND (parm, 0), arg,
 			strict, explain_p);
 	}
@@ -25378,7 +25388,7 @@ rewrite_template_parm (tree olddecl, unsigned inde
 	  for (int i = 0; i < depth; ++i)
 	    TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i);
 	  TREE_VEC_ELT (ttargs, depth)
-	    = template_parms_level_to_args (ttparms);
+	    = template_parms_level_to_args (ttparms, complain);
 	  // Substitute ttargs into ttparms to fix references to
 	  // other template parameters.
 	  ttparms = tsubst_template_parms_level (ttparms, ttargs,
@@ -25385,7 +25395,7 @@ rewrite_template_parm (tree olddecl, unsigned inde
 						 complain);
 	  // Now substitute again with args based on tparms, to reduce
 	  // the level of the ttparms.
-	  ttargs = current_template_args ();
+	  ttargs = current_template_args (complain);
 	  ttparms = tsubst_template_parms_level (ttparms, ttargs,
 						 complain);
 	  // Finally, tack the adjusted parms onto tparms.
@@ -25527,12 +25537,13 @@ build_deduction_guide (tree ctor, tree outer_args,
 		= tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
 					  tsubst_args, complain, ctor);
 	      TREE_VEC_ELT (new_vec, index) = list;
-	      TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+	      TMPL_ARG (tsubst_args, depth, i)
+		= template_parm_to_arg (list, complain);
 	    }
 
 	  /* Now we have a final set of template parms to substitute into the
 	     function signature.  */
-	  targs = template_parms_to_args (tparms);
+	  targs = template_parms_to_args (tparms, complain);
 	  fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE,
 				     complain, ctor);
 	  fargs = tsubst (fargs, tsubst_args, complain, ctor);
@@ -25950,7 +25961,7 @@ do_auto_deduction (tree type, tree init, tree auto
       }
 
   if (processing_template_decl && context != adc_unify)
-    outer_targs = current_template_args ();
+    outer_targs = current_template_args (complain);
   targs = add_to_template_args (outer_targs, targs);
   return tsubst (type, targs, complain, NULL_TREE);
 }
@@ -26187,7 +26198,8 @@ convert_generic_types_to_packs (tree parm, int sta
      template parms.  */
   if (depth > 1)
     replacement = add_to_template_args (template_parms_to_args
-					(TREE_CHAIN (current_template_parms)),
+					(TREE_CHAIN (current_template_parms),
+					 tf_none),
 					replacement);
 
   return tsubst (parm, replacement, tf_none, NULL_TREE);
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 254249)
+++ cp/tree.c	(working copy)
@@ -1208,7 +1208,7 @@ cp_build_qualified_type_real (tree type,
       tree t = PACK_EXPANSION_PATTERN (type);
 
       t = cp_build_qualified_type_real (t, type_quals, complain);
-      return make_pack_expansion (t);
+      return make_pack_expansion (t, complain);
     }
 
   /* A reference or method type shall not be cv-qualified.
Index: testsuite/g++.dg/cpp0x/variadic-crash5.C
===================================================================
--- testsuite/g++.dg/cpp0x/variadic-crash5.C	(nonexistent)
+++ testsuite/g++.dg/cpp0x/variadic-crash5.C	(working copy)
@@ -0,0 +1,28 @@
+// PR c++/81957
+// { dg-do compile { target c++11 } }
+
+template <class T, T v>
+struct integral_constant { };
+
+struct f {
+  template<bool b, typename Int>
+  void operator()(integral_constant<bool,b>, Int i) {
+  }
+};
+
+template<bool...Bs, typename F, typename ...T>
+auto dispatch(F f, T...t) -> decltype(f(integral_constant<bool,Bs>()..., t...)) {
+  return f(integral_constant<bool,Bs>()..., t...);
+}
+
+template<bool...Bs, typename F, typename ...T>
+auto dispatch(F f, bool b, T...t) -> decltype(dispatch<Bs..., true>(f, t...)) {
+  if (b)
+    return dispatch<Bs..., true>(f, t...);
+  else
+    return dispatch<Bs..., false>(f, t...);
+}
+
+int main() {
+  dispatch(f(), true, 5);
+}


More information about the Gcc-patches mailing list