aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2021-06-24 17:32:02 -0400
committerJason Merrill <jason@redhat.com>2021-06-26 00:13:46 -0400
commit2168bfb81448ae1bfa4351760a23d4ec051c2a00 (patch)
treed6d80b172fe5d8f0bf40c1332b30470439d2f28b
parent2afe882858699bb6c13f8502f4f6e862a126d4ef (diff)
downloadgcc-2168bfb81448ae1bfa4351760a23d4ec051c2a00.zip
gcc-2168bfb81448ae1bfa4351760a23d4ec051c2a00.tar.gz
gcc-2168bfb81448ae1bfa4351760a23d4ec051c2a00.tar.bz2
c++: constexpr aggr init of empty class [PR101040]
This is basically the aggregate initializer version of PR97566; as in that bug, we are trying to initialize empty field 'obj' in 'single' when there's no CONSTRUCTOR entry for the 'single' base class subobject of 'derived'. As with that bug, the fix is to stop trying to add entries for empty fields, this time in cxx_eval_bare_aggregate. The change to the other function isn't necessary for this version of the patch, but seems worthwhile for robustness anyway. PR c++/101040 PR c++/97566 gcc/cp/ChangeLog: * class.c (is_empty_field): Handle null argument. * constexpr.c (cxx_eval_bare_aggregate): Discard initializer for empty field. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/no_unique_address13.C: New test.
-rw-r--r--gcc/cp/class.c2
-rw-r--r--gcc/cp/constexpr.c9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/no_unique_address13.C24
3 files changed, 33 insertions, 2 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c89ffad..33093e1 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4220,7 +4220,7 @@ field_poverlapping_p (tree decl)
bool
is_empty_field (tree decl)
{
- if (TREE_CODE (decl) != FIELD_DECL)
+ if (!decl || TREE_CODE (decl) != FIELD_DECL)
return false;
bool r = (is_empty_class (TREE_TYPE (decl))
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index a26aead..4cd9db3 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4449,7 +4449,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
{
tree orig_value = value;
- init_subob_ctx (ctx, new_ctx, index, value);
+ /* Like in cxx_eval_store_expression, omit entries for empty fields. */
+ bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index);
+ if (no_slot)
+ new_ctx = *ctx;
+ else
+ init_subob_ctx (ctx, new_ctx, index, value);
int pos_hint = -1;
if (new_ctx.ctor != ctx->ctor)
{
@@ -4495,6 +4500,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
changed = true;
}
+ else if (no_slot)
+ changed = true;
else
{
if (TREE_CODE (type) == UNION_TYPE
diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address13.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address13.C
new file mode 100644
index 0000000..66b83d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address13.C
@@ -0,0 +1,24 @@
+// PR c++/101040
+// { dg-do compile { target c++11 } }
+
+// This class has to be empty.
+struct empty
+{};
+
+// This class has to be empty.
+struct single
+{
+ // This member has to be no_unique_address.
+ [[no_unique_address]] empty obj;
+};
+
+// This class has to be empty and derived from single.
+struct derived : single
+{
+ // This constructor has to be constexpr and take a forwarding reference.
+ template <typename Arg>
+ constexpr derived(Arg&& arg) : single{arg}
+ {}
+};
+
+auto obj = derived{empty{}};