Message ID | 20190916043328.3739-4-jason@redhat.com |
---|---|
State | New |
Headers | show |
Series | [C++,1/4] Handle location wrappers better in warn_logical_operator. | expand |
On Mon, Sep 16, 2019 at 12:33:28AM -0400, Jason Merrill wrote: > 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. > > Tested x86_64-pc-linux-gnu, applying to trunk. > > 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. > --- /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; > +} This testcase fails on all targets where int and long have the same precision. Is that a bug on the compiler side, or should the testcase just use a type with a larger precision than int (i.e. long long), like following (tested on x86_64-linux and i686-linux): 2019-09-21 Jakub Jelinek <jakub@redhat.com> PR c++/30277 * g++.dg/expr/bitfield14.C (struct S): Use signed long long instead of signed long. (foo): Use long long instead of long. --- gcc/testsuite/g++.dg/expr/bitfield14.C.jj 2019-09-20 12:25:24.833748976 +0200 +++ gcc/testsuite/g++.dg/expr/bitfield14.C 2019-09-21 08:17:18.500234760 +0200 @@ -3,10 +3,10 @@ struct S { - signed long l: 32; + signed long long l: 32; }; -void foo(long) = delete; +void foo(long long) = delete; void foo(int) {} int main() Jakub
On Sat, Sep 21, 2019 at 2:23 AM Jakub Jelinek <jakub@redhat.com> wrote: > > On Mon, Sep 16, 2019 at 12:33:28AM -0400, Jason Merrill wrote: > > 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. > > > > Tested x86_64-pc-linux-gnu, applying to trunk. > > > > 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. > > > --- /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; > > +} > > This testcase fails on all targets where int and long have the same > precision. Is that a bug on the compiler side, or should the testcase just > use a type with a larger precision than int (i.e. long long), like following > (tested on x86_64-linux and i686-linux): It's a testcase bug. > 2019-09-21 Jakub Jelinek <jakub@redhat.com> > > PR c++/30277 > * g++.dg/expr/bitfield14.C (struct S): Use signed long long instead > of signed long. > (foo): Use long long instead of long. OK, thanks. Jason
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; +} 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 <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.