From: Jason Merrill Date: Mon, 16 Sep 2019 04:34:28 +0000 (-0400) Subject: PR c++/30277 - int-width bit-field promotion. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ddc1a45b373ce98929d0d67e8c97ab6783236c40;p=gcc.git PR c++/30277 - int-width bit-field promotion. Here, if cp_perform_integral_promotions saw that the TREE_TYPE of a bit-field reference was the same as the type it promotes to, it didn't do anything. But then decay_conversion saw that the bit-field reference was unchanged, and converted it to its declared type. So I needed to add something to make it clear that promotion has been done. But then the 33819 change caused trouble by looking through the NOP_EXPR I just added. This was the wrong fix for that bug; I've now fixed that better by recognizing in cp_perform_integral_promotions that we won't promote a bit-field larger than 32 bits, so we should use the declared type. 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. From-SVN: r275746 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bed72c90a2e..7bf28f81fae 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2019-09-15 Jason Merrill + 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 620f2c9afdf..c6bf41ee7a4 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 00000000000..546af85ba10 --- /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; +}