diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b6b96781d2f..fa0aefcc469 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2004-07-08 Joseph S. Myers + Neil Booth + + PR c/2511 + PR c/3325 + * c-decl.c (finish_struct): Ensure bit-fields are given the + correct type. + * c-common.c (c_common_signed_or_unsigned_type): For C, require + the precision to match as well as the mode. + * expr.c (reduce_to_bit_field_precision): New function. + (expand_expr_real_1): Reduce expressions of bit-field type to + proper precision. + * langhooks.h (reduce_bit_field_operations): New hook. + * langhooks-def.h (LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS): + Define. + * c-lang.c, objc/objc-lang.c + (LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS): Define. + * objc/objc-act.c (check_ivars): Convert types to bit-field types + before checking. + * tree.c (build_nonstandard_integer_type): New function. + * tree.h (build_nonstandard_integer_type): New prototype. + * tree-ssa.c (tree_ssa_useless_type_conversion_1): Don't treat + conversions between integer and boolean types as useless. + 2004-07-08 Paolo Bonzini * c-common.c (c_common_nodes_and_builtins): Do not diff --git a/gcc/c-common.c b/gcc/c-common.c index 9a8039b9431..ebb5e65e404 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1636,40 +1636,51 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type) || TYPE_UNSIGNED (type) == unsignedp) return type; - /* Must check the mode of the types, not the precision. Enumeral types - in C++ have precision set to match their range, but may use a wider - mode to match an ABI. If we change modes, we may wind up with bad - conversions. */ + /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not + the precision; they have precision set to match their range, but + may use a wider mode to match an ABI. If we change modes, we may + wind up with bad conversions. For INTEGER_TYPEs in C, must check + the precision as well, so as to yield correct results for + bit-field types. C++ does not have these separate bit-field + types, and producing a signed or unsigned variant of an + ENUMERAL_TYPE may cause other problems as well. */ - if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node)) +#define TYPE_OK(node) \ + (TYPE_MODE (type) == TYPE_MODE (node) \ + && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node))) + if (TYPE_OK (signed_char_type_node)) return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_MODE (type) == TYPE_MODE (integer_type_node)) + if (TYPE_OK (integer_type_node)) return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node)) + if (TYPE_OK (short_integer_type_node)) return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node)) + if (TYPE_OK (long_integer_type_node)) return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node)) + if (TYPE_OK (long_long_integer_type_node)) return (unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node); - if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node)) + if (TYPE_OK (widest_integer_literal_type_node)) return (unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node); #if HOST_BITS_PER_WIDE_INT >= 64 - if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node)) + if (TYPE_OK (intTI_type_node)) return unsignedp ? unsigned_intTI_type_node : intTI_type_node; #endif - if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node)) + if (TYPE_OK (intDI_type_node)) return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node)) + if (TYPE_OK (intSI_type_node)) return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node)) + if (TYPE_OK (intHI_type_node)) return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node)) + if (TYPE_OK (intQI_type_node)) return unsignedp ? unsigned_intQI_type_node : intQI_type_node; +#undef TYPE_OK - return type; + if (c_dialect_cxx ()) + return type; + else + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); } /* The C version of the register_builtin_type langhook. */ diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 3f6be35d91a..2a236aa51cf 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -5162,9 +5162,11 @@ finish_struct (tree t, tree fieldlist, tree attributes) } /* Install struct as DECL_CONTEXT of each field decl. - Also process specified field sizes,m which is found in the DECL_INITIAL. - Store 0 there, except for ": 0" fields (so we can find them - and delete them, below). */ + Also process specified field sizes, found in the DECL_INITIAL, + storing 0 there after the type has been changed to precision equal + to its width, rather than the precision of the specified standard + type. (Correct layout requires the original type to have been preserved + until now.) */ saw_named_field = 0; for (x = fieldlist; x; x = TREE_CHAIN (x)) @@ -5208,8 +5210,6 @@ finish_struct (tree t, tree fieldlist, tree attributes) SET_DECL_C_BIT_FIELD (x); } - DECL_INITIAL (x) = 0; - /* Detect flexible array member in an invalid context. */ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE @@ -5250,12 +5250,21 @@ finish_struct (tree t, tree fieldlist, tree attributes) layout_type (t); - /* Delete all zero-width bit-fields from the fieldlist. */ + /* Give bit-fields their proper types. */ { tree *fieldlistp = &fieldlist; while (*fieldlistp) - if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp)) - *fieldlistp = TREE_CHAIN (*fieldlistp); + if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp) + && TREE_TYPE (*fieldlistp) != error_mark_node) + { + unsigned HOST_WIDE_INT width + = tree_low_cst (DECL_INITIAL (*fieldlistp), 1); + tree type = TREE_TYPE (*fieldlistp); + if (width != TYPE_PRECISION (type)) + TREE_TYPE (*fieldlistp) + = build_nonstandard_integer_type (width, TYPE_UNSIGNED (type)); + DECL_INITIAL (*fieldlistp) = 0; + } else fieldlistp = &TREE_CHAIN (*fieldlistp); } diff --git a/gcc/c-lang.c b/gcc/c-lang.c index f58a8990587..8166698f7e7 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -74,6 +74,8 @@ enum c_language_kind c_language = clk_c; #define LANG_HOOKS_FINISH_INCOMPLETE_DECL c_finish_incomplete_decl #undef LANG_HOOKS_UNSAFE_FOR_REEVAL #define LANG_HOOKS_UNSAFE_FOR_REEVAL c_common_unsafe_for_reeval +#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS +#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true #undef LANG_HOOKS_STATICP #define LANG_HOOKS_STATICP c_staticp #undef LANG_HOOKS_NO_BODY_BLOCKS diff --git a/gcc/expr.c b/gcc/expr.c index b2e25c75114..3be412dd56f 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -154,6 +154,7 @@ static int is_aligning_offset (tree, tree); static rtx expand_increment (tree, int, int); static void expand_operands (tree, tree, rtx, rtx*, rtx*, enum expand_modifier); +static rtx reduce_to_bit_field_precision (rtx, rtx, tree); static rtx do_store_flag (tree, rtx, enum machine_mode, int); #ifdef PUSH_ROUNDING static void emit_single_push_insn (enum machine_mode, rtx, tree); @@ -6430,9 +6431,26 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, rtx subtarget, original_target; int ignore; tree context; + bool reduce_bit_field = false; +#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore \ + ? reduce_to_bit_field_precision ((expr), \ + target, \ + type) \ + : (expr)) mode = TYPE_MODE (type); unsignedp = TYPE_UNSIGNED (type); + if (lang_hooks.reduce_bit_field_operations + && TREE_CODE (type) == INTEGER_TYPE + && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type)) + { + /* An operation in what may be a bit-field type needs the + result to be reduced to the precision of the bit-field type, + which is narrower than that of the type's mode. */ + reduce_bit_field = true; + if (modifier == EXPAND_STACK_PARM) + target = 0; + } /* Use subtarget as the target for operand 0 of a binary operation. */ subtarget = get_subtarget (target); @@ -7423,10 +7441,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, && GET_CODE (op0) == SUBREG) SUBREG_PROMOTED_VAR_P (op0) = 0; - return op0; + return REDUCE_BIT_FIELD (op0); } op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier); + op0 = REDUCE_BIT_FIELD (op0); if (GET_MODE (op0) == mode) return op0; @@ -7594,7 +7613,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, op1 = plus_constant (op1, INTVAL (constant_part)); if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER) op1 = force_operand (op1, target); - return op1; + return REDUCE_BIT_FIELD (op1); } else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST @@ -7627,7 +7646,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, op0 = plus_constant (op0, INTVAL (constant_part)); if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER) op0 = force_operand (op0, target); - return op0; + return REDUCE_BIT_FIELD (op0); } } @@ -7649,7 +7668,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), subtarget, &op0, &op1, modifier); - return simplify_gen_binary (PLUS, mode, op0, op1); + return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1)); case MINUS_EXPR: /* For initializers, we are allowed to return a MINUS of two @@ -7667,9 +7686,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* If the last operand is a CONST_INT, use plus_constant of the negated constant. Else make the MINUS. */ if (GET_CODE (op1) == CONST_INT) - return plus_constant (op0, - INTVAL (op1)); + return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1))); else - return gen_rtx_MINUS (mode, op0, op1); + return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1)); } this_optab = ! unsignedp && flag_trapv @@ -7691,7 +7710,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (GET_CODE (op1) == CONST_INT) { op1 = negate_rtx (mode, op1); - return simplify_gen_binary (PLUS, mode, op0, op1); + return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1)); } goto binop2; @@ -7723,9 +7742,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (!REG_P (op0)) op0 = copy_to_mode_reg (mode, op0); - return gen_rtx_MULT (mode, op0, + return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0, gen_int_mode (tree_low_cst (exp1, 0), - TYPE_MODE (TREE_TYPE (exp1)))); + TYPE_MODE (TREE_TYPE (exp1))))); } if (modifier == EXPAND_STACK_PARM) @@ -7803,13 +7822,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, zextend_p); if (htem != hipart) emit_move_insn (hipart, htem); - return temp; + return REDUCE_BIT_FIELD (temp); } } } expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), subtarget, &op0, &op1, 0); - return expand_mult (mode, op0, op1, target, unsignedp); + return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp)); case TRUNC_DIV_EXPR: case FLOOR_DIV_EXPR: @@ -7885,7 +7904,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ? negv_optab : neg_optab, op0, target, 0); if (temp == 0) abort (); - return temp; + return REDUCE_BIT_FIELD (temp); case ABS_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); @@ -8550,12 +8569,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: - return expand_increment (exp, 0, ignore); + return REDUCE_BIT_FIELD (expand_increment (exp, 0, ignore)); case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: /* Faster to treat as pre-increment if result is not used. */ - return expand_increment (exp, ! ignore, ignore); + return REDUCE_BIT_FIELD (expand_increment (exp, ! ignore, ignore)); case ADDR_EXPR: if (modifier == EXPAND_STACK_PARM) @@ -8915,7 +8934,37 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, unsignedp, OPTAB_LIB_WIDEN); if (temp == 0) abort (); - return temp; + return REDUCE_BIT_FIELD (temp); +} +#undef REDUCE_BIT_FIELD + +/* Subroutine of above: reduce EXP to the precision of TYPE (in the + signedness of TYPE), possibly returning the result in TARGET. */ +static rtx +reduce_to_bit_field_precision (rtx exp, rtx target, tree type) +{ + HOST_WIDE_INT prec = TYPE_PRECISION (type); + if (target && GET_MODE (target) != GET_MODE (exp)) + target = 0; + if (TYPE_UNSIGNED (type)) + { + rtx mask; + if (prec < HOST_BITS_PER_WIDE_INT) + mask = immed_double_const (((unsigned HOST_WIDE_INT) 1 << prec) - 1, 0, + GET_MODE (exp)); + else + mask = immed_double_const ((unsigned HOST_WIDE_INT) -1, + ((unsigned HOST_WIDE_INT) 1 + << (prec - HOST_BITS_PER_WIDE_INT)) - 1, + GET_MODE (exp)); + return expand_and (GET_MODE (exp), exp, mask, target); + } + else + { + tree count = build_int_2 (GET_MODE_BITSIZE (GET_MODE (exp)) - prec, 0); + exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0); + return expand_shift (RSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0); + } } /* Subroutine of above: returns 1 if OFFSET corresponds to an offset that diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 1cd44f5565e..85c77e585f1 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -116,6 +116,7 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *); #define LANG_HOOKS_MAYBE_BUILD_CLEANUP lhd_return_null_tree #define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME lhd_set_decl_assembler_name #define LANG_HOOKS_CAN_USE_BIT_FIELDS_P lhd_can_use_bit_fields_p +#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS false #define LANG_HOOKS_HONOR_READONLY false #define LANG_HOOKS_NO_BODY_BLOCKS false #define LANG_HOOKS_PRINT_STATISTICS lhd_do_nothing @@ -294,6 +295,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_MAYBE_BUILD_CLEANUP, \ LANG_HOOKS_SET_DECL_ASSEMBLER_NAME, \ LANG_HOOKS_CAN_USE_BIT_FIELDS_P, \ + LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS, \ LANG_HOOKS_HONOR_READONLY, \ LANG_HOOKS_NO_BODY_BLOCKS, \ LANG_HOOKS_PRINT_STATISTICS, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index fb36a144b84..4400aa3dc6f 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -347,6 +347,10 @@ struct lang_hooks optimizations, for instance in fold_truthop(). */ bool (*can_use_bit_fields_p) (void); + /* Nonzero if operations on types narrower than their mode should + have their results reduced to the precision of the type. */ + bool reduce_bit_field_operations; + /* Nonzero if TYPE_READONLY and TREE_READONLY should always be honored. */ bool honor_readonly; diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 4526e1845ce..308f2aca988 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -4257,6 +4257,16 @@ check_ivars (tree inter, tree imp) t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls); + if (TREE_VALUE (TREE_VALUE (rawimpdecls))) + { + /* t1 is the bit-field type, so t2 must be converted to the + bit-field type for comparison as well. */ + unsigned HOST_WIDE_INT width + = tree_low_cst (TREE_VALUE (TREE_VALUE (rawimpdecls)), 1); + if (width != TYPE_PRECISION (t2)) + t2 = build_nonstandard_integer_type (width, TYPE_UNSIGNED (t2)); + } + if (!comptypes (t1, t2) || !tree_int_cst_equal (TREE_VALUE (TREE_VALUE (rawintdecls)), TREE_VALUE (TREE_VALUE (rawimpdecls)))) diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index fde6cbd0907..c5d099b63d3 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -71,6 +71,8 @@ enum c_language_kind c_language = clk_objc; #define LANG_HOOKS_FINISH_INCOMPLETE_DECL c_finish_incomplete_decl #undef LANG_HOOKS_UNSAFE_FOR_REEVAL #define LANG_HOOKS_UNSAFE_FOR_REEVAL c_common_unsafe_for_reeval +#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS +#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true #undef LANG_HOOKS_STATICP #define LANG_HOOKS_STATICP c_staticp #undef LANG_HOOKS_NO_BODY_BLOCKS diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 244498efc22..54be7f9605d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-07-08 Joseph S. Myers + + * gcc.c-torture/execute/bitfld-1.x: Remove. + * gcc.c-torture/execute/bitfld-3.c: New test. + * gcc.dg/bitfld-2.c: Remove XFAILs. + 2004-07-07 H.J. Lu PR c++/16276 diff --git a/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x b/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x deleted file mode 100644 index 2f397b96e51..00000000000 --- a/gcc/testsuite/gcc.c-torture/execute/bitfld-1.x +++ /dev/null @@ -1,2 +0,0 @@ -set torture_execute_xfail "*-*-*" -return 0 diff --git a/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c b/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c new file mode 100644 index 00000000000..52a4147ccec --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/bitfld-3.c @@ -0,0 +1,54 @@ +/* Test that operations on bit-fields yield results reduced to bit-field + type. */ +/* Origin: Joseph Myers */ + +extern void exit (int); +extern void abort (void); + +struct s { + unsigned long long u33: 33; + unsigned long long u40: 40; + unsigned long long u41: 41; +}; + +struct s a = { 0x100000, 0x100000, 0x100000 }; +struct s b = { 0x100000000ULL, 0x100000000ULL, 0x100000000ULL }; +struct s c = { 0x1FFFFFFFFULL, 0, 0 }; + +int +main (void) +{ + if (a.u33 * a.u33 != 0 || a.u33 * a.u40 != 0 || a.u40 * a.u33 != 0 + || a.u40 * a.u40 != 0) + abort (); + if (a.u33 * a.u41 != 0x10000000000ULL + || a.u40 * a.u41 != 0x10000000000ULL + || a.u41 * a.u33 != 0x10000000000ULL + || a.u41 * a.u40 != 0x10000000000ULL + || a.u41 * a.u41 != 0x10000000000ULL) + abort (); + if (b.u33 + b.u33 != 0) + abort (); + if (b.u33 + b.u40 != 0x200000000ULL + || b.u33 + b.u41 != 0x200000000ULL + || b.u40 + b.u33 != 0x200000000ULL + || b.u40 + b.u40 != 0x200000000ULL + || b.u40 + b.u41 != 0x200000000ULL + || b.u41 + b.u33 != 0x200000000ULL + || b.u41 + b.u40 != 0x200000000ULL + || b.u41 + b.u41 != 0x200000000ULL) + abort (); + if (a.u33 - b.u33 != 0x100100000ULL + || a.u33 - b.u40 != 0xFF00100000ULL + || a.u33 - b.u41 != 0x1FF00100000ULL + || a.u40 - b.u33 != 0xFF00100000ULL + || a.u40 - b.u40 != 0xFF00100000ULL + || a.u40 - b.u41 != 0x1FF00100000ULL + || a.u41 - b.u33 != 0x1FF00100000ULL + || a.u41 - b.u40 != 0x1FF00100000ULL + || a.u41 - b.u41 != 0x1FF00100000ULL) + abort (); + if (++c.u33 != 0 || --c.u40 != 0xFFFFFFFFFFULL || c.u41-- != 0) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/bitfld-2.c b/gcc/testsuite/gcc.dg/bitfld-2.c index d3096a7caa8..b61fec60841 100644 --- a/gcc/testsuite/gcc.dg/bitfld-2.c +++ b/gcc/testsuite/gcc.dg/bitfld-2.c @@ -11,13 +11,13 @@ struct bf int b: 2; }; -struct bf p = {4, 0}; /* { dg-warning "truncated" "" { xfail *-*-* } } */ -struct bf q = {0, 2}; /* { dg-warning "overflow" "" { xfail *-*-* } } */ +struct bf p = {4, 0}; /* { dg-warning "truncated" "" } */ +struct bf q = {0, 2}; /* { dg-warning "overflow" "" } */ struct bf r = {3, -2}; /* { dg-bogus "(truncated|overflow)" } */ void foo () { - p.a = 4, p.b = 0; /* { dg-warning "truncated" "" { xfail *-*-* } } */ - q.a = 0, q.b = 2; /* { dg-warning "overflow" "" { xfail *-*-* } } */ + p.a = 4, p.b = 0; /* { dg-warning "truncated" "" } */ + q.a = 0, q.b = 2; /* { dg-warning "overflow" "" } */ r.a = 3, r.b = -2; /* { dg-bogus "(truncated|overflow)" } */ } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 3ab7ac206bb..ad1c1745c14 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -572,17 +572,22 @@ tree_ssa_useless_type_conversion_1 (tree outer_type, tree inner_type) /* If both the inner and outer types are integral types, then the conversion is not necessary if they have the same mode and - signedness and precision. Note that type _Bool can have size of - 4 (only happens on powerpc-darwin right now but can happen on any - target that defines BOOL_TYPE_SIZE to be INT_TYPE_SIZE) and a - precision of 1 while unsigned int is the same expect for a - precision of 4 so testing of precision is necessary. */ + signedness and precision, and both or neither are boolean. Some + code assumes an invariant that boolean types stay boolean and do + not become 1-bit bit-field types. Note that types with precision + not using all bits of the mode (such as bit-field types in C) + mean that testing of precision is necessary. */ else if (INTEGRAL_TYPE_P (inner_type) && INTEGRAL_TYPE_P (outer_type) && TYPE_MODE (inner_type) == TYPE_MODE (outer_type) && TYPE_UNSIGNED (inner_type) == TYPE_UNSIGNED (outer_type) && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)) - return true; + { + bool first_boolean = (TREE_CODE (inner_type) == BOOLEAN_TYPE); + bool second_boolean = (TREE_CODE (outer_type) == BOOLEAN_TYPE); + if (first_boolean == second_boolean) + return true; + } /* Recurse for complex types. */ else if (TREE_CODE (inner_type) == COMPLEX_TYPE diff --git a/gcc/tree.c b/gcc/tree.c index 009888a5b21..3804d37cb44 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4133,6 +4133,28 @@ build_index_type (tree maxval) return itype; } +/* Builds a signed or unsigned integer type of precision PRECISION. + Used for C bitfields whose precision does not match that of + built-in target types. */ +tree +build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision, + int unsignedp) +{ + tree itype = make_node (INTEGER_TYPE); + + TYPE_PRECISION (itype) = precision; + + if (unsignedp) + fixup_unsigned_type (itype); + else + fixup_signed_type (itype); + + if (host_integerp (TYPE_MAX_VALUE (itype), 1)) + return type_hash_canon (tree_low_cst (TYPE_MAX_VALUE (itype), 1), itype); + + return itype; +} + /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with low bound LOWVAL and high bound HIGHVAL. diff --git a/gcc/tree.h b/gcc/tree.h index 28582dd7ec4..74cf79e6cbc 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3472,6 +3472,7 @@ extern int real_minus_onep (tree); extern void init_ttree (void); extern void build_common_tree_nodes (int); extern void build_common_tree_nodes_2 (int); +extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int); extern tree build_range_type (tree, tree, tree); /* In function.c */