--- gcc/config/i386/i386.c.jj	2021-08-30 08:36:11.070518705 +0200
+++ gcc/config/i386/i386.c	2021-08-30 15:06:07.339940410 +0200
@@ -2062,7 +2062,8 @@ merge_classes (enum x86_64_reg_class cla
 
 static int
 classify_argument (machine_mode mode, const_tree type,
-		   enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
+		   enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset,
+		   int &cxx_bitfields)
 {
   HOST_WIDE_INT bytes
     = mode == BLKmode ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
@@ -2120,6 +2121,12 @@ classify_argument (machine_mode mode, co
 		     misaligned integers.  */
 		  if (DECL_BIT_FIELD (field))
 		    {
+		      if (DECL_FIELD_ABI_IGNORED (field))
+			{
+			  if (cxx_bitfields == 2)
+			    continue;
+			  cxx_bitfields = 1;
+			}
 		      for (i = (int_bit_position (field)
 				+ (bit_offset % 64)) / 8 / 8;
 			   i < ((int_bit_position (field) + (bit_offset % 64))
@@ -2157,7 +2164,8 @@ classify_argument (machine_mode mode, co
 		      num = classify_argument (TYPE_MODE (type), type,
 					       subclasses,
 					       (int_bit_position (field)
-						+ bit_offset) % 512);
+						+ bit_offset) % 512,
+					       cxx_bitfields);
 		      if (!num)
 			return 0;
 		      pos = (int_bit_position (field)
@@ -2175,7 +2183,8 @@ classify_argument (machine_mode mode, co
 	  {
 	    int num;
 	    num = classify_argument (TYPE_MODE (TREE_TYPE (type)),
-				     TREE_TYPE (type), subclasses, bit_offset);
+				     TREE_TYPE (type), subclasses, bit_offset,
+				     cxx_bitfields);
 	    if (!num)
 	      return 0;
 
@@ -2206,7 +2215,7 @@ classify_argument (machine_mode mode, co
 
 		  num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
 					   TREE_TYPE (field), subclasses,
-					   bit_offset);
+					   bit_offset, cxx_bitfields);
 		  if (!num)
 		    return 0;
 		  for (i = 0; i < num && i < words; i++)
@@ -2226,7 +2235,7 @@ classify_argument (machine_mode mode, co
 	     X86_64_SSEUP_CLASS, everything should be passed in
 	     memory.  */
 	  if (classes[0] != X86_64_SSE_CLASS)
-	      return 0;
+	    return 0;
 
 	  for (i = 1; i < words; i++)
 	    if (classes[i] != X86_64_SSEUP_CLASS)
@@ -2252,8 +2261,8 @@ classify_argument (machine_mode mode, co
 	      classes[i] = X86_64_SSE_CLASS;
 	    }
 
-	  /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
-	       everything should be passed in memory.  */
+	  /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+	     everything should be passed in memory.  */
 	  if (classes[i] == X86_64_X87UP_CLASS
 	      && (classes[i - 1] != X86_64_X87_CLASS))
 	    {
@@ -2462,6 +2471,43 @@ classify_argument (machine_mode mode, co
     }
 }
 
+/* Wrapper around classify_argument with the extra cxx_bitfields argument,
+   to diagnose GCC 12.1 ABI differences for C++.  */
+
+static int
+classify_argument (machine_mode mode, const_tree type,
+		   enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
+{
+  int cxx_bitfields = 0;
+  static bool warned = false;
+  int n = classify_argument (mode, type, classes, bit_offset, cxx_bitfields);
+  if (!cxx_bitfields || warned || !warn_psabi)
+    return n;
+  enum x86_64_reg_class alt_classes[MAX_CLASSES];
+  cxx_bitfields = 2;
+  if (classify_argument (mode, type, alt_classes, bit_offset,
+			 cxx_bitfields) != n)
+    cxx_bitfields = 3;
+  else
+    for (int i = 0; i < n; i++)
+      if (classes[i] != alt_classes[i])
+	{
+	  cxx_bitfields = 3;
+	  break;
+	}
+  if (cxx_bitfields == 3)
+    {
+      warned = true;
+      const char *url
+	= CHANGES_ROOT_URL "gcc-12/changes.html#cxx_zero_width_bitfields";
+
+      inform (input_location,
+	      "the ABI of passing C++ structures with zero-width bit-fields"
+	      " has changed in GCC %{12.1%}", url);
+    }
+  return n;
+}
+
 /* Examine the argument and return set number of register required in each
    class.  Return true iff parameter should be passed in memory.  */
 
--- gcc/testsuite/gcc.target/i386/pr102024.c.jj	2021-08-30 15:11:09.223718641 +0200
+++ gcc/testsuite/gcc.target/i386/pr102024.c	2021-08-30 15:11:45.426211495 +0200
@@ -0,0 +1,12 @@
+/* PR target/102024 */
+/* { dg-do compile } */
+
+struct S { float a; int : 0; float b; };
+void foo (struct S x);
+
+void
+bar (void)
+{
+  struct S s = { 0.0f, 0.0f };
+  foo (s);	/* { dg-bogus "the ABI of passing C\\+\\+ structures with zero-width bit-fields has changed in GCC 12.1" } */
+}
--- gcc/testsuite/g++.target/i386/pr102024.C.jj	2021-08-30 15:12:42.710409020 +0200
+++ gcc/testsuite/g++.target/i386/pr102024.C	2021-08-30 15:13:23.930831579 +0200
@@ -0,0 +1,12 @@
+// PR target/102024
+// { dg-do compile }
+
+struct S { float a; int : 0; float b; };
+void foo (struct S x);
+
+void
+bar (void)
+{
+  struct S s = { 0.0f, 0.0f };
+  foo (s);	// { dg-message "the ABI of passing C\\+\\+ structures with zero-width bit-fields has changed in GCC 12.1" "" { target { ! ia32 } } }
+}
