diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0f8d30cab8d4cf2a34dada168f31b3390ee4cd53..dca869b74a12798d350c1e3985526d2704cd0748 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2009-03-29  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR target/39545
+	* config/i386/i386.c (classify_argument): Ignore flexible array
+	member in struct and warn ABI change.
+
 2009-03-29  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* config/i386/i386-protos.h (ix86_agi_dependent): New.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 4a6d601ce45e7f81b0e4628a5961b5a8b2ce1034..3dec02f3acd7e4c45f1f3121a638ed8165b0bc51 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4942,8 +4942,30 @@ classify_argument (enum machine_mode mode, const_tree type,
 		    }
 		  else
 		    {
-		      num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
-					       TREE_TYPE (field), subclasses,
+		      type = TREE_TYPE (field);
+
+		      /* Flexible array member is ignored.  */
+		      if (TYPE_MODE (type) == BLKmode
+			  && TREE_CODE (type) == ARRAY_TYPE
+			  && TYPE_SIZE (type) == NULL_TREE
+			  && TYPE_DOMAIN (type) != NULL_TREE
+			  && (TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+			      == NULL_TREE))
+			{
+			  static bool warned;
+			  
+			  if (!warned && warn_psabi)
+			    {
+			      warned = true;
+			      inform (input_location,
+				      "The ABI of passing struct with"
+				      " a flexible array member has"
+				      " changed in GCC 4.4");
+			    }
+			  continue;
+			}
+		      num = classify_argument (TYPE_MODE (type), type,
+					       subclasses,
 					       (int_bit_position (field)
 						+ bit_offset) % 256);
 		      if (!num)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2f60726156537d267efddbcf8fcd13e28298e50e..7546a2d33a0baa5fec5522c8087e124f85926e88 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,19 @@
+2009-03-29  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR target/39545
+	* gcc.c-torture/compile/pr16566-2.c: Add -Wno-psabi for x86-64.
+
+	* gcc.target/i386/pr39545-1.c: New.
+	* gcc.target/i386/pr39545-2.c: Likewise.
+
+	* gcc.target/x86_64/abi/test_passing_structs.c (flex1_struct): New.
+	(flex2_struct): Likewise.
+	(check_struct_passing7): Likewise.
+	(check_struct_passing8): Likewise.
+	(f1s): Likewise.
+	(f2s): Likewise.
+	(main): Call check_struct_passing7 and check_struct_passing8.
+
 2009-03-29  Richard Guenther  <rguenther@suse.de>
 
 	* gcc.c-torture/execute/20090113-1.c: New testcase.
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr16566-2.c b/gcc/testsuite/gcc.c-torture/compile/pr16566-2.c
index c0036f0fc6458fc6586e68a477550c569797bd3a..2f7a10668a73da213518f8aab13b0334fd439cfe 100644
--- a/gcc/testsuite/gcc.c-torture/compile/pr16566-2.c
+++ b/gcc/testsuite/gcc.c-torture/compile/pr16566-2.c
@@ -1,5 +1,6 @@
 /* ICE with flexible arrays in non-lvalue structures.  Bug 16566
    (comment #5).  */
+/* { dg-options "-Wno-psabi" { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
 
 struct A
 {
diff --git a/gcc/testsuite/gcc.target/i386/pr39545-1.c b/gcc/testsuite/gcc.target/i386/pr39545-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..62bc33fa21d59dc2c82576508e97ecc90b183481
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr39545-1.c
@@ -0,0 +1,24 @@
+/* PR target/39545 */
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2" } */
+
+struct flex
+{
+  int i;
+  int flex [];
+};
+
+int
+foo (struct flex s) /* { dg-message "note: The ABI of passing struct with a flexible array member has changed in GCC 4.4" } */
+{
+  return s.i;
+}
+
+struct flex
+bar (int x)
+{
+  struct flex s;
+  s.i = x;
+  return s;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr39545-2.c b/gcc/testsuite/gcc.target/i386/pr39545-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..143c3827fd6c762b174fb9a284ba8c38e0288b11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr39545-2.c
@@ -0,0 +1,18 @@
+/* PR target/39545 */
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2" } */
+
+struct flex
+{
+  int i;
+  int flex [];
+};
+
+struct flex
+foo (int x)
+{ /* { dg-message "note: The ABI of passing struct with a flexible array member has changed in GCC 4.4" } */
+  struct flex s;
+  s.i = x;
+  return s;
+}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c
index 3ce0db14652e4ed6f579a3b9ed3fdf3830d2a55f..68eca53a2e431952ee443c8eaaef2c6130764bf7 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c
+++ b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c
@@ -92,6 +92,33 @@ check_struct_passing6 (struct m128_2_struct ms ATTRIBUTE_UNUSED)
 }
 #endif
 
+struct flex1_struct
+{
+  long i;
+  long flex[];
+};
+
+struct flex2_struct
+{
+  long i;
+  long flex[0];
+};
+
+void
+check_struct_passing7 (struct flex1_struct is ATTRIBUTE_UNUSED)
+{
+  check_int_arguments;
+}
+
+void
+check_struct_passing8 (struct flex2_struct is ATTRIBUTE_UNUSED)
+{
+  check_int_arguments;
+}
+
+static struct flex1_struct f1s = { 60, { } };
+static struct flex2_struct f2s = { 61, { } };
+
 int
 main (void)
 {
@@ -146,5 +173,17 @@ main (void)
   WRAP_CALL (check_struct_passing6)(m128_2s);
 #endif
 
+  clear_struct_registers;
+  iregs.I0 = f1s.i;
+  num_iregs = 1;
+  clear_int_hardware_registers;
+  WRAP_CALL (check_struct_passing7)(f1s);
+
+  clear_struct_registers;
+  iregs.I0 = f2s.i;
+  num_iregs = 1;
+  clear_int_hardware_registers;
+  WRAP_CALL (check_struct_passing8)(f2s);
+
   return 0;
 }