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: Add -fabi-version


An early version of CodeSourcery's C++ ABI testsuite found a new C++
ABI bug in G++:

  union U {
    int i: 4096;
  };

This union should have size 512 on a system with 8-bit chars, but
actually only had size 508.  The corresponding struct/class case works
fine; this was an interaction between unions and bit-fields whose
width is wider than that of their type.

I added detection of this case to -Wabi.  Since bit-fields whose width
exceeds that of their type are incredibly rare (this feature exists
mostly to make it hard to implement the C++ ABI correctly!), and since
putting such things in a union is even rarer, I don't expect that very
many people will notice this bug.

I also added a -fabi-version flag to the C++ front end.  With
-fabi-version=1, you get the G++ 3.2 ABI, which remains the default.
With -fabi=version=0, you get the version of the ABI that is closest
to the specification.  There's no guarantee that ABI will remain
constant over time; it's going to change when we fix new ABI bugs.
After a while, we can set -fabi-version=2 to be the current high water
mark.

I went ahead and fixed the known ABI bugs with -fabi-version=0.  But,
there are probably more lurking; we are still finding bugs on the
order of weeks, not years.

Tested on i686-pc-linux-gnu, applied on the mainline.

-- 
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2002-09-23  Mark Mitchell  <mark@codesourcery.com>

	* c-common.c (flag_abi_version): New variable.
	* c-common.h (flag_abi_version): Declare it.
	* c-opts.c (missing_arg): Add -fabi-version.
	(c_common_decode_option): Process -fabi-version.
	* doc/invoke.texi (-fabi-version): Document it.
	(-Wabi): Add information about bit-fields in unions.
	
2002-09-23  Mark Mitchell  <mark@codesourcery.com>

	* cp/class.c (layout_virtual_bases): Do not round the size of the
	type to a multiple of the alignment before laying out virtual bases.
	(layout_class_type): Correct handling of bit-fields that are wider
	than their type inside unions.  Round the size of the type to a
	even number of bytes when computing the size without virtual
	bases.
	* cp/cp-tree.h (abi_version_at_least): New macro.
	
2002-09-23  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/bitfield6.C: New test.
	* g++.dg/abi/bitfield7.C: New test.
	* g++.dg/abi/bitfield8.C: New test.
	* g++.dg/abi/vbase11.C: New test.

Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.382
diff -c -p -r1.382 c-common.c
*** c-common.c	22 Sep 2002 19:23:19 -0000	1.382
--- c-common.c	23 Sep 2002 09:12:32 -0000
*************** int flag_permissive;
*** 567,572 ****
--- 567,587 ----
  
  int flag_enforce_eh_specs = 1;
  
+ /*  The version of the C++ ABI in use.  The following values are
+     allowed:
+ 
+     0: The version of the ABI believed most conformant with the 
+        C++ ABI specification.  This ABI may change as bugs are
+        discovered and fixed.  Therefore, 0 will not necessarily
+        indicate the same ABI in different versions of G++.
+ 
+     1: The version of the ABI first used in G++ 3.2.
+ 
+     Additional positive integers will be assigned as new versions of
+     the ABI become the default version of the ABI.  */
+ 
+ int flag_abi_version = 1;
+ 
  /* Nonzero means warn about things that will change when compiling
     with an ABI-compliant compiler.  */
  
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.160
diff -c -p -r1.160 c-common.h
*** c-common.h	22 Sep 2002 02:03:14 -0000	1.160
--- c-common.h	23 Sep 2002 09:12:32 -0000
*************** extern int flag_permissive;
*** 737,742 ****
--- 737,757 ----
  
  extern int flag_enforce_eh_specs;
  
+ /*  The version of the C++ ABI in use.  The following values are
+     allowed:
+ 
+     -1: The version of the ABI believed most conformant with the 
+         C++ ABI specification.  This ABI may change as bugs are
+ 	discovered and fixed.  Therefore, -1 will not necessarily
+ 	indicate the same ABI in different versions of G++.
+ 
+     0: The version of the ABI first used in G++ 3.2.
+ 
+     Additional positive integers will be assigned as new versions of
+     the ABI become the default version of the ABI.  */
+ 
+ extern int flag_abi_version;
+ 
  /* Nonzero means warn about things that will change when compiling
     with an ABI-compliant compiler.  */
  
Index: c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.18
diff -c -p -r1.18 c-opts.c
*** c-opts.c	15 Sep 2002 18:24:01 -0000	1.18
--- c-opts.c	23 Sep 2002 09:12:33 -0000
*************** static void sanitize_cpp_opts PARAMS ((v
*** 188,193 ****
--- 188,194 ----
    OPT("Wwrite-strings",		CL_ALL,   OPT_Wwrite_strings)		     \
    OPT("ansi",			CL_ALL,   OPT_ansi)			     \
    OPT("d",                      CL_ALL | CL_JOINED, OPT_d)		     \
+   OPT("fabi-version=",          CL_CXX | CL_JOINED, OPT_fabi_version)        \
    OPT("faccess-control",	CL_CXX,   OPT_faccess_control)		     \
    OPT("fall-virtual",		CL_CXX,   OPT_fall_virtual)		     \
    OPT("falt-external-templates",CL_CXX,   OPT_falt_external_templates)	     \
*************** missing_arg (opt_index)
*** 342,347 ****
--- 343,349 ----
      {
      case OPT_Wformat_eq:
      case OPT_d:
+     case OPT_fabi_version:
      case OPT_fbuiltin_:
      case OPT_fdump:
      case OPT_fname_mangling:
*************** c_common_decode_option (argc, argv)
*** 1012,1017 ****
--- 1014,1023 ----
      case OPT_fvtable_thunks:
      case OPT_fxref:
        warning ("switch \"%s\" is no longer supported", argv[0]);
+       break;
+ 
+     case OPT_fabi_version:
+       flag_abi_version = read_integral_parameter (arg, argv[0], 1);
        break;
  
      case OPT_faccess_control:
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.467
diff -c -p -r1.467 class.c
*** cp/class.c	21 Sep 2002 12:51:52 -0000	1.467
--- cp/class.c	23 Sep 2002 09:12:34 -0000
*************** layout_virtual_bases (t, offsets)
*** 4574,4580 ****
  #endif
  
    /* DSIZE is the size of the class without the virtual bases.  */
!   dsize = TYPE_SIZE (t);
  
    /* Make every class have alignment of at least one.  */
    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
--- 4574,4583 ----
  #endif
  
    /* DSIZE is the size of the class without the virtual bases.  */
!   if (abi_version_at_least(2))
!     dsize = CLASSTYPE_SIZE (t);
!   else
!     dsize = TYPE_SIZE (t);
  
    /* Make every class have alignment of at least one.  */
    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
*************** layout_class_type (t, empty_p, vfuns_p, 
*** 4875,4882 ****
  	     field.  We have to back up by one to find the largest
  	     type that fits.  */
  	  integer_type = integer_types[itk - 1];
! 	  padding = size_binop (MINUS_EXPR, DECL_SIZE (field), 
! 				TYPE_SIZE (integer_type));
  	  DECL_SIZE (field) = TYPE_SIZE (integer_type);
  	  DECL_ALIGN (field) = TYPE_ALIGN (integer_type);
  	  DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type);
--- 4878,4898 ----
  	     field.  We have to back up by one to find the largest
  	     type that fits.  */
  	  integer_type = integer_types[itk - 1];
! 
! 	  if (abi_version_at_least (2) && TREE_CODE (t) == UNION_TYPE)
! 	    /* In a union, the padding field must have the full width
! 	       of the bit-field; all fields start at offset zero.  */
! 	    padding = DECL_SIZE (field);
! 	  else
! 	    {
! 	      if (warn_abi && TREE_CODE (t) == UNION_TYPE)
! 		warning ("size assigned to `%T' may not be "
! 			 "ABI-compliant and may change in a future "
! 			 "version of GCC", 
! 			 t);
! 	      padding = size_binop (MINUS_EXPR, DECL_SIZE (field),
! 				    TYPE_SIZE (integer_type));
! 	    }
  	  DECL_SIZE (field) = TYPE_SIZE (integer_type);
  	  DECL_ALIGN (field) = TYPE_ALIGN (integer_type);
  	  DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type);
*************** layout_class_type (t, empty_p, vfuns_p, 
*** 4944,4951 ****
  
        padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
        place_field (rli, padding);
!     }
! 
    /* Let the back-end lay out the type. Note that at this point we
       have only included non-virtual base-classes; we will lay out the
       virtual base classes later.  So, the TYPE_SIZE/TYPE_ALIGN after
--- 4960,4973 ----
  
        padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
        place_field (rli, padding);
!     } 
!   else if (abi_version_at_least (2)
! 	   && !integer_zerop (rli->bitpos))
!     /* Make sure that we are on a byte boundary so that the size of
!        the class without virtual bases will always be a round number
!        of bytes.  */
!     rli->bitpos = round_up (rli->bitpos, BITS_PER_UNIT);
!   
    /* Let the back-end lay out the type. Note that at this point we
       have only included non-virtual base-classes; we will lay out the
       virtual base classes later.  So, the TYPE_SIZE/TYPE_ALIGN after
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.751
diff -c -p -r1.751 cp-tree.h
*** cp/cp-tree.h	21 Sep 2002 12:51:53 -0000	1.751
--- cp/cp-tree.h	23 Sep 2002 09:12:35 -0000
*************** struct diagnostic_context;
*** 212,217 ****
--- 212,223 ----
  
  #endif
  
+ /* Returns TRUE if generated code should match ABI version N or
+    greater is in use.  */
+ 
+ #define abi_version_at_least(N) \
+   (flag_abi_version == 0 || flag_abi_version >= (N))
+ 
  
  /* Language-dependent contents of an identifier.  */
  
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.186
diff -c -p -r1.186 invoke.texi
*** doc/invoke.texi	22 Sep 2002 19:23:20 -0000	1.186
--- doc/invoke.texi	23 Sep 2002 09:12:38 -0000
*************** in the following sections.
*** 174,181 ****
  @item C++ Language Options
  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
  @gccoptlist{
! -fno-access-control  -fcheck-new  -fconserve-space @gol
! -fno-const-strings  -fdollars-in-identifiers @gol
  -fno-elide-constructors @gol
  -fno-enforce-eh-specs  -fexternal-templates @gol
  -falt-external-templates @gol
--- 174,181 ----
  @item C++ Language Options
  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
  @gccoptlist{
! -fabi-version=@var{n} -fno-access-control  -fcheck-new @gol
! -fconserve-space -fno-const-strings  -fdollars-in-identifiers @gol
  -fno-elide-constructors @gol
  -fno-enforce-eh-specs  -fexternal-templates @gol
  -falt-external-templates @gol
*************** language supported by GCC@.
*** 1249,1254 ****
--- 1249,1263 ----
  Here is a list of options that are @emph{only} for compiling C++ programs:
  
  @table @gcctabopt
+ 
+ @item -fabi-version=@var{n}
+ @opindex fabi-version
+ Use version @var{n} of the C++ ABI.  Version 1 is the version of the C++
+ ABI that first appeared in G++ 3.2.  Version 0 will always be the
+ version that conforms most closely to the C++ ABI specification.
+ Therefore, the ABI obtained using version 0 will change as ABI bugs are
+ fixed.
+ 
  @item -fno-access-control
  @opindex fno-access-control
  Turn off all access checking.  This switch is mainly useful for working
*************** In this case, G++ will not place @code{B
*** 1521,1526 ****
--- 1530,1548 ----
  explicitly padding @code{A} so that its size is a multiple of its
  alignment (ignoring virtual base classes); that will cause G++ and other
  compilers to layout @code{C} identically.
+ 
+ @item
+ Incorrect handling of bit-fields with declared widths greater than that
+ of their underlying types, when the bit-fields appear in a union.  For
+ example:
+ 
+ @smallexample
+ union U @{ int i : 4096; @};
+ @end smallexample
+ 
+ @noindent
+ Assuming that an @code{int} does not have 4096 bits, G++ will make the
+ union too small by the number of bits in an @code{int}.
  
  @end itemize
  
Index: testsuite/g++.dg/abi/bitfield6.C
===================================================================
RCS file: testsuite/g++.dg/abi/bitfield6.C
diff -N testsuite/g++.dg/abi/bitfield6.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/bitfield6.C	23 Sep 2002 09:12:38 -0000
***************
*** 0 ****
--- 1,14 ----
+ // { dg-do run }
+ // { dg-options "-w -fabi-version=0" }
+ 
+ #include <limits>
+ 
+ union U {
+   int i: 4096;
+ };
+ 
+ int main () {
+   if (sizeof (U) * std::numeric_limits<unsigned char>::digits != 4096)
+     return 1;
+ }
+ 
Index: testsuite/g++.dg/abi/bitfield7.C
===================================================================
RCS file: testsuite/g++.dg/abi/bitfield7.C
diff -N testsuite/g++.dg/abi/bitfield7.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/bitfield7.C	23 Sep 2002 09:12:38 -0000
***************
*** 0 ****
--- 1,7 ----
+ // { dg-do compile }
+ // { dg-options "-Wabi" }
+ 
+ union U { // { dg-warning "ABI" }
+   int i: 4096; // { dg-warning "exceeds" }
+ };
+ 
Index: testsuite/g++.dg/abi/bitfield8.C
===================================================================
RCS file: testsuite/g++.dg/abi/bitfield8.C
diff -N testsuite/g++.dg/abi/bitfield8.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/bitfield8.C	23 Sep 2002 09:12:38 -0000
***************
*** 0 ****
--- 1,20 ----
+ // { dg-do run { target i?86-*-* } }
+ // { dg-options "-fabi-version=0" }
+ 
+ struct A { 
+   virtual void f() {}
+   int f1 : 1; 
+ };
+ 
+ struct B : public A {
+   int f2 : 31;
+   int f3 : 4; 
+   int f4 : 3;
+ };
+ 
+ int main ()
+ {
+   if (sizeof (B) != 16)
+     return 1;
+ }
+   
Index: testsuite/g++.dg/abi/vbase11.C
===================================================================
RCS file: testsuite/g++.dg/abi/vbase11.C
diff -N testsuite/g++.dg/abi/vbase11.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/vbase11.C	23 Sep 2002 09:12:38 -0000
***************
*** 0 ****
--- 1,12 ----
+ // { dg-do run { target i?86-*-* } }
+ // { dg-options "-fabi-version=0" }
+ 
+ struct A { virtual void f(); char c1; };
+ struct B { B(); char c2; };
+ struct C : public A, public virtual B { };
+ 
+ int main () {
+   if (sizeof (C) != 8)
+     return 1;
+ }
+ 


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