This is the mail archive of the gcc-prs@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]

c++/4588: bogus warning concerning bit field limits



>Number:         4588
>Category:       c++
>Synopsis:       bogus warning concerning bit field limits
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Oct 17 00:56:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     ben@666.com
>Release:        2.95.3-5
>Organization:
>Environment:
Cygwin
>Description:
i get the following warnings:

/src/xemacs/mule/src/alloc.c: In function `void sledgehammer_check_ascii_begin(L
isp_Object)':
/src/xemacs/mule/src/alloc.c:1846: warning: comparison is always 0 due to width
of bitfield

but this is bogus, as the code shows.

here is the function mentioned: [line 1846 is second from bottom,
and indicated with an arrow like <=========== ]

void
sledgehammer_check_ascii_begin (Lisp_Object str)
{
  int i;

  for (i = 0; i < XSTRING_LENGTH (str); i++)
    {
      if (!BYTE_ASCII_P (XSTRING_BYTE (str, i)))
	break;
    }

  assert (i == (int) XSTRING_ASCII_BEGIN (str) ||
	  (i > MAX_STRING_ASCII_BEGIN &&
	   XSTRING_ASCII_BEGIN (str) == MAX_STRING_ASCII_BEGIN));   <==========
}



the various structures and macros look like this:

struct Lisp_String
{
  union
    {
      struct lrecord_header lheader;
      struct
	{
	  /* WARNING: Everything before ascii_begin must agree exactly with
	     struct lrecord_header */
	  unsigned int type :8;
	  unsigned int mark :1;
	  unsigned int c_readonly :1;
	  unsigned int lisp_readonly :1;
	  /* Number of chars at beginning of string that are one byte in length
	     (BYTE_ASCII_P) */
	  unsigned int ascii_begin :21;
	} v;
    } u;
  Bytecount size;
  Bufbyte *data;
  Lisp_Object plist;
};
typedef struct Lisp_String Lisp_String;

typedef EMACS_INT Bytecount; [see below]
typedef unsigned char Bufbyte;
see below for Lisp_Object

struct lrecord_header
{
  /* index into lrecord_implementations_table[] */
  unsigned int type :8;

  /* If `mark' is 0 after the GC mark phase, the object will be freed
     during the GC sweep phase.  There are 2 ways that `mark' can be 1:
     - by being referenced from other objects during the GC mark phase
     - because it is permanently on, for c_readonly objects */
  unsigned int mark :1;

  /* 1 if the object resides in logically read-only space, and does not
     reference other non-c_readonly objects.
     Invariant: if (c_readonly == 1), then (mark == 1 && lisp_readonly == 1) */
  unsigned int c_readonly :1;

  /* 1 if the object is readonly from lisp */
  unsigned int lisp_readonly :1;

  unsigned int unused :21;
};

#define MAX_STRING_ASCII_BEGIN ((2 << 21) - 1)

#define XSTRING_ASCII_BEGIN(s) string_ascii_begin (XSTRING (s))
#define string_ascii_begin(s) ((s)->u.v.ascii_begin + 0)
#define XSTRING(x) XRECORD (x, string, Lisp_String)
# define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x))
#define XPNTR(x) ((void *) XPNTRVAL(x))

NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Basically, a Lisp_Object is a [usually] 32-bit "tagged" integral type that
can hold either a pointer, a 31-bit integer, or a few other things.
XPNTR(x) just extracts the pointer.  Most of the time we use `int' as the
base type of Lisp_Object, and XPNTRVAL is just a no-op.  However, we also
have a version where the Lisp_Object is represented as a union, which
allows for better type checking, so we use it for tests.  This time, I was
using this version, so I duly report the actual structures.  But I
seriously doubt it matters whether union or int is used, since the problem
occurs after the string structure has been extracted from the Lisp_Object,
and at that point we have nothing more to do with the Lisp_Object.

Here is the int version for easy testing:

typedef EMACS_INT Lisp_Object;
#define XPNTRVAL(x) (x) /* This depends on Lisp_Type_Record == 0 */
#define EMACS_INT long

Here is the grody union version that was actually used:

typedef
union Lisp_Object
{
  /* if non-valbits are at lower addresses */
#ifdef WORDS_BIGENDIAN
  struct
  {
    EMACS_UINT val : VALBITS;
    enum_field (Lisp_Type) type : GCTYPEBITS;
  } gu;

  struct
  {
    signed EMACS_INT val : INT_VALBITS;
    unsigned int bits : INT_GCBITS;
  } s;

  struct
  {
    EMACS_UINT val : INT_VALBITS;
    unsigned int bits : INT_GCBITS;
  } u;
#else /* non-valbits are at higher addresses */
  struct
  {
    enum_field (Lisp_Type) type : GCTYPEBITS;
    EMACS_UINT val : VALBITS;
  } gu;

  struct
  {
    unsigned int bits : INT_GCBITS;
    signed EMACS_INT val : INT_VALBITS;
  } s;

  struct
  {
    unsigned int bits : INT_GCBITS;
    EMACS_UINT val : INT_VALBITS;
  } u;

#endif /* non-valbits are at higher addresses */

  EMACS_UINT ui;
  signed EMACS_INT i;

  /* This was formerly declared 'void *v' etc. but that causes
     GCC to accept any (yes, any) pointer as the argument of
     a function declared to accept a Lisp_Object. */
  struct nosuchstruct *v;
  const struct nosuchstruct *cv;
}
Lisp_Object;

# define XPNTRVAL(x) ((x).ui)

#define GCMARKBITS  0
#define GCTYPEBITS  2
#define GCBITS      2
#define INT_GCBITS  1

#define INT_VALBITS (BITS_PER_EMACS_INT - INT_GCBITS)
#define VALBITS (BITS_PER_EMACS_INT - GCBITS)
#define EMACS_UINT unsigned long
#define EMACS_INT is long
#define BITS_PER_EMACS_INT 32
WORDS_BIGENDIAN not defined.



So anyway, as you can see, ascii_begin in struct Lisp_String should be an
unsigned int bitfield of 21 bits; therefore, its range is 0 .. 2^21 - 1.
MAX_STRING_ASCII_BEGIN is 2^21 - 1, so it should be perfectly okay to
compare a bitfield value to MAX_STRING_ASCII_BEGIN.





>How-To-Repeat:

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:


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