GNU bug report logs - #8771
Remove arbitrary 32-bit limit in Emacs hash tables

Previous Next

Package: emacs;

Reported by: Paul Eggert <eggert <at> cs.ucla.edu>

Date: Tue, 31 May 2011 06:10:03 UTC

Severity: normal

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 8771 in the body.
You can then email your comments to 8771 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org:
bug#8771; Package emacs. (Tue, 31 May 2011 06:10:03 GMT) Full text and rfc822 format available.

Acknowledgement sent to Paul Eggert <eggert <at> cs.ucla.edu>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Tue, 31 May 2011 06:10:03 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: bug-gnu-emacs <at> gnu.org
Subject: Remove arbitrary 32-bit limit in Emacs hash tables
Date: Mon, 30 May 2011 23:09:34 -0700
Currently the Emacs source code uses 'unsigned' for hashes and 'int'
for hash tables, but on 64-bit hosts hash tables can in principle be
larger than what can be shoehorned into 32 bits.  Here's a proposed patch;
most of it is pretty straightforward.


Remove arbitrary limit of 2**31 entries in hash tables.
* category.c (hash_get_category_set): Use 'EMACS_UINT' and 'EMACS_INT'
for hashes and hash indexes, instead of 'unsigned' and 'int'.
* ccl.c (ccl_driver): Likewise.
* charset.c (Fdefine_charset_internal): Likewise.
* charset.h (struct charset.hash_index): Likewise.
* composite.c (get_composition_id, gstring_lookup_cache):
(composition_gstring_put_cache): Likewise.
* composite.h (struct composition.hash_index): Likewise.
* dispextern.h (struct image.hash): Likewise.
* fns.c (next_almost_prime, larger_vector, cmpfn_eql):
(cmpfn_equal, cmpfn_user_defined, hashfn_eq, hashfn_eql):
(hashfn_equal, hashfn_user_defined, make_hash_table):
(maybe_resize_hash_table, hash_lookup, hash_put):
(hash_remove_from_table, hash_clear, sweep_weak_table, SXHASH_COMBINE):
(sxhash_string, sxhash_list, sxhash_vector, sxhash_bool_vector):
(Fsxhash, Fgethash, Fputhash, Fmaphash): Likewise.
* image.c (make_image, search_image_cache, lookup_image):
(xpm_put_color_table_h): Likewise.
* lisp.h (struct Lisp_Hash_Table): Likewise, for 'count', 'cmpfn',
and 'hashfn' members.
* minibuf.c (Ftry_completion, Fall_completions, Ftest_completion):
Likewise.
* print.c (print): Likewise.
* alloc.c (allocate_vectorlike): Check for overflow in vector size
calculations.
* ccl.c (ccl_driver): Check for overflow when converting EMACS_INT
to int.
* fns.c, image.c: Remove unnecessary static decls that would otherwise
need to be updated by these changes.
* fns.c (make_hash_table, maybe_resize_hash_table): Check for integer
overflow with large hash tables.
(make_hash_table, maybe_resize_hash_table, Fmake_hash_table):
Prefer the faster XFLOAT_DATA to XFLOATINT where either will do.
(SXHASH_REDUCE): New macro.
(sxhash_string, sxhash_list, sxhash_vector, sxhash_bool_vector):
Use it instead of discarding useful hash info with large hash values.
(sxhash_float): New function.
(sxhash): Use it.  No more need for "& INTMASK" due to above changes.
* lisp.h (FIXNUM_BITS): New macro, useful for SXHASH_REDUCE etc.
(MOST_NEGATIVE_FIXNUM, MOST_POSITIVE_FIXNUM, INTMASK): Rewrite
to use FIXNUM_BITS, as this simplifies things.
(next_almost_prime, larger_vector, sxhash, hash_lookup, hash_put):
Adjust signatures to match updated version of code.
(consing_since_gc): Now EMACS_INT, since a single hash table can
use more than INT_MAX bytes.
=== modified file 'src/alloc.c'
--- src/alloc.c	2011-05-31 05:15:34 +0000
+++ src/alloc.c	2011-05-31 05:52:26 +0000
@@ -157,7 +157,7 @@

 /* Number of bytes of consing done since the last gc.  */

-int consing_since_gc;
+EMACS_INT consing_since_gc;

 /* Similar minimum, computed from Vgc_cons_percentage.  */

@@ -2788,6 +2788,11 @@
 {
   struct Lisp_Vector *p;
   size_t nbytes;
+  int header_size = offsetof (struct Lisp_Vector, contents);
+  int word_size = sizeof p->contents[0];
+
+  if ((SIZE_MAX - header_size) / word_size < len)
+    memory_full ();

   MALLOC_BLOCK_INPUT;

@@ -2801,8 +2806,7 @@
   /* This gets triggered by code which I haven't bothered to fix.  --Stef  */
   /* eassert (!handling_signal); */

-  nbytes = (offsetof (struct Lisp_Vector, contents)
-	    + len * sizeof p->contents[0]);
+  nbytes = header_size + len * word_size;
   p = (struct Lisp_Vector *) lisp_malloc (nbytes, MEM_TYPE_VECTORLIKE);

 #ifdef DOUG_LEA_MALLOC

=== modified file 'src/category.c'
--- src/category.c	2011-04-11 06:28:35 +0000
+++ src/category.c	2011-05-31 05:52:26 +0000
@@ -67,8 +67,8 @@
 hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
 {
   struct Lisp_Hash_Table *h;
-  int i;
-  unsigned hash;
+  EMACS_INT i;
+  EMACS_UINT hash;

   if (NILP (XCHAR_TABLE (table)->extras[1]))
     XCHAR_TABLE (table)->extras[1]

=== modified file 'src/ccl.c'
--- src/ccl.c	2011-05-31 05:38:59 +0000
+++ src/ccl.c	2011-05-31 05:52:26 +0000
@@ -1307,15 +1307,15 @@
 				: -1));
 		h = GET_HASH_TABLE (eop);

-		op = hash_lookup (h, make_number (reg[RRR]), NULL);
-		if (op >= 0)
+		eop = hash_lookup (h, make_number (reg[RRR]), NULL);
+		if (eop >= 0)
 		  {
 		    Lisp_Object opl;
-		    opl = HASH_VALUE (h, op);
-		    if (! CHARACTERP (opl))
+		    opl = HASH_VALUE (h, eop);
+		    if (! (IN_INT_RANGE (eop) && CHARACTERP (opl)))
 		      CCL_INVALID_CMD;
 		    reg[RRR] = charset_unicode;
-		    reg[rrr] = op;
+		    reg[rrr] = eop;
 		    reg[7] = 1; /* r7 true for success */
 		  }
 		else
@@ -1334,11 +1334,11 @@
 		i = CCL_DECODE_CHAR (reg[RRR], reg[rrr]);
 		h = GET_HASH_TABLE (eop);

-		op = hash_lookup (h, make_number (i), NULL);
-		if (op >= 0)
+		eop = hash_lookup (h, make_number (i), NULL);
+		if (eop >= 0)
 		  {
 		    Lisp_Object opl;
-		    opl = HASH_VALUE (h, op);
+		    opl = HASH_VALUE (h, eop);
 		    if (! (INTEGERP (opl) && IN_INT_RANGE (XINT (opl))))
 		      CCL_INVALID_CMD;
 		    reg[RRR] = XINT (opl);

=== modified file 'src/charset.c'
--- src/charset.c	2011-05-28 22:39:39 +0000
+++ src/charset.c	2011-05-31 05:52:26 +0000
@@ -849,7 +849,7 @@
   /* Charset attr vector.  */
   Lisp_Object attrs;
   Lisp_Object val;
-  unsigned hash_code;
+  EMACS_UINT hash_code;
   struct Lisp_Hash_Table *hash_table = XHASH_TABLE (Vcharset_hash_table);
   int i, j;
   struct charset charset;

=== modified file 'src/charset.h'
--- src/charset.h	2011-05-01 16:27:34 +0000
+++ src/charset.h	2011-05-31 05:52:26 +0000
@@ -146,7 +146,7 @@
   int id;

   /* Index to Vcharset_hash_table.  */
-  int hash_index;
+  EMACS_INT hash_index;

   /* Dimension of the charset: 1, 2, 3, or 4.  */
   int dimension;

=== modified file 'src/composite.c'
--- src/composite.c	2011-05-20 00:51:38 +0000
+++ src/composite.c	2011-05-31 05:52:26 +0000
@@ -179,8 +179,8 @@
   Lisp_Object id, length, components, key, *key_contents;
   int glyph_len;
   struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
-  int hash_index;
-  unsigned hash_code;
+  EMACS_INT hash_index;
+  EMACS_UINT hash_code;
   struct composition *cmp;
   EMACS_INT i;
   int ch;
@@ -656,7 +656,7 @@
 gstring_lookup_cache (Lisp_Object header)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
-  int i = hash_lookup (h, header, NULL);
+  EMACS_INT i = hash_lookup (h, header, NULL);

   return (i >= 0 ? HASH_VALUE (h, i) : Qnil);
 }
@@ -665,7 +665,7 @@
 composition_gstring_put_cache (Lisp_Object gstring, EMACS_INT len)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
-  unsigned hash;
+  EMACS_UINT hash;
   Lisp_Object header, copy;
   EMACS_INT i;


=== modified file 'src/composite.h'
--- src/composite.h	2011-04-11 03:39:45 +0000
+++ src/composite.h	2011-05-31 05:52:26 +0000
@@ -186,7 +186,7 @@
   enum composition_method method;

   /* Index to the composition hash table.  */
-  int hash_index;
+  EMACS_INT hash_index;

   /* For which font we have calculated the remaining members.  The
      actual type is device dependent.  */

=== modified file 'src/dispextern.h'
--- src/dispextern.h	2011-05-25 03:45:04 +0000
+++ src/dispextern.h	2011-05-31 05:52:26 +0000
@@ -2798,7 +2798,7 @@
   } data;

   /* Hash value of image specification to speed up comparisons.  */
-  unsigned hash;
+  EMACS_UINT hash;

   /* Image id of this image.  */
   int id;

=== modified file 'src/fns.c'
--- src/fns.c	2011-05-28 22:39:39 +0000
+++ src/fns.c	2011-05-31 05:52:26 +0000
@@ -3358,21 +3358,6 @@
 static struct Lisp_Hash_Table *check_hash_table (Lisp_Object);
 static size_t get_key_arg (Lisp_Object, size_t, Lisp_Object *, char *);
 static void maybe_resize_hash_table (struct Lisp_Hash_Table *);
-static int cmpfn_eql (struct Lisp_Hash_Table *, Lisp_Object, unsigned,
-                      Lisp_Object, unsigned);
-static int cmpfn_equal (struct Lisp_Hash_Table *, Lisp_Object, unsigned,
-                        Lisp_Object, unsigned);
-static int cmpfn_user_defined (struct Lisp_Hash_Table *, Lisp_Object,
-                               unsigned, Lisp_Object, unsigned);
-static unsigned hashfn_eq (struct Lisp_Hash_Table *, Lisp_Object);
-static unsigned hashfn_eql (struct Lisp_Hash_Table *, Lisp_Object);
-static unsigned hashfn_equal (struct Lisp_Hash_Table *, Lisp_Object);
-static unsigned hashfn_user_defined (struct Lisp_Hash_Table *,
-                                     Lisp_Object);
-static unsigned sxhash_string (unsigned char *, int);
-static unsigned sxhash_list (Lisp_Object, int);
-static unsigned sxhash_vector (Lisp_Object, int);
-static unsigned sxhash_bool_vector (Lisp_Object);
 static int sweep_weak_table (struct Lisp_Hash_Table *, int);


@@ -3395,8 +3380,8 @@
 /* Value is the next integer I >= N, N >= 0 which is "almost" a prime
    number.  */

-int
-next_almost_prime (int n)
+EMACS_INT
+next_almost_prime (EMACS_INT n)
 {
   if (n % 2 == 0)
     n += 1;
@@ -3436,10 +3421,10 @@
    vector that are not copied from VEC are set to INIT.  */

 Lisp_Object
-larger_vector (Lisp_Object vec, int new_size, Lisp_Object init)
+larger_vector (Lisp_Object vec, EMACS_INT new_size, Lisp_Object init)
 {
   struct Lisp_Vector *v;
-  int i, old_size;
+  EMACS_INT i, old_size;

   xassert (VECTORP (vec));
   old_size = ASIZE (vec);
@@ -3463,7 +3448,9 @@
    KEY2 are the same.  */

 static int
-cmpfn_eql (struct Lisp_Hash_Table *h, Lisp_Object key1, unsigned int hash1, Lisp_Object key2, unsigned int hash2)
+cmpfn_eql (struct Lisp_Hash_Table *h,
+	   Lisp_Object key1, EMACS_UINT hash1,
+	   Lisp_Object key2, EMACS_UINT hash2)
 {
   return (FLOATP (key1)
 	  && FLOATP (key2)
@@ -3476,7 +3463,9 @@
    KEY2 are the same.  */

 static int
-cmpfn_equal (struct Lisp_Hash_Table *h, Lisp_Object key1, unsigned int hash1, Lisp_Object key2, unsigned int hash2)
+cmpfn_equal (struct Lisp_Hash_Table *h,
+	     Lisp_Object key1, EMACS_UINT hash1,
+	     Lisp_Object key2, EMACS_UINT hash2)
 {
   return hash1 == hash2 && !NILP (Fequal (key1, key2));
 }
@@ -3487,7 +3476,9 @@
    if KEY1 and KEY2 are the same.  */

 static int
-cmpfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key1, unsigned int hash1, Lisp_Object key2, unsigned int hash2)
+cmpfn_user_defined (struct Lisp_Hash_Table *h,
+		    Lisp_Object key1, EMACS_UINT hash1,
+		    Lisp_Object key2, EMACS_UINT hash2)
 {
   if (hash1 == hash2)
     {
@@ -3507,10 +3498,10 @@
    `eq' to compare keys.  The hash code returned is guaranteed to fit
    in a Lisp integer.  */

-static unsigned
+static EMACS_UINT
 hashfn_eq (struct Lisp_Hash_Table *h, Lisp_Object key)
 {
-  unsigned hash = XUINT (key) ^ XTYPE (key);
+  EMACS_UINT hash = XUINT (key) ^ XTYPE (key);
   xassert ((hash & ~INTMASK) == 0);
   return hash;
 }
@@ -3520,10 +3511,10 @@
    `eql' to compare keys.  The hash code returned is guaranteed to fit
    in a Lisp integer.  */

-static unsigned
+static EMACS_UINT
 hashfn_eql (struct Lisp_Hash_Table *h, Lisp_Object key)
 {
-  unsigned hash;
+  EMACS_UINT hash;
   if (FLOATP (key))
     hash = sxhash (key, 0);
   else
@@ -3537,10 +3528,10 @@
    `equal' to compare keys.  The hash code returned is guaranteed to fit
    in a Lisp integer.  */

-static unsigned
+static EMACS_UINT
 hashfn_equal (struct Lisp_Hash_Table *h, Lisp_Object key)
 {
-  unsigned hash = sxhash (key, 0);
+  EMACS_UINT hash = sxhash (key, 0);
   xassert ((hash & ~INTMASK) == 0);
   return hash;
 }
@@ -3550,7 +3541,7 @@
    user-defined function to compare keys.  The hash code returned is
    guaranteed to fit in a Lisp integer.  */

-static unsigned
+static EMACS_UINT
 hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key)
 {
   Lisp_Object args[2], hash;
@@ -3593,26 +3584,33 @@
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
-  int index_size, i, sz;
+  EMACS_INT index_size, i, sz;
+  double index_float;

   /* Preconditions.  */
   xassert (SYMBOLP (test));
   xassert (INTEGERP (size) && XINT (size) >= 0);
   xassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0)
-	   || (FLOATP (rehash_size) && XFLOATINT (rehash_size) > 1.0));
+	   || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size)));
   xassert (FLOATP (rehash_threshold)
-	   && XFLOATINT (rehash_threshold) > 0
-	   && XFLOATINT (rehash_threshold) <= 1.0);
+	   && 0 < XFLOAT_DATA (rehash_threshold)
+	   && XFLOAT_DATA (rehash_threshold) <= 1.0);

   if (XFASTINT (size) == 0)
     size = make_number (1);

+  sz = XFASTINT (size);
+  index_float = sz / XFLOAT_DATA (rehash_threshold);
+  index_size = (index_float < MOST_POSITIVE_FIXNUM + 1
+		? next_almost_prime (index_float)
+		: MOST_POSITIVE_FIXNUM + 1);
+  if (MOST_POSITIVE_FIXNUM < max (index_size, 2 * sz))
+    error ("Hash table too large");
+
   /* Allocate a table and initialize it.  */
   h = allocate_hash_table ();

   /* Initialize hash table slots.  */
-  sz = XFASTINT (size);
-
   h->test = test;
   if (EQ (test, Qeql))
     {
@@ -3644,8 +3642,6 @@
   h->key_and_value = Fmake_vector (make_number (2 * sz), Qnil);
   h->hash = Fmake_vector (size, Qnil);
   h->next = Fmake_vector (size, Qnil);
-  /* Cast to int here avoids losing with gcc 2.95 on Tru64/Alpha...  */
-  index_size = next_almost_prime ((int) (sz / XFLOATINT (rehash_threshold)));
   h->index = Fmake_vector (make_number (index_size), Qnil);

   /* Set up the free list.  */
@@ -3709,20 +3705,29 @@
 {
   if (NILP (h->next_free))
     {
-      int old_size = HASH_TABLE_SIZE (h);
-      int i, new_size, index_size;
+      EMACS_INT old_size = HASH_TABLE_SIZE (h);
+      EMACS_INT i, new_size, index_size;
       EMACS_INT nsize;
+      double index_float;

       if (INTEGERP (h->rehash_size))
 	new_size = old_size + XFASTINT (h->rehash_size);
       else
-	new_size = old_size * XFLOATINT (h->rehash_size);
-      new_size = max (old_size + 1, new_size);
-      index_size = next_almost_prime ((int)
-				      (new_size
-				       / XFLOATINT (h->rehash_threshold)));
-      /* Assignment to EMACS_INT stops GCC whining about limited range
-	 of data type.  */
+	{
+	  double float_new_size = old_size * XFLOAT_DATA (h->rehash_size);
+	  if (float_new_size < MOST_POSITIVE_FIXNUM + 1)
+	    {
+	      new_size = float_new_size;
+	      if (new_size <= old_size)
+		new_size = old_size + 1;
+	    }
+	  else
+	    new_size = MOST_POSITIVE_FIXNUM + 1;
+	}
+      index_float = new_size / XFLOAT_DATA (h->rehash_threshold);
+      index_size = (index_float < MOST_POSITIVE_FIXNUM + 1
+		    ? next_almost_prime (index_float)
+		    : MOST_POSITIVE_FIXNUM + 1);
       nsize = max (index_size, 2 * new_size);
       if (nsize > MOST_POSITIVE_FIXNUM)
 	error ("Hash table too large to resize");
@@ -3756,8 +3761,8 @@
       for (i = 0; i < old_size; ++i)
 	if (!NILP (HASH_HASH (h, i)))
 	  {
-	    unsigned hash_code = XUINT (HASH_HASH (h, i));
-	    int start_of_bucket = hash_code % ASIZE (h->index);
+	    EMACS_UINT hash_code = XUINT (HASH_HASH (h, i));
+	    EMACS_INT start_of_bucket = hash_code % ASIZE (h->index);
 	    HASH_NEXT (h, i) = HASH_INDEX (h, start_of_bucket);
 	    HASH_INDEX (h, start_of_bucket) = make_number (i);
 	  }
@@ -3769,11 +3774,11 @@
    the hash code of KEY.  Value is the index of the entry in H
    matching KEY, or -1 if not found.  */

-int
-hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, unsigned int *hash)
+EMACS_INT
+hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
 {
-  unsigned hash_code;
-  int start_of_bucket;
+  EMACS_UINT hash_code;
+  EMACS_INT start_of_bucket;
   Lisp_Object idx;

   hash_code = h->hashfn (h, key);
@@ -3786,7 +3791,7 @@
   /* We need not gcpro idx since it's either an integer or nil.  */
   while (!NILP (idx))
     {
-      int i = XFASTINT (idx);
+      EMACS_INT i = XFASTINT (idx);
       if (EQ (key, HASH_KEY (h, i))
 	  || (h->cmpfn
 	      && h->cmpfn (h, key, hash_code,
@@ -3803,10 +3808,11 @@
    HASH is a previously computed hash code of KEY.
    Value is the index of the entry in H matching KEY.  */

-int
-hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value, unsigned int hash)
+EMACS_INT
+hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value,
+	  EMACS_UINT hash)
 {
-  int start_of_bucket, i;
+  EMACS_INT start_of_bucket, i;

   xassert ((hash & ~INTMASK) == 0);

@@ -3836,8 +3842,8 @@
 static void
 hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
 {
-  unsigned hash_code;
-  int start_of_bucket;
+  EMACS_UINT hash_code;
+  EMACS_INT start_of_bucket;
   Lisp_Object idx, prev;

   hash_code = h->hashfn (h, key);
@@ -3848,7 +3854,7 @@
   /* We need not gcpro idx, prev since they're either integers or nil.  */
   while (!NILP (idx))
     {
-      int i = XFASTINT (idx);
+      EMACS_INT i = XFASTINT (idx);

       if (EQ (key, HASH_KEY (h, i))
 	  || (h->cmpfn
@@ -3886,7 +3892,7 @@
 {
   if (h->count > 0)
     {
-      int i, size = HASH_TABLE_SIZE (h);
+      EMACS_INT i, size = HASH_TABLE_SIZE (h);

       for (i = 0; i < size; ++i)
 	{
@@ -3924,7 +3930,8 @@
 static int
 sweep_weak_table (struct Lisp_Hash_Table *h, int remove_entries_p)
 {
-  int bucket, n, marked;
+  EMACS_INT bucket, n;
+  int marked;

   n = ASIZE (h->index) & ~ARRAY_MARK_FLAG;
   marked = 0;
@@ -3938,7 +3945,7 @@
       prev = Qnil;
       for (idx = HASH_INDEX (h, bucket); !NILP (idx); idx = next)
 	{
-	  int i = XFASTINT (idx);
+	  EMACS_INT i = XFASTINT (idx);
 	  int key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i));
 	  int value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i));
 	  int remove_p;
@@ -4067,43 +4074,68 @@

 #define SXHASH_MAX_LEN   7

-/* Combine two integers X and Y for hashing.  */
+/* Combine two integers X and Y for hashing.  The result might not fit
+   into a Lisp integer.  */

 #define SXHASH_COMBINE(X, Y)						\
-     ((((unsigned)(X) << 4) + (((unsigned)(X) >> 24) & 0x0fffffff))	\
-      + (unsigned)(Y))
+  ((((EMACS_UINT) (X) << 4) + ((EMACS_UINT) (X) >> (BITS_PER_EMACS_INT - 4))) \
+   + (EMACS_UINT) (Y))

+/* Hash X, returning a value that fits into a Lisp integer.  */
+#define SXHASH_REDUCE(X) \
+  ((((X) ^ (X) >> (BITS_PER_EMACS_INT - FIXNUM_BITS))) & INTMASK)

 /* Return a hash for string PTR which has length LEN.  The hash
    code returned is guaranteed to fit in a Lisp integer.  */

-static unsigned
-sxhash_string (unsigned char *ptr, int len)
+static EMACS_UINT
+sxhash_string (unsigned char *ptr, EMACS_INT len)
 {
   unsigned char *p = ptr;
   unsigned char *end = p + len;
   unsigned char c;
-  unsigned hash = 0;
+  EMACS_UINT hash = 0;

   while (p != end)
     {
       c = *p++;
       if (c >= 0140)
 	c -= 40;
-      hash = ((hash << 4) + (hash >> 28) + c);
+      hash = SXHASH_COMBINE (hash, c);
     }

-  return hash & INTMASK;
-}
-
+  return SXHASH_REDUCE (hash);
+}
+
+/* Return a hash for the floating point value VAL.  */
+
+static EMACS_INT
+sxhash_float (double val)
+{
+  EMACS_UINT hash = 0;
+  enum {
+    WORDS_PER_DOUBLE = (sizeof val / sizeof hash
+			+ (sizeof val % sizeof hash != 0))
+  };
+  union {
+    double val;
+    EMACS_UINT word[WORDS_PER_DOUBLE];
+  } u;
+  int i;
+  u.val = val;
+  memset (&u.val + 1, 0, sizeof u - sizeof u.val);
+  for (i = 0; i < WORDS_PER_DOUBLE; i++)
+    hash = SXHASH_COMBINE (hash, u.word[i]);
+  return SXHASH_REDUCE (hash);
+}

 /* Return a hash for list LIST.  DEPTH is the current depth in the
    list.  We don't recurse deeper than SXHASH_MAX_DEPTH in it.  */

-static unsigned
+static EMACS_UINT
 sxhash_list (Lisp_Object list, int depth)
 {
-  unsigned hash = 0;
+  EMACS_UINT hash = 0;
   int i;

   if (depth < SXHASH_MAX_DEPTH)
@@ -4111,63 +4143,62 @@
 	 CONSP (list) && i < SXHASH_MAX_LEN;
 	 list = XCDR (list), ++i)
       {
-	unsigned hash2 = sxhash (XCAR (list), depth + 1);
+	EMACS_UINT hash2 = sxhash (XCAR (list), depth + 1);
 	hash = SXHASH_COMBINE (hash, hash2);
       }

   if (!NILP (list))
     {
-      unsigned hash2 = sxhash (list, depth + 1);
+      EMACS_UINT hash2 = sxhash (list, depth + 1);
       hash = SXHASH_COMBINE (hash, hash2);
     }

-  return hash;
+  return SXHASH_REDUCE (hash);
 }


 /* Return a hash for vector VECTOR.  DEPTH is the current depth in
    the Lisp structure.  */

-static unsigned
+static EMACS_UINT
 sxhash_vector (Lisp_Object vec, int depth)
 {
-  unsigned hash = ASIZE (vec);
+  EMACS_UINT hash = ASIZE (vec);
   int i, n;

   n = min (SXHASH_MAX_LEN, ASIZE (vec));
   for (i = 0; i < n; ++i)
     {
-      unsigned hash2 = sxhash (AREF (vec, i), depth + 1);
+      EMACS_UINT hash2 = sxhash (AREF (vec, i), depth + 1);
       hash = SXHASH_COMBINE (hash, hash2);
     }

-  return hash;
+  return SXHASH_REDUCE (hash);
 }

-
 /* Return a hash for bool-vector VECTOR.  */

-static unsigned
+static EMACS_UINT
 sxhash_bool_vector (Lisp_Object vec)
 {
-  unsigned hash = XBOOL_VECTOR (vec)->size;
+  EMACS_UINT hash = XBOOL_VECTOR (vec)->size;
   int i, n;

   n = min (SXHASH_MAX_LEN, XBOOL_VECTOR (vec)->header.size);
   for (i = 0; i < n; ++i)
     hash = SXHASH_COMBINE (hash, XBOOL_VECTOR (vec)->data[i]);

-  return hash;
+  return SXHASH_REDUCE (hash);
 }


 /* Return a hash code for OBJ.  DEPTH is the current depth in the Lisp
    structure.  Value is an unsigned integer clipped to INTMASK.  */

-unsigned
+EMACS_UINT
 sxhash (Lisp_Object obj, int depth)
 {
-  unsigned hash;
+  EMACS_UINT hash;

   if (depth > SXHASH_MAX_DEPTH)
     return 0;
@@ -4211,20 +4242,14 @@
       break;

     case Lisp_Float:
-      {
-	double val = XFLOAT_DATA (obj);
-	unsigned char *p = (unsigned char *) &val;
-	size_t i;
-	for (hash = 0, i = 0; i < sizeof val; i++)
-	  hash = SXHASH_COMBINE (hash, p[i]);
-	break;
-      }
+      hash = sxhash_float (XFLOAT_DATA (obj));
+      break;

     default:
       abort ();
     }

-  return hash & INTMASK;
+  return hash;
 }


@@ -4238,7 +4263,7 @@
        doc: /* Compute a hash code for OBJ and return it as integer.  */)
   (Lisp_Object obj)
 {
-  unsigned hash = sxhash (obj, 0);
+  EMACS_UINT hash = sxhash (obj, 0);
   return make_number (hash);
 }

@@ -4315,17 +4340,16 @@
   /* Look for `:rehash-size SIZE'.  */
   i = get_key_arg (QCrehash_size, nargs, args, used);
   rehash_size = i ? args[i] : make_float (DEFAULT_REHASH_SIZE);
-  if (!NUMBERP (rehash_size)
-      || (INTEGERP (rehash_size) && XINT (rehash_size) <= 0)
-      || XFLOATINT (rehash_size) <= 1.0)
+  if (! ((INTEGERP (rehash_size) && 0 < XINT (rehash_size))
+	 || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size))))
     signal_error ("Invalid hash table rehash size", rehash_size);

   /* Look for `:rehash-threshold THRESHOLD'.  */
   i = get_key_arg (QCrehash_threshold, nargs, args, used);
   rehash_threshold = i ? args[i] : make_float (DEFAULT_REHASH_THRESHOLD);
-  if (!FLOATP (rehash_threshold)
-      || XFLOATINT (rehash_threshold) <= 0.0
-      || XFLOATINT (rehash_threshold) > 1.0)
+  if (! (FLOATP (rehash_threshold)
+	 && 0 < XFLOAT_DATA (rehash_threshold)
+	 && XFLOAT_DATA (rehash_threshold) <= 1))
     signal_error ("Invalid hash table rehash threshold", rehash_threshold);

   /* Look for `:weakness WEAK'.  */
@@ -4437,7 +4461,7 @@
   (Lisp_Object key, Lisp_Object table, Lisp_Object dflt)
 {
   struct Lisp_Hash_Table *h = check_hash_table (table);
-  int i = hash_lookup (h, key, NULL);
+  EMACS_INT i = hash_lookup (h, key, NULL);
   return i >= 0 ? HASH_VALUE (h, i) : dflt;
 }

@@ -4449,8 +4473,8 @@
   (Lisp_Object key, Lisp_Object value, Lisp_Object table)
 {
   struct Lisp_Hash_Table *h = check_hash_table (table);
-  int i;
-  unsigned hash;
+  EMACS_INT i;
+  EMACS_UINT hash;

   i = hash_lookup (h, key, &hash);
   if (i >= 0)
@@ -4479,7 +4503,7 @@
 {
   struct Lisp_Hash_Table *h = check_hash_table (table);
   Lisp_Object args[3];
-  int i;
+  EMACS_INT i;

   for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
     if (!NILP (HASH_HASH (h, i)))

=== modified file 'src/image.c'
--- src/image.c	2011-05-30 01:12:12 +0000
+++ src/image.c	2011-05-31 05:52:26 +0000
@@ -982,7 +982,6 @@
 		 Image type independent image structures
  ***********************************************************************/

-static struct image *make_image (Lisp_Object spec, unsigned hash);
 static void free_image (struct frame *f, struct image *img);
 static int check_image_size (struct frame *f, int width, int height);

@@ -991,7 +990,7 @@
    SPEC.  SPEC has a hash value of HASH.  */

 static struct image *
-make_image (Lisp_Object spec, unsigned int hash)
+make_image (Lisp_Object spec, EMACS_UINT hash)
 {
   struct image *img = (struct image *) xmalloc (sizeof *img);
   Lisp_Object file = image_spec_value (spec, QCfile, NULL);
@@ -1388,7 +1387,6 @@
 			     Image Cache
  ***********************************************************************/

-static struct image *search_image_cache (struct frame *, Lisp_Object, unsigned);
 static void cache_image (struct frame *f, struct image *img);
 static void postprocess_image (struct frame *, struct image *);

@@ -1414,7 +1412,7 @@
 /* Find an image matching SPEC in the cache, and return it.  If no
    image is found, return NULL.  */
 static struct image *
-search_image_cache (struct frame *f, Lisp_Object spec, unsigned int hash)
+search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
 {
   struct image *img;
   struct image_cache *c = FRAME_IMAGE_CACHE (f);
@@ -1714,7 +1712,7 @@
 lookup_image (struct frame *f, Lisp_Object spec)
 {
   struct image *img;
-  unsigned hash;
+  EMACS_UINT hash;
   EMACS_TIME now;

   /* F must be a window-system frame, and SPEC must be a valid image
@@ -3751,7 +3749,7 @@
                        Lisp_Object color)
 {
   struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
-  unsigned hash_code;
+  EMACS_UINT hash_code;
   Lisp_Object chars = make_unibyte_string (chars_start, chars_len);

   hash_lookup (table, chars, &hash_code);

=== modified file 'src/lisp.h'
--- src/lisp.h	2011-05-31 05:15:34 +0000
+++ src/lisp.h	2011-05-31 05:52:26 +0000
@@ -525,22 +525,20 @@

 #define EQ(x, y) (XHASH (x) == XHASH (y))

+/* Number of bits in a fixnum, including the sign bit.  */
+#ifdef USE_2_TAGS_FOR_INTS
+# define FIXNUM_BITS (VALBITS + 1)
+#else
+# define FIXNUM_BITS VALBITS
+#endif
+
+/* Mask indicating the significant bits of a fixnum.  */
+#define INTMASK (((EMACS_INT) 1 << FIXNUM_BITS) - 1)
+
 /* Largest and smallest representable fixnum values.  These are the C
    values.  */
-
-#ifdef USE_2_TAGS_FOR_INTS
-# define MOST_NEGATIVE_FIXNUM	- ((EMACS_INT) 1 << VALBITS)
-# define MOST_POSITIVE_FIXNUM	(((EMACS_INT) 1 << VALBITS) - 1)
-/* Mask indicating the significant bits of a Lisp_Int.
-   I.e. (x & INTMASK) == XUINT (make_number (x)).  */
-# define INTMASK ((((EMACS_INT) 1) << (VALBITS + 1)) - 1)
-#else
-# define MOST_NEGATIVE_FIXNUM	- ((EMACS_INT) 1 << (VALBITS - 1))
-# define MOST_POSITIVE_FIXNUM	(((EMACS_INT) 1 << (VALBITS - 1)) - 1)
-/* Mask indicating the significant bits of a Lisp_Int.
-   I.e. (x & INTMASK) == XUINT (make_number (x)).  */
-# define INTMASK ((((EMACS_INT) 1) << VALBITS) - 1)
-#endif
+#define MOST_POSITIVE_FIXNUM (INTMASK / 2)
+#define MOST_NEGATIVE_FIXNUM (-1 - MOST_POSITIVE_FIXNUM)

 /* Value is non-zero if I doesn't fit into a Lisp fixnum.  It is
    written this way so that it also works if I is of unsigned
@@ -1179,7 +1177,7 @@
      a special way (e.g. because of weakness).  */

   /* Number of key/value entries in the table.  */
-  unsigned int count;
+  EMACS_INT count;

   /* Vector of keys and values.  The key of item I is found at index
      2 * I, the value is found at index 2 * I + 1.
@@ -1191,11 +1189,12 @@
   struct Lisp_Hash_Table *next_weak;

   /* C function to compare two keys.  */
-  int (* cmpfn) (struct Lisp_Hash_Table *, Lisp_Object,
-                 unsigned, Lisp_Object, unsigned);
+  int (*cmpfn) (struct Lisp_Hash_Table *,
+		Lisp_Object, EMACS_UINT,
+		Lisp_Object, EMACS_UINT);

   /* C function to compute hash code.  */
-  unsigned (* hashfn) (struct Lisp_Hash_Table *, Lisp_Object);
+  EMACS_UINT (*hashfn) (struct Lisp_Hash_Table *, Lisp_Object);
 };


@@ -2093,7 +2092,7 @@
 
 /* Number of bytes of structure consed since last GC.  */

-extern int consing_since_gc;
+extern EMACS_INT consing_since_gc;

 extern EMACS_INT gc_relative_threshold;

@@ -2468,19 +2467,19 @@

 /* Defined in fns.c */
 extern Lisp_Object QCrehash_size, QCrehash_threshold;
-extern int next_almost_prime (int);
-extern Lisp_Object larger_vector (Lisp_Object, int, Lisp_Object);
+extern EMACS_INT next_almost_prime (EMACS_INT);
+extern Lisp_Object larger_vector (Lisp_Object, EMACS_INT, Lisp_Object);
 extern void sweep_weak_hash_tables (void);
 extern Lisp_Object Qcursor_in_echo_area;
 extern Lisp_Object Qstring_lessp;
 extern Lisp_Object QCsize, QCtest, QCweakness, Qequal, Qeq, Qeql;
-unsigned sxhash (Lisp_Object, int);
+EMACS_UINT sxhash (Lisp_Object, int);
 Lisp_Object make_hash_table (Lisp_Object, Lisp_Object, Lisp_Object,
                              Lisp_Object, Lisp_Object, Lisp_Object,
                              Lisp_Object);
-int hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, unsigned *);
-int hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
-              unsigned);
+EMACS_INT hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *);
+EMACS_INT hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
+		    EMACS_UINT);
 void init_weak_hash_tables (void);
 extern void init_fns (void);
 EXFUN (Fmake_hash_table, MANY);

=== modified file 'src/minibuf.c'
--- src/minibuf.c	2011-05-31 03:03:38 +0000
+++ src/minibuf.c	2011-05-31 05:52:26 +0000
@@ -1209,7 +1209,7 @@
 		    && (!SYMBOLP (XCAR (collection))
 			|| NILP (XCAR (collection)))))
 	       ? list_table : function_table));
-  int idx = 0, obsize = 0;
+  EMACS_INT idx = 0, obsize = 0;
   int matchcount = 0;
   int bindcount = -1;
   Lisp_Object bucket, zero, end, tem;
@@ -1474,7 +1474,7 @@
     : NILP (collection) || (CONSP (collection)
 			    && (!SYMBOLP (XCAR (collection))
 				|| NILP (XCAR (collection))));
-  int idx = 0, obsize = 0;
+  EMACS_INT idx = 0, obsize = 0;
   int bindcount = -1;
   Lisp_Object bucket, tem, zero;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -1770,7 +1770,7 @@
   (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate)
 {
   Lisp_Object regexps, tail, tem = Qnil;
-  int i = 0;
+  EMACS_INT i = 0;

   CHECK_STRING (string);


=== modified file 'src/print.c'
--- src/print.c	2011-05-21 04:33:23 +0000
+++ src/print.c	2011-05-31 05:52:26 +0000
@@ -1082,7 +1082,7 @@
 	     Maybe a better way to do that is to copy elements to
 	     a new hash table.  */
 	  struct Lisp_Hash_Table *h = XHASH_TABLE (Vprint_number_table);
-	  int i;
+	  EMACS_INT i;

 	  for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
 	    if (!NILP (HASH_HASH (h, i))





Information forwarded to owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org:
bug#8771; Package emacs. (Tue, 31 May 2011 13:04:02 GMT) Full text and rfc822 format available.

Message #8 received at 8771 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 8771 <at> debbugs.gnu.org
Subject: Re: bug#8771: Remove arbitrary 32-bit limit in Emacs hash tables
Date: Tue, 31 May 2011 10:03:28 -0300
> Currently the Emacs source code uses 'unsigned' for hashes and 'int'
> for hash tables, but on 64-bit hosts hash tables can in principle be
> larger than what can be shoehorned into 32 bits.  Here's a proposed patch;
> most of it is pretty straightforward.

Sounds fine to me.  Style suggestions (really, nothing more than
suggestions) below.


        Stefan


> Remove arbitrary limit of 2**31 entries in hash tables.
> * category.c (hash_get_category_set): Use 'EMACS_UINT' and 'EMACS_INT'
> for hashes and hash indexes, instead of 'unsigned' and 'int'.
> * ccl.c (ccl_driver): Likewise.
> * charset.c (Fdefine_charset_internal): Likewise.
> * charset.h (struct charset.hash_index): Likewise.
> * composite.c (get_composition_id, gstring_lookup_cache):
> (composition_gstring_put_cache): Likewise.

Rather than "Likewise" you can use the following format:

   Remove arbitrary limit of 2**31 entries in hash tables.
   * category.c (hash_get_category_set):
   * ccl.c (ccl_driver):
   * charset.c (Fdefine_charset_internal):
   * charset.h (struct charset.hash_index):
   * composite.c (get_composition_id, gstring_lookup_cache):
   (composition_gstring_put_cache): Use 'EMACS_UINT' and 'EMACS_INT'
   for hashes and hash indexes, instead of 'unsigned' and 'int'.

And rather than
   
   * composite.c (get_composition_id, gstring_lookup_cache):
   (composition_gstring_put_cache): Foobar.

we usually write:
   
   * composite.c (get_composition_id, gstring_lookup_cache)
   (composition_gstring_put_cache): Foobar.





Information forwarded to owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org:
bug#8771; Package emacs. (Tue, 31 May 2011 14:51:02 GMT) Full text and rfc822 format available.

Message #11 received at 8771 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: bug-vc-dwim <at> gnu.org
Cc: 8771 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: vc-dwim problem parsing ChangeLog entries (was: Emacs bug#8771)
Date: Tue, 31 May 2011 07:50:12 -0700
On 05/31/11 06:03, Stefan Monnier wrote:
> And rather than
>    
>    * composite.c (get_composition_id, gstring_lookup_cache):
>    (composition_gstring_put_cache): Foobar.
> 
> we usually write:
>    
>    * composite.c (get_composition_id, gstring_lookup_cache)
>    (composition_gstring_put_cache): Foobar.

OK, I'll adjust that ChangeLog entry by hand.  I had appended
the extra colon to the first line because otherwise vc-dwim doesn't
parse the ChangeLog properly.

This appears to be a bug in vc-dwim so I'll send this email
to bug-vc-dwim <at> gnu.org (the original thread is at
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8771#8>).  For example,
with vc-dwim 1.5 and the following ChangeLog:

2011-05-31  Paul Eggert  <eggert <at> cs.ucla.edu>

        Remove arbitrary limit of 2**31 entries in hash tables.  (Bug#8771)
	* composite.c (get_composition_id, gstring_lookup_cache)
        (composition_gstring_put_cache):
        * composite.h (struct composition.hash_index):
        Use 'EMACS_UINT' and 'EMACS_INT'
        for hashes and hash indexes, instead of 'unsigned' and 'int'.

vc-dwim generates the following diagnostic:

vc-dwim:ChangeLog: line of unexpected form:
* composite.c (get_composition_id, gstring_lookup_cache) at /home/eggert/opt/Linux-x86_64/merged/bin/vc-dwim line 991.

This diagnostic means vc-dwim isn't understanding the newish ChangeLog
format in the GNU coding standards
<http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html>.
Also, that "line 991" is confusing, since it's not the line number in
the ChangeLog file.




Information forwarded to owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org:
bug#8771; Package emacs. (Tue, 31 May 2011 21:44:02 GMT) Full text and rfc822 format available.

Message #14 received at 8771 <at> debbugs.gnu.org (full text, mbox):

From: Jim Meyering <jim <at> meyering.net>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: bug-vc-dwim <at> gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>,
	8771 <at> debbugs.gnu.org
Subject: Re: [Bug-vc-dwim] vc-dwim problem parsing ChangeLog entries
Date: Tue, 31 May 2011 23:43:35 +0200
Paul Eggert wrote:
> On 05/31/11 06:03, Stefan Monnier wrote:
>> And rather than
>>
>>    * composite.c (get_composition_id, gstring_lookup_cache):
>>    (composition_gstring_put_cache): Foobar.
>>
>> we usually write:
>>
>>    * composite.c (get_composition_id, gstring_lookup_cache)
>>    (composition_gstring_put_cache): Foobar.
>
> OK, I'll adjust that ChangeLog entry by hand.  I had appended
> the extra colon to the first line because otherwise vc-dwim doesn't
> parse the ChangeLog properly.
>
> This appears to be a bug in vc-dwim so I'll send this email
> to bug-vc-dwim <at> gnu.org (the original thread is at
> <http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8771#8>).  For example,
> with vc-dwim 1.5 and the following ChangeLog:
>
> 2011-05-31  Paul Eggert  <eggert <at> cs.ucla.edu>
>
>         Remove arbitrary limit of 2**31 entries in hash tables.  (Bug#8771)
> 	* composite.c (get_composition_id, gstring_lookup_cache)
>         (composition_gstring_put_cache):
>         * composite.h (struct composition.hash_index):
>         Use 'EMACS_UINT' and 'EMACS_INT'
>         for hashes and hash indexes, instead of 'unsigned' and 'int'.
>
> vc-dwim generates the following diagnostic:
>
> vc-dwim:ChangeLog: line of unexpected form:
> * composite.c (get_composition_id, gstring_lookup_cache) at
> /home/eggert/opt/Linux-x86_64/merged/bin/vc-dwim line 991.
>
> This diagnostic means vc-dwim isn't understanding the newish ChangeLog
> format in the GNU coding standards
> <http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html>.
> Also, that "line 991" is confusing, since it's not the line number in
> the ChangeLog file.

Hi Paul,

Thanks for the report.
I've added a test for that and fixed it with these:

From 92d2db3ccfa024f84db6780029a2017cf5184618 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering <at> redhat.com>
Date: Tue, 31 May 2011 23:41:19 +0200
Subject: [PATCH 1/2] vc-dwim: relax file-spec ChangeLog regexp to accommodate
 new GCS-style

* vc-dwim.pl (main): Relax the file-spec matching regexp.  Before,
the regexp was /^\* (\S.*?):/, while now we also allow a line
ending in ")": /^\* (\S.*?)(:|\)$)/
* NEWS (Bug fixes): Mention it.
---
 NEWS       |    3 +++
 vc-dwim.pl |    2 +-
 2 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/NEWS b/NEWS
index 21b39f2..571b4be 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ vc-dwim NEWS                                          -*- outline -*-

 ** Bug fixes

+  vc-dwim no longer fails when it encounters a ChangeLog line like
+  "* file (...)" (i.e., with no colon) when that line ends with a ")".
+
   "vc-dwim a/ChangeLog b/ChangeLog" would mistakenly complain about
   an "--author/ChangeLog mismatch" even though the two name/email
   pairs in the ChangeLog files were identical.
diff --git a/vc-dwim.pl b/vc-dwim.pl
index e474efc..76b3ae0 100755
--- a/vc-dwim.pl
+++ b/vc-dwim.pl
@@ -989,7 +989,7 @@ sub main

           if ($line =~ /^\*/)
             {
-              $line =~ /^\* (\S.*?):/
+              $line =~ /^\* (\S.*?)(:|\)$)/
                 or die "$ME:$log: line of unexpected form:\n$line";
               my $f_spec = $1;
               foreach my $file (change_log_line_extract_file_list ($f_spec))
--
1.7.5.2.660.g9f46c


From d2083c184da222885e6fd96cbe204af95c86bd2b Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering <at> redhat.com>
Date: Tue, 31 May 2011 22:39:52 +0200
Subject: [PATCH 2/2] tests: add a test to exercise a ChangeLog syntax bug

* tests/cl-syntax: New script. Test for the bug reported by Paul Eggert
in https://lists.gnu.org/archive/html/bug-vc-dwim/2011-05/msg00006.html
* tests/Makefile.am (TESTS): Add cl-syntax.
---
 tests/Makefile.am |    1 +
 tests/cl-syntax   |   34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 0 deletions(-)
 create mode 100755 tests/cl-syntax

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 307851d..b588c3f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -14,6 +14,7 @@ TESTS = \
   git-mv \
   two-line-attr \
   cl-other-user \
+  cl-syntax \
   no-vc \
   symlinked-changelog \
   scalar \
diff --git a/tests/cl-syntax b/tests/cl-syntax
new file mode 100755
index 0000000..3a29619
--- /dev/null
+++ b/tests/cl-syntax
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Ensure that we accept relatively new ChangeLog syntax.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ..
+print_ver_ vc-dwim
+
+require_git_
+
+cat <<EOF > ChangeLog || framework_failure_
+2011-05-31  R. Andom  <random <at> example.com>
+
+	* not-checked.c: Irrelevant.
+
+EOF
+git init > /dev/null || framework_failure_
+touch foo || framework_failure_
+git add . || framework_failure_
+git commit -m m . > /dev/null || framework_failure_
+
+cat <<EOF > ChangeLog
+2011-05-31  R. Andom  <random <at> example.com>
+
+	* foo (bar)
+        (qux): Comment.
+	* not-checked.c: Irrelevant.
+
+EOF
+
+fail=0
+
+echo a > foo || framework_failure_
+vc-dwim ChangeLog || fail=1
+
+Exit $fail
--
1.7.5.2.660.g9f46c




Reply sent to Paul Eggert <eggert <at> cs.ucla.edu>:
You have taken responsibility. (Thu, 02 Jun 2011 08:06:01 GMT) Full text and rfc822 format available.

Notification sent to Paul Eggert <eggert <at> cs.ucla.edu>:
bug acknowledged by developer. (Thu, 02 Jun 2011 08:06:02 GMT) Full text and rfc822 format available.

Message #19 received at 8771-done <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: 8771-done <at> debbugs.gnu.org
Subject: Re: bug#8771: Acknowledgement (Remove arbitrary 32-bit limit in Emacs
	hash tables)
Date: Thu, 02 Jun 2011 01:05:32 -0700
I installed the change into the trunk, as bzr 104476.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Thu, 30 Jun 2011 11:24:04 GMT) Full text and rfc822 format available.

This bug report was last modified 12 years and 314 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.