From ecfbf8c8668da0021015796361272e402efe01e4 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 4 Nov 2014 00:31:31 -0800 Subject: [PATCH 4/4] 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. --- ChangeLog | 17 +++++++++++++++ lib/obstack.c | 69 +++++++++++++++++++++++++++-------------------------------- lib/obstack.h | 48 +++++++++++++++++++++++++---------------- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index ac78e88..3b3af67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2014-11-04 Paul Eggert + + 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 obstack: fix macro return values diff --git a/lib/obstack.c b/lib/obstack.c index d763c57..90555ed 100644 --- a/lib/obstack.c +++ b/lib/obstack.c @@ -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. */ - -# define CALL_CHUNKFUN(h, size) \ - (((h)->use_extra_arg) \ - ? (*(h)->chunkfun)((h)->extra_arg, (size)) \ - : (*(struct _obstack_chunk *(*)(size_t))(h)->chunkfun)((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) +/* 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. */ + +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); +} + +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 @@ _obstack_begin_worker (struct obstack *h, 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 @@ _obstack_begin (struct obstack *h, 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 @@ _obstack_begin_1 (struct obstack *h, 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 @@ _obstack_newchunk (struct obstack *h, _OBSTACK_SIZE_T length) /* 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 @@ _obstack_newchunk (struct obstack *h, _OBSTACK_SIZE_T length) 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 @@ _obstack_free (struct obstack *h, void *obj) 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. */ diff --git a/lib/obstack.h b/lib/obstack.h index 61b824b..7b6dee8 100644 --- a/lib/obstack.h +++ b/lib/obstack.h @@ -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 @@ struct obstack /* control current object in current chunk */ 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_newchunk (struct obstack *, _OBSTACK_SIZE_T); 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 @@ extern int obstack_exit_failure; /* 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))) -- 1.9.3