summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/c-common.c45
-rw-r--r--gcc/c-decl.c25
-rw-r--r--gcc/c-lang.c2
-rw-r--r--gcc/expr.c79
-rw-r--r--gcc/langhooks-def.h2
-rw-r--r--gcc/langhooks.h4
-rw-r--r--gcc/objc/objc-act.c10
-rw-r--r--gcc/objc/objc-lang.c2
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/bitfld-1.x2
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/bitfld-3.c54
-rw-r--r--gcc/testsuite/gcc.dg/bitfld-2.c8
-rw-r--r--gcc/tree-ssa.c17
-rw-r--r--gcc/tree.c22
-rw-r--r--gcc/tree.h1
16 files changed, 251 insertions, 52 deletions
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 <jsm@polyomino.org.uk>
+ Neil Booth <neil@daikokuya.co.uk>
+
+ 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 <bonzini@gnu.org>
* 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. */
-
- if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node))
+ /* 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. */
+
+#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 <jsm@polyomino.org.uk>
+
+ * 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 <hongjiu.lu@intel.com>
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 <jsm@polyomino.org.uk> */
+
+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 */