re PR c++/49136 ([C++0x][constexpr] Incorrect constexpr c'tor evaluation with bitfields)
authorJakub Jelinek <jakub@redhat.com>
Wed, 25 May 2011 07:00:01 +0000 (09:00 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 25 May 2011 07:00:01 +0000 (09:00 +0200)
PR c++/49136
* semantics.c (cxx_eval_bit_field_ref): Handle the
case when BIT_FIELD_REF doesn't cover only a single field.

* g++.dg/cpp0x/constexpr-bitfield2.C: New test.
* g++.dg/cpp0x/constexpr-bitfield3.C: New test.

From-SVN: r174168

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

index d9d8a549e62fdb4478a290e6b39ec6a0e3d181a6..2f2348ff3b62c318192ba9adf5ed1b8a25e8e503 100644 (file)
@@ -1,3 +1,9 @@
+2011-05-25  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/49136
+       * semantics.c (cxx_eval_bit_field_ref): Handle the
+       case when BIT_FIELD_REF doesn't cover only a single field.
+
 2011-05-24  Jason Merrill  <jason@redhat.com>
 
        PR c++/49042
index a7ca50d15e29e62e47ff963fbe6ed6fc2cca9180..50f25f0f72d39c3a7ac98905f98897d83de1c732 100644 (file)
@@ -6449,6 +6449,9 @@ cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
                        bool *non_constant_p)
 {
   tree orig_whole = TREE_OPERAND (t, 0);
+  tree retval, fldval, utype, mask;
+  bool fld_seen = false;
+  HOST_WIDE_INT istart, isize;
   tree whole = cxx_eval_constant_expression (call, orig_whole,
                                             allow_non_constant, addr,
                                             non_constant_p);
@@ -6469,12 +6472,47 @@ cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
     return t;
 
   start = TREE_OPERAND (t, 2);
+  istart = tree_low_cst (start, 0);
+  isize = tree_low_cst (TREE_OPERAND (t, 1), 0);
+  utype = TREE_TYPE (t);
+  if (!TYPE_UNSIGNED (utype))
+    utype = build_nonstandard_integer_type (TYPE_PRECISION (utype), 1);
+  retval = build_int_cst (utype, 0);
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
     {
-      if (bit_position (field) == start)
+      tree bitpos = bit_position (field);
+      if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
        return value;
+      if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
+         && TREE_CODE (value) == INTEGER_CST
+         && host_integerp (bitpos, 0)
+         && host_integerp (DECL_SIZE (field), 0))
+       {
+         HOST_WIDE_INT bit = tree_low_cst (bitpos, 0);
+         HOST_WIDE_INT sz = tree_low_cst (DECL_SIZE (field), 0);
+         HOST_WIDE_INT shift;
+         if (bit >= istart && bit + sz <= istart + isize)
+           {
+             fldval = fold_convert (utype, value);
+             mask = build_int_cst_type (utype, -1);
+             mask = fold_build2 (LSHIFT_EXPR, utype, mask,
+                                 size_int (TYPE_PRECISION (utype) - sz));
+             mask = fold_build2 (RSHIFT_EXPR, utype, mask,
+                                 size_int (TYPE_PRECISION (utype) - sz));
+             fldval = fold_build2 (BIT_AND_EXPR, utype, fldval, mask);
+             shift = bit - istart;
+             if (BYTES_BIG_ENDIAN)
+               shift = TYPE_PRECISION (utype) - shift - sz;
+             fldval = fold_build2 (LSHIFT_EXPR, utype, fldval,
+                                   size_int (shift));
+             retval = fold_build2 (BIT_IOR_EXPR, utype, retval, fldval);
+             fld_seen = true;
+           }
+       }
     }
-  gcc_unreachable();
+  if (fld_seen)
+    return fold_convert (TREE_TYPE (t), retval);
+  gcc_unreachable ();
   return error_mark_node;
 }
 
index b39b4c726c62cfb2f8c0e370f9056b4e4a2d93bd..af20a3ec650e09152da41ab2d894aa21d9b755f8 100644 (file)
@@ -1,3 +1,9 @@
+2011-05-25  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/49136
+       * g++.dg/cpp0x/constexpr-bitfield2.C: New test.
+       * g++.dg/cpp0x/constexpr-bitfield3.C: New test.
+
 2011-05-24  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/48757
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield2.C
new file mode 100644 (file)
index 0000000..531bf31
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/49136
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+struct day
+{
+  unsigned d : 5;
+  unsigned n : 3;
+  constexpr explicit day (int dd) : d(dd), n(7) {}
+};
+
+struct date {
+  int d;
+  constexpr date (day dd) : d(dd.n != 7 ? 7 : dd.d) {}
+};
+
+constexpr day d(0);
+constexpr date dt(d);
+static_assert (dt.d == 0, "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C
new file mode 100644 (file)
index 0000000..b0ecbfb
--- /dev/null
@@ -0,0 +1,33 @@
+// PR c++/49136
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+struct S
+{
+  unsigned : 1; unsigned s : 27; unsigned : 4;
+  constexpr S (unsigned int x) : s(x) {}
+};
+
+template <typename S>
+struct T
+{
+  unsigned int t;
+  constexpr T (S s) : t(s.s != 7 ? 0 : s.s) {}
+  constexpr T (S s, S s2) : t(s.s != s2.s ? 0 : s.s) {}
+};
+
+constexpr S s (7), s2 (7);
+constexpr T<S> t (s), t2 (s, s2);
+static_assert (t.t == 7, "Error");
+static_assert (t2.t == 7, "Error");
+
+struct U
+{
+  int a : 1; int s : 1;
+  constexpr U (int x, int y) : a (x), s (y) {}
+};
+
+constexpr U u (0, -1), u2 (-1, -1);
+constexpr T<U> t3 (u), t4 (u, u2);
+static_assert (t3.t == 0, "Error");
+static_assert (t4.t == -1, "Error");