changeset 37472:b28d8b21597d

obstack: avoid potentially-nonportable function casts * lib/obstack.c (CALL_CHUNKFUN, CALL_FREEFUN): Remove, replacing with ... (call_chunkfun, call_freefun): New static functions. All uses changed. Avoid potentially-nonportable casts. (chunkfun_type, freefun_type): Remove typedefs; no longer used. (_obstack_begin_worker): Omit last two args, since they rely on potentially-nonportable casts. All callers changed. * lib/obstack.h (_OBSTACK_CAST): New macro. Use it everywhere the old API used a potentially-nonportable cast. The new API doesn't cast. (struct obstack): Use unions rather than requiring potentially-nonportable casts. (obstack_chunkfun, obstack_freefun): Return void.
author Paul Eggert <eggert@cs.ucla.edu>
date Tue, 04 Nov 2014 00:31:31 -0800
parents 43a80886ea89
children 213e761e70fc
files ChangeLog lib/obstack.c lib/obstack.h
diffstat 3 files changed, 77 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Nov 03 17:32:27 2014 -0800
+++ b/ChangeLog	Tue Nov 04 00:31:31 2014 -0800
@@ -1,3 +1,20 @@
+2014-11-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+	obstack: avoid potentially-nonportable function casts
+	* lib/obstack.c (CALL_CHUNKFUN, CALL_FREEFUN):
+	Remove, replacing with ...
+	(call_chunkfun, call_freefun): New static functions.
+	All uses changed.  Avoid potentially-nonportable casts.
+	(chunkfun_type, freefun_type): Remove typedefs; no longer used.
+	(_obstack_begin_worker): Omit last two args, since they
+	rely on potentially-nonportable casts.  All callers changed.
+	* lib/obstack.h (_OBSTACK_CAST): New macro.
+	Use it everywhere the old API used a potentially-nonportable cast.
+	The new API doesn't cast.
+	(struct obstack): Use unions rather than requiring
+	potentially-nonportable casts.
+	(obstack_chunkfun, obstack_freefun): Return void.
+
 2014-11-03  Alan Modra  <amodra@gmail.com>
 
 	obstack: fix macro return values
--- a/lib/obstack.c	Mon Nov 03 17:32:27 2014 -0800
+++ b/lib/obstack.c	Tue Nov 04 00:31:31 2014 -0800
@@ -76,41 +76,38 @@
                                MAX (sizeof (uintmax_t),			      \
                                     sizeof (void *)))
 
-/* Define a macro that either calls functions with the traditional malloc/free
-   calling interface, or calls functions with the mmalloc/mfree interface
-   (that adds an extra first argument), based on the state of use_extra_arg.
-   For free, do not use ?:, since some compilers, like the MIPS compilers,
-   do not allow (expr) ? void : void.  */
+/* Call functions with either the traditional malloc/free calling
+   interface, or the mmalloc/mfree interface (that adds an extra first
+   argument), based on the value of use_extra_arg.  */
 
-# define CALL_CHUNKFUN(h, size) \
-  (((h)->use_extra_arg)							      \
-   ? (*(h)->chunkfun)((h)->extra_arg, (size))				      \
-   : (*(struct _obstack_chunk *(*)(size_t))(h)->chunkfun)((size)))
+static void *
+call_chunkfun (struct obstack *h, size_t size)
+{
+  if (h->use_extra_arg)
+    return h->chunkfun.extra (h->extra_arg, size);
+  else
+    return h->chunkfun.plain (size);
+}
 
-# define CALL_FREEFUN(h, old_chunk) \
-  do { \
-      if ((h)->use_extra_arg)						      \
-        (*(h)->freefun)((h)->extra_arg, (old_chunk));			      \
-      else								      \
-        (*(void (*)(void *))(h)->freefun)((old_chunk));			      \
-    } while (0)
+static void
+call_freefun (struct obstack *h, void *old_chunk)
+{
+  if (h->use_extra_arg)
+    h->freefun.extra (h->extra_arg, old_chunk);
+  else
+    h->freefun.plain (old_chunk);
+}
 
 
 /* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
    Objects start on multiples of ALIGNMENT (0 means use default).
-   CHUNKFUN is the function to use to allocate chunks,
-   and FREEFUN the function to free them.
 
    Return nonzero if successful, calls obstack_alloc_failed_handler if
    allocation fails.  */
 
-typedef struct _obstack_chunk * (*chunkfun_type) (void *, size_t);
-typedef void (*freefun_type) (void *, struct _obstack_chunk *);
-
 static int
 _obstack_begin_worker (struct obstack *h,
-                       _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
-                       chunkfun_type chunkfun, freefun_type freefun)
+                       _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment)
 {
   struct _obstack_chunk *chunk; /* points to new chunk */
 
@@ -133,12 +130,10 @@
       size = 4096 - extra;
     }
 
-  h->chunkfun = chunkfun;
-  h->freefun = freefun;
   h->chunk_size = size;
   h->alignment_mask = alignment - 1;
 
-  chunk = h->chunk = CALL_CHUNKFUN (h, h->chunk_size);
+  chunk = h->chunk = call_chunkfun (h, h->chunk_size);
   if (!chunk)
     (*obstack_alloc_failed_handler) ();
   h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
@@ -157,10 +152,10 @@
                 void *(*chunkfun) (size_t),
                 void (*freefun) (void *))
 {
+  h->chunkfun.plain = chunkfun;
+  h->freefun.plain = freefun;
   h->use_extra_arg = 0;
-  return _obstack_begin_worker (h, size, alignment,
-                                (chunkfun_type) chunkfun,
-                                (freefun_type) freefun);
+  return _obstack_begin_worker (h, size, alignment);
 }
 
 int
@@ -170,11 +165,11 @@
                   void (*freefun) (void *, void *),
                   void *arg)
 {
+  h->chunkfun.extra = chunkfun;
+  h->freefun.extra = freefun;
   h->extra_arg = arg;
   h->use_extra_arg = 1;
-  return _obstack_begin_worker (h, size, alignment,
-                                (chunkfun_type) chunkfun,
-                                (freefun_type) freefun);
+  return _obstack_begin_worker (h, size, alignment);
 }
 
 /* Allocate a new current chunk for the obstack *H
@@ -202,7 +197,7 @@
 
   /* Allocate and initialize the new chunk.  */
   if (obj_size <= sum1 && sum1 <= sum2)
-    new_chunk = CALL_CHUNKFUN (h, new_size);
+    new_chunk = call_chunkfun (h, new_size);
   if (!new_chunk)
     (*obstack_alloc_failed_handler)();
   h->chunk = new_chunk;
@@ -225,7 +220,7 @@
                           h->alignment_mask)))
     {
       new_chunk->prev = old_chunk->prev;
-      CALL_FREEFUN (h, old_chunk);
+      call_freefun (h, old_chunk);
     }
 
   h->object_base = object_base;
@@ -276,7 +271,7 @@
   while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
     {
       plp = lp->prev;
-      CALL_FREEFUN (h, lp);
+      call_freefun (h, lp);
       lp = plp;
       /* If we switch chunks, we can't tell whether the new current
          chunk contains an empty object, so assume that it may.  */
--- a/lib/obstack.h	Mon Nov 03 17:32:27 2014 -0800
+++ b/lib/obstack.h	Tue Nov 04 00:31:31 2014 -0800
@@ -116,10 +116,12 @@
    and "long" for these two types.  */
 # define _OBSTACK_SIZE_T unsigned int
 # define _CHUNK_SIZE_T unsigned long
+# define _OBSTACK_CAST(type, expr) ((type) (expr))
 #else
 /* Version 2 with sane types, especially for 64-bit hosts.  */
 # define _OBSTACK_SIZE_T size_t
 # define _CHUNK_SIZE_T size_t
+# define _OBSTACK_CAST(type, expr) (expr)
 #endif
 
 /* If B is the base of an object addressed by P, return the result of
@@ -167,11 +169,19 @@
     void *p;
   } temp;                       /* Temporary for some macros.  */
   _OBSTACK_SIZE_T alignment_mask;  /* Mask of alignment for each object. */
-  /* These prototypes vary based on 'use_extra_arg', and we use
-     casts to the prototypeless function type in all assignments,
-     but having prototypes here quiets -Wstrict-prototypes.  */
-  struct _obstack_chunk *(*chunkfun) (void *, size_t);
-  void (*freefun) (void *, struct _obstack_chunk *);
+
+  /* These prototypes vary based on 'use_extra_arg'.  */
+  union
+  {
+    void *(*plain) (size_t);
+    void *(*extra) (void *, size_t);
+  } chunkfun;
+  union
+  {
+    void (*plain) (void *);
+    void (*extra) (void *, void *);
+  } freefun;
+
   void *extra_arg;              /* first arg for chunk alloc/dealloc funcs */
   unsigned use_extra_arg : 1;     /* chunk alloc/dealloc funcs take extra arg */
   unsigned maybe_empty_object : 1; /* There is a possibility that the current
@@ -189,11 +199,11 @@
 extern void _obstack_free (struct obstack *, void *);
 extern int _obstack_begin (struct obstack *,
                            _OBSTACK_SIZE_T, _OBSTACK_SIZE_T,
-                           void *(*)(size_t), void (*)(void *));
+                           void *(*) (size_t), void (*) (void *));
 extern int _obstack_begin_1 (struct obstack *,
                              _OBSTACK_SIZE_T, _OBSTACK_SIZE_T,
-                             void *(*)(void *, size_t),
-                             void (*)(void *, void *), void *);
+                             void *(*) (void *, size_t),
+                             void (*) (void *, void *), void *);
 extern _OBSTACK_SIZE_T _obstack_memory_used (struct obstack *)
   __attribute_pure__;
 
@@ -228,29 +238,31 @@
 /* To prevent prototype warnings provide complete argument list.  */
 #define obstack_init(h)							      \
   _obstack_begin ((h), 0, 0,						      \
-                  (void *(*)(size_t))obstack_chunk_alloc,		      \
-                  (void (*)(void *))obstack_chunk_free)
+                  _OBSTACK_CAST (void *(*) (size_t), obstack_chunk_alloc),    \
+                  _OBSTACK_CAST (void (*) (void *), obstack_chunk_free))
 
 #define obstack_begin(h, size)						      \
   _obstack_begin ((h), (size), 0,					      \
-                  (void *(*)(size_t))obstack_chunk_alloc,		      \
-                  (void (*)(void *))obstack_chunk_free)
+                  _OBSTACK_CAST (void *(*) (size_t), obstack_chunk_alloc), \
+                  _OBSTACK_CAST (void (*) (void *), obstack_chunk_free))
 
 #define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)     \
   _obstack_begin ((h), (size), (alignment),				      \
-                  (void *(*)(size_t))(chunkfun),			      \
-                  (void (*)(void *))(freefun))
+                  _OBSTACK_CAST (void *(*) (size_t), chunkfun),		      \
+                  _OBSTACK_CAST (void (*) (void *), freefun))
 
 #define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
   _obstack_begin_1 ((h), (size), (alignment),				      \
-                    (void *(*)(void *, size_t))(chunkfun),		      \
-                    (void (*)(void *, void *))(freefun), (arg))
+                    _OBSTACK_CAST (void *(*) (void *, size_t), chunkfun),     \
+                    _OBSTACK_CAST (void (*) (void *, void *), freefun), arg)
 
 #define obstack_chunkfun(h, newchunkfun)				      \
-  ((h)->chunkfun = (struct _obstack_chunk *(*)(void *, size_t))(newchunkfun))
+  ((void) ((h)->chunkfun.extra = _OBSTACK_CAST (void *(*) (void *, size_t),   \
+                                                newchunkfun)))
 
 #define obstack_freefun(h, newfreefun)					      \
-  ((h)->freefun = (void (*)(void *, struct _obstack_chunk *))(newfreefun))
+  ((void) ((h)->freefun.extra = _OBSTACK_CAST (void (*) (void *, void *),     \
+                                               newfreefun)))
 
 #define obstack_1grow_fast(h, achar) ((void) (*((h)->next_free)++ = (achar)))