Here, when we walk the subobjects to determine the exception
specification of a defaulted destructor in order to apply it to a
user-provided destructor, we shouldn't look at variant members dtors,
which aren't called.

We really shouldn't be looking at variant members here at all except
to determine deletedness, but decided to go with a more limited change
since we're in stage 4.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit df8979f62c2977bd18a2e085e90dbdd4c2f8f98e
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jan 26 11:38:19 2018 -0500

            PR c++/83956 - wrong dtor error with anonymous union
    
            * method.c (walk_field_subobs): Variant members only affect
            deletedness.
            (maybe_explain_implicit_delete): Pass &deleted_p for diagnostic.

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5bc830cd820..33029d7967e 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1305,6 +1305,15 @@ walk_field_subobs (tree fields, tree fnname, 
special_function_kind sfk,
          || DECL_ARTIFICIAL (field))
        continue;
 
+      /* Variant members only affect deletedness.  In particular, they don't
+        affect the exception-specification of a user-provided destructor,
+        which we're figuring out via get_defaulted_eh_spec.  So if we aren't
+        asking if this is deleted, don't even look up the function; we don't
+        want an error about a deleted function we aren't actually calling.  */
+      if (sfk == sfk_destructor && deleted_p == NULL
+         && TREE_CODE (DECL_CONTEXT (field)) == UNION_TYPE)
+       break;
+
       mem_type = strip_array_types (TREE_TYPE (field));
       if (assign_p)
        {
@@ -1850,7 +1859,7 @@ maybe_explain_implicit_delete (tree decl)
                      "%q#D is implicitly deleted because the default "
                      "definition would be ill-formed:", decl);
              synthesized_method_walk (ctype, sfk, const_p,
-                                      NULL, NULL, NULL, NULL, true,
+                                      NULL, NULL, &deleted_p, NULL, true,
                                       &inh, parms);
            }
          else if (!comp_except_specs
diff --git a/gcc/testsuite/g++.dg/cpp0x/anon-union2.C 
b/gcc/testsuite/g++.dg/cpp0x/anon-union2.C
new file mode 100644
index 00000000000..38c91f41a5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/anon-union2.C
@@ -0,0 +1,12 @@
+// PR c++/83956
+// { dg-do compile { target c++11 } }
+
+struct a {
+  ~a() = delete;
+};
+struct b {
+  ~b() {}
+  union {
+    a c;
+  };
+};

Reply via email to