PR c++/54922
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Feb 2013 01:27:47 +0000 (01:27 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Feb 2013 01:27:47 +0000 (01:27 +0000)
* semantics.c (build_anon_member_initialization): New.
(build_data_member_initialization): Use it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@196070 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C [new file with mode: 0644]

index 1e658e9..9033b51 100644 (file)
@@ -1,5 +1,9 @@
 2013-02-14  Jason Merrill  <jason@redhat.com>
 
+       PR c++/54922
+       * semantics.c (build_anon_member_initialization): New.
+       (build_data_member_initialization): Use it.
+
        PR c++/55003
        * decl.c (cp_finish_decl): Force instantiation of an
        auto static data member.
index 95158a5..28b4b79 100644 (file)
@@ -5815,6 +5815,59 @@ is_valid_constexpr_fn (tree fun, bool complain)
   return ret;
 }
 
+/* Subroutine of build_data_member_initialization.  MEMBER is a COMPONENT_REF
+   for a member of an anonymous aggregate, INIT is the initializer for that
+   member, and VEC_OUTER is the vector of constructor elements for the class
+   whose constructor we are processing.  Add the initializer to the vector
+   and return true to indicate success.  */
+
+static bool
+build_anon_member_initialization (tree member, tree init,
+                                 vec<constructor_elt, va_gc> **vec_outer)
+{
+  /* MEMBER presents the relevant fields from the inside out, but we need
+     to build up the initializer from the outside in so that we can reuse
+     previously built CONSTRUCTORs if this is, say, the second field in an
+     anonymous struct.  So we use a vec as a stack.  */
+  vec<tree> fields;
+  fields.create (2);
+  do
+    {
+      fields.safe_push (TREE_OPERAND (member, 1));
+      member = TREE_OPERAND (member, 0);
+    }
+  while (ANON_AGGR_TYPE_P (TREE_TYPE (member)));
+
+  /* VEC has the constructor elements vector for the context of FIELD.
+     If FIELD is an anonymous aggregate, we will push inside it.  */
+  vec<constructor_elt, va_gc> **vec = vec_outer;
+  tree field;
+  while (field = fields.pop(),
+        ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+    {
+      tree ctor;
+      /* If there is already an outer constructor entry for the anonymous
+        aggregate FIELD, use it; otherwise, insert one.  */
+      if (vec_safe_is_empty (*vec)
+         || (*vec)->last().index != field)
+       {
+         ctor = build_constructor (TREE_TYPE (field), NULL);
+         CONSTRUCTOR_APPEND_ELT (*vec, field, ctor);
+       }
+      else
+       ctor = (*vec)->last().value;
+      vec = &CONSTRUCTOR_ELTS (ctor);
+    }
+
+  /* Now we're at the innermost field, the one that isn't an anonymous
+     aggregate.  Add its initializer to the CONSTRUCTOR and we're done.  */
+  gcc_assert (fields.is_empty());
+  fields.release ();
+  CONSTRUCTOR_APPEND_ELT (*vec, field, init);
+
+  return true;
+}
+
 /* Subroutine of  build_constexpr_constructor_member_initializers.
    The expression tree T represents a data member initialization
    in a (constexpr) constructor definition.  Build a pairing of
@@ -5901,12 +5954,21 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
     }
   if (TREE_CODE (member) == ADDR_EXPR)
     member = TREE_OPERAND (member, 0);
-  if (TREE_CODE (member) == COMPONENT_REF
-      /* If we're initializing a member of a subaggregate, it's a vtable
-        pointer.  Leave it as COMPONENT_REF so we remember the path to get
-        to the vfield.  */
-      && TREE_CODE (TREE_OPERAND (member, 0)) != COMPONENT_REF)
-    member = TREE_OPERAND (member, 1);
+  if (TREE_CODE (member) == COMPONENT_REF)
+    {
+      tree aggr = TREE_OPERAND (member, 0);
+      if (TREE_CODE (aggr) != COMPONENT_REF)
+       /* Normal member initialization.  */
+       member = TREE_OPERAND (member, 1);
+      else if (ANON_AGGR_TYPE_P (TREE_TYPE (aggr)))
+       /* Initializing a member of an anonymous union.  */
+       return build_anon_member_initialization (member, init, vec);
+      else
+       /* We're initializing a vtable pointer in a base.  Leave it as
+          COMPONENT_REF so we remember the path to get to the vfield.  */
+       gcc_assert (TREE_TYPE (member) == vtbl_ptr_type_node);
+    }
+
   CONSTRUCTOR_APPEND_ELT (*vec, member, init);
   return true;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C
new file mode 100644 (file)
index 0000000..a8d6b8d
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/54922
+// { dg-do compile { target c++11 } }
+
+struct nullable_int
+{
+  bool init_;
+  union {
+    unsigned char for_value_init;
+    int value_;
+  };
+
+  constexpr nullable_int() : init_(false), for_value_init() {}
+};
+
+#define SA(X) static_assert(X,#X)
+
+constexpr nullable_int n;
+SA((n.for_value_init == 0));
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C
new file mode 100644 (file)
index 0000000..e8e678d
--- /dev/null
@@ -0,0 +1,41 @@
+// PR c++/54922
+// { dg-options "-std=c++11 -pedantic" }
+
+#define SA(X) static_assert(X,#X)
+
+struct A
+{
+  union {
+    union {
+      union {
+       unsigned char i;
+       int j;
+      };
+    };
+  };
+
+  constexpr A() : i(42) {}
+};
+
+constexpr A a;
+SA((a.i == 42));
+
+struct B
+{
+  struct {
+    int h;
+    struct {
+      union {
+       unsigned char i;
+       int j;
+      };
+      int k;
+    };                         // { dg-warning "anonymous struct" }
+  };                           // { dg-warning "anonymous struct" }
+  int l;
+
+  constexpr B(): h(1), i(2), k(3), l(4) {}
+};
+
+constexpr B b;
+SA((b.h == 1 && b.i == 2 && b.k == 3 && b.l == 4));