From: Mark Mitchell Date: Sun, 23 Apr 2006 18:04:33 +0000 (+0000) Subject: re PR c++/26534 ([4.1] bitfield wrong optimize) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=38a4afeecdf392267ff73a27a69f458b5d8b424c;p=gcc.git re PR c++/26534 ([4.1] bitfield wrong optimize) 2006-04-23 Mark Mitchell PR c++/26534 * c-common.h (c_build_bitfield_integer_type): Declare. * c-decl.c (c_build_bitfield_integer_type): Move to ... * c-common.c (c_build_bitfield_integer_type): ... here. 2006-04-23 Mark Mitchell PR c++/26534 * cp-tree.h (is_bitfield_expr_with_lowered_type): New function. * typeck.c (is_bitfield_expr_with_lowered_type): New function. (decay_conversion): Convert bitfield expressions to the correct type. (build_modify_expr): Remove spurious conversions. * class.c (layout_class_type): Modify the type of bitfields to indicate a limited range. * call.c (standard_conversion): Adjust the type of bitfield expressions used in an rvalue context. (build_conditional_expr): Likewise. 2006-04-23 Mark Mitchell PR c++/26534 * g++.dg/opt/bitfield1.C: New test. * g++.dg/compat/abi/bitfield1_main.C: Add -w. * g++.dg/compat/abi/bitfield1_x.C: Likewise. * g++.dg/compat/abi/bitfield1_y.C: Likewise. * g++.dg/compat/abi/bitfield2_main.C: Likewise. * g++.dg/compat/abi/bitfield2_x.C: Likewise. * g++.dg/compat/abi/bitfield2_y.C: Likewise. * g++.dg/abi/bitfield1.C: Add dg-warning markers. * g++.dg/abi/bitfield2.C: Likewise. * g++.dg/init/bitfield1.C: Likewise. From-SVN: r113199 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ea6d17b2b23..08fc7c0197e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2006-04-23 Mark Mitchell + + PR c++/26534 + * c-common.h (c_build_bitfield_integer_type): Declare. + * c-decl.c (c_build_bitfield_integer_type): Move to ... + * c-common.c (c_build_bitfield_integer_type): ... here. + 2006-04-23 Roger Sayle PR target/21283 diff --git a/gcc/c-common.c b/gcc/c-common.c index 1a11c3b189a..35982e58c1e 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1871,6 +1871,31 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type) return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); } +/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ + +tree +c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) +{ + /* Extended integer types of the same width as a standard type have + lesser rank, so those of the same width as int promote to int or + unsigned int and are valid for printf formats expecting int or + unsigned int. To avoid such special cases, avoid creating + extended integer types for bit-fields if a standard integer type + is available. */ + if (width == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (width == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (width == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (width == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (width == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); + return build_nonstandard_integer_type (width, unsignedp); +} + /* The C version of the register_builtin_type langhook. */ void diff --git a/gcc/c-common.h b/gcc/c-common.h index ed93f97b3e9..5636685efed 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -644,6 +644,7 @@ extern tree c_common_type_for_size (unsigned int, int); extern tree c_common_unsigned_type (tree); extern tree c_common_signed_type (tree); extern tree c_common_signed_or_unsigned_type (int, tree); +extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); extern tree c_common_truthvalue_conversion (tree); extern void c_apply_type_quals_to_decl (int, tree); extern tree c_sizeof_or_alignof_type (tree, bool, int); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index db906b4456b..f4d33307bf2 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3814,29 +3814,6 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) } } -/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ -static tree -c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) -{ - /* Extended integer types of the same width as a standard type have - lesser rank, so those of the same width as int promote to int or - unsigned int and are valid for printf formats expecting int or - unsigned int. To avoid such special cases, avoid creating - extended integer types for bit-fields if a standard integer type - is available. */ - if (width == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (width == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (width == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (width == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (width == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - return build_nonstandard_integer_type (width, unsignedp); -} /* Given declspecs and a declarator, determine the name and type of the object declared diff --git a/gcc/configure b/gcc/configure index fe6f1bd3b4d..9137c4423e8 100755 --- a/gcc/configure +++ b/gcc/configure @@ -15843,6 +15843,10 @@ do lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" fi ;; + *) + # This language is not enabled; skip it. + continue + ;; esac if test -f $srcdir/$subdir/lang.opt; then diff --git a/gcc/configure.ac b/gcc/configure.ac index 447f8270fb6..2fa8d99feb9 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3325,6 +3325,10 @@ changequote(,)dnl lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h" fi ;; + *) + # This language is not enabled; skip it. + continue + ;; esac changequote([,])dnl diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 711fb7c4072..a0a44a54075 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2006-04-23 Mark Mitchell + + PR c++/26534 + * cp-tree.h (is_bitfield_expr_with_lowered_type): New function. + * typeck.c (is_bitfield_expr_with_lowered_type): New function. + (decay_conversion): Convert bitfield expressions to the correct + type. + (build_modify_expr): Remove spurious conversions. + * class.c (layout_class_type): Modify the type of bitfields to + indicate a limited range. + * call.c (standard_conversion): Adjust the type of bitfield + expressions used in an rvalue context. + (build_conditional_expr): Likewise. + 2006-04-22 Kazu Hirata * decl.c: Fix comment typos. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c9826451899..6743f924c2d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -623,7 +623,16 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, conv = build_conv (ck_lvalue, from, conv); } else if (fromref || (expr && lvalue_p (expr))) - conv = build_conv (ck_rvalue, from, conv); + { + if (expr) + { + tree bitfield_type; + bitfield_type = is_bitfield_expr_with_lowered_type (expr); + if (bitfield_type) + from = bitfield_type; + } + conv = build_conv (ck_rvalue, from, conv); + } /* Allow conversion between `__complex__' data types. */ if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE) @@ -3196,8 +3205,12 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3) array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands. */ - arg2_type = TREE_TYPE (arg2); - arg3_type = TREE_TYPE (arg3); + arg2_type = is_bitfield_expr_with_lowered_type (arg2); + if (!arg2_type) + arg2_type = TREE_TYPE (arg2); + arg3_type = is_bitfield_expr_with_lowered_type (arg3); + if (!arg3_type) + arg3_type = TREE_TYPE (arg3); if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) { /* Do the conversions. We don't these for `void' type arguments diff --git a/gcc/cp/class.c b/gcc/cp/class.c index cc26cb8f56c..1cf87dc18a3 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4727,6 +4727,29 @@ layout_class_type (tree t, tree *virtuals_p) "classes to be placed at different locations in a " "future version of GCC", field); + /* The middle end uses the type of expressions to determine the + possible range of expression values. In order to optimize + "x.i > 7" to "false" for a 2-bit bitfield "i", the middle end + must be made aware of the width of "i", via its type. + + Because C++ does not have integer types of arbitrary width, + we must (for the purposes of the front end) convert from the + type assigned here to the declared type of the bitfield + whenever a bitfield expression is used as an rvalue. + Similarly, when assigning a value to a bitfield, the value + must be converted to the type given the bitfield here. */ + if (DECL_C_BIT_FIELD (field)) + { + tree ftype; + unsigned HOST_WIDE_INT width; + ftype = TREE_TYPE (field); + width = tree_low_cst (DECL_SIZE (field), /*unsignedp=*/1); + if (width != TYPE_PRECISION (ftype)) + TREE_TYPE (field) + = c_build_bitfield_integer_type (width, + TYPE_UNSIGNED (ftype)); + } + /* If we needed additional padding after this field, add it now. */ if (padding) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0848747687f..34cccc0a911 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4351,6 +4351,7 @@ extern tree cxx_sizeof_or_alignof_expr (tree, enum tree_code); extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); #define cxx_sizeof_nowarn(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, false) extern tree inline_conversion (tree); +extern tree is_bitfield_expr_with_lowered_type (tree); extern tree decay_conversion (tree); extern tree default_conversion (tree); extern tree build_class_member_access_expr (tree, tree, tree, bool); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a7bdd55dcc7..7fc6cab7aea 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1398,21 +1398,47 @@ invalid_nonstatic_memfn_p (tree expr) return false; } +/* If EXP is a reference to a bitfield, and the type of EXP does not + match the declared type of the bitfield, return the declared type + of the bitfield. Otherwise, return NULL_TREE. */ + +tree +is_bitfield_expr_with_lowered_type (tree exp) +{ + tree field; + + if (TREE_CODE (exp) == COND_EXPR) + { + if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1))) + return NULL_TREE; + return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2)); + } + if (TREE_CODE (exp) != COMPONENT_REF) + return NULL_TREE; + field = TREE_OPERAND (exp, 1); + if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field)) + return NULL_TREE; + if (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field))) + return NULL_TREE; + return DECL_BIT_FIELD_TYPE (field); +} + /* Perform the conversions in [expr] that apply when an lvalue appears in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions. - In addition manifest constants are replaced by their values. */ + In addition, manifest constants are replaced by their values, and + bitfield references are converted to their declared types. */ tree decay_conversion (tree exp) { tree type; + tree bitfield_type; enum tree_code code; type = TREE_TYPE (exp); - code = TREE_CODE (type); - if (type == error_mark_node) return error_mark_node; @@ -1422,11 +1448,15 @@ decay_conversion (tree exp) return error_mark_node; } + bitfield_type = is_bitfield_expr_with_lowered_type (exp); + if (bitfield_type) + exp = build_nop (bitfield_type, exp); + exp = decl_constant_value (exp); /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Leave such NOP_EXPRs, since RHS is being used in non-lvalue context. */ - + code = TREE_CODE (type); if (code == VOID_TYPE) { error ("void value not ignored as it ought to be"); @@ -5500,11 +5530,9 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) cond = build_conditional_expr (TREE_OPERAND (lhs, 0), - build_modify_expr (cp_convert (TREE_TYPE (lhs), - TREE_OPERAND (lhs, 1)), + build_modify_expr (TREE_OPERAND (lhs, 1), modifycode, rhs), - build_modify_expr (cp_convert (TREE_TYPE (lhs), - TREE_OPERAND (lhs, 2)), + build_modify_expr (TREE_OPERAND (lhs, 2), modifycode, rhs)); if (cond == error_mark_node) diff --git a/gcc/print-tree.c b/gcc/print-tree.c index 02e5c7b9c61..eed02f235f6 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -458,6 +458,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent) print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); + if (DECL_BIT_FIELD_TYPE (node)) + print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), + indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7a3fb0077a0..f0c3a5d5e0a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2006-04-23 Mark Mitchell + + PR c++/26534 + * g++.dg/opt/bitfield1.C: New test. + * g++.dg/compat/abi/bitfield1_main.C: Add -w. + * g++.dg/compat/abi/bitfield1_x.C: Likewise. + * g++.dg/compat/abi/bitfield1_y.C: Likewise. + * g++.dg/compat/abi/bitfield2_main.C: Likewise. + * g++.dg/compat/abi/bitfield2_x.C: Likewise. + * g++.dg/compat/abi/bitfield2_y.C: Likewise. + * g++.dg/abi/bitfield1.C: Add dg-warning markers. + * g++.dg/abi/bitfield2.C: Likewise. + * g++.dg/init/bitfield1.C: Likewise. + 2006-04-23 Paul Thomas PR fortran/25099 diff --git a/gcc/testsuite/g++.dg/abi/bitfield1.C b/gcc/testsuite/g++.dg/abi/bitfield1.C index c707c85d82b..d5d04bcd73a 100644 --- a/gcc/testsuite/g++.dg/abi/bitfield1.C +++ b/gcc/testsuite/g++.dg/abi/bitfield1.C @@ -19,7 +19,7 @@ int main () { A a; - a.bitS = 1; + a.bitS = 1; // { dg-warning "overflow" } a.bitU = 1; a.bit = 1; diff --git a/gcc/testsuite/g++.dg/abi/bitfield2.C b/gcc/testsuite/g++.dg/abi/bitfield2.C index d4d1d582649..452861ec29a 100644 --- a/gcc/testsuite/g++.dg/abi/bitfield2.C +++ b/gcc/testsuite/g++.dg/abi/bitfield2.C @@ -19,9 +19,9 @@ int main () { A a; - a.bitS = 1; + a.bitS = 1; // { dg-warning "overflow" } a.bitU = 1; - a.bit = 1; + a.bit = 1; // { dg-warning "overflow" } if (a.bitS != -1) return 1; diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield1_main.C b/gcc/testsuite/g++.dg/compat/abi/bitfield1_main.C index cdb7a45a744..ce9aa1f09ad 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield1_main.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield1_main.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" } // Copyright (C) 2001 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 15 Dec 2001 diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield1_x.C b/gcc/testsuite/g++.dg/compat/abi/bitfield1_x.C index e081c4bc943..727632af89d 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield1_x.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield1_x.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" } #include "bitfield1.h" diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield1_y.C b/gcc/testsuite/g++.dg/compat/abi/bitfield1_y.C index 10581dab0a4..28277671825 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield1_y.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield1_y.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" } extern "C" void abort (void); diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield2_main.C b/gcc/testsuite/g++.dg/compat/abi/bitfield2_main.C index df74037b66b..4169843f93e 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield2_main.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield2_main.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" } // Copyright (C) 2001 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 15 Dec 2001 diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield2_x.C b/gcc/testsuite/g++.dg/compat/abi/bitfield2_x.C index 47b448dda26..080d21b41ea 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield2_x.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield2_x.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" } #include "bitfield1.h" diff --git a/gcc/testsuite/g++.dg/compat/abi/bitfield2_y.C b/gcc/testsuite/g++.dg/compat/abi/bitfield2_y.C index 55edab5cbfe..d2757832861 100644 --- a/gcc/testsuite/g++.dg/compat/abi/bitfield2_y.C +++ b/gcc/testsuite/g++.dg/compat/abi/bitfield2_y.C @@ -1,4 +1,4 @@ -// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" } +// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" } extern "C" void abort (void); diff --git a/gcc/testsuite/g++.dg/init/bitfield1.C b/gcc/testsuite/g++.dg/init/bitfield1.C index 786a116a562..70a06d0e144 100644 --- a/gcc/testsuite/g++.dg/init/bitfield1.C +++ b/gcc/testsuite/g++.dg/init/bitfield1.C @@ -14,11 +14,11 @@ void f (); int main () { (f(), a.j) = 1; - (f(), a).j = 2; - (b ? a.j : a2.k) = 3; + (f(), a).j = 2; // { dg-warning "overflow" } + (b ? a.j : a2.k) = 3; // { dg-warning "overflow" } (b ? a : a2).j = 0; ++(a.j) = 1; - (a.j = 2) = 3; + (a.j = 2) = 3; // { dg-warning "overflow" } } diff --git a/gcc/testsuite/g++.dg/opt/bitfield1.C b/gcc/testsuite/g++.dg/opt/bitfield1.C new file mode 100644 index 00000000000..49699961313 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/bitfield1.C @@ -0,0 +1,18 @@ +// PR c++/26534 +// { dg-do run } +// { dg-options "-w -O2" } + +struct X +{ + unsigned a:4; +}; + +unsigned i; + +int main() +{ + struct X x = { 63u }; + i = x.a; + if (i != 15) + return 1; +}