This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 30274


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;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]