diff --git a/gcc/expr.cc b/gcc/expr.cc index 10467f82c0d24757cf59f28199ee3822bc1c569b..f684e26cef78089ead787976ab8a960f00f29711 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -11796,6 +11796,7 @@ 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); + unsigned align; if (TYPE_MODE (type) == BLKmode || maybe_lt (offset, 0)) { temp = assign_stack_temp (DECL_MODE (base), @@ -11804,6 +11805,17 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, temp = adjust_address (temp, TYPE_MODE (type), offset); if (TYPE_MODE (type) == BLKmode) set_mem_size (temp, int_size_in_bytes (type)); + /* When the original ref was misaligned so will be the + access to the stack temporary. Not all targets handle + this correctly, some will ICE in sanity checking. + Handle this by doing bitfield extraction when necessary. */ + else if ((align = get_object_alignment (exp)) + < GET_MODE_ALIGNMENT (TYPE_MODE (type))) + temp + = expand_misaligned_mem_ref (temp, TYPE_MODE (type), + unsignedp, align, + modifier == EXPAND_STACK_PARM + ? NULL_RTX : target, NULL); return temp; } /* When the access is fully outside of the underlying object diff --git a/gcc/testsuite/gcc.dg/pr118695.c b/gcc/testsuite/gcc.dg/pr118695.c new file mode 100644 index 0000000000000000000000000000000000000000..55e3b767a21c45a4c742f0e9909276b3264ad02d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr118695.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +void * g(int obj) +{ + char *t = (char*)&obj; + t -= 1; + return *(int**)t; +}