This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 30274
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 10 Mar 2007 19:14:11 -0800
- Subject: C++ PATCH: PR 30274
- Reply-to: mark at codesourcery dot com
This patch fixes PR c++/30274, a P1 regression in 4.2. This PR
concerned a mishandling of boolean bitfields; it was possible for them
to end up with the values other than zero and one, as a result of
increment operators. While fixing that, I noticed several related
problems:
* we were allowing decrements of boolean bitfields, which is not
permitted by the standard
* we were not deducing template arguments correctly in the presence of
boolean bitfields
There's also a testcase for a bug that I introduced in an earlier
version of this patch -- but caught before checking in. Since the
testsuite hadn't caught the bug, I added that too.
The fix for all of these problems is to make sure that we're using the
unlowered type of the bitfield.
Tested on x86_64-unknown-linux-gnu, applied to mainline and 4.2
branches.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
2007-03-10 Mark Mitchell <mark@codesourcery.com>
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-10 Mark Mitchell <mark@codesourcery.com>
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.
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 122765)
+++ gcc/cp/typeck.c (working copy)
@@ -1410,23 +1410,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
@@ -4209,8 +4238,11 @@ build_unary_op (enum tree_code code, tre
{
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);
@@ -4288,7 +4320,7 @@ build_unary_op (enum tree_code code, tre
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)
{
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c (revision 122765)
+++ gcc/cp/call.c (working copy)
@@ -3250,12 +3250,8 @@ build_conditional_expr (tree arg1, tree
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
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 122765)
+++ gcc/cp/cp-tree.h (working copy)
@@ -4540,6 +4540,7 @@ extern tree cxx_sizeof_or_alignof_type
#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);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 122765)
+++ gcc/cp/pt.c (working copy)
@@ -9943,7 +9943,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;
}
Index: gcc/testsuite/g++.dg/expr/bitfield3.C
===================================================================
--- gcc/testsuite/g++.dg/expr/bitfield3.C (revision 0)
+++ gcc/testsuite/g++.dg/expr/bitfield3.C (revision 0)
@@ -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" }
+}
Index: gcc/testsuite/g++.dg/expr/bitfield5.C
===================================================================
--- gcc/testsuite/g++.dg/expr/bitfield5.C (revision 0)
+++ gcc/testsuite/g++.dg/expr/bitfield5.C (revision 0)
@@ -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;
+}
Index: gcc/testsuite/g++.dg/expr/bitfield4.C
===================================================================
--- gcc/testsuite/g++.dg/expr/bitfield4.C (revision 0)
+++ gcc/testsuite/g++.dg/expr/bitfield4.C (revision 0)
@@ -0,0 +1,19 @@
+// PR c++/30274
+// { dg-do link }
+
+struct S {
+ bool x : 4;
+};
+
+S s;
+
+template <typename T>
+void f(T);
+
+template <>
+void f(bool) {}
+
+int main() {
+ f(s.x++);
+ f(++s.x);
+}
Index: gcc/testsuite/g++.dg/expr/bitfield6.C
===================================================================
--- gcc/testsuite/g++.dg/expr/bitfield6.C (revision 0)
+++ gcc/testsuite/g++.dg/expr/bitfield6.C (revision 0)
@@ -0,0 +1,11 @@
+// PR c++/30274
+
+struct S {
+ bool x : 4;
+};
+
+S s;
+
+void f() {
+ ++s.x = false;
+}