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]

PATCH: PR c++/32346


This is another patch for the ongoing series of problems with
bitfields in G++.

At the point of a call, we "promote" a bitfield to its declared type
so that, for example, an "int f:3" field is promoted to full "int".
But, we don't want to promote a "long long f:32" bitfield to "long
long" if the callee is expecting "int".  That case is tricky because
we will (1) promote to "long long" at the point of use of the
bitfield, then (2) convert back to "int" to match the callee type --
and that second conversion, rather than introducing another NOP_EXPR,
removes the one created by (1), leaving us with what looks like an
unadorned bitfield.

All of these problems stem from the fact that we don't have a separate
C++ lowering pass.  So, we get confused about when we should use the
declared type of a bitfield -- as required for C++ type-checking,
etc. -- and the representation type -- as required by the GCC middle
end.  I'm not happy about the amount of special-case handling we now
have for bitfields, but I'm not sure that there's a better way.

Anyhow, tested on x86_64-unknown-linux-gnu, applied to the mainline.
I will also backport to 4.2.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-07-27  Mark Mitchell  <mark@codesourcery.com>

	PR c++/32346
	* call.c (convert_for_arg_passing): Only widen bitfields to their
	declared types if necessary.

2007-07-27  Mark Mitchell  <mark@codesourcery.com>

	PR c++/32346
	* g++.dg/expr/bitfield9.C: New test.

Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 126963)
+++ gcc/cp/call.c	(working copy)
@@ -4752,7 +4752,27 @@ type_passed_as (tree type)
 tree
 convert_for_arg_passing (tree type, tree val)
 {
-  val = convert_bitfield_to_declared_type (val);
+  tree bitfield_type;
+
+  /* If VAL is a bitfield, then -- since it has already been converted
+     to TYPE -- it cannot have a precision greater than TYPE.  
+
+     If it has a smaller precision, we must widen it here.  For
+     example, passing "int f:3;" to a function expecting an "int" will
+     not result in any conversion before this point.
+
+     If the precision is the same we must not risk widening.  For
+     example, the COMPONENT_REF for a 32-bit "long long" bitfield will
+     often have type "int", even though the C++ type for the field is
+     "long long".  If the value is being passed to a function
+     expecting an "int", then no conversions will be required.  But,
+     if we call convert_bitfield_to_declared_type, the bitfield will
+     be converted to "long long".  */
+  bitfield_type = is_bitfield_expr_with_lowered_type (val);
+  if (bitfield_type 
+      && TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
+    val = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), val);
+
   if (val == error_mark_node)
     ;
   /* Pass classes with copy ctors by invisible reference.  */
Index: gcc/testsuite/g++.dg/expr/bitfield9.C
===================================================================
--- gcc/testsuite/g++.dg/expr/bitfield9.C	(revision 0)
+++ gcc/testsuite/g++.dg/expr/bitfield9.C	(revision 0)
@@ -0,0 +1,25 @@
+// PR c++/32346
+// { dg-do run }
+
+extern "C" void abort();
+
+struct S {
+  long long i : 32;
+};
+
+void f(int i, int j) {
+  if (i != 0xabcdef01)
+    abort();
+  if (j != 0)
+    abort();
+}
+
+void g(S s) {
+  f(s.i, 0);
+}
+
+int main() {
+  S s;
+  s.i = 0xabcdef01;
+  g(s);
+}


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