re PR c++/32346 (long long bitfield passed to int argument incorrectly)
authorMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 27 Jul 2007 17:13:29 +0000 (17:13 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 27 Jul 2007 17:13:29 +0000 (17:13 +0000)
PR c++/32346
* call.c (convert_for_arg_passing): Only widen bitfields to their
declared types if necessary.
PR c++/32346
* g++.dg/expr/bitfield9.C: New test.

From-SVN: r126986

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/expr/bitfield9.C [new file with mode: 0644]

index 7b1dc9244d30f474ad8591a6b5aaf33a71173c85..3c7b8c6d472b79cac05605f6ef1048647a23c966 100644 (file)
@@ -1,3 +1,9 @@
+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-25  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * parser.c (cp_parser_string_literal, cp_parser_sizeof_operand):
index 82f8666c42e256454b426633b9236b22e0f7cc50..1f220f039109d54d015227bb869c46af26765ae5 100644 (file)
@@ -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 cc8cfc270d1d6ecf3fd142fb072abb1c1d4c3d58..76494062b00556488aa1090735ea997b9c6fbc2f 100644 (file)
@@ -1,3 +1,8 @@
+2007-07-27  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/32346
+       * g++.dg/expr/bitfield9.C: New test.
+
 2007-07-26  Steven G. Kargl  <kargl@gcc.gnu.org>
 
        PR fortran/32899
@@ -22,7 +27,7 @@
 
        * gcc.target/mips/ins-1.c: New test.
 
-2007-07-26  Nathan Froyd  <froydnj@codesourcery.com>
+'2007-07-26  Nathan Froyd  <froydnj@codesourcery.com>
 
        PR/19232
        * gcc.dg/assign-warn-3.c (f0): Declare as inline.
diff --git a/gcc/testsuite/g++.dg/expr/bitfield9.C b/gcc/testsuite/g++.dg/expr/bitfield9.C
new file mode 100644 (file)
index 0000000..047b1bf
--- /dev/null
@@ -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);
+}