PR c++/89089 - ICE with [[no_unique_address]].
In 89089, we were never actually setting DECL_SIZE on an empty data member, because its type is a POD, so we didn't set it in the maybe-overlapping section. Fixed by also handling empty types there. In 88865, we were failing to consider empty data members in include_empty_classes. Fixed by making end_of_class always include them. While looking at these I noticed that the ABI says that a potentially-overlapping data member makes its class non-layout-POD, and that an empty data member doesn't prevent its class from being empty, so I've implemented those points as well. PR c++/88865 - wrong layout with [[no_unique_address]]. * class.c (check_field_decls): A potentially-overlapping field makes the class non-layout-POD, but not non-empty. (end_of_class): Always consider empty data members. (layout_class_type): Set DECL_SIZE for empty fields. From-SVN: r268368
This commit is contained in:
parent
6065f1c588
commit
7e574f68fa
|
@ -1,3 +1,12 @@
|
|||
2019-01-28 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/89089 - ICE with [[no_unique_address]].
|
||||
PR c++/88865 - wrong layout with [[no_unique_address]].
|
||||
* class.c (check_field_decls): A potentially-overlapping field makes
|
||||
the class non-layout-POD, but not non-empty.
|
||||
(end_of_class): Always consider empty data members.
|
||||
(layout_class_type): Set DECL_SIZE for empty fields.
|
||||
|
||||
2019-01-28 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/88358 - name wrongly treated as type.
|
||||
|
|
|
@ -206,6 +206,7 @@ static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree);
|
|||
static tree end_of_base (tree);
|
||||
static tree get_vcall_index (tree, tree);
|
||||
static bool type_maybe_constexpr_default_constructor (tree);
|
||||
static bool field_poverlapping_p (tree);
|
||||
|
||||
/* Return a COND_EXPR that executes TRUE_STMT if this execution of the
|
||||
'structor is in charge of 'structing virtual bases, or FALSE_STMT
|
||||
|
@ -3556,6 +3557,11 @@ 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 (x) && is_empty_class (type))
|
||||
{
|
||||
/* Empty data members also don't make a class non-empty. */
|
||||
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The class is non-empty. */
|
||||
|
@ -3608,6 +3614,11 @@ check_field_decls (tree t, tree *access_decls,
|
|||
to be allowed in POD structs. */
|
||||
CLASSTYPE_NON_LAYOUT_POD_P (t) = 1;
|
||||
|
||||
if (field_poverlapping_p (x))
|
||||
/* A potentially-overlapping non-static data member makes the class
|
||||
non-layout-POD. */
|
||||
CLASSTYPE_NON_LAYOUT_POD_P (t) = 1;
|
||||
|
||||
if (!std_layout_type_p (type))
|
||||
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
|
||||
|
||||
|
@ -5926,13 +5937,12 @@ end_of_base (tree binfo)
|
|||
return size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), size);
|
||||
}
|
||||
|
||||
/* Returns the offset of the byte just past the end of the base class
|
||||
with the highest offset in T. If INCLUDE_VIRTUALS_P is zero, then
|
||||
only non-virtual bases are included. If INCLUDE_FIELDS_P is true,
|
||||
then also consider non-static data members. */
|
||||
/* Returns the offset of the byte just past the end of the base class or empty
|
||||
data member with the highest offset in T. If INCLUDE_VIRTUALS_P is zero,
|
||||
then only non-virtual bases are included. */
|
||||
|
||||
static tree
|
||||
end_of_class (tree t, bool include_virtuals_p, bool include_fields_p = false)
|
||||
end_of_class (tree t, bool include_virtuals_p)
|
||||
{
|
||||
tree result = size_zero_node;
|
||||
vec<tree, va_gc> *vbases;
|
||||
|
@ -5955,15 +5965,19 @@ end_of_class (tree t, bool include_virtuals_p, bool include_fields_p = false)
|
|||
result = offset;
|
||||
}
|
||||
|
||||
if (include_fields_p)
|
||||
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
|
||||
if (TREE_CODE (field) == FIELD_DECL)
|
||||
{
|
||||
offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
|
||||
DECL_SIZE_UNIT (field));
|
||||
if (tree_int_cst_lt (result, offset))
|
||||
result = offset;
|
||||
}
|
||||
/* Also consider empty data members. */
|
||||
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
|
||||
if (TREE_CODE (field) == FIELD_DECL
|
||||
&& !DECL_ARTIFICIAL (field)
|
||||
&& field_poverlapping_p (field)
|
||||
&& is_empty_class (TREE_TYPE (field)))
|
||||
{
|
||||
/* Update sizeof(C) to max (sizeof(C), offset(D)+sizeof(D)) */
|
||||
offset = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
|
||||
TYPE_SIZE_UNIT (TREE_TYPE (field)));
|
||||
if (tree_int_cst_lt (result, offset))
|
||||
result = offset;
|
||||
}
|
||||
|
||||
if (include_virtuals_p)
|
||||
for (vbases = CLASSTYPE_VBASECLASSES (t), i = 0;
|
||||
|
@ -6154,12 +6168,14 @@ layout_class_type (tree t, tree *virtuals_p)
|
|||
bool might_overlap = field_poverlapping_p (field);
|
||||
|
||||
if (might_overlap && CLASS_TYPE_P (type)
|
||||
&& CLASSTYPE_NON_LAYOUT_POD_P (type))
|
||||
&& (CLASSTYPE_NON_LAYOUT_POD_P (type) || CLASSTYPE_EMPTY_P (type)))
|
||||
{
|
||||
/* if D is a potentially-overlapping data member, update sizeof(C) to
|
||||
max (sizeof(C), offset(D)+max (nvsize(D), dsize(D))). */
|
||||
tree nvsize = CLASSTYPE_SIZE_UNIT (type);
|
||||
tree dsize = end_of_class (type, /*vbases*/true, /*fields*/true);
|
||||
/* end_of_class doesn't always give dsize, but it does in the case of
|
||||
a class with virtual bases, which is when dsize > nvsize. */
|
||||
tree dsize = end_of_class (type, /*vbases*/true);
|
||||
if (tree_int_cst_le (dsize, nvsize))
|
||||
{
|
||||
DECL_SIZE_UNIT (field) = nvsize;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// Test that [[no_unique_address]] makes the enclosing class non-layout-POD.
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct A {};
|
||||
struct B1: A {
|
||||
int i;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct B2 {
|
||||
[[no_unique_address]] A a;
|
||||
int i;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct C1: B1 {
|
||||
char d;
|
||||
};
|
||||
|
||||
struct C2: B2 {
|
||||
char d;
|
||||
};
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(sizeof(C1) == sizeof(C2));
|
|
@ -0,0 +1,18 @@
|
|||
// PR c++/88865
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct B {};
|
||||
struct A {
|
||||
[[no_unique_address]] B a;
|
||||
[[no_unique_address]] B b;
|
||||
[[no_unique_address]] B c;
|
||||
[[no_unique_address]] B d;
|
||||
};
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(sizeof(A) == 4);
|
||||
|
||||
A a;
|
||||
SA(&a.a != &a.b);
|
||||
SA(&a.c != &a.b);
|
||||
SA(&a.c != &a.d);
|
|
@ -0,0 +1,12 @@
|
|||
// PR c++/89089
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
template <typename...> struct A {};
|
||||
template <typename T, typename... U> struct A<T, U...> {
|
||||
private:
|
||||
[[no_unique_address]] A<U...> a;
|
||||
};
|
||||
struct B {
|
||||
template <typename... U> A<U...> operator()(U...) { return A<U...>(); }
|
||||
} f;
|
||||
auto fn = f (int{}, [] {});
|
Loading…
Reference in New Issue