diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/expr/bitfield14.C | 17 |
3 files changed, 41 insertions, 11 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bed72c9..7bf28f8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2019-09-15 Jason Merrill <jason@redhat.com> + PR c++/30277 - int-width bit-field promotion. + PR c++/33819 - long bit-field promotion. + * typeck.c (cp_perform_integral_promotions): Handle large bit-fields + properly. Handle 32-bit non-int bit-fields properly. + (is_bitfield_expr_with_lowered_type): Don't look through NOP_EXPR. + PR c++/82165 - enum bitfields and operator overloading. * call.c (build_new_op_1): Use unlowered_expr_type. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 620f2c9..c6bf41e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1971,12 +1971,6 @@ is_bitfield_expr_with_lowered_type (const_tree exp) else return NULL_TREE; - CASE_CONVERT: - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0))) - == TYPE_MAIN_VARIANT (TREE_TYPE (exp))) - return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0)); - /* Fallthrough. */ - default: return NULL_TREE; } @@ -2189,13 +2183,23 @@ cp_perform_integral_promotions (tree expr, tsubst_flags_t complain) if (error_operand_p (expr)) return error_mark_node; + type = TREE_TYPE (expr); + /* [conv.prom] - If the bitfield has an enumerated type, it is treated as any - other value of that type for promotion purposes. */ - type = is_bitfield_expr_with_lowered_type (expr); - if (!type || TREE_CODE (type) != ENUMERAL_TYPE) - type = TREE_TYPE (expr); + A prvalue for an integral bit-field (11.3.9) can be converted to a prvalue + of type int if int can represent all the values of the bit-field; + otherwise, it can be converted to unsigned int if unsigned int can + represent all the values of the bit-field. If the bit-field is larger yet, + no integral promotion applies to it. If the bit-field has an enumerated + type, it is treated as any other value of that type for promotion + purposes. */ + tree bitfield_type = is_bitfield_expr_with_lowered_type (expr); + if (bitfield_type + && (TREE_CODE (bitfield_type) == ENUMERAL_TYPE + || TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node))) + type = bitfield_type; + gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type)); /* Scoped enums don't promote. */ if (SCOPED_ENUM_P (type)) @@ -2203,6 +2207,9 @@ cp_perform_integral_promotions (tree expr, tsubst_flags_t complain) promoted_type = type_promotes_to (type); if (type != promoted_type) expr = cp_convert (promoted_type, expr, complain); + else if (bitfield_type && bitfield_type != type) + /* Prevent decay_conversion from converting to bitfield_type. */ + expr = build_nop (type, expr); return expr; } diff --git a/gcc/testsuite/g++.dg/expr/bitfield14.C b/gcc/testsuite/g++.dg/expr/bitfield14.C new file mode 100644 index 0000000..546af85 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/bitfield14.C @@ -0,0 +1,17 @@ +// PR c++/30277 +// { dg-do compile { target c++11 } } + +struct S +{ + signed long l: 32; +}; + +void foo(long) = delete; +void foo(int) {} + +int main() +{ + S x = {1}; + foo(x.l+0); + return 0; +} |