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 is_empty_field isn't necessary for this version of
the patch, but seems worthwhile for robustness anyway.

Tested x86_64-pc-linux-gnu, applying to trunk.

        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.
---
 gcc/cp/class.c                                |  2 +-
 gcc/cp/constexpr.c                            |  9 ++++++-
 .../g++.dg/cpp2a/no_unique_address13.C        | 24 +++++++++++++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address13.C

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c89ffadcef8..33093e1e1ef 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 a26aead6dc2..4cd9db33a1a 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 00000000000..66b83d68137
--- /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{}};

base-commit: 05516402f8eb8ec282a13fa1e38d9f9c5b3dd3e5
prerequisite-patch-id: 5514b2574504cceea4064fa53a3a97d77c936e66
-- 
2.27.0

Reply via email to