diff mbox series

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

Message ID 20200428200216.GH2375@tucnak
State New
Headers show
Series [v3] 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, 8:02 p.m. UTC
On Tue, Apr 28, 2020 at 05:42:00PM +0200, Jakub Jelinek wrote:
> Ok, below in the updated patch:

This is what I've successfully bootstrapped/regtested on powerpc64le-linux
(last posted patch with the lto-common.c addition included).
Jason has already approved the non-rs6000 parts, so are those ok for trunk too?

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.

	* lto-common.c (compare_tree_sccs_1): Handle DECL_FIELD_ABI_IGNORED.

	* 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

David Edelsohn April 28, 2020, 11:37 p.m. UTC | #1
On Tue, Apr 28, 2020 at 4:02 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Tue, Apr 28, 2020 at 05:42:00PM +0200, Jakub Jelinek wrote:
> > Ok, below in the updated patch:
>
> This is what I've successfully bootstrapped/regtested on powerpc64le-linux
> (last posted patch with the lto-common.c addition included).
> Jason has already approved the non-rs6000 parts, so are those ok for trunk too?

I bootstrapped the revised patch on AIX and do not see any of the
struct-layout not new target testcase failures.

The rs6000 parts of this patch are okay.

Again, thanks for your diligent effort to track down and fix the
fallout from the c++17 empty base class and same address changes.

Thanks, David


>
> 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.
>
>         * lto-common.c (compare_tree_sccs_1): Handle DECL_FIELD_ABI_IGNORED.
>
>         * 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/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)
> --- 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 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/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)
--- 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"