diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-25 07:00:01 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-25 07:00:01 +0000 |
commit | 793c6646f29ce31f7d7085bb86a0454b884f7777 (patch) | |
tree | e983cd89f9335030a3aef83f37438b9d6cb1e8bc /gcc/cp | |
parent | 33317c39a26fddca642084ecf351055dc5364e5a (diff) | |
download | gcc-793c6646f29ce31f7d7085bb86a0454b884f7777.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174168 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 42 |
2 files changed, 46 insertions, 2 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d9d8a549e62..2f2348ff3b6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a7ca50d15e2..50f25f0f72d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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; } |