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;
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
/* 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);
/* A flexible array can't be intialized here, so don't complain
that it isn't. */
continue;
- if (DECL_SIZE (field) && integer_zerop (DECL_SIZE (field)))
+ if (is_empty_field (field))
/* An empty field doesn't need an initializer. */
continue;
ftype = strip_array_types (ftype);
type = refs->pop();
tree index = refs->pop();
- if (TREE_CODE (index) == FIELD_DECL
- && !(same_type_ignoring_top_level_qualifiers_p
- (DECL_CONTEXT (index), TREE_TYPE (*valp))))
- {
- /* INDEX isn't a member of *valp. This can happen if it's a member
- of an empty base which isn't represented with a FIELD_DECL. Stop
- trying to build a CONSTRUCTOR for the inner target; we'll notice
- this disconnect again below and just return init. */
- gcc_assert (is_empty_class (DECL_CONTEXT (index)));
- break;
- }
+ if (is_empty_field (index))
+ /* Don't build a sub-CONSTRUCTOR for an empty base or field, as they
+ have no data and might have an offset lower than previously declared
+ fields, which confuses the middle-end. The code below will notice
+ that we don't have a CONSTRUCTOR for our inner target and just
+ return init. */
+ break;
if (code == UNION_TYPE && CONSTRUCTOR_NELTS (*valp)
&& CONSTRUCTOR_ELT (*valp, 0)->index != index)
extern tree lookup_vfn_in_binfo (tree, tree);
extern void maybe_add_class_template_decl_list (tree, tree, int);
extern void unreverse_member_declarations (tree);
+extern bool is_empty_field (tree);
extern void invalidate_class_lookup_cache (void);
extern void maybe_note_name_used_in_class (tree, tree);
extern void note_name_declared_in_class (tree, tree);
}
if (init == error_mark_node)
return;
- if (DECL_SIZE (member) && integer_zerop (DECL_SIZE (member))
+ if (is_empty_field (member)
&& !TREE_SIDE_EFFECTS (init))
/* Don't add trivial initialization of an empty base/field, as they
might not be ordered the way the back-end expects. */
}
}
- if (DECL_SIZE (field) && integer_zerop (DECL_SIZE (field))
+ if (is_empty_field (field)
&& !TREE_SIDE_EFFECTS (next))
/* Don't add trivial initialization of an empty base/field to the
constructor, as they might not be ordered the way the back-end
--- /dev/null
+// Make sure [[no_unique_address]] doesn't affect is_standard_layout.
+// { dg-do compile { target c++11 } }
+
+struct E1 { }; struct E2 { };
+struct A
+{
+ [[no_unique_address]] E1 e;
+};
+
+struct B: A
+{
+ [[no_unique_address]] E2 e;
+};
+
+static_assert(__is_standard_layout (A), "");
+static_assert(!__is_standard_layout (B), "");
--- /dev/null
+// PR c++/97566
+// { dg-do compile { target c++14 } }
+
+// error disappears if E doesn't inherit from B
+struct B {};
+struct E : B {};
+
+struct counter {
+ constexpr void inc() { size++; }
+
+ // error disappears if you remove or reorder this value
+ int unused = 0;
+ int size = 0;
+ [[no_unique_address]] E empty = {};
+};
+
+#define SA(X) static_assert((X),#X)
+
+constexpr int test1() {
+ counter x;
+ x.inc();
+ return x.size;
+}
+SA(test1() == 1);
+
+constexpr int test2() {
+ counter x = { 0, 1, {} };
+ x.inc();
+ return x.size;
+}
+SA(test2() == 2);
+
+counter y;
+
+struct counter2 {
+ constexpr counter2() { inc(); }
+ constexpr void inc() { size++; }
+
+ // error disappears if you remove or reorder this value
+ int unused = 0;
+ int size = 0;
+ [[no_unique_address]] E empty = {};
+};
+
+constexpr int test3() {
+ counter2 x;
+ x.inc();
+ return x.size;
+}
+SA(test3() == 2);