[PATCH] arm: Fix parameter passing for [[no_unique_address]]
Kyrylo Tkachov
Kyrylo.Tkachov@arm.com
Wed Apr 29 10:42:18 GMT 2020
Hi Richard,
> -----Original Message-----
> From: Richard Sandiford <richard.sandiford@arm.com>
> Sent: 29 April 2020 11:04
> To: gcc-patches@gcc.gnu.org
> Cc: nickc@redhat.com; Richard Earnshaw <Richard.Earnshaw@arm.com>;
> Ramana Radhakrishnan <Ramana.Radhakrishnan@arm.com>; Kyrylo
> Tkachov <Kyrylo.Tkachov@arm.com>
> Subject: [PATCH] arm: Fix parameter passing for [[no_unique_address]]
>
> This patch makes the ABI code ignore zero-sized [[no_unique_address]]
> fields when deciding whether something is a HFA or HVA.
>
> For the tests, I wanted an -march setting that was stable enough
> to use check-function-bodies and also wanted to force -mfloat-abi=hard.
> I couldn't see any existing way of doing both together, since most
> arm-related effective-target keywords are agnostic about the choice
> between -mfloat-abi=softfp and -mfloat-abi=hard. I therefore added
> a new effective-target keyword for this combination.
>
> I used the arm_arch_* framework for the effective-target rather than
> writing a new set of custom Tcl routines. This has the nice property
> of separating the "compile and assemble" cases from the "link and run"
> cases. I only need compilation to work for the new tests, so requiring
> linking to work would be an unnecessary restriction.
>
> However, including an ABI requirement is arguably stretching what the
> list was originally intended to handle. The name arm_arch_v8a_hard
> doesn't fit very naturally with some of the NEON-based tests.
> On the other hand, the naming convention isn't entirely consistent,
> so any choice would be inconsistent with something.
>
> Like with the aarch64 patch, clang produces equivalent code for all
> tests except unions Q and R, which clang passes in s0 rather than r0.
> I think this is a clang bug, since the "x" field contains a single-byte
> FDT and so shouldn't be ignored.
Worth reporting it?
>
> Tested on arm-linux-gnueabihf and armeb-eabi. OK to install?
Ok.
Thanks,
Kyrill
>
> Richard
>
>
> 2020-04-29 Richard Sandiford <richard.sandiford@arm.com>
>
> gcc/
> * doc/sourcebuild.texi (arm_arch_v8a_hard_ok): Document new
> effective-target keyword.
> (arm_arch_v8a_hard_multilib): Likewise.
> (arm_arch_v8a_hard): Document new dg-add-options keyword.
> * config/arm/arm.c (arm_return_in_memory): Note that the APCS
> code is deprecated and has not been updated to handle
> DECL_FIELD_ABI_IGNORED.
> (WARN_PSABI_EMPTY_CXX17_BASE): New constant.
> (WARN_PSABI_NO_UNIQUE_ADDRESS): Likewise.
> (aapcs_vfp_sub_candidate): Replace the boolean pointer parameter
> avoid_cxx17_empty_base with a pointer to a bitmask. Ignore fields
> whose DECL_FIELD_ABI_IGNORED bit is set when determining
> whether
> something actually is a HFA or HVA. Record whether we see a
> [[no_unique_address]] field that previous GCCs would not have
> ignored in this way.
> (aapcs_vfp_is_call_or_return_candidate): Update the calls to
> aapcs_vfp_sub_candidate and report a -Wpsabi warning for the
> [[no_unique_address]] case. Use TYPE_MAIN_VARIANT in the
> diagnostic messages.
> (arm_needs_doubleword_align): Add a comment explaining why we
> consider even zero-sized fields.
>
> gcc/testsuite/
> * lib/target-supports.exp: Add v8a_hard to the list of arm_arch_*
> targets.
> * g++.target/arm/no_unique_address_1.C: New test.
> * g++.target/arm/no_unique_address_2.C: Likewise.
> ---
> gcc/config/arm/arm.c | 108 +++++++---
> gcc/doc/sourcebuild.texi | 15 ++
> .../g++.target/arm/no_unique_address_1.C | 201 ++++++++++++++++++
> .../g++.target/arm/no_unique_address_2.C | 201 ++++++++++++++++++
> gcc/testsuite/lib/target-supports.exp | 1 +
> 5 files changed, 498 insertions(+), 28 deletions(-)
> create mode 100644 gcc/testsuite/g++.target/arm/no_unique_address_1.C
> create mode 100644 gcc/testsuite/g++.target/arm/no_unique_address_2.C
>
> diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
> index b69612024be..d8da77d5ba4 100644
> --- a/gcc/doc/sourcebuild.texi
> +++ b/gcc/doc/sourcebuild.texi
> @@ -1829,6 +1829,16 @@ Some multilibs may be incompatible with these
> options.
> ARM target supports @code{-mfpu=vfp3 -mfloat-abi=softfp}.
> Some multilibs may be incompatible with these options.
>
> +@item arm_arch_v8a_hard_ok
> +The compiler is targeting @code{arm*-*-*} and can compile and assemble
> code
> +using the options @code{-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-
> abi=hard}.
> +This is not enough to guarantee that linking works.
> +
> +@item arm_arch_v8a_hard_multilib
> +The compiler is targeting @code{arm*-*-*} and can build programs using
> +the options @code{-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-
> abi=hard}.
> +The target can also run the resulting binaries.
> +
> @item arm_v8_vfp_ok
> ARM target supports @code{-mfpu=fp-armv8 -mfloat-abi=softfp}.
> Some multilibs may be incompatible with these options.
> @@ -2586,6 +2596,11 @@ the
> @ref{arm_neon_fp16_ok,,arm_neon_fp16_ok effective target keyword}.
> arm vfp3 floating point support; see
> the @ref{arm_vfp3_ok,,arm_vfp3_ok effective target keyword}.
>
> +@item arm_arch_v8a_hard
> +Add options for ARMv8-A and the hard-float variant of the AAPCS,
> +if this is supported by the compiler; see the
> +@ref{arm_arch_v8a_hard_ok,,arm_arch_v8a_hard_ok} effective target
> keyword.
> +
> @item arm_v8_1a_neon
> Add options for ARMv8.1-A with Adv.SIMD support, if this is supported
> by the target; see the @ref{arm_v8_1a_neon_ok,,arm_v8_1a_neon_ok}
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 30a2a3aeb0e..dcaae7bf7aa 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -5963,6 +5963,8 @@ arm_return_in_memory (const_tree type,
> const_tree fntype)
>
> /* Find the first field, ignoring non FIELD_DECL things which will
> have been created by C++. */
> + /* NOTE: This code is deprecated and has not been updated to handle
> + DECL_FIELD_ABI_IGNORED. */
> for (field = TYPE_FIELDS (type);
> field && TREE_CODE (field) != FIELD_DECL;
> field = DECL_CHAIN (field))
> @@ -6135,23 +6137,42 @@ aapcs_vfp_cum_init (CUMULATIVE_ARGS *pcum
> ATTRIBUTE_UNUSED,
> pcum->aapcs_vfp_reg_alloc = 0;
> }
>
> +/* Bitmasks that indicate whether earlier versions of GCC would have
> + taken a different path through the ABI logic. This should result in
> + a -Wpsabi warning if the earlier path led to a different ABI decision.
> +
> + WARN_PSABI_EMPTY_CXX17_BASE
> + Indicates that the type includes an artificial empty C++17 base field
> + that, prior to GCC 10.1, would prevent the type from being treated as
> + a HFA or HVA. See PR94711 for details.
> +
> + WARN_PSABI_NO_UNIQUE_ADDRESS
> + Indicates that the type includes an empty [[no_unique_address]] field
> + that, prior to GCC 10.1, would prevent the type from being treated as
> + a HFA or HVA. */
> +const unsigned int WARN_PSABI_EMPTY_CXX17_BASE = 1U << 0;
> +const unsigned int WARN_PSABI_NO_UNIQUE_ADDRESS = 1U << 1;
> +
> /* Walk down the type tree of TYPE counting consecutive base elements.
> If *MODEP is VOIDmode, then set it to the first valid floating point
> type. If a non-floating point type is found, or if a floating point
> type that doesn't match a non-VOIDmode *MODEP is found, then return -
> 1,
> otherwise return the count in the sub-tree.
>
> - The AVOID_CXX17_EMPTY_BASE argument is to allow the caller to check
> whether
> - this function has changed its behavior after the fix for PR94384 -- this fix
> - is to avoid artificial fields in empty base classes.
> - When called with this argument as a NULL pointer this function does not
> - avoid the artificial fields -- this is useful to check whether the function
> - returns something different after the fix.
> - When called pointing at a value, this function avoids such artificial fields
> - and sets the value to TRUE when one of these fields has been set. */
> + The WARN_PSABI_FLAGS argument allows the caller to check whether this
> + function has changed its behavior relative to earlier versions of GCC.
> + Normally the argument should be nonnull and point to a zero-initialized
> + variable. The function then records whether the ABI decision might
> + be affected by a known fix to the ABI logic, setting the associated
> + WARN_PSABI_* bits if so.
> +
> + When the argument is instead a null pointer, the function tries to
> + simulate the behavior of GCC before all such ABI fixes were made.
> + This is useful to check whether the function returns something
> + different after the ABI fixes. */
> static int
> aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep,
> - bool *avoid_cxx17_empty_base)
> + unsigned int *warn_psabi_flags)
> {
> machine_mode mode;
> HOST_WIDE_INT size;
> @@ -6224,7 +6245,7 @@ aapcs_vfp_sub_candidate (const_tree type,
> machine_mode *modep,
> return -1;
>
> count = aapcs_vfp_sub_candidate (TREE_TYPE (type), modep,
> - avoid_cxx17_empty_base);
> + warn_psabi_flags);
> if (count == -1
> || !index
> || !TYPE_MAX_VALUE (index)
> @@ -6262,20 +6283,30 @@ aapcs_vfp_sub_candidate (const_tree type,
> machine_mode *modep,
> if (TREE_CODE (field) != FIELD_DECL)
> continue;
>
> - /* Ignore C++17 empty base fields, while their type indicates they
> - contain padding, this is only sometimes contributed to the
> derived
> - class.
> - When the padding is contributed to the derived class that's
> - caught by the general test for padding below. */
> - if (cxx17_empty_base_field_p (field)
> - && avoid_cxx17_empty_base)
> + if (DECL_FIELD_ABI_IGNORED (field))
> {
> - *avoid_cxx17_empty_base = true;
> - continue;
> + /* See whether this is something that earlier versions of
> + GCC failed to ignore. */
> + unsigned int flag;
> + if (lookup_attribute ("no_unique_address",
> + DECL_ATTRIBUTES (field)))
> + flag = WARN_PSABI_NO_UNIQUE_ADDRESS;
> + else if (cxx17_empty_base_field_p (field))
> + flag = WARN_PSABI_EMPTY_CXX17_BASE;
> + else
> + /* No compatibility problem. */
> + continue;
> +
> + /* Simulate the old behavior when WARN_PSABI_FLAGS is
> null. */
> + if (warn_psabi_flags)
> + {
> + *warn_psabi_flags |= flag;
> + continue;
> + }
> }
>
> sub_count = aapcs_vfp_sub_candidate (TREE_TYPE (field), modep,
> - avoid_cxx17_empty_base);
> + warn_psabi_flags);
> if (sub_count < 0)
> return -1;
> count += sub_count;
> @@ -6309,7 +6340,7 @@ aapcs_vfp_sub_candidate (const_tree type,
> machine_mode *modep,
> continue;
>
> sub_count = aapcs_vfp_sub_candidate (TREE_TYPE (field), modep,
> - avoid_cxx17_empty_base);
> + warn_psabi_flags);
> if (sub_count < 0)
> return -1;
> count = count > sub_count ? count : sub_count;
> @@ -6371,24 +6402,32 @@ aapcs_vfp_is_call_or_return_candidate (enum
> arm_pcs pcs_variant,
> out from the mode. */
> if (type)
> {
> - bool avoided = false;
> - int ag_count = aapcs_vfp_sub_candidate (type, &new_mode, &avoided);
> + unsigned int warn_psabi_flags = 0;
> + int ag_count = aapcs_vfp_sub_candidate (type, &new_mode,
> + &warn_psabi_flags);
> if (ag_count > 0 && ag_count <= 4)
> {
> static unsigned last_reported_type_uid;
> unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
> int alt;
> if (warn_psabi
> - && avoided
> + && warn_psabi_flags
> && uid != last_reported_type_uid
> && ((alt = aapcs_vfp_sub_candidate (type, &new_mode, NULL))
> != ag_count))
> {
> gcc_assert (alt == -1);
> last_reported_type_uid = 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);
> + /* Use TYPE_MAIN_VARIANT to strip any redundant const
> + qualification. */
> + if (warn_psabi_flags & WARN_PSABI_NO_UNIQUE_ADDRESS)
> + inform (input_location, "parameter passing for argument of "
> + "type %qT with %<[[no_unique_address]]%>
> members "
> + "changed in GCC 10.1", TYPE_MAIN_VARIANT (type));
> + else if (warn_psabi_flags & WARN_PSABI_EMPTY_CXX17_BASE)
> + 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_MAIN_VARIANT (type));
> }
> *count = ag_count;
> }
> @@ -6933,7 +6972,20 @@ arm_needs_doubleword_align (machine_mode
> mode, const_tree type)
>
> int ret = 0;
> int ret2 = 0;
> - /* Record/aggregate types: Use greatest member alignment of any
> member. */
> + /* Record/aggregate types: Use greatest member alignment of any
> member.
> +
> + Note that we explicitly consider zero-sized fields here, even though
> + they don't map to AAPCS machine types. For example, in:
> +
> + struct __attribute__((aligned(8))) empty {};
> +
> + struct s {
> + [[no_unique_address]] empty e;
> + int x;
> + };
> +
> + "s" contains only one Fundamental Data Type (the int field)
> + but gains 8-byte alignment and size thanks to "e". */
> for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> if (DECL_ALIGN (field) > PARM_BOUNDARY)
> {
> diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-
> supports.exp
> index f416d5cafda..13761491e63 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -4443,6 +4443,7 @@ foreach { armfunc armflag armdefs } {
> v7ve "-march=armv7ve -marm"
> "__ARM_ARCH_7A__ && __ARM_FEATURE_IDIV"
> v8a "-march=armv8-a" __ARM_ARCH_8A__
> + v8a_hard "-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-abi=hard"
> __ARM_ARCH_8A__
> v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
> v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
> v8r "-march=armv8-r" __ARM_ARCH_8R__
> diff --git a/gcc/testsuite/g++.target/arm/no_unique_address_1.C
> b/gcc/testsuite/g++.target/arm/no_unique_address_1.C
> new file mode 100644
> index 00000000000..038aa00a499
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/arm/no_unique_address_1.C
> @@ -0,0 +1,201 @@
> +/* { dg-require-effective-target arm_arch_v8a_hard_ok } */
> +/* { dg-options "-std=c++11 -O -foptimize-sibling-calls" } */
> +/* { dg-add-options arm_arch_v8a_hard } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct W : public X { X q; };
> +
> +struct A { float a; };
> +
> +struct B : public X { float a; };
> +struct C : public Y { float a; };
> +struct D : public Z { float a; };
> +struct E : public W { float a; };
> +
> +struct F { [[no_unique_address]] X x; float a; };
> +struct G { [[no_unique_address]] Y y; float a; };
> +struct H { [[no_unique_address]] Z z; float a; };
> +struct I { [[no_unique_address]] W w; float a; };
> +
> +struct J { float a; [[no_unique_address]] X x; float b; };
> +struct K { float a; [[no_unique_address]] Y y; float b; };
> +struct L { float a; [[no_unique_address]] Z z; float b; };
> +struct M { float a; [[no_unique_address]] W w; float b; };
> +
> +struct N : public A { float b; };
> +struct O { [[no_unique_address]] A a; float b; };
> +
> +struct P : public Y { int : 0; float a, b, c, d; };
> +
> +union Q { X x; float a; };
> +union R { [[no_unique_address]] X x; float a; };
> +
> +union S { A a; float b; };
> +union T { F f; float b; };
> +union U { N n; O o; };
> +
> +typedef S Salias;
> +typedef T Talias;
> +typedef U Ualias;
> +
> +#define T(S, s) extern int callee_##s (S)
> +
> +/*
> +** _Z8caller_aR1A:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of
> type 'A'} } */
> +
> +/*
> +** _Z8caller_bR1B:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-bogus {argument
> of type 'B'} } */
> +
> +/*
> +** _Z8caller_cR1C:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-bogus {argument of
> type 'C'} } */
> +
> +/*
> +** _Z8caller_dR1D:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument
> of type 'D'} } */
> +
> +/*
> +** _Z8caller_eR1E:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of
> type 'E'} } */
> +
> +/*
> +** _Z8caller_fR1F:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (F, f); int caller_f (F &f) { return callee_f (f); } /* { dg-message {parameter
> passing for argument of type 'F' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_gR1G:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (G, g); int caller_g (G &g) { return callee_g (g); } /* { dg-message
> {parameter passing for argument of type 'G' with
> '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_hR1H:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument
> of type 'H'} } */
> +
> +/*
> +** _Z8caller_iR1I:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type
> 'I'} } */
> +
> +/*
> +** _Z8caller_jR1J:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (J, j); int caller_j (J &j) { return callee_j (j); } /* { dg-message {parameter
> passing for argument of type 'J' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_kR1K:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (K, k); int caller_k (K &k) { return callee_k (k); } /* { dg-message {parameter
> passing for argument of type 'K' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_lR1L:
> +** ldm r0, {r0, r1, r2}
> +** b .*
> +*/
> +T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of
> type 'L'} } */
> +
> +/*
> +** _Z8caller_mR1M:
> +** ldm r0, {r0, r1, r2}
> +** b .*
> +*/
> +T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus
> {argument of type 'M'} } */
> +
> +/*
> +** _Z8caller_nR1N:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument
> of type 'N'} } */
> +
> +/*
> +** _Z8caller_oR1O:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument
> of type 'O'} } */
> +
> +/*
> +** _Z8caller_pR1P:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** vldr.32 s2, \[r0, #8\]
> +** vldr.32 s3, \[r0, #12\]
> +** b .*
> +*/
> +T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-bogus {argument of
> type 'P'} } */
> +
> +/*
> +** _Z8caller_qR1Q:
> +** ldr r0, \[r0\]
> +** b .*
> +*/
> +T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument
> of type 'Q'} } */
> +
> +/*
> +** _Z8caller_rR1R:
> +** ldr r0, \[r0\]
> +** b .*
> +*/
> +T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of
> type 'R'} } */
> +
> +/*
> +** _Z8caller_sR1S:
> +** vldr.32 s0, \[r0\] @ int
> +** b .*
> +*/
> +T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus
> {argument of type 'S'} } */
> +
> +/*
> +** _Z8caller_tR1T:
> +** vldr.32 s0, \[r0\] @ int
> +** b .*
> +*/
> +T (Talias, t); int caller_t (Talias &t) { return callee_t (t); } /* { dg-message
> {parameter passing for argument of type 'T' with '\[\[no_unique_address\]\]'
> members changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_uR1U:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (Ualias, u); int caller_u (Ualias &u) { return callee_u (u); } /* { dg-bogus
> {argument of type 'U'} } */
> +
> +/* { dg-bogus {argument of type 'const} "should not be printed as const"
> { target *-*-*} 0 } */
> diff --git a/gcc/testsuite/g++.target/arm/no_unique_address_2.C
> b/gcc/testsuite/g++.target/arm/no_unique_address_2.C
> new file mode 100644
> index 00000000000..8be5de2539a
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/arm/no_unique_address_2.C
> @@ -0,0 +1,201 @@
> +/* { dg-require-effective-target arm_arch_v8a_hard_ok } */
> +/* { dg-options "-std=c++17 -O -foptimize-sibling-calls" } */
> +/* { dg-add-options arm_arch_v8a_hard } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +struct X { };
> +struct Y { int : 0; };
> +struct Z { int : 0; Y y; };
> +struct W : public X { X q; };
> +
> +struct A { float a; };
> +
> +struct B : public X { float a; };
> +struct C : public Y { float a; };
> +struct D : public Z { float a; };
> +struct E : public W { float a; };
> +
> +struct F { [[no_unique_address]] X x; float a; };
> +struct G { [[no_unique_address]] Y y; float a; };
> +struct H { [[no_unique_address]] Z z; float a; };
> +struct I { [[no_unique_address]] W w; float a; };
> +
> +struct J { float a; [[no_unique_address]] X x; float b; };
> +struct K { float a; [[no_unique_address]] Y y; float b; };
> +struct L { float a; [[no_unique_address]] Z z; float b; };
> +struct M { float a; [[no_unique_address]] W w; float b; };
> +
> +struct N : public A { float b; };
> +struct O { [[no_unique_address]] A a; float b; };
> +
> +struct P : public Y { int : 0; float a, b, c, d; };
> +
> +union Q { X x; float a; };
> +union R { [[no_unique_address]] X x; float a; };
> +
> +union S { A a; float b; };
> +union T { F f; float b; };
> +union U { N n; O o; };
> +
> +typedef S Salias;
> +typedef T Talias;
> +typedef U Ualias;
> +
> +#define T(S, s) extern int callee_##s (S)
> +
> +/*
> +** _Z8caller_aR1A:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of
> type 'A'} } */
> +
> +/*
> +** _Z8caller_bR1B:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-message
> {parameter passing for argument of type 'B' when C\+\+17 is enabled
> changed to match C\+\+14 in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_cR1C:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-message {parameter
> passing for argument of type 'C' when C\+\+17 is enabled changed to match
> C\+\+14 in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_dR1D:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument
> of type 'D'} } */
> +
> +/*
> +** _Z8caller_eR1E:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of
> type 'E'} } */
> +
> +/*
> +** _Z8caller_fR1F:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (F, f); int caller_f (F &f) { return callee_f (f); } /* { dg-message {parameter
> passing for argument of type 'F' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_gR1G:
> +** vldr.32 s0, \[r0\]
> +** b .*
> +*/
> +T (G, g); int caller_g (G &g) { return callee_g (g); } /* { dg-message
> {parameter passing for argument of type 'G' with
> '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_hR1H:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument
> of type 'H'} } */
> +
> +/*
> +** _Z8caller_iR1I:
> +** ldm r0, {r0, r1}
> +** b .*
> +*/
> +T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type
> 'I'} } */
> +
> +/*
> +** _Z8caller_jR1J:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (J, j); int caller_j (J &j) { return callee_j (j); } /* { dg-message {parameter
> passing for argument of type 'J' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_kR1K:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (K, k); int caller_k (K &k) { return callee_k (k); } /* { dg-message {parameter
> passing for argument of type 'K' with '\[\[no_unique_address\]\]' members
> changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_lR1L:
> +** ldm r0, {r0, r1, r2}
> +** b .*
> +*/
> +T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of
> type 'L'} } */
> +
> +/*
> +** _Z8caller_mR1M:
> +** ldm r0, {r0, r1, r2}
> +** b .*
> +*/
> +T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus
> {argument of type 'M'} } */
> +
> +/*
> +** _Z8caller_nR1N:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument
> of type 'N'} } */
> +
> +/*
> +** _Z8caller_oR1O:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument
> of type 'O'} } */
> +
> +/*
> +** _Z8caller_pR1P:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** vldr.32 s2, \[r0, #8\]
> +** vldr.32 s3, \[r0, #12\]
> +** b .*
> +*/
> +T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-message
> {parameter passing for argument of type 'P' when C\+\+17 is enabled
> changed to match C\+\+14 in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_qR1Q:
> +** ldr r0, \[r0\]
> +** b .*
> +*/
> +T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument
> of type 'Q'} } */
> +
> +/*
> +** _Z8caller_rR1R:
> +** ldr r0, \[r0\]
> +** b .*
> +*/
> +T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of
> type 'R'} } */
> +
> +/*
> +** _Z8caller_sR1S:
> +** vldr.32 s0, \[r0\] @ int
> +** b .*
> +*/
> +T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus
> {argument of type 'S'} } */
> +
> +/*
> +** _Z8caller_tR1T:
> +** vldr.32 s0, \[r0\] @ int
> +** b .*
> +*/
> +T (Talias, t); int caller_t (Talias &t) { return callee_t (t); } /* { dg-message
> {parameter passing for argument of type 'T' with '\[\[no_unique_address\]\]'
> members changed in GCC 10.1} } */
> +
> +/*
> +** _Z8caller_uR1U:
> +** vldr.32 s0, \[r0\]
> +** vldr.32 s1, \[r0, #4\]
> +** b .*
> +*/
> +T (Ualias, u); int caller_u (Ualias &u) { return callee_u (u); } /* { dg-bogus
> {argument of type 'U'} } */
> +
> +/* { dg-bogus {argument of type 'const} "should not be printed as const"
> { target *-*-*} 0 } */
More information about the Gcc-patches
mailing list