static bool aarch64_vfp_is_call_or_return_candidate (machine_mode,
const_tree,
machine_mode *, int *,
- bool *);
+ bool *, bool);
static void aarch64_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
static void aarch64_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
static void aarch64_override_options_after_change (void);
passed in SVE registers. */
static bool
-aarch64_pass_by_reference_1 (const function_arg_info &arg)
+aarch64_pass_by_reference_1 (CUMULATIVE_ARGS *pcum,
+ const function_arg_info &arg)
{
HOST_WIDE_INT size;
machine_mode dummymode;
/* Can this be a candidate to be passed in fp/simd register(s)? */
if (aarch64_vfp_is_call_or_return_candidate (arg.mode, arg.type,
- &dummymode, &nregs,
- NULL))
+ &dummymode, &nregs, NULL,
+ !pcum || pcum->silent_p))
return false;
/* Arguments which are variable sized or larger than 2 registers are
CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
if (!arg.type)
- return aarch64_pass_by_reference_1 (arg);
+ return aarch64_pass_by_reference_1 (pcum, arg);
pure_scalable_type_info pst_info;
switch (pst_info.analyze (arg.type))
|| pcum->aapcs_nprn + pst_info.num_pr () > NUM_PR_ARG_REGS);
case pure_scalable_type_info::DOESNT_MATTER:
- gcc_assert (aarch64_pass_by_reference_1 (arg));
+ gcc_assert (aarch64_pass_by_reference_1 (pcum, arg));
return true;
case pure_scalable_type_info::NO_ABI_IDENTITY:
case pure_scalable_type_info::ISNT_PST:
- return aarch64_pass_by_reference_1 (arg);
+ return aarch64_pass_by_reference_1 (pcum, arg);
}
gcc_unreachable ();
}
is always passed/returned in the least significant bits of fp/simd
register(s). */
if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (valtype), valtype,
- &dummy_mode, &dummy_int, NULL))
+ &dummy_mode, &dummy_int, NULL,
+ false))
return false;
/* Likewise pure scalable types for SVE vector and predicate registers. */
int count;
machine_mode ag_mode;
- if (aarch64_vfp_is_call_or_return_candidate (mode, type,
- &ag_mode, &count, NULL))
+ if (aarch64_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &count,
+ NULL, false))
{
gcc_assert (!sve_p);
if (!aarch64_composite_type_p (type, mode))
/* Simple scalar types always returned in registers. */
return false;
- if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type),
- type,
- &ag_mode,
- &count,
- NULL))
+ if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), type,
+ &ag_mode, &count, NULL, false))
return false;
/* Types larger than 2 registers returned in memory. */
const_tree type, int *nregs)
{
CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
- return aarch64_vfp_is_call_or_return_candidate (mode,
- type,
+ return aarch64_vfp_is_call_or_return_candidate (mode, type,
&pcum->aapcs_vfp_rmode,
- nregs,
- NULL);
+ nregs, NULL, pcum->silent_p);
}
/* Given MODE and TYPE of a function argument, return the alignment in
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
+ /* Note that we explicitly consider zero-sized fields here,
+ even though they don't map to AAPCS64 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". */
alignment = std::max (alignment, DECL_ALIGN (field));
if (DECL_BIT_FIELD_TYPE (field))
bitfield_alignment
machine_mode mode ATTRIBUTE_UNUSED; /* To pass pointer as argument. */
int nregs ATTRIBUTE_UNUSED; /* Likewise. */
if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), type,
- &mode, &nregs, NULL))
+ &mode, &nregs, NULL, false))
aarch64_err_no_fpadvsimd (TYPE_MODE (type));
}
dw_align = false;
adjust = 0;
- if (aarch64_vfp_is_call_or_return_candidate (mode,
- type,
- &ag_mode,
- &nregs,
- &is_ha))
+ if (aarch64_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &nregs,
+ &is_ha, false))
{
/* No frontends can create types with variable-sized modes, so we
shouldn't be asked to pass or return them. */
return default_member_type_forces_blk (field_or_array, mode);
}
+/* 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 PR94383 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;
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)
if (TREE_CODE (field) != FIELD_DECL)
continue;
- /* Ignore C++17 empty base fields, while their type indicates
- they do contain padding, they have zero size and thus don't
- contain any padding. */
- 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;
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;
Upon successful return, *COUNT returns the number of needed registers,
*BASE_MODE returns the mode of the individual register and when IS_HAF
is not NULL, *IS_HA indicates whether or not the argument is a homogeneous
- floating-point aggregate or a homogeneous short-vector aggregate. */
+ floating-point aggregate or a homogeneous short-vector aggregate.
+
+ SILENT_P is true if the function should refrain from reporting any
+ diagnostics. This should only be used if the caller is certain that
+ any ABI decisions would eventually come through this function with
+ SILENT_P set to false. */
static bool
aarch64_vfp_is_call_or_return_candidate (machine_mode mode,
const_tree type,
machine_mode *base_mode,
int *count,
- bool *is_ha)
+ bool *is_ha,
+ bool silent_p)
{
if (is_ha != NULL) *is_ha = false;
}
else if (type && composite_p)
{
- 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 <= HA_MAX_NUM_FLDS)
{
static unsigned last_reported_type_uid;
unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
int alt;
- if (warn_psabi
- && avoided
+ if (!silent_p
+ && warn_psabi
+ && 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));
}
if (is_ha != NULL) *is_ha = true;
--- /dev/null
+/* { dg-options "-std=c++11 -O -foptimize-sibling-calls -fpeephole2" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+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:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */
+
+/*
+** _Z8caller_bR1B:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-bogus {argument of type 'B'} } */
+
+/*
+** _Z8caller_cR1C:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-bogus {argument of type 'C'} } */
+
+/*
+** _Z8caller_dR1D:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */
+
+/*
+** _Z8caller_eR1E:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */
+
+/*
+** _Z8caller_fR1F:
+** ldr s0, \[x0\]
+** 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:
+** ldr s0, \[x0\]
+** 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:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */
+
+/*
+** _Z8caller_iR1I:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */
+
+/*
+** _Z8caller_jR1J:
+** ldp s0, s1, \[x0\]
+** 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:
+** ldp s0, s1, \[x0\]
+** 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: { target aarch64_little_endian }
+** (
+** ldr w1, \[x0, 8\]
+** ldr x0, \[x0\]
+** |
+** mov (x[0-9]+), x0
+** ldr x0, \[x0\]
+** ldr w1, \[\1, 8\]
+** )
+** b .*
+*/
+T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */
+
+/*
+** _Z8caller_mR1M: { target aarch64_little_endian }
+** (
+** ldr w1, \[x0, 8\]
+** ldr x0, \[x0\]
+** |
+** mov (x[0-9]+), x0
+** ldr x0, \[x0\]
+** ldr w1, \[\1, 8\]
+** )
+** b .*
+*/
+T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */
+
+/*
+** _Z8caller_nR1N:
+** ldp s0, s1, \[x0\]
+** b .*
+*/
+T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */
+
+/*
+** _Z8caller_oR1O:
+** ldp s0, s1, \[x0\]
+** b .*
+*/
+T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */
+
+/*
+** _Z8caller_pR1P:
+** ldp s0, s1, \[x0\]
+** ldp s2, s3, \[x0, 8\]
+** b .*
+*/
+T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-bogus {argument of type 'P'} } */
+
+/*
+** _Z8caller_qR1Q: { target aarch64_little_endian }
+** ldr w0, \[x0\]
+** b .*
+*/
+T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */
+
+/*
+** _Z8caller_rR1R: { target aarch64_little_endian }
+** ldr w0, \[x0\]
+** b .*
+*/
+T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */
+
+/*
+** _Z8caller_sR1S:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */
+
+/*
+** _Z8caller_tR1T:
+** ldr s0, \[x0\]
+** 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:
+** ldp s0, s1, \[x0\]
+** 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 } */
--- /dev/null
+/* { dg-options "-std=c++17 -O -foptimize-sibling-calls -fpeephole2" } */
+/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
+
+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:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */
+
+/*
+** _Z8caller_bR1B:
+** ldr s0, \[x0\]
+** 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:
+** ldr s0, \[x0\]
+** 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:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */
+
+/*
+** _Z8caller_eR1E:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */
+
+/*
+** _Z8caller_fR1F:
+** ldr s0, \[x0\]
+** 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:
+** ldr s0, \[x0\]
+** 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:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */
+
+/*
+** _Z8caller_iR1I:
+** ldr x0, \[x0\]
+** b .*
+*/
+T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */
+
+/*
+** _Z8caller_jR1J:
+** ldp s0, s1, \[x0\]
+** 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:
+** ldp s0, s1, \[x0\]
+** 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: { target aarch64_little_endian }
+** (
+** ldr w1, \[x0, 8\]
+** ldr x0, \[x0\]
+** |
+** mov (x[0-9]+), x0
+** ldr x0, \[x0\]
+** ldr w1, \[\1, 8\]
+** )
+** b .*
+*/
+T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */
+
+/*
+** _Z8caller_mR1M: { target aarch64_little_endian }
+** (
+** ldr w1, \[x0, 8\]
+** ldr x0, \[x0\]
+** |
+** mov (x[0-9]+), x0
+** ldr x0, \[x0\]
+** ldr w1, \[\1, 8\]
+** )
+** b .*
+*/
+T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */
+
+/*
+** _Z8caller_nR1N:
+** ldp s0, s1, \[x0\]
+** b .*
+*/
+T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */
+
+/*
+** _Z8caller_oR1O:
+** ldp s0, s1, \[x0\]
+** b .*
+*/
+T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */
+
+/*
+** _Z8caller_pR1P:
+** ldp s0, s1, \[x0\]
+** ldp s2, s3, \[x0, 8\]
+** 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: { target aarch64_little_endian }
+** ldr w0, \[x0\]
+** b .*
+*/
+T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */
+
+/*
+** _Z8caller_rR1R: { target aarch64_little_endian }
+** ldr w0, \[x0\]
+** b .*
+*/
+T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */
+
+/*
+** _Z8caller_sR1S:
+** ldr s0, \[x0\]
+** b .*
+*/
+T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */
+
+/*
+** _Z8caller_tR1T:
+** ldr s0, \[x0\]
+** 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:
+** ldp s0, s1, \[x0\]
+** 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 } */