From f9aa54d3c5c8b4993678c52b2c4d2ee2f7bdabaf Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Sun, 11 Mar 2007 03:07:59 +0000 Subject: re PR c++/30274 (bool bit-field: wrong increment and decremenet) PR c++/30274 * cp-tree.h (unlowered_expr_type): New function. * typeck.c (is_bitfield_expr_with_lowered_type): Handle COMPOUND_EXPR, MODIFY_EXPR, and SAVE_EXPR. (unlowered_expr_type): New function. (build_unary_op): Disallow predecrements of bool bitfields. * call.c (build_conditional_expr): Use unlowered_expr_type. * pt.c (type_unification_real): Likewise. PR c++/30274 * g++.dg/expr/bitfield3.C: New test. * g++.dg/expr/bitfield4.C: Likewise. * g++.dg/expr/bitfield5.C: Likewise. * g++.dg/expr/bitfield6.C: Likewise. From-SVN: r122813 --- gcc/cp/ChangeLog | 11 +++++++ gcc/cp/call.c | 8 ++--- gcc/cp/cp-tree.h | 1 + gcc/cp/pt.c | 2 +- gcc/cp/typeck.c | 58 +++++++++++++++++++++++++++-------- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/g++.dg/expr/bitfield3.C | 12 ++++++++ gcc/testsuite/g++.dg/expr/bitfield4.C | 19 ++++++++++++ gcc/testsuite/g++.dg/expr/bitfield5.C | 17 ++++++++++ gcc/testsuite/g++.dg/expr/bitfield6.C | 11 +++++++ 10 files changed, 125 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/expr/bitfield3.C create mode 100644 gcc/testsuite/g++.dg/expr/bitfield4.C create mode 100644 gcc/testsuite/g++.dg/expr/bitfield5.C create mode 100644 gcc/testsuite/g++.dg/expr/bitfield6.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 886b305..2f9b251 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2007-03-10 Mark Mitchell + + PR c++/30274 + * cp-tree.h (unlowered_expr_type): New function. + * typeck.c (is_bitfield_expr_with_lowered_type): Handle + COMPOUND_EXPR, MODIFY_EXPR, and SAVE_EXPR. + (unlowered_expr_type): New function. + (build_unary_op): Disallow predecrements of bool bitfields. + * call.c (build_conditional_expr): Use unlowered_expr_type. + * pt.c (type_unification_real): Likewise. + 2007-03-09 Douglas Gregor PR c++/20599 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index fb4609e..637671b 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3250,12 +3250,8 @@ 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 = 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); + arg2_type = unlowered_expr_type (arg2); + arg3_type = unlowered_expr_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/cp-tree.h b/gcc/cp/cp-tree.h index c90d529..2632137 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4645,6 +4645,7 @@ 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 unlowered_expr_type (tree); extern tree decay_conversion (tree); extern tree build_class_member_access_expr (tree, tree, tree, bool); extern tree finish_class_member_access_expr (tree, tree, bool); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bf82f8c..f947da2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11260,7 +11260,7 @@ type_unification_real (tree tparms, return 1; continue; } - arg = TREE_TYPE (arg); + arg = unlowered_expr_type (arg); if (arg == error_mark_node) return 1; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index c774671..e8f1a18 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1418,23 +1418,52 @@ invalid_nonstatic_memfn_p (tree expr) tree is_bitfield_expr_with_lowered_type (tree exp) { - tree field; - - if (TREE_CODE (exp) == COND_EXPR) + switch (TREE_CODE (exp)) { + case 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)); + + case COMPOUND_EXPR: + return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)); + + case MODIFY_EXPR: + case SAVE_EXPR: + return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0)); + + case COMPONENT_REF: + { + tree field; + + 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); + } + + default: + return NULL_TREE; } - 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); +} + +/* Like is_bitfield_with_lowered_type, except that if EXP is not a + bitfield with a lowered type, the type of EXP is returned, rather + than NULL_TREE. */ + +tree +unlowered_expr_type (tree exp) +{ + tree type; + + type = is_bitfield_expr_with_lowered_type (exp); + if (!type) + type = TREE_TYPE (exp); + + return type; } /* Perform the conversions in [expr] that apply when an lvalue appears @@ -4217,8 +4246,11 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) { tree inc; + tree declared_type; tree result_type = TREE_TYPE (arg); + declared_type = unlowered_expr_type (arg); + arg = get_unwidened (arg, 0); argtype = TREE_TYPE (arg); @@ -4296,7 +4328,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) return error_mark_node; /* Forbid using -- on `bool'. */ - if (same_type_p (TREE_TYPE (arg), boolean_type_node)) + if (same_type_p (declared_type, boolean_type_node)) { if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4447fd8..edc908c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2007-03-10 Mark Mitchell + PR c++/30274 + * g++.dg/expr/bitfield3.C: New test. + * g++.dg/expr/bitfield4.C: Likewise. + * g++.dg/expr/bitfield5.C: Likewise. + * g++.dg/expr/bitfield6.C: Likewise. + PR c++/30924 * g++.dg/template/array18.C: New test. diff --git a/gcc/testsuite/g++.dg/expr/bitfield3.C b/gcc/testsuite/g++.dg/expr/bitfield3.C new file mode 100644 index 0000000..7b856e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/bitfield3.C @@ -0,0 +1,12 @@ +// PR c++/30274 + +struct S { + bool x : 4; +}; + +S s; + +void f() { + s.x--; // { dg-error "bool" } + --s.x; // { dg-error "bool" } +} diff --git a/gcc/testsuite/g++.dg/expr/bitfield4.C b/gcc/testsuite/g++.dg/expr/bitfield4.C new file mode 100644 index 0000000..d824964 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/bitfield4.C @@ -0,0 +1,19 @@ +// PR c++/30274 +// { dg-do link } + +struct S { + bool x : 4; +}; + +S s; + +template +void f(T); + +template <> +void f(bool) {} + +int main() { + f(s.x++); + f(++s.x); +} diff --git a/gcc/testsuite/g++.dg/expr/bitfield5.C b/gcc/testsuite/g++.dg/expr/bitfield5.C new file mode 100644 index 0000000..3d18e15 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/bitfield5.C @@ -0,0 +1,17 @@ +// PR c++/30274 +// { dg-do run } + +struct S { + bool x : 4; +}; + +S s; + +int main() { + s.x++; + if (s.x != 1) + return 1; + ++s.x; + if (s.x != 1) + return 2; +} diff --git a/gcc/testsuite/g++.dg/expr/bitfield6.C b/gcc/testsuite/g++.dg/expr/bitfield6.C new file mode 100644 index 0000000..6f6d559 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/bitfield6.C @@ -0,0 +1,11 @@ +// PR c++/30274 + +struct S { + bool x : 4; +}; + +S s; + +void f() { + ++s.x = false; +} -- cgit v1.1