Bug 28160 - Bogus "size of array 'foo' is too large" error with -mms-bitfields
Summary: Bogus "size of array 'foo' is too large" error with -mms-bitfields
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2006-06-25 07:48 UTC by Kazumoto Kojima
Modified: 2006-07-15 23:12 UTC (History)
2 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work: 4.1.1
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kazumoto Kojima 2006-06-25 07:48:46 UTC
Several g++ tests in tmpdir-g++.dg-struct-layout-1 fail during
the compilation with the error message like

  error: size of array 'foo' is too large

with -mms-bitfields.  A reduced testcase is

typedef long int along __attribute__((aligned (32)));
struct S
{
  unsigned char a;
  along d:130;
  int e:66;
} A[1];

It looks the ms-bitfield code in stor-layout.c doesn't take
the bit field with excessive size into account and it makes
the negative remaining_in_alignment which causes the above
error.
Comment 1 Seongbae Park 2006-06-26 20:46:07 UTC
I belive this is a bug in stor-layout.c:place_field() around line 10503
bitpos is calculated as bit_offset of rli->prev_field + type size.
However, the prev_field is not really the immediately previous field but the first field of the consecutive same-sized fields.
Hence, in this case:

struct S
{
  long long d:23;
  int e:32;
  int f:32;
} a;

rli->prev_field is "d" when "field" is f. 
The correct fix should calculate the bitpos as 
rli->bitpos + type size.
Comment 2 Seongbae Park 2006-06-26 20:47:24 UTC
Oops. Mu previous comment is misplaced. It should have been on PR28161. 
Please ignore it.
Comment 3 Seongbae Park 2006-06-26 21:08:23 UTC
The immediate cause of the problem is in stor-layout.c:place_field():

   1118           if (DECL_SIZE (field) != NULL
   1119               && host_integerp (TYPE_SIZE (TREE_TYPE (field)), 0)
   1120               && host_integerp (DECL_SIZE (field), 0))
   1121             rli->remaining_in_alignment
   1122               = tree_low_cst (TYPE_SIZE (TREE_TYPE(field)), 1)
   1123                 - tree_low_cst (DECL_SIZE (field), 1);

For the field "d", 
remiaining_in_alignment becomes negative after line 1121-1123
- because the DECL_SIZE is larger than TYPE_SIZE for "d".

Comment 4 Kazumoto Kojima 2006-06-26 22:42:37 UTC
Thanks for your comment. Perhaps one solution would be to handle
such bit fields with excessive sizes as the case of "no remaining
bits in alignment".  I'm testing the appended patch which changes
lines you've pointed out.

--- ORIG/trunk/gcc/stor-layout.c	2006-06-13 09:06:36.000000000 +0900
+++ LOCAL/trunk/gcc/stor-layout.c	2006-06-26 16:43:12.000000000 +0900
@@ -1047,17 +1047,20 @@ place_field (record_layout_info rli, tre
 
 	      if (rli->remaining_in_alignment < bitsize)
 		{
+		  HOST_WIDE_INT typesize = tree_low_cst (TYPE_SIZE (type), 1);
+
 		  /* out of bits; bump up to next 'word'.  */
-		  rli->offset = DECL_FIELD_OFFSET (rli->prev_field);
 		  rli->bitpos
-		    = size_binop (PLUS_EXPR, TYPE_SIZE (type),
-				  DECL_FIELD_BIT_OFFSET (rli->prev_field));
+		    = size_binop (PLUS_EXPR, rli->bitpos,
+				  bitsize_int (rli->remaining_in_alignment));
 		  rli->prev_field = field;
-		  rli->remaining_in_alignment
-		    = tree_low_cst (TYPE_SIZE (type), 1);
+		  if (typesize < bitsize)
+		    rli->remaining_in_alignment = 0;
+		  else
+		    rli->remaining_in_alignment = typesize - bitsize;
 		}
-
-	      rli->remaining_in_alignment -= bitsize;
+	      else
+		rli->remaining_in_alignment -= bitsize;
 	    }
 	  else
 	    {
@@ -1119,9 +1121,16 @@ place_field (record_layout_info rli, tre
 	  if (DECL_SIZE (field) != NULL
 	      && host_integerp (TYPE_SIZE (TREE_TYPE (field)), 0)
 	      && host_integerp (DECL_SIZE (field), 0))
-	    rli->remaining_in_alignment
-	      = tree_low_cst (TYPE_SIZE (TREE_TYPE(field)), 1)
-		- tree_low_cst (DECL_SIZE (field), 1);
+	    {
+	      HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 1);
+	      HOST_WIDE_INT typesize
+		= tree_low_cst (TYPE_SIZE (TREE_TYPE (field)), 1);
+
+	      if (typesize < bitsize)
+		rli->remaining_in_alignment = 0;
+	      else
+		rli->remaining_in_alignment = typesize - bitsize;
+	    }
 
 	  /* Now align (conventionally) for the new type.  */
 	  type_align = TYPE_ALIGN (TREE_TYPE (field));
Comment 5 patchapp@dberlin.org 2006-06-29 21:45:26 UTC
Subject: Bug number PR middle-end/28160

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01472.html
Comment 6 Kazumoto Kojima 2006-07-15 06:59:07 UTC
Subject: Bug 28160

Author: kkojima
Date: Sat Jul 15 06:58:57 2006
New Revision: 115464

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=115464
Log:
	PR middle-end/28160
	* stor-layout.c (place_field): Take the bit field with
	an excessive size into account in the ms-bitfiled case.

	PR middle-end/28161
	* stor-layout.c (place_field): Use DECL_BIT_FIELD_TYPE of
	the previous bit field.


Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/stor-layout.c

Comment 7 Kazumoto Kojima 2006-07-15 23:12:30 UTC
Fixed.