diff mbox

[RFH,/] PR 51222

Message ID 4FA0A39C.5030404@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 2, 2012, 3:01 a.m. UTC
Hi,

On 05/02/2012 03:47 AM, Jason Merrill wrote:
> On 05/01/2012 08:14 PM, Paolo Carlini wrote:
>>> I think we need to handle FIELD_DECL, too.
>> Are there hopes that handling FIELD_DECL like FUNCTION_DECL and VAR_DECL
>> (besides the DECL_LANG_SPECIFIC check) would work?
> I would think so.
Ok, if we want it, I adjusted the code, see attached.
>> A data point I can give you, I put a gcc_assert (TREE_CODE (t) != 
>> FIELD_DECL) in the default case of the walk_template_parms_r switch, 
>> and it never triggers for the whole testsuite.
>
> With your patch, what happens if you have a member access like
>
> template <class T>
> struct A
> {
>   T t;
>   auto f(A a) -> decltype (sizeof (a.t)) { }
> };
>
> I would expect that to hit the FIELD_DECL case.
Well, not really. The first time walk_template_parms_r is called, t is a 
SIZEOF_EXPR which remains unhandled, the function returns NULL_TREE. The 
second time, t is a COMPONENT_REF, thus !TYPE_P (t) is true, TREE_TYPE 
is NULL, the function immediately returns error_mark_node and the 
iteration ends (with the correct result that the expression is 
instantiation-dependent).

Does it make sense?

Anyway, the attached appear to also pass the testsuite, I could test it 
more completely tomorrow. If the FIELD_DECL bits seem safe to have... ;)

Thanks,
Paolo.

Comments

Jason Merrill May 2, 2012, 3:03 p.m. UTC | #1
On 05/01/2012 11:01 PM, Paolo Carlini wrote:
> Well, not really. The first time walk_template_parms_r is called, t is a
> SIZEOF_EXPR which remains unhandled, the function returns NULL_TREE. The
> second time, t is a COMPONENT_REF, thus !TYPE_P (t) is true, TREE_TYPE
> is NULL, the function immediately returns error_mark_node and the
> iteration ends (with the correct result that the expression is
> instantiation-dependent).

Ah, I guess we can't get to a FIELD_DECL without going through an 
expression with null type.  OK, can leave out the FIELD_DECL case then 
with a comment.

> I also booted and tested a variant, attached, which changes finish_static_assert to also use instantiation_dependent_expression_p and also passes testing: nice, between front-end and library we stress the new function quite a bit more.

Great.  Let's also use it for sizeof/alignof, controlled with 
abi_version_at_least (7), since it affects mangling.  And then figure 
out what we're going to to about ABI transition in 4.8...

Jason
diff mbox

Patch

Index: pt.c
===================================================================
--- pt.c	(revision 187012)
+++ 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,26 +7752,34 @@  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;
   tree_fn_t fn = pfd->fn;
   void *data = pfd->data;
 
+  /* If the type is null, this is a type-dependent expression, and if
+     we're checking types, we would find the relevant template parameters.
+     And fn must be null, so we can just return.  */ 
+  if (pfd->check_types && !TYPE_P (t) && TREE_TYPE (t) == NULL_TREE)
+    return error_mark_node;
+
   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 +7793,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 +7838,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 +7852,48 @@  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))
+    case FIELD_DECL:
+      if ((TREE_CODE (t) == FIELD_DECL
+	   || DECL_LANG_SPECIFIC (t)) && DECL_TEMPLATE_INFO (t)
+	  && 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 +7909,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 +7920,27 @@  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;
-      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))
+      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 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 +7949,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 non-null, 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;
 
+  gcc_assert (!check_types || !fn);
+
   /* Set up.  */
   pfd.fn = 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 +7991,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 +8052,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 +19762,27 @@  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;
+
+  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: semantics.c
===================================================================
--- semantics.c	(revision 187012)
+++ 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).  */
@@ -8171,7 +8170,7 @@  potential_constant_expression_1 (tree t, bool want
       /* -- a reinterpret_cast.  FIXME not implemented, and this rule
 	 may change to something more specific to type-punning (DR 1312).  */
       {
-        tree from = TREE_OPERAND (t, 0);
+	tree from = TREE_OPERAND (t, 0);
         return (potential_constant_expression_1
 		(from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
       }
Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 187012)
+++ 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);