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.

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.
This commit is contained in:
Richard Sandiford 2020-04-29 11:51:03 +01:00
parent e6e616074f
commit 127abeb2e8
7 changed files with 529 additions and 28 deletions

View File

@ -1,3 +1,27 @@
2020-04-29 Richard Sandiford <richard.sandiford@arm.com>
* 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.
2020-04-29 Richard Biener <rguenther@suse.de>
Li Zekun <lizekun1@huawei.com>

View File

@ -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)
{

View File

@ -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}

View File

@ -1,3 +1,10 @@
2020-04-29 Richard Sandiford <richard.sandiford@arm.com>
* 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.
2020-04-29 Richard Biener <rguenther@suse.de>
Li Zekun <lizekun1@huawei.com>

View File

@ -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 } */

View File

@ -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 } */

View File

@ -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__