diff options
author | Jason Merrill <jason@redhat.com> | 2019-01-29 10:39:40 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2019-01-29 10:39:40 -0500 |
commit | 7e574f68fa82e7c5f879fd468291ec8b5ebecc83 (patch) | |
tree | 1f21833e2d6af54eca9bc56c95e022c7ebb25c54 | |
parent | 6065f1c5889159c9fa1b6c74726d04fc9abea9fe (diff) | |
download | gcc-7e574f68fa82e7c5f879fd468291ec8b5ebecc83.tar.gz |
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
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/class.c | 48 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/no_unique_address4.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/no_unique_address5.C | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/no_unique_address2.C | 12 |
5 files changed, 96 insertions, 16 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5e2f69ddc1f..3cdc7790f43 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index e8773c2a0b0..48da081212a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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; diff --git a/gcc/testsuite/g++.dg/abi/no_unique_address4.C b/gcc/testsuite/g++.dg/abi/no_unique_address4.C new file mode 100644 index 00000000000..c62cfe1f2c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/no_unique_address4.C @@ -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)); diff --git a/gcc/testsuite/g++.dg/abi/no_unique_address5.C b/gcc/testsuite/g++.dg/abi/no_unique_address5.C new file mode 100644 index 00000000000..3e94048b909 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/no_unique_address5.C @@ -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); diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address2.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address2.C new file mode 100644 index 00000000000..aae2394383e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address2.C @@ -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{}, [] {}); |