aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/class.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2021-01-24 00:55:49 -0500
committerJason Merrill <jason@redhat.com>2021-01-26 15:00:38 -0500
commita4dfd0f089af33f2af57bf422f9859405b9b4a16 (patch)
treea464db65d5d3e2c6ce5e0afe1ef258cca6a7aa0e /gcc/cp/class.c
parente80f1f6b7a339bce1db03567e497658ae32d135e (diff)
downloadgcc-a4dfd0f089af33f2af57bf422f9859405b9b4a16.zip
gcc-a4dfd0f089af33f2af57bf422f9859405b9b4a16.tar.gz
gcc-a4dfd0f089af33f2af57bf422f9859405b9b4a16.tar.bz2
c++: constexpr and empty fields [PR97566]
In the discussion of PR98463, Jakub pointed out that in C++17 and up, cxx_fold_indirect_ref_1 could use the field we build for an empty base. I tried implementing that, but it broke one of the tuple tests, so I did some more digging. To start with, I generalized the PR98463 patch to handle the case where we do have a field, for an empty base or [[no_unique_address]] member. This is enough also for the no-field case because the member of the empty base must itself be an empty field; if it weren't, the base would not be empty. I looked for related PRs and found 97566, which was also fixed by the patch. After some poking around to figure out why, I noticed that the testcase had been breaking because E, though an empty class, has an ABI nvsize of one byte, and we were giving the [[no_unique_address]] FIELD_DECL that DECL_SIZE, whereas in build_base_field_1 empty base fields always get DECL_SIZE zero, and various places were relying on that to recognize empty fields. So I adjusted both the size and the checking. When I adjusted check_bases I wondered if we were correctly handling bases with only empty data members, but it appears we do. I'm deferring the cxx_fold_indirect_ref_1 change until stage 1, as I don't think it actually fixes anything. gcc/cp/ChangeLog: PR c++/97566 PR c++/98463 * class.c (layout_class_type): An empty field gets size 0. (is_empty_field): New. (check_bases): Check it. * cp-tree.h (is_empty_field): Declare it. * constexpr.c (cxx_eval_store_expression): Check it. (cx_check_missing_mem_inits): Likewise. * init.c (perform_member_init): Likewise. * typeck2.c (process_init_constructor_record): Likewise. gcc/testsuite/ChangeLog: PR c++/97566 * g++.dg/cpp2a/no_unique_address10.C: New test. * g++.dg/cpp2a/no_unique_address9.C: New test.
Diffstat (limited to 'gcc/cp/class.c')
-rw-r--r--gcc/cp/class.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 00c0dba..40f5fef 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1835,15 +1835,13 @@ check_bases (tree t,
else if (CLASSTYPE_REPEATED_BASE_P (t))
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
else
- /* ...either has no non-static data members in the most-derived
- class and at most one base class with non-static data
- members, or has no base classes with non-static data
- members. FIXME This was reworded in DR 1813. */
+ /* ...has all non-static data members and bit-fields in the class
+ and its base classes first declared in the same class. */
for (basefield = TYPE_FIELDS (basetype); basefield;
basefield = DECL_CHAIN (basefield))
if (TREE_CODE (basefield) == FIELD_DECL
&& !(DECL_FIELD_IS_BASE (basefield)
- && integer_zerop (DECL_SIZE (basefield))))
+ && is_empty_field (basefield)))
{
if (field)
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
@@ -4226,6 +4224,25 @@ field_poverlapping_p (tree decl)
DECL_ATTRIBUTES (decl));
}
+/* Return true iff DECL is an empty field, either for an empty base or a
+ [[no_unique_address]] data member. */
+
+bool
+is_empty_field (tree decl)
+{
+ if (TREE_CODE (decl) != FIELD_DECL)
+ return false;
+
+ bool r = (is_empty_class (TREE_TYPE (decl))
+ && (DECL_FIELD_IS_BASE (decl)
+ || field_poverlapping_p (decl)));
+
+ /* Empty fields should have size zero. */
+ gcc_checking_assert (!r || integer_zerop (DECL_SIZE (decl)));
+
+ return r;
+}
+
/* Record all of the empty subobjects of DECL_OR_BINFO. */
static void
@@ -6612,7 +6629,9 @@ layout_class_type (tree t, tree *virtuals_p)
/* 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))
+ if (CLASSTYPE_EMPTY_P (type))
+ DECL_SIZE (field) = DECL_SIZE_UNIT (field) = size_zero_node;
+ else if (tree_int_cst_le (dsize, nvsize))
{
DECL_SIZE_UNIT (field) = nvsize;
DECL_SIZE (field) = CLASSTYPE_SIZE (type);