aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2006-04-23 18:04:33 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2006-04-23 18:04:33 +0000
commit38a4afeecdf392267ff73a27a69f458b5d8b424c (patch)
tree795f298e0af32f79064b451399d8021ab268f911 /gcc/cp
parentacb188c1ba3c0a94da659f679d4227f955488037 (diff)
downloadgcc-38a4afeecdf392267ff73a27a69f458b5d8b424c.zip
gcc-38a4afeecdf392267ff73a27a69f458b5d8b424c.tar.gz
gcc-38a4afeecdf392267ff73a27a69f458b5d8b424c.tar.bz2
re PR c++/26534 ([4.1] bitfield wrong optimize)
2006-04-23 Mark Mitchell <mark@codesourcery.com> 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 <mark@codesourcery.com> 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 <mark@codesourcery.com> 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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/call.c19
-rw-r--r--gcc/cp/class.c23
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/typeck.c44
5 files changed, 90 insertions, 11 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 711fb7c..a0a44a5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,17 @@
+2006-04-23 Mark Mitchell <mark@codesourcery.com>
+
+ 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 <kazu@codesourcery.com>
* decl.c: Fix comment typos.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c9826451..6743f92 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 cc26cb8..1cf87dc 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 0848747..34cccc0 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 a7bdd55..7fc6cab 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)