aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/expr.cc9
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr114552.c24
2 files changed, 30 insertions, 3 deletions
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 2918c46..8a1875d 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -5466,6 +5466,7 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
/* If source is a constant VAR_DECL with a simple constructor,
store the constructor to the stack instead of moving it. */
const_tree decl;
+ HOST_WIDE_INT sz;
if (partial == 0
&& MEM_P (xinner)
&& SYMBOL_REF_P (XEXP (xinner, 0))
@@ -5473,9 +5474,11 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
&& VAR_P (decl)
&& TREE_READONLY (decl)
&& !TREE_SIDE_EFFECTS (decl)
- && immediate_const_ctor_p (DECL_INITIAL (decl), 2))
- store_constructor (DECL_INITIAL (decl), target, 0,
- int_expr_size (DECL_INITIAL (decl)), false);
+ && immediate_const_ctor_p (DECL_INITIAL (decl), 2)
+ && (sz = int_expr_size (DECL_INITIAL (decl))) > 0
+ && CONST_INT_P (size)
+ && INTVAL (size) == sz)
+ store_constructor (DECL_INITIAL (decl), target, 0, sz, false);
else
emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM);
}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr114552.c b/gcc/testsuite/gcc.c-torture/execute/pr114552.c
new file mode 100644
index 0000000..22cb4ee
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr114552.c
@@ -0,0 +1,24 @@
+/* PR middle-end/114552 */
+
+struct __attribute__((packed)) S { short b; int c; };
+struct T { struct S b; int e; };
+static const struct T k = { { 1, 0 }, 0 };
+
+__attribute__((noinline)) void
+foo (void)
+{
+ asm volatile ("" : : : "memory");
+}
+
+__attribute__((noinline)) void
+bar (struct S n)
+{
+ foo ();
+}
+
+int
+main ()
+{
+ bar (k.b);
+ return 0;
+}