re PR c++/52377 (C++11 non-static initializers in unions are not used)
authorJason Merrill <jason@redhat.com>
Thu, 30 May 2013 19:20:08 +0000 (15:20 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 30 May 2013 19:20:08 +0000 (15:20 -0400)
PR c++/52377
* class.c (common_enclosing_class): New.
* cp-tree.h: Declare it.
* init.c (sort_mem_initializers): Don't splice out a union member
with an NSDMI.

From-SVN: r199455

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C [new file with mode: 0644]

index ed26fa0de231a9201dc8eb80788d9c68b83a92c6..6ccc776580f874a23c0e0913a0bd5c425b6d50cb 100644 (file)
@@ -1,3 +1,11 @@
+2013-05-30  Jason Merrill  <jason@redhat.com>
+
+       PR c++/52377
+       * class.c (common_enclosing_class): New.
+       * cp-tree.h: Declare it.
+       * init.c (sort_mem_initializers): Don't splice out a union member
+       with an NSDMI.
+
 2013-05-29  Jan Hubicka  <jh@suse.cz>
 
        * tree.c (cp_fix_function_decl_p): Update for new symtab flags.
index d6684cfd68b43074b54c9a9620a5477424ec3063..22cdf90f735b9254d23476736c1074570a16cb22 100644 (file)
@@ -9259,4 +9259,30 @@ publicly_uniquely_derived_p (tree parent, tree type)
   return base && base != error_mark_node;
 }
 
+/* CTX1 and CTX2 are declaration contexts.  Return the innermost common
+   class between them, if any.  */
+
+tree
+common_enclosing_class (tree ctx1, tree ctx2)
+{
+  if (!TYPE_P (ctx1) || !TYPE_P (ctx2))
+    return NULL_TREE;
+  gcc_assert (ctx1 == TYPE_MAIN_VARIANT (ctx1)
+             && ctx2 == TYPE_MAIN_VARIANT (ctx2));
+  if (ctx1 == ctx2)
+    return ctx1;
+  for (tree t = ctx1; TYPE_P (t); t = TYPE_CONTEXT (t))
+    TYPE_MARKED_P (t) = true;
+  tree found = NULL_TREE;
+  for (tree t = ctx2; TYPE_P (t); t = TYPE_CONTEXT (t))
+    if (TYPE_MARKED_P (t))
+      {
+       found = t;
+       break;
+      }
+  for (tree t = ctx1; TYPE_P (t); t = TYPE_CONTEXT (t))
+    TYPE_MARKED_P (t) = false;
+  return found;
+}
+
 #include "gt-cp-class.h"
index 1f85ca7196fafccba623b7c8f827522b8191648f..aebc440a4272f100b2d43d7f38b8d49fc20cae66 100644 (file)
@@ -5112,6 +5112,7 @@ extern void deduce_noexcept_on_destructor       (tree);
 extern void insert_late_enum_def_into_classtype_sorted_fields (tree, tree);
 extern bool uniquely_derived_from_p             (tree, tree);
 extern bool publicly_uniquely_derived_p         (tree, tree);
+extern tree common_enclosing_class             (tree, tree);
 
 /* in cvt.c */
 extern tree convert_to_reference               (tree, tree, int, int, tree,
index 671c774587d9f2e6e33fc6b882634df2f8f2be5c..4edd150d91360b3d3b22fda5d6619bf9fb92c462 100644 (file)
@@ -914,13 +914,12 @@ sort_mem_initializers (tree t, tree mem_inits)
      Here we also splice out uninitialized union members.  */
   if (uses_unions_p)
     {
-      tree last_field = NULL_TREE;
+      tree *last_p = NULL;
       tree *p;
       for (p = &sorted_inits; *p; )
        {
          tree field;
          tree ctx;
-         int done;
 
          init = *p;
 
@@ -940,22 +939,25 @@ sort_mem_initializers (tree t, tree mem_inits)
          for (ctx = DECL_CONTEXT (field);
               !same_type_p (ctx, t);
               ctx = TYPE_CONTEXT (ctx))
-           if (TREE_CODE (ctx) == UNION_TYPE)
+           if (TREE_CODE (ctx) == UNION_TYPE
+               || !ANON_AGGR_TYPE_P (ctx))
              break;
          /* If this field is not a member of a union, skip it.  */
          if (TREE_CODE (ctx) != UNION_TYPE)
            goto next;
 
-         /* If this union member has no explicit initializer, splice
-            it out.  */
-         if (!TREE_VALUE (init))
+         /* If this union member has no explicit initializer and no NSDMI,
+            splice it out.  */
+         if (TREE_VALUE (init) || DECL_INITIAL (field))
+           /* OK.  */;
+         else
            goto splice;
 
          /* It's only an error if we have two initializers for the same
             union type.  */
-         if (!last_field)
+         if (!last_p)
            {
-             last_field = field;
+             last_p = p;
              goto next;
            }
 
@@ -967,41 +969,23 @@ sort_mem_initializers (tree t, tree mem_inits)
               union { struct { int i; int j; }; };
 
             initializing both `i' and `j' makes sense.  */
-         ctx = DECL_CONTEXT (field);
-         done = 0;
-         do
-           {
-             tree last_ctx;
-
-             last_ctx = DECL_CONTEXT (last_field);
-             while (1)
-               {
-                 if (same_type_p (last_ctx, ctx))
-                   {
-                     if (TREE_CODE (ctx) == UNION_TYPE)
-                       error_at (DECL_SOURCE_LOCATION (current_function_decl),
-                                 "initializations for multiple members of %qT",
-                                 last_ctx);
-                     done = 1;
-                     break;
-                   }
+         ctx = common_enclosing_class (DECL_CONTEXT (field),
+                                       DECL_CONTEXT (TREE_PURPOSE (*last_p)));
 
-                 if (same_type_p (last_ctx, t))
-                   break;
-
-                 last_ctx = TYPE_CONTEXT (last_ctx);
-               }
-
-             /* If we've reached the outermost class, then we're
-                done.  */
-             if (same_type_p (ctx, t))
-               break;
-
-             ctx = TYPE_CONTEXT (ctx);
+         if (ctx && TREE_CODE (ctx) == UNION_TYPE)
+           {
+             /* A mem-initializer hides an NSDMI.  */
+             if (TREE_VALUE (init) && !TREE_VALUE (*last_p))
+               *last_p = TREE_CHAIN (*last_p);
+             else if (TREE_VALUE (*last_p) && !TREE_VALUE (init))
+               goto splice;
+             else
+               error_at (DECL_SOURCE_LOCATION (current_function_decl),
+                         "initializations for multiple members of %qT",
+                         ctx);
            }
-         while (!done);
 
-         last_field = field;
+         last_p = p;
 
        next:
          p = &TREE_CHAIN (*p);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C
new file mode 100644 (file)
index 0000000..11bdd88
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/52377
+// { dg-do run { target c++11 } }
+
+union Test
+{
+  int a{4};
+};
+
+union B
+{
+  int i = 42;
+  double d;
+  B() = default;
+  B(double d): d(d) { }
+};
+
+int main()
+{
+  Test t;
+  B b;
+  B b2(4.2);
+
+  if (t.a != 4 || b.i != 42 || b2.d != 4.2)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C
new file mode 100644 (file)
index 0000000..b45fe83
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/52377
+// { dg-do run { target c++11 } }
+
+union A                                // { dg-error "multiple" }
+{
+  int i = 4;
+  int j = 2;
+};
+
+A a;
+
+union B
+{
+  int i,j;
+  B(): i(1), j(2) {}           // { dg-error "multiple" }
+};
+
+B b;