diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 870b1e5..5435c48 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,21 @@
 2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
 
+	* tree-sra.c (instantiate_missing_elements): Canonicalize
+	bit-field types.
+	(sra_build_assignment): New.
+	(generate_copy_inout, generate_element_copy,
+	generate_element_zero, generate_one_element_init): Use it.
+
+2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
+
+	* tree-sra.c (instantiate_missing_elements): Canonicalize
+	bit-field types.
+	(sra_build_assignment): New.
+	(generate_copy_inout, generate_element_copy,
+	generate_element_zero, generate_one_element_init): Use it.
+
+2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
+
 	* dwarf2out.c (dwarf2out_finish): Accept namespaces as context of
 	limbo die nodes.
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2c93af2..bd936c0 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,13 @@
 2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
 
+	* g++.dg/tree-ssa/sra-1.C: New.
+
+2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
+
+	* g++.dg/tree-ssa/sra-1.C: New.
+
+2007-02-15  Alexandre Oliva  <aoliva@redhat.com>
+
 	* g++.dg/ext/interface4.C, g++.dg/ext/interface4.h: New.
 
 2007-02-14  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
diff --git a/gcc/testsuite/g++.dg/tree-ssa/sra-1.C b/gcc/testsuite/g++.dg/tree-ssa/sra-1.C
new file mode 100644
index 0000000..e3e3918
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/sra-1.C
@@ -0,0 +1,29 @@
+/* https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=223576 */
+
+/* SRA failed to canonicalize bit-field types, introducing type
+   mismatches.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+struct A
+{
+  int a:16;
+  /* These dummy bit-fields are here to prevent GCC 4.2+ from merging
+     the bit-field compares into a single word compare, which disables
+     SRA.  */
+  int a2:16;
+  int a3:16;
+  int a4:16;
+  int b:8;
+  bool operator==(A const x) const
+  {
+    return (this->a == x.a && this->b == x.b);
+  }
+};
+
+bool
+foo (A const x, A const y)
+{
+  return x == y;
+}
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index e4a1107..364c763 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -1,7 +1,8 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007
+     Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -1355,7 +1356,23 @@ instantiate_missing_elements (struct sra_elt *elt)
 	tree f;
 	for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
 	  if (TREE_CODE (f) == FIELD_DECL)
-	    instantiate_missing_elements_1 (elt, f, TREE_TYPE (f));
+	    {
+	      tree field_type = TREE_TYPE (f);
+
+	      /* canonicalize_component_ref() unwidens some bit-field
+		 types (not marked as DECL_BIT_FIELD in C++), so we
+		 must do the same, lest we may introduce type
+		 mismatches.  */
+	      if (INTEGRAL_TYPE_P (field_type)
+		  && DECL_MODE (f) != TYPE_MODE (field_type))
+		field_type = TREE_TYPE (get_unwidened (build3 (COMPONENT_REF,
+							       field_type,
+							       elt->element,
+							       f, NULL_TREE),
+						       NULL_TREE));
+
+	      instantiate_missing_elements_1 (elt, f, field_type);
+	    }
 	break;
       }
 
@@ -1706,6 +1723,14 @@ generate_element_ref (struct sra_elt *elt)
     return elt->element;
 }
 
+static tree
+sra_build_assignment (tree dst, tree src)
+{
+  gcc_assert (TYPE_CANONICAL (TYPE_MAIN_VARIANT (TREE_TYPE (dst)))
+	      == TYPE_CANONICAL (TYPE_MAIN_VARIANT (TREE_TYPE (src))));
+  return build2 (GIMPLE_MODIFY_STMT, void_type_node, dst, src);
+}
+
 /* Generate a set of assignment statements in *LIST_P to copy all
    instantiated elements under ELT to or from the equivalent structure
    rooted at EXPR.  COPY_OUT controls the direction of the copy, with
@@ -1729,16 +1754,16 @@ generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
       i = c->replacement;
 
       t = build2 (COMPLEX_EXPR, elt->type, r, i);
-      t = build2 (GIMPLE_MODIFY_STMT, void_type_node, expr, t);
+      t = sra_build_assignment (expr, t);
       SSA_NAME_DEF_STMT (expr) = t;
       append_to_statement_list (t, list_p);
     }
   else if (elt->replacement)
     {
       if (copy_out)
-	t = build2 (GIMPLE_MODIFY_STMT, void_type_node, elt->replacement, expr);
+	t = sra_build_assignment (elt->replacement, expr);
       else
-	t = build2 (GIMPLE_MODIFY_STMT, void_type_node, expr, elt->replacement);
+	t = sra_build_assignment (expr, elt->replacement);
       append_to_statement_list (t, list_p);
     }
   else
@@ -1773,8 +1798,7 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
 
       gcc_assert (src->replacement);
 
-      t = build2 (GIMPLE_MODIFY_STMT, void_type_node, dst->replacement,
-		  src->replacement);
+      t = sra_build_assignment (dst->replacement, src->replacement);
       append_to_statement_list (t, list_p);
     }
 }
@@ -1805,7 +1829,7 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
       gcc_assert (elt->is_scalar);
       t = fold_convert (elt->type, integer_zero_node);
 
-      t = build2 (GIMPLE_MODIFY_STMT, void_type_node, elt->replacement, t);
+      t = sra_build_assignment (elt->replacement, t);
       append_to_statement_list (t, list_p);
     }
 }
@@ -1817,7 +1841,7 @@ static void
 generate_one_element_init (tree var, tree init, tree *list_p)
 {
   /* The replacement can be almost arbitrarily complex.  Gimplify.  */
-  tree stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, var, init);
+  tree stmt = sra_build_assignment (var, init);
   gimplify_and_add (stmt, list_p);
 }