Patchwork [Ada] Fix wrong code for size computation

login
register
mail settings
Submitter Eric Botcazou
Date Nov. 3, 2010, 12:15 a.m.
Message ID <201011030115.40151.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/69938/
State New
Headers show

Comments

Eric Botcazou - Nov. 3, 2010, 12:15 a.m.
Another installment in the long-running series of glitches involving a size 
computation in Ada, with an interesting twist: it only happens at -O0, as it 
stems from a bad interaction between the constant folder and the parameter 
attribute cache we use at -O0 exclusively.

Tested on i586-suse-linux, applied on the mainline.


2010-11-02  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/gigi.h (add_stmt_force): Declare.
	(add_stmt_with_node_force): Likewise.
	* gcc-interface/trans.c (Attribute_to_gnu): Don't set TREE_SIDE_EFFECTS
	on the SAVE_EXPR built for cached expressions of parameter attributes.
	(Subprogram_Body_to_gnu): Force evaluation of the SAVE_EXPR built for
	cached expressions of parameter attributes.
	(add_stmt_force): New function.
	(add_stmt_with_node_force): Likewise.


2010-11-02  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/sizetype4.adb: New test.

Patch

Index: gcc-interface/gigi.h
===================================================================
--- gcc-interface/gigi.h	(revision 166172)
+++ gcc-interface/gigi.h	(working copy)
@@ -57,12 +57,19 @@  extern void rest_of_type_decl_compilatio
 /* Start a new statement group chained to the previous group.  */
 extern void start_stmt_group (void);
 
-/* Add GNU_STMT to the current BLOCK_STMT node.  */
+/* Add GNU_STMT to the current statement group.  If it is an expression with
+   no effects, it is ignored.  */
 extern void add_stmt (tree gnu_stmt);
 
-/* Similar, but set the location of GNU_STMT to that of GNAT_NODE.  */
+/* Similar, but the statement is always added, regardless of side-effects.  */
+extern void add_stmt_force (tree gnu_stmt);
+
+/* Like add_stmt, but set the location of GNU_STMT to that of GNAT_NODE.  */
 extern void add_stmt_with_node (tree gnu_stmt, Node_Id gnat_node);
 
+/* Similar, but the statement is always added, regardless of side-effects.  */
+extern void add_stmt_with_node_force (tree gnu_stmt, Node_Id gnat_node);
+
 /* Return code corresponding to the current code group.  It is normally
    a STATEMENT_LIST, but may also be a BIND_EXPR or TRY_FINALLY_EXPR if
    BLOCK or cleanups were set.  */
Index: gcc-interface/trans.c
===================================================================
--- gcc-interface/trans.c	(revision 166172)
+++ gcc-interface/trans.c	(working copy)
@@ -1739,12 +1739,13 @@  Attribute_to_gnu (Node_Id gnat_node, tre
 
 	/* Cache the expression we have just computed.  Since we want to do it
 	   at run time, we force the use of a SAVE_EXPR and let the gimplifier
-	   create the temporary.  */
+	   create the temporary in the outermost binding level.  We will make
+	   sure in Subprogram_Body_to_gnu that it is evaluated on all possible
+	   paths by forcing its evaluation on entry of the function.  */
 	if (pa)
 	  {
 	    gnu_result
 	      = build1 (SAVE_EXPR, TREE_TYPE (gnu_result), gnu_result);
-	    TREE_SIDE_EFFECTS (gnu_result) = 1;
 	    if (attribute == Attr_First)
 	      pa->first = gnu_result;
 	    else if (attribute == Attr_Last)
@@ -2634,8 +2635,9 @@  Subprogram_Body_to_gnu (Node_Id gnat_nod
 
   VEC_pop (tree, gnu_return_label_stack);
 
-  /* If we populated the parameter attributes cache, we need to make sure
-     that the cached expressions are evaluated on all possible paths.  */
+  /* If we populated the parameter attributes cache, we need to make sure that
+     the cached expressions are evaluated on all the possible paths leading to
+     their uses.  So we force their evaluation on entry of the function.  */
   cache = DECL_STRUCT_FUNCTION (gnu_subprog_decl)->language->parm_attr_cache;
   if (cache)
     {
@@ -2647,11 +2649,11 @@  Subprogram_Body_to_gnu (Node_Id gnat_nod
       FOR_EACH_VEC_ELT (parm_attr, cache, i, pa)
 	{
 	  if (pa->first)
-	    add_stmt_with_node (pa->first, gnat_node);
+	    add_stmt_with_node_force (pa->first, gnat_node);
 	  if (pa->last)
-	    add_stmt_with_node (pa->last, gnat_node);
+	    add_stmt_with_node_force (pa->last, gnat_node);
 	  if (pa->length)
-	    add_stmt_with_node (pa->length, gnat_node);
+	    add_stmt_with_node_force (pa->length, gnat_node);
 	}
 
       add_stmt (gnu_result);
@@ -5969,7 +5971,8 @@  start_stmt_group (void)
   current_stmt_group = group;
 }
 
-/* Add GNU_STMT to the current statement group.  */
+/* Add GNU_STMT to the current statement group.  If it is an expression with
+   no effects, it is ignored.  */
 
 void
 add_stmt (tree gnu_stmt)
@@ -5977,7 +5980,15 @@  add_stmt (tree gnu_stmt)
   append_to_statement_list (gnu_stmt, &current_stmt_group->stmt_list);
 }
 
-/* Similar, but set the location of GNU_STMT to that of GNAT_NODE.  */
+/* Similar, but the statement is always added, regardless of side-effects.  */
+
+void
+add_stmt_force (tree gnu_stmt)
+{
+  append_to_statement_list_force (gnu_stmt, &current_stmt_group->stmt_list);
+}
+
+/* Like add_stmt, but set the location of GNU_STMT to that of GNAT_NODE.  */
 
 void
 add_stmt_with_node (tree gnu_stmt, Node_Id gnat_node)
@@ -5987,6 +5998,16 @@  add_stmt_with_node (tree gnu_stmt, Node_
   add_stmt (gnu_stmt);
 }
 
+/* Similar, but the statement is always added, regardless of side-effects.  */
+
+void
+add_stmt_with_node_force (tree gnu_stmt, Node_Id gnat_node)
+{
+  if (Present (gnat_node))
+    set_expr_location_from_node (gnu_stmt, gnat_node);
+  add_stmt_force (gnu_stmt);
+}
+
 /* Add a declaration statement for GNU_DECL to the current statement group.
    Get SLOC from Entity_Id.  */