cp-gimplify.c (simple_empty_class_p): New.
authorAldy Hernandez <aldyh@redhat.com>
Wed, 11 Mar 2015 15:01:37 +0000 (15:01 +0000)
committerAldy Hernandez <aldyh@gcc.gnu.org>
Wed, 11 Mar 2015 15:01:37 +0000 (15:01 +0000)
* cp-gimplify.c (simple_empty_class_p): New.
* cp-gimplify.c (cp_gimplify_expr): Handle RETURN_EXPR.  Abstract
the code for empty class copies into simple_empty_class_p, and
adapt it to handle COMPOUND_EXPRs.

From-SVN: r221347

gcc/cp/ChangeLog
gcc/cp/cp-gimplify.c
gcc/testsuite/g++.dg/other/empty-class.C [new file with mode: 0644]

index 625b03409ca754b101cfd949723cfb94dc06caae..f350705c3767ea404edbeaadbb3803d11f132857 100644 (file)
@@ -1,3 +1,10 @@
+2015-03-11  Aldy Hernandez  <aldyh@redhat.com>
+
+       * cp-gimplify.c (simple_empty_class_p): New.
+       * cp-gimplify.c (cp_gimplify_expr): Handle RETURN_EXPR.  Abstract
+       the code for empty class copies into simple_empty_class_p, and
+       adapt it to handle COMPOUND_EXPRs.
+
 2015-03-10  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/65370
index 4233a64aefe88da857bee8fb6e1c3cd389fbc51b..70645b59b80449dbea4753a11cb3ec8c83d67573 100644 (file)
@@ -53,6 +53,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
+#include "gimplify.h"
+#include "gimple-expr.h"
 
 /* Forward declarations.  */
 
@@ -528,6 +530,29 @@ gimplify_must_not_throw_expr (tree *expr_p, gimple_seq *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Return TRUE if an operand (OP) of a given TYPE being copied is
+   really just an empty class copy.
+
+   Check that the operand has a simple form so that TARGET_EXPRs and
+   non-empty CONSTRUCTORs get reduced properly, and we leave the
+   return slot optimization alone because it isn't a copy.  */
+
+static bool
+simple_empty_class_p (tree type, tree op)
+{
+  return
+    ((TREE_CODE (op) == COMPOUND_EXPR
+      && simple_empty_class_p (type, TREE_OPERAND (op, 1)))
+     || is_gimple_lvalue (op)
+     || INDIRECT_REF_P (op)
+     || (TREE_CODE (op) == CONSTRUCTOR
+        && CONSTRUCTOR_NELTS (op) == 0
+        && !TREE_CLOBBER_P (op))
+     || (TREE_CODE (op) == CALL_EXPR
+        && !CALL_EXPR_RETURN_SLOT_OPT (op)))
+    && is_really_empty_class (type);
+}
+
 /* Do C++-specific gimplification.  Args are as for gimplify_expr.  */
 
 int
@@ -597,6 +622,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
        return GS_OK;
       /* Otherwise fall through.  */
     case MODIFY_EXPR:
+    modify_expr_case:
       {
        if (fn_contains_cilk_spawn_p (cfun)
            && cilk_detect_spawn_and_unwrap (expr_p)
@@ -616,31 +642,22 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
          TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
                                              TREE_TYPE (op0), op1);
 
-       else if ((is_gimple_lvalue (op1) || INDIRECT_REF_P (op1)
-                 || (TREE_CODE (op1) == CONSTRUCTOR
-                     && CONSTRUCTOR_NELTS (op1) == 0
-                     && !TREE_CLOBBER_P (op1))
-                 || (TREE_CODE (op1) == CALL_EXPR
-                     && !CALL_EXPR_RETURN_SLOT_OPT (op1)))
-                && is_really_empty_class (TREE_TYPE (op0)))
+       else if (simple_empty_class_p (TREE_TYPE (op0), op1))
          {
-           /* Remove any copies of empty classes.  We check that the RHS
-              has a simple form so that TARGET_EXPRs and non-empty
-              CONSTRUCTORs get reduced properly, and we leave the return
-              slot optimization alone because it isn't a copy (FIXME so it
-              shouldn't be represented as one).
-
-              Also drop volatile variables on the RHS to avoid infinite
-              recursion from gimplify_expr trying to load the value.  */
-           if (!TREE_SIDE_EFFECTS (op1))
-             *expr_p = op0;
-           else if (TREE_THIS_VOLATILE (op1)
-                    && (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
-             *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p),
-                               build_fold_addr_expr (op1), op0);
-           else
-             *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p),
-                               op0, op1);
+           /* Remove any copies of empty classes.  Also drop volatile
+              variables on the RHS to avoid infinite recursion from
+              gimplify_expr trying to load the value.  */
+           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                          is_gimple_lvalue, fb_lvalue);
+           if (TREE_SIDE_EFFECTS (op1))
+             {
+               if (TREE_THIS_VOLATILE (op1)
+                   && (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
+                 op1 = build_fold_addr_expr (op1);
+
+               gimplify_and_add (op1, pre_p);
+             }
+           *expr_p = TREE_OPERAND (*expr_p, 0);
          }
       }
       ret = GS_OK;
@@ -740,6 +757,19 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
        }
       break;
 
+    case RETURN_EXPR:
+      if (TREE_OPERAND (*expr_p, 0)
+         && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR
+             || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR))
+       {
+         expr_p = &TREE_OPERAND (*expr_p, 0);
+         code = TREE_CODE (*expr_p);
+         /* Avoid going through the INIT_EXPR case, which can
+            degrade INIT_EXPRs into AGGR_INIT_EXPRs.  */
+         goto modify_expr_case;
+       }
+      /* Fall through.  */
+
     default:
       ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p);
       break;
diff --git a/gcc/testsuite/g++.dg/other/empty-class.C b/gcc/testsuite/g++.dg/other/empty-class.C
new file mode 100644 (file)
index 0000000..a14c437
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple" } */
+
+/* Test that we return retval directly, instead of going through an
+   intermediate temporary, when returning an empty class.  */
+
+class obj {
+  public:
+   obj(int);
+};
+
+obj funky(){
+    return obj(555);
+}
+
+/* { dg-final { scan-tree-dump-times "return <retval>;" 1 "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */