diff mbox series

[committed] d: Fix ICE in gimplify_var_or_parm_decl, at gimplify.c:2755 (PR100882)

Message ID 20210604185337.2476201-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Fix ICE in gimplify_var_or_parm_decl, at gimplify.c:2755 (PR100882) | expand

Commit Message

Iain Buclaw June 4, 2021, 6:53 p.m. UTC
Hi,

Constructor calls for temporaries were reusing the TARGET_EXPR_SLOT of a
TARGET_EXPR for an assignment, which later got passed to `build_assign',
which stripped away the outer TARGET_EXPR, leaving a reference to a lone
temporary with no declaration.

This stripping away of the TARGET_EXPR also discarded any cleanups that
may have been assigned to the expression as well.

So now the reuse of TARGET_EXPR_SLOT has been removed, and
`build_assign' now constructs assignments inside the TARGET_EXPR_INITIAL
slot.  This has also been extended to `return_expr', to deal with
possibility of a TARGET_EXPR being returned.

Bootstrapped and regression tested on x86_64-linux-gnu{-m32,-mx32},
committed to mainline, and backported to the releases/gcc-9,
releases/gcc-10, and releases/gcc-11 branches.

Regards,
Iain.

---
gcc/d/ChangeLog:

	PR d/100882
	* d-codegen.cc (build_assign): Construct initializations inside
	TARGET_EXPR_INITIAL.
	(compound_expr): Remove intermediate expressions that have no
	side-effects.
	(return_expr): Construct returns inside TARGET_EXPR_INITIAL.
	* expr.cc (ExprVisitor::visit (CallExp *)): Remove useless assignment
	to TARGET_EXPR_SLOT.

gcc/testsuite/ChangeLog:

	PR d/100882
	* gdc.dg/pr100882a.d: New test.
	* gdc.dg/pr100882b.d: New test.
	* gdc.dg/pr100882c.d: New test.
	* gdc.dg/torture/pr100882.d: New test.
---
 gcc/d/d-codegen.cc                      | 36 ++++++++++++++++++++-----
 gcc/d/expr.cc                           |  7 +----
 gcc/testsuite/gdc.dg/pr100882a.d        | 35 ++++++++++++++++++++++++
 gcc/testsuite/gdc.dg/pr100882b.d        | 19 +++++++++++++
 gcc/testsuite/gdc.dg/pr100882c.d        | 25 +++++++++++++++++
 gcc/testsuite/gdc.dg/torture/pr100882.d | 21 +++++++++++++++
 6 files changed, 131 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gdc.dg/pr100882a.d
 create mode 100644 gcc/testsuite/gdc.dg/pr100882b.d
 create mode 100644 gcc/testsuite/gdc.dg/pr100882c.d
 create mode 100644 gcc/testsuite/gdc.dg/torture/pr100882.d
diff mbox series

Patch

diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 5fa1acd9240..9a9447371aa 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1330,6 +1330,7 @@  component_ref (tree object, tree field)
 tree
 build_assign (tree_code code, tree lhs, tree rhs)
 {
+  tree result;
   tree init = stabilize_expr (&lhs);
   init = compound_expr (init, stabilize_expr (&rhs));
 
@@ -1348,22 +1349,27 @@  build_assign (tree_code code, tree lhs, tree rhs)
   if (TREE_CODE (rhs) == TARGET_EXPR)
     {
       /* If CODE is not INIT_EXPR, can't initialize LHS directly,
-	 since that would cause the LHS to be constructed twice.
-	 So we force the TARGET_EXPR to be expanded without a target.  */
+	 since that would cause the LHS to be constructed twice.  */
       if (code != INIT_EXPR)
 	{
 	  init = compound_expr (init, rhs);
-	  rhs = TARGET_EXPR_SLOT (rhs);
+	  result = build_assign (code, lhs, TARGET_EXPR_SLOT (rhs));
 	}
       else
 	{
 	  d_mark_addressable (lhs);
-	  rhs = TARGET_EXPR_INITIAL (rhs);
+	  TARGET_EXPR_INITIAL (rhs) = build_assign (code, lhs,
+						    TARGET_EXPR_INITIAL (rhs));
+	  result = rhs;
 	}
     }
+  else
+    {
+      /* Simple assignment.  */
+      result = fold_build2_loc (input_location, code,
+				TREE_TYPE (lhs), lhs, rhs);
+    }
 
-  tree result = fold_build2_loc (input_location, code,
-				 TREE_TYPE (lhs), lhs, rhs);
   return compound_expr (init, result);
 }
 
@@ -1485,6 +1491,11 @@  compound_expr (tree arg0, tree arg1)
   if (arg0 == NULL_TREE || !TREE_SIDE_EFFECTS (arg0))
     return arg1;
 
+  /* Remove intermediate expressions that have no side-effects.  */
+  while (TREE_CODE (arg0) == COMPOUND_EXPR
+	 && !TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
+    arg0 = TREE_OPERAND (arg0, 0);
+
   if (TREE_CODE (arg1) == TARGET_EXPR)
     {
       /* If the rhs is a TARGET_EXPR, then build the compound expression
@@ -1505,6 +1516,19 @@  compound_expr (tree arg0, tree arg1)
 tree
 return_expr (tree ret)
 {
+  /* Same as build_assign, the DECL_RESULT assignment replaces the temporary
+     in TARGET_EXPR_SLOT.  */
+  if (ret != NULL_TREE && TREE_CODE (ret) == TARGET_EXPR)
+    {
+      tree exp = TARGET_EXPR_INITIAL (ret);
+      tree init = stabilize_expr (&exp);
+
+      exp = fold_build1_loc (input_location, RETURN_EXPR, void_type_node, exp);
+      TARGET_EXPR_INITIAL (ret) = compound_expr (init, exp);
+
+      return ret;
+    }
+
   return fold_build1_loc (input_location, RETURN_EXPR,
 			  void_type_node, ret);
 }
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index aad7cbbf947..e76cae98f7e 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1894,15 +1894,10 @@  public:
       exp = d_convert (build_ctype (e->type), exp);
 
     /* If this call was found to be a constructor for a temporary with a
-       cleanup, then move the call inside the TARGET_EXPR.  The original
-       initializer is turned into an assignment, to keep its side effect.  */
+       cleanup, then move the call inside the TARGET_EXPR.  */
     if (cleanup != NULL_TREE)
       {
 	tree init = TARGET_EXPR_INITIAL (cleanup);
-	tree slot = TARGET_EXPR_SLOT (cleanup);
-	d_mark_addressable (slot);
-	init = build_assign (INIT_EXPR, slot, init);
-
 	TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
 	exp = cleanup;
       }
diff --git a/gcc/testsuite/gdc.dg/pr100882a.d b/gcc/testsuite/gdc.dg/pr100882a.d
new file mode 100644
index 00000000000..de92ab3bef1
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr100882a.d
@@ -0,0 +1,35 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100882
+// { dg-do compile }
+
+struct AllocatorList(Factory)
+{
+    Factory factory;
+    auto make(size_t n) { return factory(n); }
+    this(Factory plant)
+    {
+        factory = plant;
+    }
+}
+
+struct Region
+{
+    ~this()
+    {
+    }
+}
+
+auto mmapRegionList()
+{
+    struct Factory
+    {
+        this(size_t )
+        {
+        }
+        auto opCall(size_t )
+        {
+            return Region();
+        }
+    }
+    auto shop = Factory();
+    AllocatorList!Factory(shop);
+}
diff --git a/gcc/testsuite/gdc.dg/pr100882b.d b/gcc/testsuite/gdc.dg/pr100882b.d
new file mode 100644
index 00000000000..deaa4b44a16
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr100882b.d
@@ -0,0 +1,19 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100882
+// { dg-do compile }
+
+auto iota(int, int)
+{
+    struct Result
+    {
+        this(int)
+        {
+        }
+    }
+    return Result();
+}
+
+auto iota(int end)
+{
+    int begin;
+    return iota(begin, end);
+}
diff --git a/gcc/testsuite/gdc.dg/pr100882c.d b/gcc/testsuite/gdc.dg/pr100882c.d
new file mode 100644
index 00000000000..f4e6e4d3651
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr100882c.d
@@ -0,0 +1,25 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100882
+// { dg-do compile }
+
+struct CowArray
+{
+    this(this)
+    {
+    }
+}
+
+struct Tuple
+{
+    CowArray expand;
+}
+
+auto tuple(CowArray)
+{
+    return Tuple();
+}
+
+auto parseCharTerm()
+{
+    CowArray set;
+    return tuple(set);
+}
diff --git a/gcc/testsuite/gdc.dg/torture/pr100882.d b/gcc/testsuite/gdc.dg/torture/pr100882.d
new file mode 100644
index 00000000000..d94baff97ac
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/pr100882.d
@@ -0,0 +1,21 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100882
+// { dg-additional-options "-fmain" }
+// { dg-do run }
+
+__gshared int counter = 0;
+struct S100882
+{
+    this(int) { counter++; }
+    ~this() { counter++; }
+}
+static S100882 s;
+static this()
+{
+    s = cast(shared) S100882(0);
+    assert(counter == 2);
+}
+
+auto test100882()
+{
+    return cast(shared) S100882(0);
+}