Commit 3bb33002 by Jason Merrill

c++: [[no_unique_address]] fixes. [PR96105]

We were wrongly checking is_empty_class on the result of strip_array_types
rather than the actual field type.  We weren't considering the alignment of
the data member.  We needed to handle unions the same way as
layout_nonempty_base_or_field.

gcc/cp/ChangeLog:

	PR c++/96105
	PR c++/96052
	PR c++/95976
	* class.c (check_field_decls): An array of empty classes is not an
	empty data member.
	(layout_empty_base_or_field): Handle explicit alignment.
	Fix union handling.

gcc/testsuite/ChangeLog:

	PR c++/96105
	PR c++/96052
	PR c++/95976
	* g++.dg/cpp2a/no_unique_address4.C: New test.
	* g++.dg/cpp2a/no_unique_address5.C: New test.
	* g++.dg/cpp2a/no_unique_address6.C: New test.
parent 8614106f
......@@ -3719,7 +3719,8 @@ check_field_decls (tree t, tree *access_decls,
/* We don't treat zero-width bitfields as making a class
non-empty. */
;
else if (field_poverlapping_p (field) && is_empty_class (type))
else if (field_poverlapping_p (field)
&& is_empty_class (TREE_TYPE (field)))
/* Empty data members also don't make a class non-empty. */
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 1;
else
......@@ -4386,15 +4387,20 @@ layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl,
/* This routine should only be used for empty classes. */
gcc_assert (is_empty_class (type));
alignment = size_int (CLASSTYPE_ALIGN_UNIT (type));
if (decl && DECL_USER_ALIGN (decl))
alignment = size_int (DECL_ALIGN_UNIT (decl));
else
alignment = size_int (CLASSTYPE_ALIGN_UNIT (type));
/* This is an empty base class. We first try to put it at offset
zero. */
tree offset = size_zero_node;
if (layout_conflict_p (type,
offset,
offsets,
/*vbases_p=*/0))
if (TREE_CODE (rli->t) != UNION_TYPE
&& layout_conflict_p (type,
offset,
offsets,
/*vbases_p=*/0))
{
/* That didn't work. Now, we move forward from the next
available spot in the class. */
......@@ -4414,7 +4420,14 @@ layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl,
}
}
if (CLASSTYPE_USER_ALIGN (type))
if (decl && DECL_USER_ALIGN (decl))
{
rli->record_align = MAX (rli->record_align, DECL_ALIGN (decl));
if (warn_packed)
rli->unpacked_align = MAX (rli->unpacked_align, DECL_ALIGN (decl));
TYPE_USER_ALIGN (rli->t) = 1;
}
else if (CLASSTYPE_USER_ALIGN (type))
{
rli->record_align = MAX (rli->record_align, CLASSTYPE_ALIGN (type));
if (warn_packed)
......
// PR c++/96105
// { dg-do compile { target c++20 } }
struct Empty {};
struct A {
Empty emp [[no_unique_address]][3];
};
struct B : A {
float f;
};
struct C {
Empty emp [[no_unique_address]][3];
float f;
};
extern char szc[sizeof(C)];
extern char szc[sizeof(float) * 2]; // GCC likes this
extern char szb[sizeof(B)];
extern char szb[sizeof(float) * 2]; // GCC does not like this
// PR c++/96052
// { dg-do compile { target c++20 } }
struct Q {
struct {
} emp alignas(8) [[no_unique_address]];
char x;
};
struct QQ {
char x;
Q q;
};
struct Z {
char x alignas(8) [[no_unique_address]];
};
struct ZZ {
char x;
Z z;
};
extern char qx[sizeof(QQ)];
extern char qx[16];
extern char qz[sizeof(ZZ)];
extern char qz[16];
// PR c++/95976
// { dg-do compile { target c++20 } }
struct empty {};
union no_attribute_t
{
empty _0;
empty _1;
};
union with_attribute_t
{
[[no_unique_address]] empty _0;
[[no_unique_address]] empty _1;
};
constexpr no_attribute_t no_attribute{};
constexpr with_attribute_t with_attribute{};
// This succeeds
static_assert( &no_attribute._0 == &no_attribute._1 );
// This fails
static_assert( &with_attribute._0 == &with_attribute._1 );
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment