gimplify.c (gimplify_call_expr): Make return in memory explicit.
authorJason Merrill <jason@redhat.com>
Sat, 7 Aug 2004 16:11:10 +0000 (12:11 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 7 Aug 2004 16:11:10 +0000 (12:11 -0400)
        * gimplify.c (gimplify_call_expr): Make return in memory explicit.
        (gimplify_modify_expr_rhs): Likewise.
        * c-common.c (c_warn_unused_result): Check TREE_USED before
        warning about a CALL_EXPR with an unused value.

From-SVN: r85671

gcc/ChangeLog
gcc/c-common.c
gcc/gimplify.c

index a55a3d92921322ed9b91fe956a866ee3d5eb9774..80dec91322456ea9522482a7972028b2780f4d92 100644 (file)
@@ -1,3 +1,10 @@
+2004-08-07  Jason Merrill  <jason@redhat.com>
+
+       * gimplify.c (gimplify_call_expr): Make return in memory explicit.
+       (gimplify_modify_expr_rhs): Likewise.
+       * c-common.c (c_warn_unused_result): Check TREE_USED before
+       warning about a CALL_EXPR with an unused value.
+
 2004-08-06  Mark Mitchell  <mark@codesourcery.com>
 
        * config/arm/symbian.h (CC1_SPEC): Avoid passing duplicate options
index c3dc4ea6359ce357481aaa5c21636c4d3c9cd36d..868088f0e1c3dce7f7e976e4989545578a223f06 100644 (file)
@@ -5378,6 +5378,9 @@ c_warn_unused_result (tree *top_p)
       break;
 
     case CALL_EXPR:
+      if (TREE_USED (t))
+       break;
+
       /* This is a naked call, as opposed to a CALL_EXPR nested inside
         a MODIFY_EXPR.  All calls whose value is ignored should be
         represented like this.  Look for the attribute.  */
index 53cf1feac32494457a51bd9e0b5bb75d7d362e47..cd2a4a0beecc6dd346d5ee7dccbd0f904b864db5 100644 (file)
@@ -1805,6 +1805,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   tree decl;
   tree arglist;
   enum gimplify_status ret;
+  tree slot;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != CALL_EXPR)
@@ -1867,6 +1868,19 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
   ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
                       is_gimple_call_addr, fb_rvalue);
 
+  /* Make the return slot explicit if it isn't already.  */
+  if (aggregate_value_p (*expr_p, decl)
+      && !CALL_EXPR_HAS_RETURN_SLOT_ADDR (*expr_p))
+    {
+      slot = create_tmp_var (TREE_TYPE (*expr_p), NULL);
+      arglist = build_fold_addr_expr (slot);
+      arglist = tree_cons (NULL_TREE, arglist, TREE_OPERAND (*expr_p, 1));
+      TREE_OPERAND (*expr_p, 1) = arglist;
+      CALL_EXPR_HAS_RETURN_SLOT_ADDR (*expr_p) = 1;
+    }
+  else
+    slot = NULL_TREE;
+
   if (PUSH_ARGS_REVERSED)
     TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
   for (arglist = TREE_OPERAND (*expr_p, 1); arglist;
@@ -1904,6 +1918,22 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
       && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
     TREE_SIDE_EFFECTS (*expr_p) = 0;
 
+  /* If we have a return slot, use it in the containing expression.  */
+  if (want_value && CALL_EXPR_HAS_RETURN_SLOT_ADDR (*expr_p))
+    {
+      /* Don't warn about an unused return value.  */
+      TREE_USED (*expr_p) = 1;
+
+      if (slot == NULL_TREE)
+       {
+         slot = TREE_OPERAND (*expr_p, 1);
+         slot = TREE_VALUE (slot);
+         slot = build_fold_indirect_ref (slot);
+       }
+      append_to_statement_list (*expr_p, pre_p);
+      *expr_p = slot;
+    }
+
   return ret;
 }
 
@@ -2706,6 +2736,39 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
          ret = GS_UNHANDLED;
        break;
 
+      case CALL_EXPR:
+       /* Transform 'a = f();' to 'f(&a), a' if f returns in memory.  */
+       if (aggregate_value_p (*from_p, *from_p))
+         {
+           tree arg;
+           if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (*from_p))
+             abort ();
+
+           ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue,
+                                fb_lvalue);
+           if (ret == GS_ERROR)
+             return ret;
+
+           arg = build_fold_addr_expr (*to_p);
+           arg = tree_cons (NULL_TREE, arg, TREE_OPERAND (*from_p, 1));
+           TREE_OPERAND (*from_p, 1) = arg;
+           CALL_EXPR_HAS_RETURN_SLOT_ADDR (*from_p) = 1;
+           /* Don't warn about an unused return value.  */
+           TREE_USED (*from_p) = 1;
+
+           if (want_value)
+             {
+               gimplify_and_add (*from_p, pre_p);
+               *expr_p = *to_p;
+             }
+           else
+             *expr_p = *from_p;
+           return GS_OK;
+         }
+       else
+         ret = GS_UNHANDLED;
+       break;
+
       default:
        ret = GS_UNHANDLED;
        break;
@@ -3021,12 +3084,14 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
 
     default:
       /* We use fb_either here because the C frontend sometimes takes
-        the address of a call that returns a struct.  */
+        the address of a call that returns a struct; see
+        gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
+        the implied temporary explicit.  */
       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
                           is_gimple_addressable, fb_either);
       if (ret != GS_ERROR)
        {
-         /* The above may have made an INDIRECT ref (e.g, Ada's NULL_EXPR),
+         /* The above may have made an INDIRECT_REF (e.g, Ada's NULL_EXPR),
             so check for it here.  It's not worth checking for the other
             cases above.  */
          if (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF)