Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 203044)
+++ gcc/expr.c	(working copy)
@@ -9573,6 +9573,7 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 	align = get_object_alignment (exp);
 	if (modifier != EXPAND_WRITE
 	    && modifier != EXPAND_MEMORY
+	    && modifier != EXPAND_REFERENCE
 	    && mode != BLKmode
 	    && align < GET_MODE_ALIGNMENT (mode)
 	    /* If the target does not have special handling for unaligned
@@ -9653,6 +9654,7 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 	  MEM_VOLATILE_P (temp) = 1;
 	if (modifier != EXPAND_WRITE
 	    && modifier != EXPAND_MEMORY
+	    && modifier != EXPAND_REFERENCE
 	    && mode != BLKmode
 	    && align < GET_MODE_ALIGNMENT (mode))
 	  {
@@ -9886,7 +9888,7 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 			  && modifier != EXPAND_STACK_PARM
 			  ? target : NULL_RTX),
 			 VOIDmode,
-			 modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+			 EXPAND_REFERENCE);
 
 	/* If the bitfield is volatile, we want to access it in the
 	   field's mode, not the computed mode.
@@ -10245,7 +10247,7 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 			      && modifier != EXPAND_STACK_PARM
 			      ? target : NULL_RTX),
 			     VOIDmode,
-			     modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+			     EXPAND_REFERENCE);
 
 	    if (MEM_P (orig_op0))
 	      {
@@ -10339,7 +10341,10 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 	      op0 = copy_rtx (op0);
 	      set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
 	    }
-	  else if (mode != BLKmode
+	  else if (modifier != EXPAND_WRITE
+		   && modifier != EXPAND_MEMORY
+		   && modifier != EXPAND_REFERENCE
+		   && mode != BLKmode
 		   && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)
 		   /* If the target does have special handling for unaligned
 		      loads of mode then use them.  */
@@ -10360,6 +10365,9 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
 	      return reg;
 	    }
 	  else if (STRICT_ALIGNMENT
+		   && modifier != EXPAND_WRITE
+		   && modifier != EXPAND_MEMORY
+		   && modifier != EXPAND_REFERENCE
 		   && mode != BLKmode
 		   && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
 	    {
Index: gcc/expr.h
===================================================================
--- gcc/expr.h	(revision 203044)
+++ gcc/expr.h	(working copy)
@@ -41,10 +41,13 @@ along with GCC; see the file COPYING3.  If not see
     is a constant that is not a legitimate address.
    EXPAND_WRITE means we are only going to write to the resulting rtx.
    EXPAND_MEMORY means we are interested in a memory result, even if
-    the memory is constant and we could have propagated a constant value.  */
+    the memory is constant and we could have propagated a constant value,
+    or the memory is unaligned on a STRICT_ALIGNMENT target.
+   EXPAND_REFERENCE is similar to EXPAND_MEMORY, used internally to expand
+    the inner reference of a component.  */
 enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM, EXPAND_SUM,
 		      EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE,
-		      EXPAND_MEMORY};
+		      EXPAND_MEMORY, EXPAND_REFERENCE};
 
 /* Prevent the compiler from deferring stack pops.  See
    inhibit_defer_pop for more information.  */
Index: gcc/testsuite/gcc.dg/torture/pr57748-3.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr57748-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr57748-3.c	(revision 0)
@@ -0,0 +1,40 @@
+/* PR middle-end/57748 */
+/* { dg-do run } */
+/* wrong code in expand_expr_real_1.  */
+
+#include <stdlib.h>
+
+extern void abort (void);
+
+typedef long long V
+  __attribute__ ((vector_size (2 * sizeof (long long)), may_alias));
+
+typedef struct S { V a; V b[0]; } P __attribute__((aligned (1)));
+
+struct __attribute__((packed)) T { char c; P s; };
+
+void __attribute__((noinline, noclone))
+check (P *p)
+{
+  if (p->b[0][0] != 3 || p->b[0][1] != 4)
+    abort ();
+}
+
+void __attribute__((noinline, noclone))
+foo (struct T *t)
+{
+  V a = { 3, 4 };
+  t->s.b[0] = a;
+}
+
+int
+main ()
+{
+  struct T *t = (struct T *) calloc (128, 1);
+
+  foo (t);
+  check (&t->s);
+
+  free (t);
+  return 0;
+}
