When RTL expansion of an out-of-bound access of a register falls
back to a BIT_FIELD_REF we have to ensure that's valid.  The
following avoids negative offsets by expanding through a stack
temporary.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

OK if that succeeds?

Thanks,
Richard.

        PR middle-end/118643
        * expr.cc (expand_expr_real_1): Avoid falling back to BIT_FIELD_REF
        expansion for negative offset.

        * gcc.dg/pr118643.c: New testcase.
---
 gcc/expr.cc                     |  8 +++++---
 gcc/testsuite/gcc.dg/pr118643.c | 11 +++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr118643.c

diff --git a/gcc/expr.cc b/gcc/expr.cc
index a310b2d9131..4bfcde54523 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -11796,13 +11796,15 @@ expand_expr_real_1 (tree exp, rtx target, 
machine_mode tmode,
                && known_eq (GET_MODE_BITSIZE (DECL_MODE (base)), type_size))
              return expand_expr (build1 (VIEW_CONVERT_EXPR, type, base),
                                  target, tmode, modifier);
-           if (TYPE_MODE (type) == BLKmode)
+           if (TYPE_MODE (type) == BLKmode
+               || maybe_lt (offset, 0))
              {
                temp = assign_stack_temp (DECL_MODE (base),
                                          GET_MODE_SIZE (DECL_MODE (base)));
                store_expr (base, temp, 0, false, false);
-               temp = adjust_address (temp, BLKmode, offset);
-               set_mem_size (temp, int_size_in_bytes (type));
+               temp = adjust_address (temp, TYPE_MODE (type), offset);
+               if (TYPE_MODE (type) == BLKmode)
+                 set_mem_size (temp, int_size_in_bytes (type));
                return temp;
              }
            exp = build3 (BIT_FIELD_REF, type, base, TYPE_SIZE (type),
diff --git a/gcc/testsuite/gcc.dg/pr118643.c b/gcc/testsuite/gcc.dg/pr118643.c
new file mode 100644
index 00000000000..ff2b081ae0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118643.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef __attribute__((__vector_size__(1))) unsigned char V;
+
+V x;
+void foo()
+{
+  V v = x;
+  x = *(V *)(&v - 1);
+}
-- 
2.43.0

Reply via email to