[RFH / Patch] PR 51222

Paolo Carlini paolo.carlini@oracle.com
Tue May 1 20:06:00 GMT 2012


Hi,

On 05/01/2012 08:02 PM, Jason Merrill wrote:
> On 05/01/2012 08:00 AM, Paolo Carlini wrote:
>>> I think either approach would be fine; I lean toward the first, but
>>> changing the name and adding a flag for clarity. Changing the walking
>>> behavior based on fn being null is too subtle.
>> Agreed. The below is what I booted and tested on x86_64-linux.
>
>> +   If ANY_P is true, return 1 if any, 0 otherwise.
>
> This isn't really what the parameter means; it means also look into 
> the types of declarations used in the expression.  So perhaps call it 
> "check_types"?
Ok.
>
>> +   If ANY_P is false, for each the iteration calls FN with the 
>> parameter
>> +   and the DATA.
>
> This doesn't actually depend on ANY_P, it depends on whether or not FN 
> is null.
Ok.
>
>>       /* If there's no type, then this thing must be some expression
>>          involving template parameters.  */
>>       if (!fn && !TREE_TYPE (t))
>>         return error_mark_node;
>
> Hmm, this preexisting code seems to assume that any type-dependent 
> expression must include a direct use of a template parameter, but it 
> might just have a declaration with dependent type.  We should also 
> test any_p/check_types, and this should apply to all expressions, not 
> just these.
>
>>     case MODOP_EXPR:
>>     case CAST_EXPR:
>>     case IMPLICIT_CONV_EXPR:
>>     case REINTERPRET_CAST_EXPR:
>>     case CONST_CAST_EXPR:
>>     case STATIC_CAST_EXPR:
>>     case DYNAMIC_CAST_EXPR:
>>     case ARROW_EXPR:
>>     case DOTSTAR_EXPR:
>>     case TYPEID_EXPR:
>>     case PSEUDO_DTOR_EXPR:
>>       if (!fn)
>>         return error_mark_node;
>>       break;
>
> This pre-existing code seems like it will do the wrong thing; these 
> codes don't necessarily imply a dependent expression.  We can drop 
> these cases, too.
I'm not 100% sure to understand the last two comments. I'm removing 
completely the latter cases and changing the former like the below. Note 
that the way I handle fn in walk_template_parms implies that when 
check_types is true then pfd->fn is always NULL in  walk_template_parms_r.

The attached passes testing.

Paolo.

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


-------------- next part --------------
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 187012)
+++ cp/pt.c	(working copy)
@@ -145,8 +145,8 @@ static tree convert_nontype_argument_function (tre
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
 static tree convert_template_argument (tree, tree, tree,
 				       tsubst_flags_t, int, tree);
-static int for_each_template_parm (tree, tree_fn_t, void*,
-				   struct pointer_set_t*, bool);
+static int walk_template_parms (tree, tree_fn_t, void*,
+				struct pointer_set_t*, bool, bool);
 static tree expand_template_argument_pack (tree);
 static tree build_template_parm_index (int, int, int, int, tree, tree);
 static bool inline_needs_template_parms (tree);
@@ -185,7 +185,7 @@ static int coerce_template_template_parms (tree, t
 static bool template_template_parm_bindings_ok_p (tree, tree);
 static int template_args_equal (tree, tree);
 static void tsubst_default_arguments (tree);
-static tree for_each_template_parm_r (tree *, int *, void *);
+static tree walk_template_parms_r (tree *, int *, void *);
 static tree copy_default_args_to_explicit_spec_1 (tree, tree);
 static void copy_default_args_to_explicit_spec (tree);
 static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
@@ -4276,8 +4276,8 @@ mark_template_parm (tree t, void* data)
       tpd->arg_uses_template_parms[tpd->current_arg] = 1;
     }
 
-  /* Return zero so that for_each_template_parm will continue the
-     traversal of the tree; we want to mark *every* template parm.  */
+  /* Return zero so that walk_template_parms will continue the traversal
+     of the tree; we want to mark *every* template parm.  */
   return 0;
 }
 
@@ -4344,11 +4344,12 @@ process_partial_specialization (tree decl)
   for (i = 0; i < nargs; ++i)
     {
       tpd.current_arg = i;
-      for_each_template_parm (TREE_VEC_ELT (inner_args, i),
-			      &mark_template_parm,
-			      &tpd,
-			      NULL,
-			      /*include_nondeduced_p=*/false);
+      walk_template_parms (TREE_VEC_ELT (inner_args, i),
+			   &mark_template_parm,
+			   &tpd,
+			   NULL,
+			   /*check_types=*/false,
+			   /*include_nondeduced_p=*/false);
     }
   for (i = 0; i < ntparms; ++i)
     if (tpd.parms[i] == 0)
@@ -4481,11 +4482,12 @@ process_partial_specialization (tree decl)
                   tpd2.current_arg = i;
                   tpd2.arg_uses_template_parms[i] = 0;
                   memset (tpd2.parms, 0, sizeof (int) * nargs);
-                  for_each_template_parm (type,
-                                          &mark_template_parm,
-                                          &tpd2,
-                                          NULL,
-					  /*include_nondeduced_p=*/false);
+                  walk_template_parms (type,
+				       &mark_template_parm,
+				       &tpd2,
+				       NULL,
+				       /*check_types=*/false,
+				       /*include_nondeduced_p=*/false);
 
                   if (tpd2.arg_uses_template_parms [i])
                     {
@@ -4755,7 +4757,7 @@ check_default_tmpl_args (tree decl, tree parms, in
 }
 
 /* Worker for push_template_decl_real, called via
-   for_each_template_parm.  DATA is really an int, indicating the
+   walk_template_parms.  DATA is really an int, indicating the
    level of the parameters we are interested in.  If T is a template
    parameter of that level, return nonzero.  */
 
@@ -7750,16 +7752,17 @@ struct pair_fn_data
 {
   tree_fn_t fn;
   void *data;
+  bool check_types;
   /* True when we should also visit template parameters that occur in
      non-deduced contexts.  */
   bool include_nondeduced_p;
   struct pointer_set_t *visited;
 };
 
-/* Called from for_each_template_parm via walk_tree.  */
+/* Called from walk_template_parms via walk_tree.  */
 
 static tree
-for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
+walk_template_parms_r (tree *tp, int *walk_subtrees, void *d)
 {
   tree t = *tp;
   struct pair_fn_data *pfd = (struct pair_fn_data *) d;
@@ -7768,8 +7771,9 @@ static tree
 
   if (TYPE_P (t)
       && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE)
-      && for_each_template_parm (TYPE_CONTEXT (t), fn, data, pfd->visited,
-				 pfd->include_nondeduced_p))
+      && walk_template_parms (TYPE_CONTEXT (t), fn, data,
+			      pfd->visited, pfd->check_types,
+			      pfd->include_nondeduced_p))
     return error_mark_node;
 
   switch (TREE_CODE (t))
@@ -7783,34 +7787,39 @@ static tree
     case ENUMERAL_TYPE:
       if (!TYPE_TEMPLATE_INFO (t))
 	*walk_subtrees = 0;
-      else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
-				       fn, data, pfd->visited, 
-				       pfd->include_nondeduced_p))
+      else if (walk_template_parms (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
+				    fn, data, pfd->visited,
+				    pfd->check_types,
+				    pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case INTEGER_TYPE:
-      if (for_each_template_parm (TYPE_MIN_VALUE (t),
-				  fn, data, pfd->visited, 
-				  pfd->include_nondeduced_p)
-	  || for_each_template_parm (TYPE_MAX_VALUE (t),
-				     fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_MIN_VALUE (t),
+			       fn, data, pfd->visited,
+			       pfd->check_types,
+			       pfd->include_nondeduced_p)
+	  || walk_template_parms (TYPE_MAX_VALUE (t),
+				  fn, data, pfd->visited,
+				  pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case METHOD_TYPE:
       /* Since we're not going to walk subtrees, we have to do this
 	 explicitly here.  */
-      if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data,
-				  pfd->visited, pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_METHOD_BASETYPE (t), fn, data,
+			       pfd->visited, pfd->check_types,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
     case FUNCTION_TYPE:
       /* Check the return type.  */
-      if (for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
+      if (walk_template_parms (TREE_TYPE (t), fn, data,
+			       pfd->visited, pfd->check_types,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
 
       /* Check the parameter types.  Since default arguments are not
@@ -7823,8 +7832,9 @@ static tree
 	tree parm;
 
 	for (parm = TYPE_ARG_TYPES (t); parm; parm = TREE_CHAIN (parm))
-	  if (for_each_template_parm (TREE_VALUE (parm), fn, data,
-				      pfd->visited, pfd->include_nondeduced_p))
+	  if (walk_template_parms (TREE_VALUE (parm), fn, data,
+				   pfd->visited, pfd->check_types,
+				   pfd->include_nondeduced_p))
 	    return error_mark_node;
 
 	/* Since we've already handled the TYPE_ARG_TYPES, we don't
@@ -7836,37 +7846,46 @@ static tree
     case TYPEOF_TYPE:
     case UNDERLYING_TYPE:
       if (pfd->include_nondeduced_p
-	  && for_each_template_parm (TYPE_FIELDS (t), fn, data,
-				     pfd->visited, 
-				     pfd->include_nondeduced_p))
+	  && walk_template_parms (TYPE_FIELDS (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case FUNCTION_DECL:
     case VAR_DECL:
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
-	  && for_each_template_parm (DECL_TI_ARGS (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_TI_ARGS (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
     case PARM_DECL:
     case CONST_DECL:
       if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (DECL_INITIAL (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_INITIAL (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       if (DECL_CONTEXT (t)
 	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (DECL_CONTEXT (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (DECL_CONTEXT (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
+      if (pfd->check_types && TREE_TYPE (t)
+	  && walk_template_parms (TREE_TYPE(t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
+	return error_mark_node;
       break;
 
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       /* Record template parameters such as `T' inside `TT<T>'.  */
-      if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
+      if (walk_template_parms (TYPE_TI_ARGS (t), fn, data,
+			       pfd->visited, pfd->check_types,
+			       pfd->include_nondeduced_p))
 	return error_mark_node;
       /* Fall through.  */
 
@@ -7882,8 +7901,9 @@ static tree
     case TEMPLATE_DECL:
       /* A template template parameter is encountered.  */
       if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
+	  && walk_template_parms (TREE_TYPE (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
 
       /* Already substituted template template parameter */
@@ -7892,44 +7912,36 @@ static tree
 
     case TYPENAME_TYPE:
       if (!fn
-	  || for_each_template_parm (TYPENAME_TYPE_FULLNAME (t), fn,
-				     data, pfd->visited, 
-				     pfd->include_nondeduced_p))
+	  || walk_template_parms (TYPENAME_TYPE_FULLNAME (t), fn,
+				  data, pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
 
     case CONSTRUCTOR:
       if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))
 	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
-				     (TREE_TYPE (t)), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
+	  && walk_template_parms (TYPE_PTRMEMFUNC_FN_TYPE
+				  (TREE_TYPE (t)), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
+      else if (pfd->check_types && TREE_TYPE (t)
+	       && walk_template_parms (TREE_TYPE (t), fn, data,
+				       pfd->visited, pfd->check_types,
+				       pfd->include_nondeduced_p))
+	return error_mark_node;
       break;
 
     case INDIRECT_REF:
     case COMPONENT_REF:
-      /* If there's no type, then this thing must be some expression
-	 involving template parameters.  */
-      if (!fn && !TREE_TYPE (t))
+      if (!fn && TREE_TYPE (t)
+	  && walk_template_parms (TREE_TYPE (t), fn, data,
+				  pfd->visited, pfd->check_types,
+				  pfd->include_nondeduced_p))
 	return error_mark_node;
       break;
-
-    case MODOP_EXPR:
-    case CAST_EXPR:
-    case IMPLICIT_CONV_EXPR:
-    case REINTERPRET_CAST_EXPR:
-    case CONST_CAST_EXPR:
-    case STATIC_CAST_EXPR:
-    case DYNAMIC_CAST_EXPR:
-    case ARROW_EXPR:
-    case DOTSTAR_EXPR:
-    case TYPEID_EXPR:
-    case PSEUDO_DTOR_EXPR:
-      if (!fn)
-	return error_mark_node;
-      break;
-
+ 
     default:
       break;
     }
@@ -7938,35 +7950,41 @@ static tree
   return NULL_TREE;
 }
 
-/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
-   BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX in T,
-   call FN with the parameter and the DATA.
-   If FN returns nonzero, the iteration is terminated, and
-   for_each_template_parm returns 1.  Otherwise, the iteration
-   continues.  If FN never returns a nonzero value, the value
-   returned by for_each_template_parm is 0.  If FN is NULL, it is
-   considered to be the function which always returns 1.
+/* Walk T looking for TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
+   BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX.
 
+   If CHECK_TYPES, return 1 if any, 0 otherwise.
+
+   If FN is nonnull, for each the iteration calls FN with the parameter
+   and the DATA.  If FN returns nonzero, the iteration is terminated,
+   and walk_template_parms returns 1.  Otherwise, the iteration continues.
+   If FN never returns a nonzero value, the value returned by
+   walk_template_parms is 0.  If FN is NULL, it is considered to be the
+   function which always returns 1.
+
    If INCLUDE_NONDEDUCED_P, then this routine will also visit template
    parameters that occur in non-deduced contexts.  When false, only
    visits those template parameters that can be deduced.  */
 
 static int
-for_each_template_parm (tree t, tree_fn_t fn, void* data,
-			struct pointer_set_t *visited,
-			bool include_nondeduced_p)
+walk_template_parms (tree t, tree_fn_t fn, void* data,
+		     struct pointer_set_t *visited,
+		     bool check_types, bool include_nondeduced_p)
 {
   struct pair_fn_data pfd;
   int result;
 
   /* Set up.  */
-  pfd.fn = fn;
+  /* When check_types is true, fn plays no role, thus make sure is NULL,
+     which simplifies a bit walk_template_parms_r.  */
+  pfd.fn = check_types ? NULL : fn;
   pfd.data = data;
+  pfd.check_types = check_types;
   pfd.include_nondeduced_p = include_nondeduced_p;
 
   /* Walk the tree.  (Conceptually, we would like to walk without
-     duplicates, but for_each_template_parm_r recursively calls
-     for_each_template_parm, so we would need to reorganize a fair
+     duplicates, but walk_template_parms_r recursively calls
+     walk_template_parms, so we would need to reorganize a fair
      bit to use walk_tree_without_duplicates, so we keep our own
      visited list.)  */
   if (visited)
@@ -7974,7 +7992,7 @@ static int
   else
     pfd.visited = pointer_set_create ();
   result = cp_walk_tree (&t,
-		         for_each_template_parm_r,
+		         walk_template_parms_r,
 		         &pfd,
 		         pfd.visited) != NULL_TREE;
 
@@ -8035,8 +8053,9 @@ uses_template_parms (tree t)
 int
 uses_template_parms_level (tree t, int level)
 {
-  return for_each_template_parm (t, template_parm_this_level_p, &level, NULL,
-				 /*include_nondeduced_p=*/true);
+  return walk_template_parms (t, template_parm_this_level_p, &level, NULL,
+			      /*check_types=*/false,
+			      /*include_nondeduced_p=*/true);
 }
 
 /* Returns TRUE iff INST is an instantiation we don't need to do in an
@@ -19744,6 +19763,30 @@ type_dependent_expression_p (tree expression)
   return (dependent_type_p (TREE_TYPE (expression)));
 }
 
+/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the
+   sense defined by the ABI:
+
+   "An expression is instantiation-dependent if it is type-dependent
+   or value-dependent, or it has a subexpression that is type-dependent
+   or value-dependent."  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  if (!processing_template_decl)
+    return false;
+
+  if (expression == error_mark_node)
+    return false;
+
+  if (!TREE_TYPE (expression))
+    return true;
+
+  return walk_template_parms (expression, /*fn=*/NULL, NULL, NULL,
+			      /*check_types=*/true,
+			      /*include_nondeduced_p=*/true);
+}
+
 /* Like type_dependent_expression_p, but it also works while not processing
    a template definition, i.e. during substitution or mangling.  */
 
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 187012)
+++ cp/semantics.c	(working copy)
@@ -5168,8 +5168,7 @@ finish_decltype_type (tree expr, bool id_expressio
       return error_mark_node;
     }
 
-  /* FIXME instantiation-dependent  */
-  if (type_dependent_expression_p (expr)
+  if (instantiation_dependent_expression_p (expr)
       /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
 	 if it isn't dependent, so that we can check access control at
 	 instantiation time, so defer the decltype as well (PR 42277).  */
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 187012)
+++ cp/cp-tree.h	(working copy)
@@ -5363,6 +5363,7 @@ extern bool any_type_dependent_arguments_p      (c
 extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
+extern bool instantiation_dependent_expression_p(tree);
 extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);


More information about the Gcc-patches mailing list