diff mbox series

[v2] c++, middle-end, rs6000: Fix C++17 ABI incompatibilities during class layout and [[no_unique_address]] handling [PR94707]

Message ID 20200428140458.GP2424@tucnak
State New
Headers show
Series [v2] c++, middle-end, rs6000: Fix C++17 ABI incompatibilities during class layout and [[no_unique_address]] handling [PR94707] | expand

Commit Message

Jakub Jelinek April 28, 2020, 2:04 p.m. UTC
Hi!

On Tue, Apr 28, 2020 at 08:53:31AM -0400, Jason Merrill wrote:
> That sounds good.

So like this?  Or better name for the new macro?

The calls.h macro is there only after all the backends are converted
to use ABI_IGNORED_FIELD_P.

Not sure if I shouldn't
if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))
ABI_IGNORED_FIELD_P (field) = 1;
in end_of_class, as there seems to be some ObjC++ partially overlapping
case too and probably we don't want to change ABI for that.

This patch is a merge of the powerpc64le-linux patch for
[[no_unique_address]] and the powerpc*-{darwin,aix}* patch with the
langhook etc. removed for ABI_IGNORED_FIELD_P.

Untested so far.

2020-04-28  Jakub Jelinek  <jakub@redhat.com>

	PR target/94707
	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
	ABI_IGNORED_FIELD_P.
	* tree.h (ABI_IGNORED_FIELD_P): Define.
	* calls.h (cxx17_empty_base_field_p): Change into a temporary
	macro, check ABI_IGNORED_FIELD_P flag with no "no_unique_address"
	attribute.
	* calls.c (cxx17_empty_base_field_p): Remove.
	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
	ABI_IGNORED_FIELD_P.
	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
	* lto-streamer-out.c (hash_tree): Likewise.
	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
	cxx17_empty_base_seen to empty_base_seen, change type to int *,
	adjust recursive calls, use ABI_IGNORED_FIELD_P instead of
	cxx17_empty_base_field_p, if "no_unique_address" attribute is
	present, propagate that to the caller too.
	(rs6000_discover_homogeneous_aggregate): Adjust
	rs6000_aggregate_candidate caller, emit different diagnostics
	when c++17 empty base fields are present and when empty
	[[no_unique_address]] fields are present.
	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
	darwin_rs6000_special_round_type_align): Skip ABI_IGNORED_FIELD_P
	fields.

	* class.c (build_base_field): Set ABI_IGNORED_FIELD_P on C++17 empty
	base artificial FIELD_DECLs.
	(end_of_class): Set ABI_IGNORED_FIELD_P on empty class
	field_poverlapping_p FIELD_DECLs.

	* g++.target/powerpc/pr94707-1.C: New test.
	* g++.target/powerpc/pr94707-2.C: New test.
	* g++.target/powerpc/pr94707-3.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.
	* g++.target/powerpc/pr94707-5.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.



	Jakub

Comments

Jason Merrill April 28, 2020, 2:18 p.m. UTC | #1
On 4/28/20 10:04 AM, Jakub Jelinek wrote:
> Hi!
> 
> On Tue, Apr 28, 2020 at 08:53:31AM -0400, Jason Merrill wrote:
>> That sounds good.
> 
> So like this?  Or better name for the new macro?
> 
> The calls.h macro is there only after all the backends are converted
> to use ABI_IGNORED_FIELD_P.
> 
> Not sure if I shouldn't
> if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))
> ABI_IGNORED_FIELD_P (field) = 1;
> in end_of_class, as there seems to be some ObjC++ partially overlapping
> case too and probably we don't want to change ABI for that.

I would think it would make sense to set it here:

>       else if (might_overlap && is_empty_class (type))
>         layout_empty_base_or_field (rli, field, empty_base_offsets);

Jason
Jakub Jelinek April 28, 2020, 2:57 p.m. UTC | #2
Hi!

On Tue, Apr 28, 2020 at 10:18:44AM -0400, Jason Merrill wrote:
> I would think it would make sense to set it here:
> 
> >       else if (might_overlap && is_empty_class (type))
> >         layout_empty_base_or_field (rli, field, empty_base_offsets);

That works too, plus on the IRC suggested change
ABI_IGNORED_FIELD_P -> DECL_FIELD_ABI_IGNORED.

Ok for trunk if it passes bootstrap/regtest on powerpc64{,le}-linux?

2020-04-28  Jakub Jelinek  <jakub@redhat.com>

	PR target/94707
	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
	DECL_FIELD_ABI_IGNORED.
	* tree.h (DECL_FIELD_ABI_IGNORED): Define.
	* calls.h (cxx17_empty_base_field_p): Change into a temporary
	macro, check DECL_FIELD_ABI_IGNORED flag with no "no_unique_address"
	attribute.
	* calls.c (cxx17_empty_base_field_p): Remove.
	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
	DECL_FIELD_ABI_IGNORED.
	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
	* lto-streamer-out.c (hash_tree): Likewise.
	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
	cxx17_empty_base_seen to empty_base_seen, change type to int *,
	adjust recursive calls, use DECL_FIELD_ABI_IGNORED instead of
	cxx17_empty_base_field_p, if "no_unique_address" attribute is
	present, propagate that to the caller too.
	(rs6000_discover_homogeneous_aggregate): Adjust
	rs6000_aggregate_candidate caller, emit different diagnostics
	when c++17 empty base fields are present and when empty
	[[no_unique_address]] fields are present.
	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
	darwin_rs6000_special_round_type_align): Skip DECL_FIELD_ABI_IGNORED
	fields.

	* class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty
	base artificial FIELD_DECLs.
	(layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class
	field_poverlapping_p FIELD_DECLs.

	* g++.target/powerpc/pr94707-1.C: New test.
	* g++.target/powerpc/pr94707-2.C: New test.
	* g++.target/powerpc/pr94707-3.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.
	* g++.target/powerpc/pr94707-5.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.

--- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
+++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
@@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
   unsigned lang_flag_8 : 1;
 
   /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
-     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
+     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
+     In FIELD_DECL, this is DECL_FIELD_ABI_IGNORED.  */
   unsigned decl_flag_0 : 1;
   /* In FIELD_DECL, this is DECL_BIT_FIELD
      In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
--- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
+++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
@@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
 /* In a FIELD_DECL, indicates this field should be bit-packed.  */
 #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
 
+/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
+   like passing/returning containing struct by value.
+   Set for C++17 empty base artificial FIELD_DECLs as well as
+   empty [[no_unique_address]] non-static data members.  */
+#define DECL_FIELD_ABI_IGNORED(NODE) \
+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
+
 /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
    specially.  */
 #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
--- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
+++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
@@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
 extern void maybe_warn_nonstring_arg (tree, tree);
 extern bool get_size_range (tree, tree[2], bool = false);
 extern rtx rtx_for_static_chain (const_tree, bool);
-extern bool cxx17_empty_base_field_p (const_tree);
+/* FIXME: Remove after all backends are converted.  */
+#define cxx17_empty_base_field_p(t) \
+  (DECL_FIELD_ABI_IGNORED (t)						\
+   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
 
 #endif // GCC_CALLS_H
--- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
+++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
@@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
   return targetm.calls.must_pass_in_stack (arg);
 }
 
-/* Return true if FIELD is the C++17 empty base field that should
-   be ignored for ABI calling convention decisions in order to
-   maintain ABI compatibility between C++14 and earlier, which doesn't
-   add this FIELD to classes with empty bases, and C++17 and later
-   which does.  */
-
-bool
-cxx17_empty_base_field_p (const_tree field)
-{
-  return (TREE_CODE (field) == FIELD_DECL
-	  && DECL_ARTIFICIAL (field)
-	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
-	  && DECL_SIZE (field)
-	  && integer_zerop (DECL_SIZE (field))
-	  && TYPE_SIZE (TREE_TYPE (field))
-	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
-}
-
 /* Tell the garbage collector about GTY markers in this source file.  */
 #include "gt-calls.h"
--- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
@@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
       bp_pack_value (bp, DECL_PACKED (expr), 1);
       bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
       bp_pack_value (bp, DECL_PADDING_P (expr), 1);
+      bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
       bp_pack_value (bp, expr->decl_common.off_align, 8);
     }
 
--- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
@@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
       DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_FIELD_ABI_IGNORED (expr) = (unsigned) bp_unpack_value (bp, 1);
       expr->decl_common.off_align = bp_unpack_value (bp, 8);
     }
 
--- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
+++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
@@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
 	  hstate.add_flag (DECL_PACKED (t));
 	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
 	  hstate.add_flag (DECL_PADDING_P (t));
+	  hstate.add_flag (DECL_FIELD_ABI_IGNORED (t));
 	  hstate.add_int (DECL_OFFSET_ALIGN (t));
 	}
       else if (code == VAR_DECL)
--- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
+++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
@@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
 
 static int
 rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
-			    bool *cxx17_empty_base_seen)
+			    int *empty_base_seen)
 {
   machine_mode mode;
   HOST_WIDE_INT size;
@@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
 	  return -1;
 
 	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
-					    cxx17_empty_base_seen);
+					    empty_base_seen);
 	if (count == -1
 	    || !index
 	    || !TYPE_MAX_VALUE (index)
@@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
 	    if (TREE_CODE (field) != FIELD_DECL)
 	      continue;
 
-	    if (cxx17_empty_base_field_p (field))
+	    if (DECL_FIELD_ABI_IGNORED (field))
 	      {
-		*cxx17_empty_base_seen = true;
+		if (lookup_attribute ("no_unique_address",
+				      DECL_ATTRIBUTES (field)))
+		  *empty_base_seen |= 2;
+		else
+		  *empty_base_seen |= 1;
 		continue;
 	      }
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count += sub_count;
@@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
 	      continue;
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count = count > sub_count ? count : sub_count;
@@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
       && AGGREGATE_TYPE_P (type))
     {
       machine_mode field_mode = VOIDmode;
-      bool cxx17_empty_base_seen = false;
+      int empty_base_seen = false;
       int field_count = rs6000_aggregate_candidate (type, &field_mode,
-						    &cxx17_empty_base_seen);
+						    &empty_base_seen);
 
       if (field_count > 0)
 	{
@@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
 		*elt_mode = field_mode;
 	      if (n_elts)
 		*n_elts = field_count;
-	      if (cxx17_empty_base_seen && warn_psabi)
+	      if (empty_base_seen && warn_psabi)
 		{
 		  static unsigned last_reported_type_uid;
 		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
 		  if (uid != last_reported_type_uid)
 		    {
-		      inform (input_location,
-			      "parameter passing for argument of type %qT "
-			      "when C++17 is enabled changed to match C++14 "
-			      "in GCC 10.1", type);
+		      if (empty_base_seen & 1)
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"when C++17 is enabled changed to match C++14 "
+				"in GCC 10.1", type);
+		      else
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"with %<[[no_unique_address]]%> members "
+				"changed in GCC 10.1", type);
 		      last_reported_type_uid = uid;
 		    }
 		}
--- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
+++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
@@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
   tree field = TYPE_FIELDS (type);
 
   /* Skip all non field decls */
-  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+  while (field != NULL
+	 && (TREE_CODE (field) != FIELD_DECL
+	     || DECL_FIELD_ABI_IGNORED (field)))
     field = DECL_CHAIN (field);
 
   if (field != NULL && field != type)
@@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
   do {
     tree field = TYPE_FIELDS (type);
     /* Skip all non field decls */
-    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+    while (field != NULL
+	   && (TREE_CODE (field) != FIELD_DECL
+	       || DECL_FIELD_ABI_IGNORED (field)))
       field = DECL_CHAIN (field);
     if (! field)
       break;
--- gcc/cp/class.c.jj	2020-04-28 16:15:39.570540960 +0200
+++ gcc/cp/class.c	2020-04-28 16:35:18.423859735 +0200
@@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
 	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
 	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
 	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
+	  DECL_FIELD_ABI_IGNORED (decl) = 1;
 	}
 
       /* An empty virtual base causes a class to be non-empty
@@ -6522,7 +6523,10 @@ layout_class_type (tree t, tree *virtual
 	  SET_DECL_MODE (field, TYPE_MODE (type));
 	}
       else if (might_overlap && is_empty_class (type))
-	layout_empty_base_or_field (rli, field, empty_base_offsets);
+	{
+	  DECL_FIELD_ABI_IGNORED (field) = 1;
+	  layout_empty_base_or_field (rli, field, empty_base_offsets);
+	}
       else
 	layout_nonempty_base_or_field (rli, field, NULL_TREE,
 				       empty_base_offsets);
--- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
@@ -0,0 +1,34 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
@@ -0,0 +1,30 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
@@ -0,0 +1,36 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
@@ -0,0 +1,30 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 16:47:31.488901028 +0200
@@ -0,0 +1,35 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-std=c++14" }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { double a; };
+struct B : public X { double a; };
+struct C : public Y { double a; };
+struct D : public Z { double a; };
+struct E : public U { double a; };
+struct F { [[no_unique_address]] X x; double a; };
+struct G { [[no_unique_address]] Y y; double a; };
+struct H { [[no_unique_address]] Z z; double a; };
+struct I { [[no_unique_address]] U u; double a; };
+struct J { double a; [[no_unique_address]] X x; };
+struct K { double a; [[no_unique_address]] Y y; };
+struct L { double a; [[no_unique_address]] Z z; };
+struct M { double a; [[no_unique_address]] U u; };
+static_assert (__alignof__ (A) == 8, "");
+static_assert (__alignof__ (B) == 8, "");
+static_assert (__alignof__ (C) == 8, "");
+static_assert (__alignof__ (D) == 4, "");
+static_assert (__alignof__ (E) == 4, "");
+static_assert (__alignof__ (F) == 8, "");
+static_assert (__alignof__ (G) == 8, "");
+static_assert (__alignof__ (H) == 4, "");
+static_assert (__alignof__ (I) == 4, "");
+static_assert (__alignof__ (J) == 8, "");
+static_assert (__alignof__ (K) == 8, "");
+static_assert (__alignof__ (L) == 8, "");
+static_assert (__alignof__ (M) == 8, "");
--- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 16:47:54.056563731 +0200
@@ -0,0 +1,6 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-O2 -std=c++17" }
+
+#include "pr94707-5.C"


	Jakub
Li, Pan2 via Gcc-patches April 28, 2020, 3:16 p.m. UTC | #3
Jakub, thanks for continuing to track down and fix all these cases.

I think this looks good.  My only comment would be to please add some
comments in the test cases about the purpose, or at least to explain
the regexes in the scan-assembler-* directives, to save us all some
mental cycles in the future.

Need Segher/David to approve the rs6000 bits, of course.

Thanks!
Bill


On 4/28/20 9:04 AM, Jakub Jelinek via Gcc-patches wrote:
> Hi!
>
> On Tue, Apr 28, 2020 at 08:53:31AM -0400, Jason Merrill wrote:
>> That sounds good.
> So like this?  Or better name for the new macro?
>
> The calls.h macro is there only after all the backends are converted
> to use ABI_IGNORED_FIELD_P.
>
> Not sure if I shouldn't
> if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))
> ABI_IGNORED_FIELD_P (field) = 1;
> in end_of_class, as there seems to be some ObjC++ partially overlapping
> case too and probably we don't want to change ABI for that.
>
> This patch is a merge of the powerpc64le-linux patch for
> [[no_unique_address]] and the powerpc*-{darwin,aix}* patch with the
> langhook etc. removed for ABI_IGNORED_FIELD_P.
>
> Untested so far.
>
> 2020-04-28  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR target/94707
> 	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
> 	ABI_IGNORED_FIELD_P.
> 	* tree.h (ABI_IGNORED_FIELD_P): Define.
> 	* calls.h (cxx17_empty_base_field_p): Change into a temporary
> 	macro, check ABI_IGNORED_FIELD_P flag with no "no_unique_address"
> 	attribute.
> 	* calls.c (cxx17_empty_base_field_p): Remove.
> 	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
> 	ABI_IGNORED_FIELD_P.
> 	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
> 	* lto-streamer-out.c (hash_tree): Likewise.
> 	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
> 	cxx17_empty_base_seen to empty_base_seen, change type to int *,
> 	adjust recursive calls, use ABI_IGNORED_FIELD_P instead of
> 	cxx17_empty_base_field_p, if "no_unique_address" attribute is
> 	present, propagate that to the caller too.
> 	(rs6000_discover_homogeneous_aggregate): Adjust
> 	rs6000_aggregate_candidate caller, emit different diagnostics
> 	when c++17 empty base fields are present and when empty
> 	[[no_unique_address]] fields are present.
> 	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
> 	darwin_rs6000_special_round_type_align): Skip ABI_IGNORED_FIELD_P
> 	fields.
>
> 	* class.c (build_base_field): Set ABI_IGNORED_FIELD_P on C++17 empty
> 	base artificial FIELD_DECLs.
> 	(end_of_class): Set ABI_IGNORED_FIELD_P on empty class
> 	field_poverlapping_p FIELD_DECLs.
>
> 	* g++.target/powerpc/pr94707-1.C: New test.
> 	* g++.target/powerpc/pr94707-2.C: New test.
> 	* g++.target/powerpc/pr94707-3.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
> 	* g++.target/powerpc/pr94707-5.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
>
> --- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
> +++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
> @@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
>     unsigned lang_flag_8 : 1;
>   
>     /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
> -     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
> +     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
> +     In FIELD_DECL, this is ABI_IGNORED_FIELD_P.  */
>     unsigned decl_flag_0 : 1;
>     /* In FIELD_DECL, this is DECL_BIT_FIELD
>        In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
> --- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
> +++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
> @@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
>   /* In a FIELD_DECL, indicates this field should be bit-packed.  */
>   #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
>   
> +/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
> +   like passing/returning containing struct by value.
> +   Set for C++17 empty base artificial FIELD_DECLs as well as
> +   empty [[no_unique_address]] non-static data members.  */
> +#define ABI_IGNORED_FIELD_P(NODE) \
> +  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
> +
>   /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
>      specially.  */
>   #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
> --- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
> +++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
> @@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
>   extern void maybe_warn_nonstring_arg (tree, tree);
>   extern bool get_size_range (tree, tree[2], bool = false);
>   extern rtx rtx_for_static_chain (const_tree, bool);
> -extern bool cxx17_empty_base_field_p (const_tree);
> +/* FIXME: Remove after all backends are converted.  */
> +#define cxx17_empty_base_field_p(t) \
> +  (ABI_IGNORED_FIELD_P (t)						\
> +   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
>   
>   #endif // GCC_CALLS_H
> --- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
> +++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
> @@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
>     return targetm.calls.must_pass_in_stack (arg);
>   }
>   
> -/* Return true if FIELD is the C++17 empty base field that should
> -   be ignored for ABI calling convention decisions in order to
> -   maintain ABI compatibility between C++14 and earlier, which doesn't
> -   add this FIELD to classes with empty bases, and C++17 and later
> -   which does.  */
> -
> -bool
> -cxx17_empty_base_field_p (const_tree field)
> -{
> -  return (TREE_CODE (field) == FIELD_DECL
> -	  && DECL_ARTIFICIAL (field)
> -	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
> -	  && DECL_SIZE (field)
> -	  && integer_zerop (DECL_SIZE (field))
> -	  && TYPE_SIZE (TREE_TYPE (field))
> -	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
> -}
> -
>   /* Tell the garbage collector about GTY markers in this source file.  */
>   #include "gt-calls.h"
> --- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
> @@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
>         bp_pack_value (bp, DECL_PACKED (expr), 1);
>         bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
>         bp_pack_value (bp, DECL_PADDING_P (expr), 1);
> +      bp_pack_value (bp, ABI_IGNORED_FIELD_P (expr), 1);
>         bp_pack_value (bp, expr->decl_common.off_align, 8);
>       }
>   
> --- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
> @@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
>         DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      ABI_IGNORED_FIELD_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>         expr->decl_common.off_align = bp_unpack_value (bp, 8);
>       }
>   
> --- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
> +++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
> @@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
>   	  hstate.add_flag (DECL_PACKED (t));
>   	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
>   	  hstate.add_flag (DECL_PADDING_P (t));
> +	  hstate.add_flag (ABI_IGNORED_FIELD_P (t));
>   	  hstate.add_int (DECL_OFFSET_ALIGN (t));
>   	}
>         else if (code == VAR_DECL)
> --- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
> +++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
> @@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
>   
>   static int
>   rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
> -			    bool *cxx17_empty_base_seen)
> +			    int *empty_base_seen)
>   {
>     machine_mode mode;
>     HOST_WIDE_INT size;
> @@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
>   	  return -1;
>   
>   	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
> -					    cxx17_empty_base_seen);
> +					    empty_base_seen);
>   	if (count == -1
>   	    || !index
>   	    || !TYPE_MAX_VALUE (index)
> @@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
>   	    if (TREE_CODE (field) != FIELD_DECL)
>   	      continue;
>   
> -	    if (cxx17_empty_base_field_p (field))
> +	    if (ABI_IGNORED_FIELD_P (field))
>   	      {
> -		*cxx17_empty_base_seen = true;
> +		if (lookup_attribute ("no_unique_address",
> +				      DECL_ATTRIBUTES (field)))
> +		  *empty_base_seen |= 2;
> +		else
> +		  *empty_base_seen |= 1;
>   		continue;
>   	      }
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count += sub_count;
> @@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
>   	      continue;
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count = count > sub_count ? count : sub_count;
> @@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
>         && AGGREGATE_TYPE_P (type))
>       {
>         machine_mode field_mode = VOIDmode;
> -      bool cxx17_empty_base_seen = false;
> +      int empty_base_seen = false;
>         int field_count = rs6000_aggregate_candidate (type, &field_mode,
> -						    &cxx17_empty_base_seen);
> +						    &empty_base_seen);
>   
>         if (field_count > 0)
>   	{
> @@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
>   		*elt_mode = field_mode;
>   	      if (n_elts)
>   		*n_elts = field_count;
> -	      if (cxx17_empty_base_seen && warn_psabi)
> +	      if (empty_base_seen && warn_psabi)
>   		{
>   		  static unsigned last_reported_type_uid;
>   		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
>   		  if (uid != last_reported_type_uid)
>   		    {
> -		      inform (input_location,
> -			      "parameter passing for argument of type %qT "
> -			      "when C++17 is enabled changed to match C++14 "
> -			      "in GCC 10.1", type);
> +		      if (empty_base_seen & 1)
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"when C++17 is enabled changed to match C++14 "
> +				"in GCC 10.1", type);
> +		      else
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"with %<[[no_unique_address]]%> members "
> +				"changed in GCC 10.1", type);
>   		      last_reported_type_uid = uid;
>   		    }
>   		}
> --- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
> +++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
> @@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
>     tree field = TYPE_FIELDS (type);
>   
>     /* Skip all non field decls */
> -  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +  while (field != NULL
> +	 && (TREE_CODE (field) != FIELD_DECL
> +	     || ABI_IGNORED_FIELD_P (field)))
>       field = DECL_CHAIN (field);
>   
>     if (field != NULL && field != type)
> @@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
>     do {
>       tree field = TYPE_FIELDS (type);
>       /* Skip all non field decls */
> -    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +    while (field != NULL
> +	   && (TREE_CODE (field) != FIELD_DECL
> +	       || ABI_IGNORED_FIELD_P (field)))
>         field = DECL_CHAIN (field);
>       if (! field)
>         break;
> --- gcc/cp/class.c.jj	2020-04-27 09:10:50.717967010 +0200
> +++ gcc/cp/class.c	2020-04-28 15:22:55.576914814 +0200
> @@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
>   	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
>   	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
>   	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
> +	  ABI_IGNORED_FIELD_P (decl) = 1;
>   	}
>   
>         /* An empty virtual base causes a class to be non-empty
> @@ -6235,6 +6236,7 @@ end_of_class (tree t, bool include_virtu
>   	&& field_poverlapping_p (field)
>   	&& is_empty_class (TREE_TYPE (field)))
>         {
> +	ABI_IGNORED_FIELD_P (field) = 1;
>   	/* Update sizeof(C) to max (sizeof(C), offset(D)+sizeof(D)) */
>   	offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
>   			     TYPE_SIZE_UNIT (TREE_TYPE (field)));
> --- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
> @@ -0,0 +1,34 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
> @@ -0,0 +1,30 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
> @@ -0,0 +1,36 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
> @@ -0,0 +1,30 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 15:43:13.052722888 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 15:47:03.707275087 +0200
> @@ -0,0 +1,34 @@
> +// PR target/94707
> +// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
> +// { dg-options "-std=c++14" }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { double a; };
> +struct B : public X { double a; };
> +struct C : public Y { double a; };
> +struct D : public Z { double a; };
> +struct E : public U { double a; };
> +struct F { [[no_unique_address]] X x; double a; };
> +struct G { [[no_unique_address]] Y y; double a; };
> +struct H { [[no_unique_address]] Z z; double a; };
> +struct I { [[no_unique_address]] U u; double a; };
> +struct J { double a; [[no_unique_address]] X x; };
> +struct K { double a; [[no_unique_address]] Y y; };
> +struct L { double a; [[no_unique_address]] Z z; };
> +struct M { double a; [[no_unique_address]] U u; };
> +static_assert (__alignof__ (A) == 8, "");
> +static_assert (__alignof__ (B) == 8, "");
> +static_assert (__alignof__ (C) == 8, "");
> +static_assert (__alignof__ (D) == 4, "");
> +static_assert (__alignof__ (E) == 4, "");
> +static_assert (__alignof__ (F) == 8, "");
> +static_assert (__alignof__ (G) == 8, "");
> +static_assert (__alignof__ (H) == 4, "");
> +static_assert (__alignof__ (I) == 4, "");
> +static_assert (__alignof__ (J) == 8, "");
> +static_assert (__alignof__ (K) == 8, "");
> +static_assert (__alignof__ (L) == 8, "");
> +static_assert (__alignof__ (M) == 8, "");
> --- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 15:47:23.482979480 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 15:47:19.132044522 +0200
> @@ -0,0 +1,5 @@
> +// PR target/94707
> +// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
> +// { dg-options "-O2 -std=c++17" }
> +
> +#include "pr94707-5.C"
>
>
> 	Jakub
>
Jason Merrill April 28, 2020, 3:17 p.m. UTC | #4
On 4/28/20 10:57 AM, Jakub Jelinek wrote:
> Hi!
> 
> On Tue, Apr 28, 2020 at 10:18:44AM -0400, Jason Merrill wrote:
>> I would think it would make sense to set it here:
>>
>>>        else if (might_overlap && is_empty_class (type))
>>>          layout_empty_base_or_field (rli, field, empty_base_offsets);
> 
> That works too, plus on the IRC suggested change
> ABI_IGNORED_FIELD_P -> DECL_FIELD_ABI_IGNORED.
> 
> Ok for trunk if it passes bootstrap/regtest on powerpc64{,le}-linux?

OK.

> 2020-04-28  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR target/94707
> 	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
> 	DECL_FIELD_ABI_IGNORED.
> 	* tree.h (DECL_FIELD_ABI_IGNORED): Define.
> 	* calls.h (cxx17_empty_base_field_p): Change into a temporary
> 	macro, check DECL_FIELD_ABI_IGNORED flag with no "no_unique_address"
> 	attribute.
> 	* calls.c (cxx17_empty_base_field_p): Remove.
> 	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
> 	DECL_FIELD_ABI_IGNORED.
> 	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
> 	* lto-streamer-out.c (hash_tree): Likewise.
> 	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
> 	cxx17_empty_base_seen to empty_base_seen, change type to int *,
> 	adjust recursive calls, use DECL_FIELD_ABI_IGNORED instead of
> 	cxx17_empty_base_field_p, if "no_unique_address" attribute is
> 	present, propagate that to the caller too.
> 	(rs6000_discover_homogeneous_aggregate): Adjust
> 	rs6000_aggregate_candidate caller, emit different diagnostics
> 	when c++17 empty base fields are present and when empty
> 	[[no_unique_address]] fields are present.
> 	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
> 	darwin_rs6000_special_round_type_align): Skip DECL_FIELD_ABI_IGNORED
> 	fields.
> 
> 	* class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty
> 	base artificial FIELD_DECLs.
> 	(layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class
> 	field_poverlapping_p FIELD_DECLs.
> 
> 	* g++.target/powerpc/pr94707-1.C: New test.
> 	* g++.target/powerpc/pr94707-2.C: New test.
> 	* g++.target/powerpc/pr94707-3.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
> 	* g++.target/powerpc/pr94707-5.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
> 
> --- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
> +++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
> @@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
>     unsigned lang_flag_8 : 1;
>   
>     /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
> -     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
> +     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
> +     In FIELD_DECL, this is DECL_FIELD_ABI_IGNORED.  */
>     unsigned decl_flag_0 : 1;
>     /* In FIELD_DECL, this is DECL_BIT_FIELD
>        In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
> --- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
> +++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
> @@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
>   /* In a FIELD_DECL, indicates this field should be bit-packed.  */
>   #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
>   
> +/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
> +   like passing/returning containing struct by value.
> +   Set for C++17 empty base artificial FIELD_DECLs as well as
> +   empty [[no_unique_address]] non-static data members.  */
> +#define DECL_FIELD_ABI_IGNORED(NODE) \
> +  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
> +
>   /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
>      specially.  */
>   #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
> --- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
> +++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
> @@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
>   extern void maybe_warn_nonstring_arg (tree, tree);
>   extern bool get_size_range (tree, tree[2], bool = false);
>   extern rtx rtx_for_static_chain (const_tree, bool);
> -extern bool cxx17_empty_base_field_p (const_tree);
> +/* FIXME: Remove after all backends are converted.  */
> +#define cxx17_empty_base_field_p(t) \
> +  (DECL_FIELD_ABI_IGNORED (t)						\
> +   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
>   
>   #endif // GCC_CALLS_H
> --- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
> +++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
> @@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
>     return targetm.calls.must_pass_in_stack (arg);
>   }
>   
> -/* Return true if FIELD is the C++17 empty base field that should
> -   be ignored for ABI calling convention decisions in order to
> -   maintain ABI compatibility between C++14 and earlier, which doesn't
> -   add this FIELD to classes with empty bases, and C++17 and later
> -   which does.  */
> -
> -bool
> -cxx17_empty_base_field_p (const_tree field)
> -{
> -  return (TREE_CODE (field) == FIELD_DECL
> -	  && DECL_ARTIFICIAL (field)
> -	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
> -	  && DECL_SIZE (field)
> -	  && integer_zerop (DECL_SIZE (field))
> -	  && TYPE_SIZE (TREE_TYPE (field))
> -	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
> -}
> -
>   /* Tell the garbage collector about GTY markers in this source file.  */
>   #include "gt-calls.h"
> --- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
> @@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
>         bp_pack_value (bp, DECL_PACKED (expr), 1);
>         bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
>         bp_pack_value (bp, DECL_PADDING_P (expr), 1);
> +      bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>         bp_pack_value (bp, expr->decl_common.off_align, 8);
>       }
>   
> --- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
> @@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
>         DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_FIELD_ABI_IGNORED (expr) = (unsigned) bp_unpack_value (bp, 1);
>         expr->decl_common.off_align = bp_unpack_value (bp, 8);
>       }
>   
> --- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
> +++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
> @@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
>   	  hstate.add_flag (DECL_PACKED (t));
>   	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
>   	  hstate.add_flag (DECL_PADDING_P (t));
> +	  hstate.add_flag (DECL_FIELD_ABI_IGNORED (t));
>   	  hstate.add_int (DECL_OFFSET_ALIGN (t));
>   	}
>         else if (code == VAR_DECL)
> --- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
> +++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
> @@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
>   
>   static int
>   rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
> -			    bool *cxx17_empty_base_seen)
> +			    int *empty_base_seen)
>   {
>     machine_mode mode;
>     HOST_WIDE_INT size;
> @@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
>   	  return -1;
>   
>   	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
> -					    cxx17_empty_base_seen);
> +					    empty_base_seen);
>   	if (count == -1
>   	    || !index
>   	    || !TYPE_MAX_VALUE (index)
> @@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
>   	    if (TREE_CODE (field) != FIELD_DECL)
>   	      continue;
>   
> -	    if (cxx17_empty_base_field_p (field))
> +	    if (DECL_FIELD_ABI_IGNORED (field))
>   	      {
> -		*cxx17_empty_base_seen = true;
> +		if (lookup_attribute ("no_unique_address",
> +				      DECL_ATTRIBUTES (field)))
> +		  *empty_base_seen |= 2;
> +		else
> +		  *empty_base_seen |= 1;
>   		continue;
>   	      }
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count += sub_count;
> @@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
>   	      continue;
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count = count > sub_count ? count : sub_count;
> @@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
>         && AGGREGATE_TYPE_P (type))
>       {
>         machine_mode field_mode = VOIDmode;
> -      bool cxx17_empty_base_seen = false;
> +      int empty_base_seen = false;
>         int field_count = rs6000_aggregate_candidate (type, &field_mode,
> -						    &cxx17_empty_base_seen);
> +						    &empty_base_seen);
>   
>         if (field_count > 0)
>   	{
> @@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
>   		*elt_mode = field_mode;
>   	      if (n_elts)
>   		*n_elts = field_count;
> -	      if (cxx17_empty_base_seen && warn_psabi)
> +	      if (empty_base_seen && warn_psabi)
>   		{
>   		  static unsigned last_reported_type_uid;
>   		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
>   		  if (uid != last_reported_type_uid)
>   		    {
> -		      inform (input_location,
> -			      "parameter passing for argument of type %qT "
> -			      "when C++17 is enabled changed to match C++14 "
> -			      "in GCC 10.1", type);
> +		      if (empty_base_seen & 1)
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"when C++17 is enabled changed to match C++14 "
> +				"in GCC 10.1", type);
> +		      else
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"with %<[[no_unique_address]]%> members "
> +				"changed in GCC 10.1", type);
>   		      last_reported_type_uid = uid;
>   		    }
>   		}
> --- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
> +++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
> @@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
>     tree field = TYPE_FIELDS (type);
>   
>     /* Skip all non field decls */
> -  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +  while (field != NULL
> +	 && (TREE_CODE (field) != FIELD_DECL
> +	     || DECL_FIELD_ABI_IGNORED (field)))
>       field = DECL_CHAIN (field);
>   
>     if (field != NULL && field != type)
> @@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
>     do {
>       tree field = TYPE_FIELDS (type);
>       /* Skip all non field decls */
> -    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +    while (field != NULL
> +	   && (TREE_CODE (field) != FIELD_DECL
> +	       || DECL_FIELD_ABI_IGNORED (field)))
>         field = DECL_CHAIN (field);
>       if (! field)
>         break;
> --- gcc/cp/class.c.jj	2020-04-28 16:15:39.570540960 +0200
> +++ gcc/cp/class.c	2020-04-28 16:35:18.423859735 +0200
> @@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
>   	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
>   	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
>   	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
> +	  DECL_FIELD_ABI_IGNORED (decl) = 1;
>   	}
>   
>         /* An empty virtual base causes a class to be non-empty
> @@ -6522,7 +6523,10 @@ layout_class_type (tree t, tree *virtual
>   	  SET_DECL_MODE (field, TYPE_MODE (type));
>   	}
>         else if (might_overlap && is_empty_class (type))
> -	layout_empty_base_or_field (rli, field, empty_base_offsets);
> +	{
> +	  DECL_FIELD_ABI_IGNORED (field) = 1;
> +	  layout_empty_base_or_field (rli, field, empty_base_offsets);
> +	}
>         else
>   	layout_nonempty_base_or_field (rli, field, NULL_TREE,
>   				       empty_base_offsets);
> --- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
> @@ -0,0 +1,34 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
> @@ -0,0 +1,30 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
> @@ -0,0 +1,36 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
> @@ -0,0 +1,30 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 16:33:53.431130852 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 16:47:31.488901028 +0200
> @@ -0,0 +1,35 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc*-*-darwin* } }
> +// { dg-require-effective-target ilp32 }
> +// { dg-options "-std=c++14" }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { double a; };
> +struct B : public X { double a; };
> +struct C : public Y { double a; };
> +struct D : public Z { double a; };
> +struct E : public U { double a; };
> +struct F { [[no_unique_address]] X x; double a; };
> +struct G { [[no_unique_address]] Y y; double a; };
> +struct H { [[no_unique_address]] Z z; double a; };
> +struct I { [[no_unique_address]] U u; double a; };
> +struct J { double a; [[no_unique_address]] X x; };
> +struct K { double a; [[no_unique_address]] Y y; };
> +struct L { double a; [[no_unique_address]] Z z; };
> +struct M { double a; [[no_unique_address]] U u; };
> +static_assert (__alignof__ (A) == 8, "");
> +static_assert (__alignof__ (B) == 8, "");
> +static_assert (__alignof__ (C) == 8, "");
> +static_assert (__alignof__ (D) == 4, "");
> +static_assert (__alignof__ (E) == 4, "");
> +static_assert (__alignof__ (F) == 8, "");
> +static_assert (__alignof__ (G) == 8, "");
> +static_assert (__alignof__ (H) == 4, "");
> +static_assert (__alignof__ (I) == 4, "");
> +static_assert (__alignof__ (J) == 8, "");
> +static_assert (__alignof__ (K) == 8, "");
> +static_assert (__alignof__ (L) == 8, "");
> +static_assert (__alignof__ (M) == 8, "");
> --- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 16:33:53.431130852 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 16:47:54.056563731 +0200
> @@ -0,0 +1,6 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc*-*-darwin* } }
> +// { dg-require-effective-target ilp32 }
> +// { dg-options "-O2 -std=c++17" }
> +
> +#include "pr94707-5.C"
> 
> 
> 	Jakub
>
Jakub Jelinek April 28, 2020, 3:42 p.m. UTC | #5
On Tue, Apr 28, 2020 at 10:16:24AM -0500, Bill Schmidt via Gcc-patches wrote:
> I think this looks good.  My only comment would be to please add some
> comments in the test cases about the purpose, or at least to explain
> the regexes in the scan-assembler-* directives, to save us all some
> mental cycles in the future.

Ok, below in the updated patch:

2020-04-28  Jakub Jelinek  <jakub@redhat.com>

	PR target/94707
	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
	DECL_FIELD_ABI_IGNORED.
	* tree.h (DECL_FIELD_ABI_IGNORED): Define.
	* calls.h (cxx17_empty_base_field_p): Change into a temporary
	macro, check DECL_FIELD_ABI_IGNORED flag with no "no_unique_address"
	attribute.
	* calls.c (cxx17_empty_base_field_p): Remove.
	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
	DECL_FIELD_ABI_IGNORED.
	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
	* lto-streamer-out.c (hash_tree): Likewise.
	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
	cxx17_empty_base_seen to empty_base_seen, change type to int *,
	adjust recursive calls, use DECL_FIELD_ABI_IGNORED instead of
	cxx17_empty_base_field_p, if "no_unique_address" attribute is
	present, propagate that to the caller too.
	(rs6000_discover_homogeneous_aggregate): Adjust
	rs6000_aggregate_candidate caller, emit different diagnostics
	when c++17 empty base fields are present and when empty
	[[no_unique_address]] fields are present.
	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
	darwin_rs6000_special_round_type_align): Skip DECL_FIELD_ABI_IGNORED
	fields.

	* class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty
	base artificial FIELD_DECLs.
	(layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class
	field_poverlapping_p FIELD_DECLs.

	* g++.target/powerpc/pr94707-1.C: New test.
	* g++.target/powerpc/pr94707-2.C: New test.
	* g++.target/powerpc/pr94707-3.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.
	* g++.target/powerpc/pr94707-5.C: New test.
	* g++.target/powerpc/pr94707-4.C: New test.

--- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
+++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
@@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
   unsigned lang_flag_8 : 1;
 
   /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
-     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
+     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
+     In FIELD_DECL, this is DECL_FIELD_ABI_IGNORED.  */
   unsigned decl_flag_0 : 1;
   /* In FIELD_DECL, this is DECL_BIT_FIELD
      In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
--- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
+++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
@@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
 /* In a FIELD_DECL, indicates this field should be bit-packed.  */
 #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
 
+/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
+   like passing/returning containing struct by value.
+   Set for C++17 empty base artificial FIELD_DECLs as well as
+   empty [[no_unique_address]] non-static data members.  */
+#define DECL_FIELD_ABI_IGNORED(NODE) \
+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
+
 /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
    specially.  */
 #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
--- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
+++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
@@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
 extern void maybe_warn_nonstring_arg (tree, tree);
 extern bool get_size_range (tree, tree[2], bool = false);
 extern rtx rtx_for_static_chain (const_tree, bool);
-extern bool cxx17_empty_base_field_p (const_tree);
+/* FIXME: Remove after all backends are converted.  */
+#define cxx17_empty_base_field_p(t) \
+  (DECL_FIELD_ABI_IGNORED (t)						\
+   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
 
 #endif // GCC_CALLS_H
--- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
+++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
@@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
   return targetm.calls.must_pass_in_stack (arg);
 }
 
-/* Return true if FIELD is the C++17 empty base field that should
-   be ignored for ABI calling convention decisions in order to
-   maintain ABI compatibility between C++14 and earlier, which doesn't
-   add this FIELD to classes with empty bases, and C++17 and later
-   which does.  */
-
-bool
-cxx17_empty_base_field_p (const_tree field)
-{
-  return (TREE_CODE (field) == FIELD_DECL
-	  && DECL_ARTIFICIAL (field)
-	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
-	  && DECL_SIZE (field)
-	  && integer_zerop (DECL_SIZE (field))
-	  && TYPE_SIZE (TREE_TYPE (field))
-	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
-}
-
 /* Tell the garbage collector about GTY markers in this source file.  */
 #include "gt-calls.h"
--- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
@@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
       bp_pack_value (bp, DECL_PACKED (expr), 1);
       bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
       bp_pack_value (bp, DECL_PADDING_P (expr), 1);
+      bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
       bp_pack_value (bp, expr->decl_common.off_align, 8);
     }
 
--- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
@@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
       DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+      DECL_FIELD_ABI_IGNORED (expr) = (unsigned) bp_unpack_value (bp, 1);
       expr->decl_common.off_align = bp_unpack_value (bp, 8);
     }
 
--- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
+++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
@@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
 	  hstate.add_flag (DECL_PACKED (t));
 	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
 	  hstate.add_flag (DECL_PADDING_P (t));
+	  hstate.add_flag (DECL_FIELD_ABI_IGNORED (t));
 	  hstate.add_int (DECL_OFFSET_ALIGN (t));
 	}
       else if (code == VAR_DECL)
--- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
+++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
@@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
 
 static int
 rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
-			    bool *cxx17_empty_base_seen)
+			    int *empty_base_seen)
 {
   machine_mode mode;
   HOST_WIDE_INT size;
@@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
 	  return -1;
 
 	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
-					    cxx17_empty_base_seen);
+					    empty_base_seen);
 	if (count == -1
 	    || !index
 	    || !TYPE_MAX_VALUE (index)
@@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
 	    if (TREE_CODE (field) != FIELD_DECL)
 	      continue;
 
-	    if (cxx17_empty_base_field_p (field))
+	    if (DECL_FIELD_ABI_IGNORED (field))
 	      {
-		*cxx17_empty_base_seen = true;
+		if (lookup_attribute ("no_unique_address",
+				      DECL_ATTRIBUTES (field)))
+		  *empty_base_seen |= 2;
+		else
+		  *empty_base_seen |= 1;
 		continue;
 	      }
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count += sub_count;
@@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
 	      continue;
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count = count > sub_count ? count : sub_count;
@@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
       && AGGREGATE_TYPE_P (type))
     {
       machine_mode field_mode = VOIDmode;
-      bool cxx17_empty_base_seen = false;
+      int empty_base_seen = 0;
       int field_count = rs6000_aggregate_candidate (type, &field_mode,
-						    &cxx17_empty_base_seen);
+						    &empty_base_seen);
 
       if (field_count > 0)
 	{
@@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
 		*elt_mode = field_mode;
 	      if (n_elts)
 		*n_elts = field_count;
-	      if (cxx17_empty_base_seen && warn_psabi)
+	      if (empty_base_seen && warn_psabi)
 		{
 		  static unsigned last_reported_type_uid;
 		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
 		  if (uid != last_reported_type_uid)
 		    {
-		      inform (input_location,
-			      "parameter passing for argument of type %qT "
-			      "when C++17 is enabled changed to match C++14 "
-			      "in GCC 10.1", type);
+		      if (empty_base_seen & 1)
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"when C++17 is enabled changed to match C++14 "
+				"in GCC 10.1", type);
+		      else
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"with %<[[no_unique_address]]%> members "
+				"changed in GCC 10.1", type);
 		      last_reported_type_uid = uid;
 		    }
 		}
--- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
+++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
@@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
   tree field = TYPE_FIELDS (type);
 
   /* Skip all non field decls */
-  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+  while (field != NULL
+	 && (TREE_CODE (field) != FIELD_DECL
+	     || DECL_FIELD_ABI_IGNORED (field)))
     field = DECL_CHAIN (field);
 
   if (field != NULL && field != type)
@@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
   do {
     tree field = TYPE_FIELDS (type);
     /* Skip all non field decls */
-    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+    while (field != NULL
+	   && (TREE_CODE (field) != FIELD_DECL
+	       || DECL_FIELD_ABI_IGNORED (field)))
       field = DECL_CHAIN (field);
     if (! field)
       break;
--- gcc/cp/class.c.jj	2020-04-28 16:15:39.570540960 +0200
+++ gcc/cp/class.c	2020-04-28 16:35:18.423859735 +0200
@@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
 	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
 	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
 	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
+	  DECL_FIELD_ABI_IGNORED (decl) = 1;
 	}
 
       /* An empty virtual base causes a class to be non-empty
@@ -6522,7 +6523,10 @@ layout_class_type (tree t, tree *virtual
 	  SET_DECL_MODE (field, TYPE_MODE (type));
 	}
       else if (might_overlap && is_empty_class (type))
-	layout_empty_base_or_field (rli, field, empty_base_offsets);
+	{
+	  DECL_FIELD_ABI_IGNORED (field) = 1;
+	  layout_empty_base_or_field (rli, field, empty_base_offsets);
+	}
       else
 	layout_nonempty_base_or_field (rli, field, NULL_TREE,
 				       empty_base_offsets);
--- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
@@ -0,0 +1,38 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// Test that for all the calls in this testcase the C++17 empty base
+// artificial fields and [[no_unique_address]] empty class non-static
+// data members are ignored in the decision about passing homogeneous
+// arguments.
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
@@ -0,0 +1,34 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// Test that for no calls in this testcase the C++17 empty base
+// artificial fields and [[no_unique_address]] empty class non-static
+// data members are ignored in the decision about passing homogeneous
+// arguments.
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
@@ -0,0 +1,40 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// Test that for all the calls in this testcase the C++17 empty base
+// artificial fields and [[no_unique_address]] empty class non-static
+// data members are ignored in the decision about passing homogeneous
+// arguments.
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
@@ -0,0 +1,34 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// Test that for no calls in this testcase the C++17 empty base
+// artificial fields and [[no_unique_address]] empty class non-static
+// data members are ignored in the decision about passing homogeneous
+// arguments.
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 16:47:31.488901028 +0200
@@ -0,0 +1,35 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-std=c++14" }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { double a; };
+struct B : public X { double a; };
+struct C : public Y { double a; };
+struct D : public Z { double a; };
+struct E : public U { double a; };
+struct F { [[no_unique_address]] X x; double a; };
+struct G { [[no_unique_address]] Y y; double a; };
+struct H { [[no_unique_address]] Z z; double a; };
+struct I { [[no_unique_address]] U u; double a; };
+struct J { double a; [[no_unique_address]] X x; };
+struct K { double a; [[no_unique_address]] Y y; };
+struct L { double a; [[no_unique_address]] Z z; };
+struct M { double a; [[no_unique_address]] U u; };
+static_assert (__alignof__ (A) == 8, "");
+static_assert (__alignof__ (B) == 8, "");
+static_assert (__alignof__ (C) == 8, "");
+static_assert (__alignof__ (D) == 4, "");
+static_assert (__alignof__ (E) == 4, "");
+static_assert (__alignof__ (F) == 8, "");
+static_assert (__alignof__ (G) == 8, "");
+static_assert (__alignof__ (H) == 4, "");
+static_assert (__alignof__ (I) == 4, "");
+static_assert (__alignof__ (J) == 8, "");
+static_assert (__alignof__ (K) == 8, "");
+static_assert (__alignof__ (L) == 8, "");
+static_assert (__alignof__ (M) == 8, "");
--- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 16:47:54.056563731 +0200
@@ -0,0 +1,6 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-O2 -std=c++17" }
+
+#include "pr94707-5.C"


	Jakub
Richard Biener April 28, 2020, 3:47 p.m. UTC | #6
On April 28, 2020 4:04:58 PM GMT+02:00, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>Hi!
>
>On Tue, Apr 28, 2020 at 08:53:31AM -0400, Jason Merrill wrote:
>> That sounds good.
>
>So like this?  Or better name for the new macro?

I think you miss a hunk for lto/ to compare the flag for tree merging. 

>The calls.h macro is there only after all the backends are converted
>to use ABI_IGNORED_FIELD_P.
>
>Not sure if I shouldn't
>if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))
>ABI_IGNORED_FIELD_P (field) = 1;
>in end_of_class, as there seems to be some ObjC++ partially overlapping
>case too and probably we don't want to change ABI for that.
>
>This patch is a merge of the powerpc64le-linux patch for
>[[no_unique_address]] and the powerpc*-{darwin,aix}* patch with the
>langhook etc. removed for ABI_IGNORED_FIELD_P.
>
>Untested so far.
>
>2020-04-28  Jakub Jelinek  <jakub@redhat.com>
>
>	PR target/94707
>	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
>	ABI_IGNORED_FIELD_P.
>	* tree.h (ABI_IGNORED_FIELD_P): Define.
>	* calls.h (cxx17_empty_base_field_p): Change into a temporary
>	macro, check ABI_IGNORED_FIELD_P flag with no "no_unique_address"
>	attribute.
>	* calls.c (cxx17_empty_base_field_p): Remove.
>	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
>	ABI_IGNORED_FIELD_P.
>	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
>	* lto-streamer-out.c (hash_tree): Likewise.
>	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
>	cxx17_empty_base_seen to empty_base_seen, change type to int *,
>	adjust recursive calls, use ABI_IGNORED_FIELD_P instead of
>	cxx17_empty_base_field_p, if "no_unique_address" attribute is
>	present, propagate that to the caller too.
>	(rs6000_discover_homogeneous_aggregate): Adjust
>	rs6000_aggregate_candidate caller, emit different diagnostics
>	when c++17 empty base fields are present and when empty
>	[[no_unique_address]] fields are present.
>	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
>	darwin_rs6000_special_round_type_align): Skip ABI_IGNORED_FIELD_P
>	fields.
>
>	* class.c (build_base_field): Set ABI_IGNORED_FIELD_P on C++17 empty
>	base artificial FIELD_DECLs.
>	(end_of_class): Set ABI_IGNORED_FIELD_P on empty class
>	field_poverlapping_p FIELD_DECLs.
>
>	* g++.target/powerpc/pr94707-1.C: New test.
>	* g++.target/powerpc/pr94707-2.C: New test.
>	* g++.target/powerpc/pr94707-3.C: New test.
>	* g++.target/powerpc/pr94707-4.C: New test.
>	* g++.target/powerpc/pr94707-5.C: New test.
>	* g++.target/powerpc/pr94707-4.C: New test.
>
>--- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
>+++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
>@@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
>   unsigned lang_flag_8 : 1;
> 
>   /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
>-     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P. 
>*/
>+     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
>+     In FIELD_DECL, this is ABI_IGNORED_FIELD_P.  */
>   unsigned decl_flag_0 : 1;
>   /* In FIELD_DECL, this is DECL_BIT_FIELD
>      In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
>--- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
>+++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
>@@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
> /* In a FIELD_DECL, indicates this field should be bit-packed.  */
>#define DECL_PACKED(NODE) (FIELD_DECL_CHECK
>(NODE)->base.u.bits.packed_flag)
> 
>+/* In a FIELD_DECL, indicates this field should be ignored for ABI
>decisions
>+   like passing/returning containing struct by value.
>+   Set for C++17 empty base artificial FIELD_DECLs as well as
>+   empty [[no_unique_address]] non-static data members.  */
>+#define ABI_IGNORED_FIELD_P(NODE) \
>+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
>+
>/* Nonzero in a FIELD_DECL means it is a bit field, and must be
>accessed
>    specially.  */
>#define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK
>(NODE)->decl_common.decl_flag_1)
>--- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
>+++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
>@@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
> extern void maybe_warn_nonstring_arg (tree, tree);
> extern bool get_size_range (tree, tree[2], bool = false);
> extern rtx rtx_for_static_chain (const_tree, bool);
>-extern bool cxx17_empty_base_field_p (const_tree);
>+/* FIXME: Remove after all backends are converted.  */
>+#define cxx17_empty_base_field_p(t) \
>+  (ABI_IGNORED_FIELD_P (t)						\
>+   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
> 
> #endif // GCC_CALLS_H
>--- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
>+++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
>@@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
>   return targetm.calls.must_pass_in_stack (arg);
> }
> 
>-/* Return true if FIELD is the C++17 empty base field that should
>-   be ignored for ABI calling convention decisions in order to
>-   maintain ABI compatibility between C++14 and earlier, which doesn't
>-   add this FIELD to classes with empty bases, and C++17 and later
>-   which does.  */
>-
>-bool
>-cxx17_empty_base_field_p (const_tree field)
>-{
>-  return (TREE_CODE (field) == FIELD_DECL
>-	  && DECL_ARTIFICIAL (field)
>-	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
>-	  && DECL_SIZE (field)
>-	  && integer_zerop (DECL_SIZE (field))
>-	  && TYPE_SIZE (TREE_TYPE (field))
>-	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
>-}
>-
>/* Tell the garbage collector about GTY markers in this source file. 
>*/
> #include "gt-calls.h"
>--- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
>+++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
>@@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
>       bp_pack_value (bp, DECL_PACKED (expr), 1);
>       bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
>       bp_pack_value (bp, DECL_PADDING_P (expr), 1);
>+      bp_pack_value (bp, ABI_IGNORED_FIELD_P (expr), 1);
>       bp_pack_value (bp, expr->decl_common.off_align, 8);
>     }
> 
>--- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
>+++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
>@@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
>       DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
>     DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>       DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>+      ABI_IGNORED_FIELD_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>       expr->decl_common.off_align = bp_unpack_value (bp, 8);
>     }
> 
>--- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
>+++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
>@@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
> 	  hstate.add_flag (DECL_PACKED (t));
> 	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
> 	  hstate.add_flag (DECL_PADDING_P (t));
>+	  hstate.add_flag (ABI_IGNORED_FIELD_P (t));
> 	  hstate.add_int (DECL_OFFSET_ALIGN (t));
> 	}
>       else if (code == VAR_DECL)
>--- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084
>+0200
>+++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
>@@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
> 
> static int
> rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
>-			    bool *cxx17_empty_base_seen)
>+			    int *empty_base_seen)
> {
>   machine_mode mode;
>   HOST_WIDE_INT size;
>@@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
> 	  return -1;
> 
> 	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
>-					    cxx17_empty_base_seen);
>+					    empty_base_seen);
> 	if (count == -1
> 	    || !index
> 	    || !TYPE_MAX_VALUE (index)
>@@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
> 	    if (TREE_CODE (field) != FIELD_DECL)
> 	      continue;
> 
>-	    if (cxx17_empty_base_field_p (field))
>+	    if (ABI_IGNORED_FIELD_P (field))
> 	      {
>-		*cxx17_empty_base_seen = true;
>+		if (lookup_attribute ("no_unique_address",
>+				      DECL_ATTRIBUTES (field)))
>+		  *empty_base_seen |= 2;
>+		else
>+		  *empty_base_seen |= 1;
> 		continue;
> 	      }
> 
> 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
>-						    cxx17_empty_base_seen);
>+						    empty_base_seen);
> 	    if (sub_count < 0)
> 	      return -1;
> 	    count += sub_count;
>@@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
> 	      continue;
> 
> 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
>-						    cxx17_empty_base_seen);
>+						    empty_base_seen);
> 	    if (sub_count < 0)
> 	      return -1;
> 	    count = count > sub_count ? count : sub_count;
>@@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
>       && AGGREGATE_TYPE_P (type))
>     {
>       machine_mode field_mode = VOIDmode;
>-      bool cxx17_empty_base_seen = false;
>+      int empty_base_seen = false;
>       int field_count = rs6000_aggregate_candidate (type, &field_mode,
>-						    &cxx17_empty_base_seen);
>+						    &empty_base_seen);
> 
>       if (field_count > 0)
> 	{
>@@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
> 		*elt_mode = field_mode;
> 	      if (n_elts)
> 		*n_elts = field_count;
>-	      if (cxx17_empty_base_seen && warn_psabi)
>+	      if (empty_base_seen && warn_psabi)
> 		{
> 		  static unsigned last_reported_type_uid;
> 		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
> 		  if (uid != last_reported_type_uid)
> 		    {
>-		      inform (input_location,
>-			      "parameter passing for argument of type %qT "
>-			      "when C++17 is enabled changed to match C++14 "
>-			      "in GCC 10.1", type);
>+		      if (empty_base_seen & 1)
>+			inform (input_location,
>+				"parameter passing for argument of type %qT "
>+				"when C++17 is enabled changed to match C++14 "
>+				"in GCC 10.1", type);
>+		      else
>+			inform (input_location,
>+				"parameter passing for argument of type %qT "
>+				"with %<[[no_unique_address]]%> members "
>+				"changed in GCC 10.1", type);
> 		      last_reported_type_uid = uid;
> 		    }
> 		}
>--- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
>+++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
>@@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
>   tree field = TYPE_FIELDS (type);
> 
>   /* Skip all non field decls */
>-  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
>+  while (field != NULL
>+	 && (TREE_CODE (field) != FIELD_DECL
>+	     || ABI_IGNORED_FIELD_P (field)))
>     field = DECL_CHAIN (field);
> 
>   if (field != NULL && field != type)
>@@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
>   do {
>     tree field = TYPE_FIELDS (type);
>     /* Skip all non field decls */
>-    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
>+    while (field != NULL
>+	   && (TREE_CODE (field) != FIELD_DECL
>+	       || ABI_IGNORED_FIELD_P (field)))
>       field = DECL_CHAIN (field);
>     if (! field)
>       break;
>--- gcc/cp/class.c.jj	2020-04-27 09:10:50.717967010 +0200
>+++ gcc/cp/class.c	2020-04-28 15:22:55.576914814 +0200
>@@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
> 	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
> 	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
> 	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
>+	  ABI_IGNORED_FIELD_P (decl) = 1;
> 	}
> 
>       /* An empty virtual base causes a class to be non-empty
>@@ -6235,6 +6236,7 @@ end_of_class (tree t, bool include_virtu
> 	&& field_poverlapping_p (field)
> 	&& is_empty_class (TREE_TYPE (field)))
>       {
>+	ABI_IGNORED_FIELD_P (field) = 1;
> 	/* Update sizeof(C) to max (sizeof(C), offset(D)+sizeof(D)) */
> 	offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
> 			     TYPE_SIZE_UNIT (TREE_TYPE (field)));
>--- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28
>13:26:01.417418105 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28
>13:25:19.555046878 +0200
>@@ -0,0 +1,34 @@
>+// PR target/94707
>+// { dg-do compile { target powerpc_elfv2 } }
>+// { dg-options "-O2 -std=c++14" }
>+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
>+
>+struct X { };
>+struct Y { int : 0; };
>+struct Z { int : 0; Y y; };
>+struct U : public X { X q; };
>+struct A { float a, b, c, d; };
>+struct B : public X { float a, b, c, d; };
>+struct C : public Y { float a, b, c, d; };
>+struct D : public Z { float a, b, c, d; };
>+struct E : public U { float a, b, c, d; };
>+struct F { [[no_unique_address]] X x; float a, b, c, d; };
>+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
>+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
>+struct I { [[no_unique_address]] U u; float a, b, c, d; };
>+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
>+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
>+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
>+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
>+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () {
>foo##s (s); return 0; }
>+// { dg-message "parameter passing for argument of type 'F' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-1 }
>+// { dg-message "parameter passing for argument of type 'G' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-2 }
>+// { dg-message "parameter passing for argument of type 'J' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-3 }
>+// { dg-message "parameter passing for argument of type 'K' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-4 }
>+T (A, a)
>+T (B, b)
>+T (C, c)
>+T (F, f)
>+T (G, g)
>+T (J, j)
>+T (K, k)
>--- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28
>13:26:04.782367567 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28
>13:25:29.240901395 +0200
>@@ -0,0 +1,30 @@
>+// PR target/94707
>+// { dg-do compile { target powerpc_elfv2 } }
>+// { dg-options "-O2 -std=c++14" }
>+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
>+
>+struct X { };
>+struct Y { int : 0; };
>+struct Z { int : 0; Y y; };
>+struct U : public X { X q; };
>+struct A { float a, b, c, d; };
>+struct B : public X { float a, b, c, d; };
>+struct C : public Y { float a, b, c, d; };
>+struct D : public Z { float a, b, c, d; };
>+struct E : public U { float a, b, c, d; };
>+struct F { [[no_unique_address]] X x; float a, b, c, d; };
>+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
>+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
>+struct I { [[no_unique_address]] U u; float a, b, c, d; };
>+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
>+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
>+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
>+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
>+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () {
>foo##s (s); return 0; }
>+// { dg-bogus "parameter passing for argument of type" }
>+T (D, d)
>+T (E, e)
>+T (H, h)
>+T (I, i)
>+T (L, l)
>+T (M, m)
>--- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28
>13:26:07.485326967 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28
>13:25:40.206736691 +0200
>@@ -0,0 +1,36 @@
>+// PR target/94707
>+// { dg-do compile { target powerpc_elfv2 } }
>+// { dg-options "-O2 -std=c++17" }
>+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
>+
>+struct X { };
>+struct Y { int : 0; };
>+struct Z { int : 0; Y y; };
>+struct U : public X { X q; };
>+struct A { float a, b, c, d; };
>+struct B : public X { float a, b, c, d; };
>+struct C : public Y { float a, b, c, d; };
>+struct D : public Z { float a, b, c, d; };
>+struct E : public U { float a, b, c, d; };
>+struct F { [[no_unique_address]] X x; float a, b, c, d; };
>+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
>+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
>+struct I { [[no_unique_address]] U u; float a, b, c, d; };
>+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
>+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
>+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
>+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
>+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () {
>foo##s (s); return 0; }
>+// { dg-message "parameter passing for argument of type 'B' when
>C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" {
>target *-*-* } .-1 }
>+// { dg-message "parameter passing for argument of type 'C' when
>C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" {
>target *-*-* } .-2 }
>+// { dg-message "parameter passing for argument of type 'F' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-3 }
>+// { dg-message "parameter passing for argument of type 'G' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-4 }
>+// { dg-message "parameter passing for argument of type 'J' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-5 }
>+// { dg-message "parameter passing for argument of type 'K' with
>'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" {
>target *-*-* } .-6 }
>+T (A, a)
>+T (B, b)
>+T (C, c)
>+T (F, f)
>+T (G, g)
>+T (J, j)
>+T (K, k)
>--- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28
>13:26:10.257285341 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28
>13:25:56.925485580 +0200
>@@ -0,0 +1,30 @@
>+// PR target/94707
>+// { dg-do compile { target powerpc_elfv2 } }
>+// { dg-options "-O2 -std=c++17" }
>+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
>+
>+struct X { };
>+struct Y { int : 0; };
>+struct Z { int : 0; Y y; };
>+struct U : public X { X q; };
>+struct A { float a, b, c, d; };
>+struct B : public X { float a, b, c, d; };
>+struct C : public Y { float a, b, c, d; };
>+struct D : public Z { float a, b, c, d; };
>+struct E : public U { float a, b, c, d; };
>+struct F { [[no_unique_address]] X x; float a, b, c, d; };
>+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
>+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
>+struct I { [[no_unique_address]] U u; float a, b, c, d; };
>+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
>+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
>+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
>+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
>+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () {
>foo##s (s); return 0; }
>+// { dg-bogus "parameter passing for argument of type" }
>+T (D, d)
>+T (E, e)
>+T (H, h)
>+T (I, i)
>+T (L, l)
>+T (M, m)
>--- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28
>15:43:13.052722888 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28
>15:47:03.707275087 +0200
>@@ -0,0 +1,34 @@
>+// PR target/94707
>+// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
>+// { dg-options "-std=c++14" }
>+
>+struct X { };
>+struct Y { int : 0; };
>+struct Z { int : 0; Y y; };
>+struct U : public X { X q; };
>+struct A { double a; };
>+struct B : public X { double a; };
>+struct C : public Y { double a; };
>+struct D : public Z { double a; };
>+struct E : public U { double a; };
>+struct F { [[no_unique_address]] X x; double a; };
>+struct G { [[no_unique_address]] Y y; double a; };
>+struct H { [[no_unique_address]] Z z; double a; };
>+struct I { [[no_unique_address]] U u; double a; };
>+struct J { double a; [[no_unique_address]] X x; };
>+struct K { double a; [[no_unique_address]] Y y; };
>+struct L { double a; [[no_unique_address]] Z z; };
>+struct M { double a; [[no_unique_address]] U u; };
>+static_assert (__alignof__ (A) == 8, "");
>+static_assert (__alignof__ (B) == 8, "");
>+static_assert (__alignof__ (C) == 8, "");
>+static_assert (__alignof__ (D) == 4, "");
>+static_assert (__alignof__ (E) == 4, "");
>+static_assert (__alignof__ (F) == 8, "");
>+static_assert (__alignof__ (G) == 8, "");
>+static_assert (__alignof__ (H) == 4, "");
>+static_assert (__alignof__ (I) == 4, "");
>+static_assert (__alignof__ (J) == 8, "");
>+static_assert (__alignof__ (K) == 8, "");
>+static_assert (__alignof__ (L) == 8, "");
>+static_assert (__alignof__ (M) == 8, "");
>--- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28
>15:47:23.482979480 +0200
>+++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28
>15:47:19.132044522 +0200
>@@ -0,0 +1,5 @@
>+// PR target/94707
>+// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
>+// { dg-options "-O2 -std=c++17" }
>+
>+#include "pr94707-5.C"
>
>
>	Jakub
Jakub Jelinek April 28, 2020, 3:54 p.m. UTC | #7
On Tue, Apr 28, 2020 at 05:47:27PM +0200, Richard Biener wrote:
> On April 28, 2020 4:04:58 PM GMT+02:00, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >Hi!
> >
> >On Tue, Apr 28, 2020 at 08:53:31AM -0400, Jason Merrill wrote:
> >> That sounds good.
> >
> >So like this?  Or better name for the new macro?
> 
> I think you miss a hunk for lto/ to compare the flag for tree merging. 

You're right,
	* lto-common.c (compare_tree_sccs_1): Handle DECL_FIELD_ABI_IGNORED.

--- gcc/lto/lto-common.c.jj	2020-04-17 14:18:44.357438048 +0200
+++ gcc/lto/lto-common.c	2020-04-28 17:53:04.809821198 +0200
@@ -1179,6 +1179,7 @@ compare_tree_sccs_1 (tree t1, tree t2, t
 	  compare_values (DECL_PACKED);
 	  compare_values (DECL_NONADDRESSABLE_P);
 	  compare_values (DECL_PADDING_P);
+	  compare_values (DECL_FIELD_ABI_IGNORED);
 	  compare_values (DECL_OFFSET_ALIGN);
 	}
       else if (code == VAR_DECL)

added to my copy of the patch.

	Jakub
Li, Pan2 via Gcc-patches April 28, 2020, 3:57 p.m. UTC | #8
On 4/28/20 10:42 AM, Jakub Jelinek wrote:
> On Tue, Apr 28, 2020 at 10:16:24AM -0500, Bill Schmidt via Gcc-patches wrote:
>> I think this looks good.  My only comment would be to please add some
>> comments in the test cases about the purpose, or at least to explain
>> the regexes in the scan-assembler-* directives, to save us all some
>> mental cycles in the future.
> Ok, below in the updated patch:

Thanks!  Perfect.

Bill

>
> 2020-04-28  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR target/94707
> 	* tree-core.h (tree_decl_common): Note decl_flag_0 used for
> 	DECL_FIELD_ABI_IGNORED.
> 	* tree.h (DECL_FIELD_ABI_IGNORED): Define.
> 	* calls.h (cxx17_empty_base_field_p): Change into a temporary
> 	macro, check DECL_FIELD_ABI_IGNORED flag with no "no_unique_address"
> 	attribute.
> 	* calls.c (cxx17_empty_base_field_p): Remove.
> 	* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
> 	DECL_FIELD_ABI_IGNORED.
> 	* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
> 	* lto-streamer-out.c (hash_tree): Likewise.
> 	* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
> 	cxx17_empty_base_seen to empty_base_seen, change type to int *,
> 	adjust recursive calls, use DECL_FIELD_ABI_IGNORED instead of
> 	cxx17_empty_base_field_p, if "no_unique_address" attribute is
> 	present, propagate that to the caller too.
> 	(rs6000_discover_homogeneous_aggregate): Adjust
> 	rs6000_aggregate_candidate caller, emit different diagnostics
> 	when c++17 empty base fields are present and when empty
> 	[[no_unique_address]] fields are present.
> 	* config/rs6000/rs6000.c (rs6000_special_round_type_align,
> 	darwin_rs6000_special_round_type_align): Skip DECL_FIELD_ABI_IGNORED
> 	fields.
>
> 	* class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty
> 	base artificial FIELD_DECLs.
> 	(layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class
> 	field_poverlapping_p FIELD_DECLs.
>
> 	* g++.target/powerpc/pr94707-1.C: New test.
> 	* g++.target/powerpc/pr94707-2.C: New test.
> 	* g++.target/powerpc/pr94707-3.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
> 	* g++.target/powerpc/pr94707-5.C: New test.
> 	* g++.target/powerpc/pr94707-4.C: New test.
>
> --- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
> +++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
> @@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
>     unsigned lang_flag_8 : 1;
>   
>     /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
> -     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
> +     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
> +     In FIELD_DECL, this is DECL_FIELD_ABI_IGNORED.  */
>     unsigned decl_flag_0 : 1;
>     /* In FIELD_DECL, this is DECL_BIT_FIELD
>        In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
> --- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
> +++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
> @@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
>   /* In a FIELD_DECL, indicates this field should be bit-packed.  */
>   #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
>   
> +/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
> +   like passing/returning containing struct by value.
> +   Set for C++17 empty base artificial FIELD_DECLs as well as
> +   empty [[no_unique_address]] non-static data members.  */
> +#define DECL_FIELD_ABI_IGNORED(NODE) \
> +  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
> +
>   /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
>      specially.  */
>   #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
> --- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
> +++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
> @@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
>   extern void maybe_warn_nonstring_arg (tree, tree);
>   extern bool get_size_range (tree, tree[2], bool = false);
>   extern rtx rtx_for_static_chain (const_tree, bool);
> -extern bool cxx17_empty_base_field_p (const_tree);
> +/* FIXME: Remove after all backends are converted.  */
> +#define cxx17_empty_base_field_p(t) \
> +  (DECL_FIELD_ABI_IGNORED (t)						\
> +   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
>   
>   #endif // GCC_CALLS_H
> --- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
> +++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
> @@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
>     return targetm.calls.must_pass_in_stack (arg);
>   }
>   
> -/* Return true if FIELD is the C++17 empty base field that should
> -   be ignored for ABI calling convention decisions in order to
> -   maintain ABI compatibility between C++14 and earlier, which doesn't
> -   add this FIELD to classes with empty bases, and C++17 and later
> -   which does.  */
> -
> -bool
> -cxx17_empty_base_field_p (const_tree field)
> -{
> -  return (TREE_CODE (field) == FIELD_DECL
> -	  && DECL_ARTIFICIAL (field)
> -	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
> -	  && DECL_SIZE (field)
> -	  && integer_zerop (DECL_SIZE (field))
> -	  && TYPE_SIZE (TREE_TYPE (field))
> -	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
> -}
> -
>   /* Tell the garbage collector about GTY markers in this source file.  */
>   #include "gt-calls.h"
> --- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
> @@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
>         bp_pack_value (bp, DECL_PACKED (expr), 1);
>         bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
>         bp_pack_value (bp, DECL_PADDING_P (expr), 1);
> +      bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
>         bp_pack_value (bp, expr->decl_common.off_align, 8);
>       }
>   
> --- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
> +++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
> @@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
>         DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>         DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +      DECL_FIELD_ABI_IGNORED (expr) = (unsigned) bp_unpack_value (bp, 1);
>         expr->decl_common.off_align = bp_unpack_value (bp, 8);
>       }
>   
> --- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
> +++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
> @@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
>   	  hstate.add_flag (DECL_PACKED (t));
>   	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
>   	  hstate.add_flag (DECL_PADDING_P (t));
> +	  hstate.add_flag (DECL_FIELD_ABI_IGNORED (t));
>   	  hstate.add_int (DECL_OFFSET_ALIGN (t));
>   	}
>         else if (code == VAR_DECL)
> --- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
> +++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
> @@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
>   
>   static int
>   rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
> -			    bool *cxx17_empty_base_seen)
> +			    int *empty_base_seen)
>   {
>     machine_mode mode;
>     HOST_WIDE_INT size;
> @@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
>   	  return -1;
>   
>   	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
> -					    cxx17_empty_base_seen);
> +					    empty_base_seen);
>   	if (count == -1
>   	    || !index
>   	    || !TYPE_MAX_VALUE (index)
> @@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
>   	    if (TREE_CODE (field) != FIELD_DECL)
>   	      continue;
>   
> -	    if (cxx17_empty_base_field_p (field))
> +	    if (DECL_FIELD_ABI_IGNORED (field))
>   	      {
> -		*cxx17_empty_base_seen = true;
> +		if (lookup_attribute ("no_unique_address",
> +				      DECL_ATTRIBUTES (field)))
> +		  *empty_base_seen |= 2;
> +		else
> +		  *empty_base_seen |= 1;
>   		continue;
>   	      }
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count += sub_count;
> @@ -5679,7 +5683,7 @@ rs6000_aggregate_candidate (const_tree t
>   	      continue;
>   
>   	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
> -						    cxx17_empty_base_seen);
> +						    empty_base_seen);
>   	    if (sub_count < 0)
>   	      return -1;
>   	    count = count > sub_count ? count : sub_count;
> @@ -5720,9 +5724,9 @@ rs6000_discover_homogeneous_aggregate (m
>         && AGGREGATE_TYPE_P (type))
>       {
>         machine_mode field_mode = VOIDmode;
> -      bool cxx17_empty_base_seen = false;
> +      int empty_base_seen = 0;
>         int field_count = rs6000_aggregate_candidate (type, &field_mode,
> -						    &cxx17_empty_base_seen);
> +						    &empty_base_seen);
>   
>         if (field_count > 0)
>   	{
> @@ -5737,16 +5741,22 @@ rs6000_discover_homogeneous_aggregate (m
>   		*elt_mode = field_mode;
>   	      if (n_elts)
>   		*n_elts = field_count;
> -	      if (cxx17_empty_base_seen && warn_psabi)
> +	      if (empty_base_seen && warn_psabi)
>   		{
>   		  static unsigned last_reported_type_uid;
>   		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
>   		  if (uid != last_reported_type_uid)
>   		    {
> -		      inform (input_location,
> -			      "parameter passing for argument of type %qT "
> -			      "when C++17 is enabled changed to match C++14 "
> -			      "in GCC 10.1", type);
> +		      if (empty_base_seen & 1)
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"when C++17 is enabled changed to match C++14 "
> +				"in GCC 10.1", type);
> +		      else
> +			inform (input_location,
> +				"parameter passing for argument of type %qT "
> +				"with %<[[no_unique_address]]%> members "
> +				"changed in GCC 10.1", type);
>   		      last_reported_type_uid = uid;
>   		    }
>   		}
> --- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
> +++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
> @@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
>     tree field = TYPE_FIELDS (type);
>   
>     /* Skip all non field decls */
> -  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +  while (field != NULL
> +	 && (TREE_CODE (field) != FIELD_DECL
> +	     || DECL_FIELD_ABI_IGNORED (field)))
>       field = DECL_CHAIN (field);
>   
>     if (field != NULL && field != type)
> @@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
>     do {
>       tree field = TYPE_FIELDS (type);
>       /* Skip all non field decls */
> -    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
> +    while (field != NULL
> +	   && (TREE_CODE (field) != FIELD_DECL
> +	       || DECL_FIELD_ABI_IGNORED (field)))
>         field = DECL_CHAIN (field);
>       if (! field)
>         break;
> --- gcc/cp/class.c.jj	2020-04-28 16:15:39.570540960 +0200
> +++ gcc/cp/class.c	2020-04-28 16:35:18.423859735 +0200
> @@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
>   	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
>   	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
>   	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
> +	  DECL_FIELD_ABI_IGNORED (decl) = 1;
>   	}
>   
>         /* An empty virtual base causes a class to be non-empty
> @@ -6522,7 +6523,10 @@ layout_class_type (tree t, tree *virtual
>   	  SET_DECL_MODE (field, TYPE_MODE (type));
>   	}
>         else if (might_overlap && is_empty_class (type))
> -	layout_empty_base_or_field (rli, field, empty_base_offsets);
> +	{
> +	  DECL_FIELD_ABI_IGNORED (field) = 1;
> +	  layout_empty_base_or_field (rli, field, empty_base_offsets);
> +	}
>         else
>   	layout_nonempty_base_or_field (rli, field, NULL_TREE,
>   				       empty_base_offsets);
> --- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
> @@ -0,0 +1,38 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// Test that for all the calls in this testcase the C++17 empty base
> +// artificial fields and [[no_unique_address]] empty class non-static
> +// data members are ignored in the decision about passing homogeneous
> +// arguments.
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
> @@ -0,0 +1,34 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++14" }
> +// Test that for no calls in this testcase the C++17 empty base
> +// artificial fields and [[no_unique_address]] empty class non-static
> +// data members are ignored in the decision about passing homogeneous
> +// arguments.
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
> @@ -0,0 +1,40 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// Test that for all the calls in this testcase the C++17 empty base
> +// artificial fields and [[no_unique_address]] empty class non-static
> +// data members are ignored in the decision about passing homogeneous
> +// arguments.
> +// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
> +// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
> +// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
> +// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
> +// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
> +// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
> +T (A, a)
> +T (B, b)
> +T (C, c)
> +T (F, f)
> +T (G, g)
> +T (J, j)
> +T (K, k)
> --- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
> @@ -0,0 +1,34 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc_elfv2 } }
> +// { dg-options "-O2 -std=c++17" }
> +// Test that for no calls in this testcase the C++17 empty base
> +// artificial fields and [[no_unique_address]] empty class non-static
> +// data members are ignored in the decision about passing homogeneous
> +// arguments.
> +// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { float a, b, c, d; };
> +struct B : public X { float a, b, c, d; };
> +struct C : public Y { float a, b, c, d; };
> +struct D : public Z { float a, b, c, d; };
> +struct E : public U { float a, b, c, d; };
> +struct F { [[no_unique_address]] X x; float a, b, c, d; };
> +struct G { [[no_unique_address]] Y y; float a, b, c, d; };
> +struct H { [[no_unique_address]] Z z; float a, b, c, d; };
> +struct I { [[no_unique_address]] U u; float a, b, c, d; };
> +struct J { float a, b; [[no_unique_address]] X x; float c, d; };
> +struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
> +struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
> +struct M { float a, b; [[no_unique_address]] U u; float c, d; };
> +#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
> +// { dg-bogus "parameter passing for argument of type" }
> +T (D, d)
> +T (E, e)
> +T (H, h)
> +T (I, i)
> +T (L, l)
> +T (M, m)
> --- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 16:33:53.431130852 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 16:47:31.488901028 +0200
> @@ -0,0 +1,35 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc*-*-darwin* } }
> +// { dg-require-effective-target ilp32 }
> +// { dg-options "-std=c++14" }
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct U : public X { X q; };
> +struct A { double a; };
> +struct B : public X { double a; };
> +struct C : public Y { double a; };
> +struct D : public Z { double a; };
> +struct E : public U { double a; };
> +struct F { [[no_unique_address]] X x; double a; };
> +struct G { [[no_unique_address]] Y y; double a; };
> +struct H { [[no_unique_address]] Z z; double a; };
> +struct I { [[no_unique_address]] U u; double a; };
> +struct J { double a; [[no_unique_address]] X x; };
> +struct K { double a; [[no_unique_address]] Y y; };
> +struct L { double a; [[no_unique_address]] Z z; };
> +struct M { double a; [[no_unique_address]] U u; };
> +static_assert (__alignof__ (A) == 8, "");
> +static_assert (__alignof__ (B) == 8, "");
> +static_assert (__alignof__ (C) == 8, "");
> +static_assert (__alignof__ (D) == 4, "");
> +static_assert (__alignof__ (E) == 4, "");
> +static_assert (__alignof__ (F) == 8, "");
> +static_assert (__alignof__ (G) == 8, "");
> +static_assert (__alignof__ (H) == 4, "");
> +static_assert (__alignof__ (I) == 4, "");
> +static_assert (__alignof__ (J) == 8, "");
> +static_assert (__alignof__ (K) == 8, "");
> +static_assert (__alignof__ (L) == 8, "");
> +static_assert (__alignof__ (M) == 8, "");
> --- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 16:33:53.431130852 +0200
> +++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 16:47:54.056563731 +0200
> @@ -0,0 +1,6 @@
> +// PR target/94707
> +// { dg-do compile { target powerpc*-*-darwin* } }
> +// { dg-require-effective-target ilp32 }
> +// { dg-options "-O2 -std=c++17" }
> +
> +#include "pr94707-5.C"
>
>
> 	Jakub
>
diff mbox series

Patch

--- gcc/tree-core.h.jj	2020-04-08 18:15:36.936946772 +0200
+++ gcc/tree-core.h	2020-04-28 15:14:06.598814022 +0200
@@ -1709,7 +1709,8 @@  struct GTY(()) tree_decl_common {
   unsigned lang_flag_8 : 1;
 
   /* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
-     IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.  */
+     In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
+     In FIELD_DECL, this is ABI_IGNORED_FIELD_P.  */
   unsigned decl_flag_0 : 1;
   /* In FIELD_DECL, this is DECL_BIT_FIELD
      In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
--- gcc/tree.h.jj	2020-04-08 18:15:36.939946727 +0200
+++ gcc/tree.h	2020-04-28 15:13:07.579695258 +0200
@@ -2750,6 +2750,13 @@  extern void decl_value_expr_insert (tree
 /* In a FIELD_DECL, indicates this field should be bit-packed.  */
 #define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
 
+/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
+   like passing/returning containing struct by value.
+   Set for C++17 empty base artificial FIELD_DECLs as well as
+   empty [[no_unique_address]] non-static data members.  */
+#define ABI_IGNORED_FIELD_P(NODE) \
+  (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
+
 /* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
    specially.  */
 #define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_1)
--- gcc/calls.h.jj	2020-04-27 14:31:09.123020831 +0200
+++ gcc/calls.h	2020-04-28 15:26:29.221724466 +0200
@@ -135,6 +135,9 @@  extern tree get_attr_nonstring_decl (tre
 extern void maybe_warn_nonstring_arg (tree, tree);
 extern bool get_size_range (tree, tree[2], bool = false);
 extern rtx rtx_for_static_chain (const_tree, bool);
-extern bool cxx17_empty_base_field_p (const_tree);
+/* FIXME: Remove after all backends are converted.  */
+#define cxx17_empty_base_field_p(t) \
+  (ABI_IGNORED_FIELD_P (t)						\
+   && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
 
 #endif // GCC_CALLS_H
--- gcc/calls.c.jj	2020-04-27 14:31:09.117020922 +0200
+++ gcc/calls.c	2020-04-28 15:26:42.276529517 +0200
@@ -6261,23 +6261,5 @@  must_pass_va_arg_in_stack (tree type)
   return targetm.calls.must_pass_in_stack (arg);
 }
 
-/* Return true if FIELD is the C++17 empty base field that should
-   be ignored for ABI calling convention decisions in order to
-   maintain ABI compatibility between C++14 and earlier, which doesn't
-   add this FIELD to classes with empty bases, and C++17 and later
-   which does.  */
-
-bool
-cxx17_empty_base_field_p (const_tree field)
-{
-  return (TREE_CODE (field) == FIELD_DECL
-	  && DECL_ARTIFICIAL (field)
-	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
-	  && DECL_SIZE (field)
-	  && integer_zerop (DECL_SIZE (field))
-	  && TYPE_SIZE (TREE_TYPE (field))
-	  && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
-}
-
 /* Tell the garbage collector about GTY markers in this source file.  */
 #include "gt-calls.h"
--- gcc/tree-streamer-out.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-out.c	2020-04-28 15:24:40.062354539 +0200
@@ -217,6 +217,7 @@  pack_ts_decl_common_value_fields (struct
       bp_pack_value (bp, DECL_PACKED (expr), 1);
       bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
       bp_pack_value (bp, DECL_PADDING_P (expr), 1);
+      bp_pack_value (bp, ABI_IGNORED_FIELD_P (expr), 1);
       bp_pack_value (bp, expr->decl_common.off_align, 8);
     }
 
--- gcc/tree-streamer-in.c.jj	2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-in.c	2020-04-28 15:24:22.511616625 +0200
@@ -256,6 +256,7 @@  unpack_ts_decl_common_value_fields (stru
       DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+      ABI_IGNORED_FIELD_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       expr->decl_common.off_align = bp_unpack_value (bp, 8);
     }
 
--- gcc/lto-streamer-out.c.jj	2020-04-03 10:04:44.775971053 +0200
+++ gcc/lto-streamer-out.c	2020-04-28 15:23:51.361081794 +0200
@@ -1080,6 +1080,7 @@  hash_tree (struct streamer_tree_cache_d
 	  hstate.add_flag (DECL_PACKED (t));
 	  hstate.add_flag (DECL_NONADDRESSABLE_P (t));
 	  hstate.add_flag (DECL_PADDING_P (t));
+	  hstate.add_flag (ABI_IGNORED_FIELD_P (t));
 	  hstate.add_int (DECL_OFFSET_ALIGN (t));
 	}
       else if (code == VAR_DECL)
--- gcc/config/rs6000/rs6000-call.c.jj	2020-04-23 14:42:26.323839084 +0200
+++ gcc/config/rs6000/rs6000-call.c	2020-04-28 15:28:11.353199343 +0200
@@ -5529,7 +5529,7 @@  const struct altivec_builtin_types altiv
 
 static int
 rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
-			    bool *cxx17_empty_base_seen)
+			    int *empty_base_seen)
 {
   machine_mode mode;
   HOST_WIDE_INT size;
@@ -5600,7 +5600,7 @@  rs6000_aggregate_candidate (const_tree t
 	  return -1;
 
 	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
-					    cxx17_empty_base_seen);
+					    empty_base_seen);
 	if (count == -1
 	    || !index
 	    || !TYPE_MAX_VALUE (index)
@@ -5638,14 +5638,18 @@  rs6000_aggregate_candidate (const_tree t
 	    if (TREE_CODE (field) != FIELD_DECL)
 	      continue;
 
-	    if (cxx17_empty_base_field_p (field))
+	    if (ABI_IGNORED_FIELD_P (field))
 	      {
-		*cxx17_empty_base_seen = true;
+		if (lookup_attribute ("no_unique_address",
+				      DECL_ATTRIBUTES (field)))
+		  *empty_base_seen |= 2;
+		else
+		  *empty_base_seen |= 1;
 		continue;
 	      }
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count += sub_count;
@@ -5679,7 +5683,7 @@  rs6000_aggregate_candidate (const_tree t
 	      continue;
 
 	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
-						    cxx17_empty_base_seen);
+						    empty_base_seen);
 	    if (sub_count < 0)
 	      return -1;
 	    count = count > sub_count ? count : sub_count;
@@ -5720,9 +5724,9 @@  rs6000_discover_homogeneous_aggregate (m
       && AGGREGATE_TYPE_P (type))
     {
       machine_mode field_mode = VOIDmode;
-      bool cxx17_empty_base_seen = false;
+      int empty_base_seen = false;
       int field_count = rs6000_aggregate_candidate (type, &field_mode,
-						    &cxx17_empty_base_seen);
+						    &empty_base_seen);
 
       if (field_count > 0)
 	{
@@ -5737,16 +5741,22 @@  rs6000_discover_homogeneous_aggregate (m
 		*elt_mode = field_mode;
 	      if (n_elts)
 		*n_elts = field_count;
-	      if (cxx17_empty_base_seen && warn_psabi)
+	      if (empty_base_seen && warn_psabi)
 		{
 		  static unsigned last_reported_type_uid;
 		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
 		  if (uid != last_reported_type_uid)
 		    {
-		      inform (input_location,
-			      "parameter passing for argument of type %qT "
-			      "when C++17 is enabled changed to match C++14 "
-			      "in GCC 10.1", type);
+		      if (empty_base_seen & 1)
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"when C++17 is enabled changed to match C++14 "
+				"in GCC 10.1", type);
+		      else
+			inform (input_location,
+				"parameter passing for argument of type %qT "
+				"with %<[[no_unique_address]]%> members "
+				"changed in GCC 10.1", type);
 		      last_reported_type_uid = uid;
 		    }
 		}
--- gcc/config/rs6000/rs6000.c.jj	2020-04-27 09:11:14.090608782 +0200
+++ gcc/config/rs6000/rs6000.c	2020-04-28 15:29:25.166097098 +0200
@@ -7204,7 +7204,9 @@  rs6000_special_round_type_align (tree ty
   tree field = TYPE_FIELDS (type);
 
   /* Skip all non field decls */
-  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+  while (field != NULL
+	 && (TREE_CODE (field) != FIELD_DECL
+	     || ABI_IGNORED_FIELD_P (field)))
     field = DECL_CHAIN (field);
 
   if (field != NULL && field != type)
@@ -7236,7 +7238,9 @@  darwin_rs6000_special_round_type_align (
   do {
     tree field = TYPE_FIELDS (type);
     /* Skip all non field decls */
-    while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+    while (field != NULL
+	   && (TREE_CODE (field) != FIELD_DECL
+	       || ABI_IGNORED_FIELD_P (field)))
       field = DECL_CHAIN (field);
     if (! field)
       break;
--- gcc/cp/class.c.jj	2020-04-27 09:10:50.717967010 +0200
+++ gcc/cp/class.c	2020-04-28 15:22:55.576914814 +0200
@@ -4515,6 +4515,7 @@  build_base_field (record_layout_info rli
 	  DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
 	  DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
 	  SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
+	  ABI_IGNORED_FIELD_P (decl) = 1;
 	}
 
       /* An empty virtual base causes a class to be non-empty
@@ -6235,6 +6236,7 @@  end_of_class (tree t, bool include_virtu
 	&& field_poverlapping_p (field)
 	&& is_empty_class (TREE_TYPE (field)))
       {
+	ABI_IGNORED_FIELD_P (field) = 1;
 	/* Update sizeof(C) to max (sizeof(C), offset(D)+sizeof(D)) */
 	offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
 			     TYPE_SIZE_UNIT (TREE_TYPE (field)));
--- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj	2020-04-28 13:26:01.417418105 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-1.C	2020-04-28 13:25:19.555046878 +0200
@@ -0,0 +1,34 @@ 
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj	2020-04-28 13:26:04.782367567 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-2.C	2020-04-28 13:25:29.240901395 +0200
@@ -0,0 +1,30 @@ 
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj	2020-04-28 13:26:07.485326967 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-3.C	2020-04-28 13:25:40.206736691 +0200
@@ -0,0 +1,36 @@ 
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'F' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-3 }
+// { dg-message "parameter passing for argument of type 'G' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-4 }
+// { dg-message "parameter passing for argument of type 'J' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-5 }
+// { dg-message "parameter passing for argument of type 'K' with '\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* } .-6 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj	2020-04-28 13:26:10.257285341 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-4.C	2020-04-28 13:25:56.925485580 +0200
@@ -0,0 +1,30 @@ 
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj	2020-04-28 15:43:13.052722888 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-5.C	2020-04-28 15:47:03.707275087 +0200
@@ -0,0 +1,34 @@ 
+// PR target/94707
+// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
+// { dg-options "-std=c++14" }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { double a; };
+struct B : public X { double a; };
+struct C : public Y { double a; };
+struct D : public Z { double a; };
+struct E : public U { double a; };
+struct F { [[no_unique_address]] X x; double a; };
+struct G { [[no_unique_address]] Y y; double a; };
+struct H { [[no_unique_address]] Z z; double a; };
+struct I { [[no_unique_address]] U u; double a; };
+struct J { double a; [[no_unique_address]] X x; };
+struct K { double a; [[no_unique_address]] Y y; };
+struct L { double a; [[no_unique_address]] Z z; };
+struct M { double a; [[no_unique_address]] U u; };
+static_assert (__alignof__ (A) == 8, "");
+static_assert (__alignof__ (B) == 8, "");
+static_assert (__alignof__ (C) == 8, "");
+static_assert (__alignof__ (D) == 4, "");
+static_assert (__alignof__ (E) == 4, "");
+static_assert (__alignof__ (F) == 8, "");
+static_assert (__alignof__ (G) == 8, "");
+static_assert (__alignof__ (H) == 4, "");
+static_assert (__alignof__ (I) == 4, "");
+static_assert (__alignof__ (J) == 8, "");
+static_assert (__alignof__ (K) == 8, "");
+static_assert (__alignof__ (L) == 8, "");
+static_assert (__alignof__ (M) == 8, "");
--- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj	2020-04-28 15:47:23.482979480 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-6.C	2020-04-28 15:47:19.132044522 +0200
@@ -0,0 +1,5 @@ 
+// PR target/94707
+// { dg-do compile { target { { powerpc*-darwin* } && ilp32 } } }
+// { dg-options "-O2 -std=c++17" }
+
+#include "pr94707-5.C"