C++ PATCH: Rest DECL_MODE for over-long bitfields

Mark Mitchell mark@codesourcery.com
Mon Sep 15 00:26:00 GMT 2003


When layout a class like:

  struct S {
    char c : 124;
  };

we temporarily give the FIELD_DECL for "c" a different type, so as to
implement the C++ ABI rules (which treat "c" as if it had the
alignment of "long long" in this case).

We were resetting the DECL_SIZE -- but not the DECL_MODE -- for the
FIELD_DECL when we were done.  

This resulted in using 2-byte store instructions to write to the
field, even though all but the first 8 bits are padding.  On a
big-endian machine, that's disastrous; it means that an incorrect
value is being written to the bit-field.  Our C++ ABI Testsuite caught
this bug.

This is an ABI change -- although the layout will be identical,
different bits will be used to store the field.  Therefore, this
change is guarded with flag_abi_version.

Tested on i686-pc-linux-gnu and ia64-hp-hpux11.22, applied on the
mainline and on the branch.  (On the branch, we want the -Wabi
warning, and there is no reason not to have the -fabi-version=0 fix as
well.)

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2003-09-14  Mark Mitchell  <mark@codesourcery.com>

	* class.c (layout_class_type): Make DECL_MODE match TYPE_MODE for
	an bit-field whose width exceeds that of its type.

2003-09-14  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/bitfield11.C: New test.
	* g++.dg/abi/bitfield12.C: Likewise.

Index: class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.569
diff -c -5 -p -r1.569 class.c
*** class.c	11 Sep 2003 15:18:46 -0000	1.569
--- class.c	15 Sep 2003 00:23:36 -0000
*************** layout_class_type (tree t, tree *virtual
*** 4757,4766 ****
--- 4757,4775 ----
  	    DECL_NAME (field) = NULL_TREE;
  	  /* Now that layout has been performed, set the size of the
  	     field to the size of its declared type; the rest of the
  	     field is effectively invisible.  */
  	  DECL_SIZE (field) = TYPE_SIZE (type);
+ 	  /* We must also reset the DECL_MODE of the field.  */
+ 	  if (abi_version_at_least (2))
+ 	    DECL_MODE (field) = TYPE_MODE (type);
+ 	  else if (warn_abi
+ 		   && DECL_MODE (field) != TYPE_MODE (type))
+ 	    /* Versions of G++ before G++ 3.4 did not reset the
+ 	       DECL_MODE.  */
+ 	    warning ("the offset of `%D' may not be ABI-compliant and may "
+ 		     "change in a future version of GCC", field);
  	}
        else
  	layout_nonempty_base_or_field (rli, field, NULL_TREE,
  				       empty_base_offsets);
  
Index: testsuite/g++.dg/abi/bitfield11.C
===================================================================
RCS file: testsuite/g++.dg/abi/bitfield11.C
diff -N testsuite/g++.dg/abi/bitfield11.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/bitfield11.C	15 Sep 2003 00:24:36 -0000
***************
*** 0 ****
--- 1,14 ----
+ // { dg-do run } 
+ // { dg-options "-w -fabi-version=0" }
+ 
+ struct S {
+   char c : 1024;
+ };
+ 
+ S s;
+ 
+ int main () {
+   s.c = 1;
+   if (*(char *)&s != 1)
+     return 1;
+ }
Index: testsuite/g++.dg/abi/bitfield12.C
===================================================================
RCS file: testsuite/g++.dg/abi/bitfield12.C
diff -N testsuite/g++.dg/abi/bitfield12.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/bitfield12.C	15 Sep 2003 00:24:36 -0000
***************
*** 0 ****
--- 1,5 ----
+ // { dg-options "-Wabi -fabi-version=1" }
+ 
+ struct S { // { dg-warning "ABI" }
+   char c : 1024; // { dg-warning "width" }
+ };



More information about the Gcc-patches mailing list