diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index daad24950ad73cc3a9d77c13128de8d04ee31190..c0e4634def9a411e50acab0f7fbcad5014f3ea8a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2009-12-13  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/42357
+	* tree-sra.c (sra_modify_assign): Do not tear apart struct copies.
+
 2009-12-12  Richard Guenther  <rguenther@suse.de>
 
 	* tree.c (need_assembler_name_p): Abstract decls do not need
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a553545905c43b47e6f2285758ad0a6a3281e434..da700243eacbbd7ab7660a1008d205b89969d863 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-12-13  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/42357
+	* g++.dg/torture/pr42357.C: New testcase.
+
 2009-12-11  Janus Weil  <janus@gcc.gnu.org>
 
 	PR fortran/42257
diff --git a/gcc/testsuite/g++.dg/torture/pr42357.C b/gcc/testsuite/g++.dg/torture/pr42357.C
new file mode 100644
index 0000000000000000000000000000000000000000..1a1d64e4f8e9fb4cffd158de1a9428a2f237ead3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr42357.C
@@ -0,0 +1,30 @@
+// { dg-do compile }
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+class PixelARGB {
+public:
+    ~PixelARGB() throw() { }
+    PixelARGB (const uint32 argb_) throw() : argb (argb_)     { }
+    inline __attribute__((always_inline)) uint8 getRed() const throw() {
+	return components.r;
+    }
+    union     {
+	uint32 argb;
+	struct         {
+	    uint8 b, g, r, a;
+	} components;
+    };
+};
+class Colour {
+public:
+    Colour() throw() : argb (0) {};
+    uint8 getRed() const throw() {
+	return argb.getRed();
+    }
+    PixelARGB argb;
+};
+uint8 writeImage (void) {
+    Colour pixel;
+    pixel = Colour ();
+    return pixel.getRed();
+}
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index a6a1a90d757995a86d3328d8ec1bae752115fde6..8fdbb727607342ea6f871dfe2ead140bef3299af 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -2441,7 +2441,8 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
 	  if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
 	    {
 	      rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs);
-	      if (!is_gimple_reg (lhs))
+	      if (is_gimple_reg_type (TREE_TYPE (lhs))
+		  && TREE_CODE (lhs) != SSA_NAME)
 		force_gimple_rhs = true;
 	    }
 	}