Fix segfault on discriminated record type

Message ID
State New
Headers show

Commit Message

Eric Botcazou Oct. 20, 2010, 11:06 a.m.
This is a regression present on the mainline and 4.5 branch: the gimplifier 
crashes during the placeholder substitution in maybe_with_size_expr on an 
assignment statement involving a self-referential size.  The root cause of 
the problem is the way COND_EXPR is gimplified, namely by modifying the node 
in place instead of building a new one.  But this has been so since day #1 so 
should probably be left as-is.

It turns out that the COND_EXPR should never have come into play here because 
COND_EXPRs are meant to be factored out in self-referential size expressions; 
that was the initial design of size functions.  This doesn't happen any more 
in some cases because skip_simple_arithmetic sometimes skips more than simple 
arithmetic operations; this was changed when TREE_INVARIANT was replaced with 
the tree_invariant_p predicate.  That's probably a good thing in most cases 
but, for size functions, we really want to get only simple operations.

So the patch introduces skip_simple_constant_arithmetic, which is equivalent 
to the old skip_simple_arithmetic with s/TREE_INVARIANT/TREE_CONSTANT/ and 
uses it for size functions, thus bringing us back to the original design.

Tested on i586-suse-linux, applied on the mainline and 4.5 branch as obvious.
This only affects the Ada compiler.

2010-10-20  Eric Botcazou  <>

	* stor-layout.c (skip_simple_constant_arithmetic): New function.
	(self_referential_size): Use it instead of skip_simple_arithmetic.

2010-10-20  Eric Botcazou  <>

	* gnat.dg/discr25.adb: New test.
	* gnat.dg/[sb]: New helper.


Index: stor-layout.c
--- stor-layout.c	(revision 165610)
+++ stor-layout.c	(working copy)
@@ -173,6 +173,32 @@  variable_size (tree size)
 /* An array of functions used for self-referential size computation.  */
 static GTY(()) VEC (tree, gc) *size_functions;
+/* Look inside EXPR into simple arithmetic operations involving constants.
+   Return the outermost non-arithmetic or non-constant node.  */
+static tree
+skip_simple_constant_arithmetic (tree expr)
+  while (true)
+    {
+      if (UNARY_CLASS_P (expr))
+	expr = TREE_OPERAND (expr, 0);
+      else if (BINARY_CLASS_P (expr))
+	{
+	  if (TREE_CONSTANT (TREE_OPERAND (expr, 1)))
+	    expr = TREE_OPERAND (expr, 0);
+	  else if (TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+	    expr = TREE_OPERAND (expr, 1);
+	  else
+	    break;
+	}
+      else
+	break;
+    }
+  return expr;
 /* Similar to copy_tree_r but do not copy component references involving
    PLACEHOLDER_EXPRs.  These nodes are spotted in find_placeholder_in_expr
    and substituted in substitute_in_expr.  */
@@ -241,7 +267,7 @@  self_referential_size (tree size)
   VEC(tree,gc) *args = NULL;
   /* Do not factor out simple operations.  */
-  t = skip_simple_arithmetic (size);
+  t = skip_simple_constant_arithmetic (size);
   if (TREE_CODE (t) == CALL_EXPR)
     return size;