From e47dfca5aa473e77fdff95d631dc39de87a41eec Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 9 Jul 2020 15:11:12 -0400 Subject: [PATCH] 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. --- gcc/cp/class.c | 27 ++++++++++++++----- .../g++.dg/cpp2a/no_unique_address4.C | 22 +++++++++++++++ .../g++.dg/cpp2a/no_unique_address5.C | 25 +++++++++++++++++ .../g++.dg/cpp2a/no_unique_address6.C | 25 +++++++++++++++++ 4 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 7b5f1669d04..14380c7a08c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3718,7 +3718,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 @@ -4385,15 +4386,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. */ @@ -4413,7 +4419,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) diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C new file mode 100644 index 00000000000..2fe44e37163 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C @@ -0,0 +1,22 @@ +// 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 diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C new file mode 100644 index 00000000000..5fca35dbd81 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C @@ -0,0 +1,25 @@ +// 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]; diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C new file mode 100644 index 00000000000..427db4439dd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C @@ -0,0 +1,25 @@ +// 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 ); -- 2.30.2