From: Rusty Russell Date: Wed, 6 Apr 2011 22:54:41 +0000 (+0930) Subject: typesafe_cb: simplify, preserve namespace. X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=b0fa019adb998c20a8740f5696b61ae87d2a77a6 typesafe_cb: simplify, preserve namespace. Get rid of many variants, which were just confusing for most people. Keep typesafe_cb(), typesafe_cb_preargs() and typesafe_cb_postarts(), and rework cast_if_type() into typesafe_cb_cast() so we stay in our namespace. I should have done this as soon as I discovered the limitation that the types have to be defined if I want const-taking callbacks. --- diff --git a/ccan/antithread/antithread.h b/ccan/antithread/antithread.h index 0e3a011e..77f722c3 100644 --- a/ccan/antithread/antithread.h +++ b/ccan/antithread/antithread.h @@ -16,7 +16,7 @@ const void *at_pool_ctx(struct at_pool *atp); /* Creating an antithread via fork(). Returned athread is child of pool. */ #define at_run(pool, fn, arg) \ _at_run(pool, \ - typesafe_cb_preargs(void *, (fn), (arg), struct at_pool *), \ + typesafe_cb_preargs(void *, void *, (fn), (arg), struct at_pool *), \ (arg)) /* Fork and execvp, with added arguments for child to grab. diff --git a/ccan/asearch/asearch.h b/ccan/asearch/asearch.h index 84625d98..d252284e 100644 --- a/ccan/asearch/asearch.h +++ b/ccan/asearch/asearch.h @@ -23,10 +23,11 @@ #if HAVE_TYPEOF #define asearch(key, base, num, cmp) \ ((__typeof__(*(base))*)(bsearch((key), (base), (num), sizeof(*(base)), \ - cast_if_type(int (*)(const void *, const void *), \ - (cmp), &*(cmp), \ - int (*)(const __typeof__(*(key)) *, \ - const __typeof__(*(base)) *))))) + typesafe_cb_cast(int (*)(const void *, const void *), \ + int (*)(const __typeof__(*(key)) *, \ + const __typeof__(*(base)) *), \ + (cmp))))) + #else #define asearch(key, base, num, cmp) \ (bsearch((key), (base), (num), sizeof(*(base)), \ diff --git a/ccan/asort/asort.h b/ccan/asort/asort.h index 5024a057..b7178c5b 100644 --- a/ccan/asort/asort.h +++ b/ccan/asort/asort.h @@ -19,11 +19,12 @@ */ #define asort(base, num, cmp, ctx) \ _asort((base), (num), sizeof(*(base)), \ - cast_if_type(int (*)(const void *, const void *, void *), \ - (cmp), &*(cmp), \ - int (*)(const __typeof__(*(base)) *, \ - const __typeof__(*(base)) *, \ - __typeof__(ctx))), (ctx)) + typesafe_cb_cast(int (*)(const void *, const void *, void *), \ + int (*)(const __typeof__(*(base)) *, \ + const __typeof__(*(base)) *, \ + __typeof__(ctx)), \ + (cmp)), \ + (ctx)) #if HAVE_QSORT_R_PRIVATE_LAST #define _asort(b, n, s, cmp, ctx) qsort_r(b, n, s, cmp, ctx) diff --git a/ccan/opt/opt.h b/ccan/opt/opt.h index 9075ceed..e06cd442 100644 --- a/ccan/opt/opt.h +++ b/ccan/opt/opt.h @@ -315,22 +315,22 @@ struct opt_table { /* Resolves to the four parameters for non-arg callbacks. */ #define OPT_CB_NOARG(cb, arg) \ OPT_NOARG, \ - cast_if_any(char *(*)(void *), (cb), 0?(cb):(cb),\ - char *(*)(typeof(*(arg))*), \ - char *(*)(const typeof(*(arg))*), \ - char *(*)(const void *)), \ + typesafe_cb_cast3(char *(*)(void *), \ + char *(*)(typeof(*(arg))*), \ + char *(*)(const typeof(*(arg))*), \ + char *(*)(const void *), (cb)), \ NULL, NULL /* Resolves to the four parameters for arg callbacks. */ #define OPT_CB_ARG(cb, show, arg) \ OPT_HASARG, NULL, \ - cast_if_any(char *(*)(const char *,void *), (cb), 0?(cb):(cb), \ - char *(*)(const char *, typeof(*(arg))*), \ - char *(*)(const char *, const typeof(*(arg))*), \ - char *(*)(const char *, const void *)), \ - cast_if_type(void (*)(char buf[], const void *), (show), \ - 0?(show):(show), \ - void (*)(char buf[], const typeof(*(arg))*)) + typesafe_cb_cast3(char *(*)(const char *,void *), \ + char *(*)(const char *, typeof(*(arg))*), \ + char *(*)(const char *, const typeof(*(arg))*), \ + char *(*)(const char *, const void *), \ + (cb)), \ + typesafe_cb_cast(void (*)(char buf[], const void *), \ + void (*)(char buf[], const typeof(*(arg))*), (show)) /* Non-typesafe register function. */ void _opt_register(const char *names, enum opt_type type, diff --git a/ccan/sparse_bsearch/_info b/ccan/sparse_bsearch/_info index 4e358235..13d24197 100644 --- a/ccan/sparse_bsearch/_info +++ b/ccan/sparse_bsearch/_info @@ -15,7 +15,7 @@ * Example: * #include * - * static bool val_valid(unsigned int *val) + * static bool val_valid(const unsigned int *val) * { * return *val != 0; * } diff --git a/ccan/sparse_bsearch/sparse_bsearch.h b/ccan/sparse_bsearch/sparse_bsearch.h index 731f9a4f..5a0a7348 100644 --- a/ccan/sparse_bsearch/sparse_bsearch.h +++ b/ccan/sparse_bsearch/sparse_bsearch.h @@ -14,9 +14,10 @@ * @validfn: whether this element is valid. * * Binary search of a sorted array, which may have some invalid entries. + * Note that cmpfn and validfn take const pointers. * * Example: - * static bool val_valid(unsigned int *val) + * static bool val_valid(const unsigned int *val) * { * return *val != 0; * } @@ -40,8 +41,13 @@ #define sparse_bsearch(key, base, nmemb, cmpfn, validfn) \ _sparse_bsearch((key)+check_types_match((key), &(base)[0]), \ (base), (nmemb), sizeof((base)[0]), \ - typesafe_cb_cmp(int, (cmpfn), (base)), \ - typesafe_cb_const(bool, (validfn), (base))) + typesafe_cb_cast(int (*)(const void *, const void *), \ + int (*)(const __typeof__(*(base)) *, \ + const __typeof__(*(base)) *), \ + (cmpfn)), \ + typesafe_cb_cast(bool (*)(const void *), \ + bool (*)(const __typeof__(*(base)) *), \ + (validfn))) void *_sparse_bsearch(const void *key, const void *base, size_t nmemb, size_t size, diff --git a/ccan/talloc/talloc.h b/ccan/talloc/talloc.h index b1b5e9ac..0ca338b7 100644 --- a/ccan/talloc/talloc.h +++ b/ccan/talloc/talloc.h @@ -210,7 +210,7 @@ int talloc_free(const void *ptr); * talloc, talloc_free */ #define talloc_set_destructor(ptr, function) \ - _talloc_set_destructor((ptr), typesafe_cb_def(int, (function), (ptr))) + _talloc_set_destructor((ptr), typesafe_cb(int, void *, (function), (ptr))) /** * talloc_zero - allocate zeroed dynamic memory for a type diff --git a/ccan/tdb2/tdb2.h b/ccan/tdb2/tdb2.h index 84228bdc..ffbc7760 100644 --- a/ccan/tdb2/tdb2.h +++ b/ccan/tdb2/tdb2.h @@ -311,7 +311,7 @@ enum TDB_ERROR tdb_transaction_prepare_commit(struct tdb_context *tdb); * a negative enum TDB_ERROR value. */ #define tdb_traverse(tdb, fn, p) \ - tdb_traverse_(tdb, typesafe_cb_preargs(int, (fn), (p), \ + tdb_traverse_(tdb, typesafe_cb_preargs(int, void *, (fn), (p), \ struct tdb_context *, \ TDB_DATA, TDB_DATA), (p)) @@ -334,7 +334,8 @@ int64_t tdb_traverse_(struct tdb_context *tdb, */ #define tdb_parse_record(tdb, key, parse, p) \ tdb_parse_record_((tdb), (key), \ - typesafe_cb_preargs(enum TDB_ERROR, (parse), (p), \ + typesafe_cb_preargs(enum TDB_ERROR, void *, \ + (parse), (p), \ TDB_DATA, TDB_DATA), (p)) enum TDB_ERROR tdb_parse_record_(struct tdb_context *tdb, @@ -472,7 +473,7 @@ enum TDB_ERROR tdb_wipe_all(struct tdb_context *tdb); * Returns TDB_SUCCESS or an error. */ #define tdb_check(tdb, check, private_data) \ - tdb_check_((tdb), typesafe_cb_preargs(enum TDB_ERROR, \ + tdb_check_((tdb), typesafe_cb_preargs(enum TDB_ERROR, void *, \ (check), (private_data), \ struct tdb_data, \ struct tdb_data), \ diff --git a/ccan/typesafe_cb/_info b/ccan/typesafe_cb/_info index 7417febe..2fe4fec0 100644 --- a/ccan/typesafe_cb/_info +++ b/ccan/typesafe_cb/_info @@ -5,7 +5,7 @@ /** * typesafe_cb - macros for safe callbacks. * - * The basis of the typesafe_cb header is cast_if_type(): a + * The basis of the typesafe_cb header is typesafe_cb_cast(): a * conditional cast macro. If an expression exactly matches a given * type, it is cast to the target type, otherwise it is left alone. * @@ -35,15 +35,16 @@ * the exactly correct function type to match the argument, or a * function which takes a void *. * - * This is where typesafe_cb() comes in: it uses cast_if_type() to + * This is where typesafe_cb() comes in: it uses typesafe_cb_cast() to * cast the callback function if it matches the argument type: * * void _register_callback(void (*cb)(void *arg), void *arg); * #define register_callback(cb, arg) \ - * _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) + * _register_callback(typesafe_cb(void, void *, (cb), (arg)), \ + * (arg)) * * On compilers which don't support the extensions required - * cast_if_type() and friend become an unconditional cast, so your + * typesafe_cb_cast() and friend become an unconditional cast, so your * code will compile but you won't get type checking. * * Example: @@ -72,7 +73,8 @@ * } * #define register_callback(value, cb, arg) \ * _register_callback(value, \ - * typesafe_cb_preargs(int, (cb), (arg), int),\ + * typesafe_cb_preargs(int, void *, \ + * (cb), (arg), int),\ * (arg)) * * static struct callback *find_callback(int value) diff --git a/ccan/typesafe_cb/test/compile_fail-cast_if_any.c b/ccan/typesafe_cb/test/compile_fail-cast_if_any.c deleted file mode 100644 index dfb51167..00000000 --- a/ccan/typesafe_cb/test/compile_fail-cast_if_any.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -struct foo { - int x; -}; - -struct bar { - int x; -}; - -struct baz { - int x; -}; - -struct any { - int x; -}; - -struct other { - int x; -}; - -static void take_any(struct any *any) -{ -} - -int main(int argc, char *argv[]) -{ -#ifdef FAIL - struct other -#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." -#endif -#else - struct foo -#endif - *arg = NULL; - take_any(cast_if_any(struct any *, arg, arg, - struct foo *, struct bar *, struct baz *)); - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_fail-cast_if_type-promotable.c b/ccan/typesafe_cb/test/compile_fail-cast_if_type-promotable.c index 016d0e2a..11d42f4c 100644 --- a/ccan/typesafe_cb/test/compile_fail-cast_if_type-promotable.c +++ b/ccan/typesafe_cb/test/compile_fail-cast_if_type-promotable.c @@ -6,14 +6,14 @@ static void _set_some_value(void *val) } #define set_some_value(expr) \ - _set_some_value(cast_if_type(void *, (expr), (expr), long)) + _set_some_value(typesafe_cb_cast(void *, long, (expr))) int main(int argc, char *argv[]) { #ifdef FAIL bool x = 0; #if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." #endif #else long x = 0; diff --git a/ccan/typesafe_cb/test/compile_fail-cast_if_type.c b/ccan/typesafe_cb/test/compile_fail-cast_if_type.c deleted file mode 100644 index 61079351..00000000 --- a/ccan/typesafe_cb/test/compile_fail-cast_if_type.c +++ /dev/null @@ -1,25 +0,0 @@ -#include - -void _set_some_value(void *val); - -void _set_some_value(void *val) -{ -} - -#define set_some_value(expr) \ - _set_some_value(cast_if_type(void *, (expr), (expr), unsigned long)) - -int main(int argc, char *argv[]) -{ -#ifdef FAIL - int x = 0; - set_some_value(x); -#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." -#endif -#else - void *p = 0; - set_some_value(p); -#endif - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb.c index bcc6ed63..81e36d7b 100644 --- a/ccan/typesafe_cb/test/compile_fail-typesafe_cb.c +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb.c @@ -6,7 +6,7 @@ static void _register_callback(void (*cb)(void *arg), void *arg) } #define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) + _register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) static void my_callback(char *p) { @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) #ifdef FAIL int *p; #if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." #endif #else char *p; diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast-multi.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast-multi.c new file mode 100644 index 00000000..d7d481cb --- /dev/null +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast-multi.c @@ -0,0 +1,43 @@ +#include +#include + +struct foo { + int x; +}; + +struct bar { + int x; +}; + +struct baz { + int x; +}; + +struct any { + int x; +}; + +struct other { + int x; +}; + +static void take_any(struct any *any) +{ +} + +int main(int argc, char *argv[]) +{ +#ifdef FAIL + struct other +#if !HAVE_TYPEOF || !HAVE_CAST_TO_UNION +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." +#endif +#else + struct foo +#endif + *arg = NULL; + take_any(typesafe_cb_cast3(struct any *, + struct foo *, struct bar *, struct baz *, + arg)); + return 0; +} diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast.c new file mode 100644 index 00000000..07a204f6 --- /dev/null +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_cast.c @@ -0,0 +1,25 @@ +#include + +void _set_some_value(void *val); + +void _set_some_value(void *val) +{ +} + +#define set_some_value(expr) \ + _set_some_value(typesafe_cb_cast(void *, unsigned long, (expr))) + +int main(int argc, char *argv[]) +{ +#ifdef FAIL + int x = 0; + set_some_value(x); +#if !HAVE_TYPEOF||!HAVE_CAST_TO_UNION +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." +#endif +#else + void *p = 0; + set_some_value(p); +#endif + return 0; +} diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c deleted file mode 100644 index 0f61d5de..00000000 --- a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -static void _register_callback(void (*cb)(void *arg), const void *arg) -{ -} - -#define register_callback(cb, arg) \ - _register_callback(typesafe_cb_exact(void, (cb), (arg)), (arg)) - -static void my_callback(const char *p) -{ -} - -int main(int argc, char *argv[]) -{ -#ifdef FAIL - char *p; -#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." -#endif -#else - const char *p; -#endif - p = NULL; - - /* This should work always. */ - register_callback(my_callback, (const char *)"hello world"); - - /* This will fail with FAIL defined */ - register_callback(my_callback, p); - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_postargs.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_postargs.c index 885a3c55..7d353085 100644 --- a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_postargs.c +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_postargs.c @@ -5,7 +5,7 @@ static void _register_callback(void (*cb)(void *arg, int x), void *arg) { } #define register_callback(cb, arg) \ - _register_callback(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) + _register_callback(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) static void my_callback(char *p, int x) { @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) #ifdef FAIL int *p; #if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." #endif #else char *p; diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_preargs.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_preargs.c index c7dc6f1e..bd55c672 100644 --- a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_preargs.c +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_preargs.c @@ -6,7 +6,7 @@ static void _register_callback(void (*cb)(int x, void *arg), void *arg) } #define register_callback(cb, arg) \ - _register_callback(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) + _register_callback(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) static void my_callback(int x, char *p) { @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) #ifdef FAIL int *p; #if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P -#error "Unfortunately we don't fail if cast_if_type is a noop." +#error "Unfortunately we don't fail if typesafe_cb_cast is a noop." #endif #else char *p; diff --git a/ccan/typesafe_cb/test/compile_ok-cast_if_any.c b/ccan/typesafe_cb/test/compile_ok-cast_if_any.c deleted file mode 100644 index e8f3c494..00000000 --- a/ccan/typesafe_cb/test/compile_ok-cast_if_any.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -struct foo { - int x; -}; - -struct bar { - int x; -}; - -struct baz { - int x; -}; - -struct any { - int x; -}; - -static void take_any(struct any *any) -{ -} - -int main(int argc, char *argv[]) -{ -#if HAVE_TYPEOF - /* Otherwise we get unused warnings for these. */ - struct foo *foo = NULL; - struct bar *bar = NULL; - struct baz *baz = NULL; -#endif - struct other *arg = NULL; - - take_any(cast_if_any(struct any *, arg, foo, - struct foo *, struct bar *, struct baz *)); - take_any(cast_if_any(struct any *, arg, bar, - struct foo *, struct bar *, struct baz *)); - take_any(cast_if_any(struct any *, arg, baz, - struct foo *, struct bar *, struct baz *)); - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c index 9346170d..265de8b1 100644 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c @@ -1,21 +1,17 @@ #include #include -/* NULL args for callback function should be OK for _exact and _def. */ +/* NULL args for callback function should be OK for normal and _def. */ static void _register_callback(void (*cb)(const void *arg), const void *arg) { } -#define register_callback_def(cb, arg) \ - _register_callback(typesafe_cb_def(void, (cb), (arg)), (arg)) - -#define register_callback_exact(cb, arg) \ - _register_callback(typesafe_cb_exact(void, (cb), (arg)), (arg)) +#define register_callback(cb, arg) \ + _register_callback(typesafe_cb(void, const void *, (cb), (arg)), (arg)) int main(int argc, char *argv[]) { - register_callback_def(NULL, "hello world"); - register_callback_exact(NULL, "hello world"); + register_callback(NULL, "hello world"); return 0; } diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-const.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-const.c deleted file mode 100644 index 7c2d62ef..00000000 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-const.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -/* const args in callbacks should be OK. */ - -static void _register_callback(void (*cb)(void *arg), void *arg) -{ -} - -#define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) - -#define register_callback_def(cb, arg) \ - _register_callback(typesafe_cb_def(void, (cb), (arg)), (arg)) - -static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) -{ -} - -#define register_callback_pre(cb, arg) \ - _register_callback_pre(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) - -static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) -{ -} - -#define register_callback_post(cb, arg) \ - _register_callback_post(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) - -static void my_callback(const char *p) -{ -} - -static void my_callback_pre(int x, /*const*/ char *p) -{ -} - -static void my_callback_post(/*const*/ char *p, int x) -{ -} - -int main(int argc, char *argv[]) -{ - char p[] = "hello world"; - register_callback(my_callback, p); - register_callback_def(my_callback, p); - register_callback_pre(my_callback_pre, p); - register_callback_post(my_callback_post, p); - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-undefined.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-undefined.c index 62867e7e..aa50bad6 100644 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-undefined.c +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-undefined.c @@ -8,25 +8,25 @@ static void _register_callback(void (*cb)(void *arg), void *arg) } #define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) + _register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) { } #define register_callback_pre(cb, arg) \ - _register_callback_pre(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) + _register_callback_pre(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) { } #define register_callback_post(cb, arg) \ - _register_callback_post(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) + _register_callback_post(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) struct undefined; -static void my_callback(const struct undefined *undef) +static void my_callback(struct undefined *undef) { } diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-vars.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-vars.c index ce0700bc..f6a2bfec 100644 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-vars.c +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-vars.c @@ -8,25 +8,25 @@ static void _register_callback(void (*cb)(void *arg), void *arg) } #define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) + _register_callback(typesafe_cb(void, void *, (cb), (arg)), (arg)) static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) { } #define register_callback_pre(cb, arg) \ - _register_callback_pre(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) + _register_callback_pre(typesafe_cb_preargs(void, void *, (cb), (arg), int), (arg)) static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) { } #define register_callback_post(cb, arg) \ - _register_callback_post(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) + _register_callback_post(typesafe_cb_postargs(void, void *, (cb), (arg), int), (arg)) struct undefined; -static void my_callback(const struct undefined *undef) +static void my_callback(struct undefined *undef) { } @@ -41,7 +41,7 @@ static void my_callback_post(struct undefined *undef, int x) int main(int argc, char *argv[]) { struct undefined *handle = NULL; - void (*cb)(const struct undefined *undef) = my_callback; + void (*cb)(struct undefined *undef) = my_callback; void (*pre)(int x, struct undefined *undef) = my_callback_pre; void (*post)(struct undefined *undef, int x) = my_callback_post; diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-volatile.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-volatile.c deleted file mode 100644 index 3fcb1ff6..00000000 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-volatile.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -/* volatile args in callbacks should be OK. */ - -static void _register_callback(void (*cb)(void *arg), void *arg) -{ -} - -#define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) - -static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) -{ -} - -#define register_callback_pre(cb, arg) \ - _register_callback_pre(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) - -static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) -{ -} - -#define register_callback_post(cb, arg) \ - _register_callback_post(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) - -static void my_callback(volatile char *p) -{ -} - -/* FIXME: Can't handle volatile for these */ -static void my_callback_pre(int x, /* volatile */ char *p) -{ -} - -static void my_callback_post(/* volatile */ char *p, int x) -{ -} - -int main(int argc, char *argv[]) -{ - char p[] = "hello world"; - register_callback(my_callback, p); - register_callback_pre(my_callback_pre, p); - register_callback_post(my_callback_post, p); - return 0; -} diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb_cast.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb_cast.c new file mode 100644 index 00000000..4bb3b8bf --- /dev/null +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb_cast.c @@ -0,0 +1,41 @@ +#include +#include + +struct foo { + int x; +}; + +struct bar { + int x; +}; + +struct baz { + int x; +}; + +struct any { + int x; +}; + +static void take_any(struct any *any) +{ +} + +int main(int argc, char *argv[]) +{ + /* Otherwise we get unused warnings for these. */ + struct foo *foo = NULL; + struct bar *bar = NULL; + struct baz *baz = NULL; + + take_any(typesafe_cb_cast3(struct any *, + struct foo *, struct bar *, struct baz *, + foo)); + take_any(typesafe_cb_cast3(struct any *, + struct foo *, struct bar *, struct baz *, + bar)); + take_any(typesafe_cb_cast3(struct any *, + struct foo *, struct bar *, struct baz *, + baz)); + return 0; +} diff --git a/ccan/typesafe_cb/test/compile_ok-typesafe_cb_def-const.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb_def-const.c deleted file mode 100644 index 01e090f1..00000000 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb_def-const.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -/* const args in callbacks should be OK. */ - -static void _register_callback(void (*cb)(void *arg), void *arg) -{ -} - -#define register_callback(cb, arg) \ - _register_callback(typesafe_cb(void, (cb), (arg)), (arg)) - -static void _register_callback_pre(void (*cb)(int x, void *arg), void *arg) -{ -} - -#define register_callback_pre(cb, arg) \ - _register_callback_pre(typesafe_cb_preargs(void, (cb), (arg), int), (arg)) - -static void _register_callback_post(void (*cb)(void *arg, int x), void *arg) -{ -} - -#define register_callback_post(cb, arg) \ - _register_callback_post(typesafe_cb_postargs(void, (cb), (arg), int), (arg)) - -static void my_callback(const char *p) -{ -} - -static void my_callback_pre(int x, /*const*/ char *p) -{ -} - -static void my_callback_post(/*const*/ char *p, int x) -{ -} - -int main(int argc, char *argv[]) -{ - char p[] = "hello world"; - register_callback(my_callback, p); - register_callback_pre(my_callback_pre, p); - register_callback_post(my_callback_post, p); - return 0; -} diff --git a/ccan/typesafe_cb/test/run.c b/ccan/typesafe_cb/test/run.c index 5afbb918..79863db8 100644 --- a/ccan/typesafe_cb/test/run.c +++ b/ccan/typesafe_cb/test/run.c @@ -12,7 +12,7 @@ static void _set_some_value(void *val) } #define set_some_value(expr) \ - _set_some_value(cast_if_type(void *, (expr), (expr), unsigned long)) + _set_some_value(typesafe_cb_cast(void *, unsigned long, (expr))) static void _callback_onearg(void (*fn)(void *arg), void *arg) { @@ -30,30 +30,19 @@ static void _callback_postargs(void (*fn)(void *arg, int a, int b), void *arg) } #define callback_onearg(cb, arg) \ - _callback_onearg(typesafe_cb(void, (cb), (arg)), (arg)) + _callback_onearg(typesafe_cb(void, void *, (cb), (arg)), (arg)) #define callback_preargs(cb, arg) \ - _callback_preargs(typesafe_cb_preargs(void, (cb), (arg), int, int), (arg)) + _callback_preargs(typesafe_cb_preargs(void, void *, (cb), (arg), int, int), (arg)) #define callback_postargs(cb, arg) \ - _callback_postargs(typesafe_cb_postargs(void, (cb), (arg), int, int), (arg)) + _callback_postargs(typesafe_cb_postargs(void, void *, (cb), (arg), int, int), (arg)) static void my_callback_onearg(char *p) { ok1(strcmp(p, "hello world") == 0); } -static void my_callback_onearg_const(const char *p) -{ - ok1(strcmp(p, "hello world") == 0); -} - -static void my_callback_onearg_volatile(volatile char *p) -{ - /* Double cast avoids warning on gcc's -Wcast-qual */ - ok1(strcmp((char *)(intptr_t)p, "hello world") == 0); -} - static void my_callback_preargs(int a, int b, char *p) { ok1(a == 1); @@ -61,22 +50,6 @@ static void my_callback_preargs(int a, int b, char *p) ok1(strcmp(p, "hello world") == 0); } -#if 0 /* FIXME */ -static void my_callback_preargs_const(int a, int b, const char *p) -{ - ok1(a == 1); - ok1(b == 2); - ok1(strcmp(p, "hello world") == 0); -} - -static void my_callback_preargs_volatile(int a, int b, volatile char *p) -{ - ok1(a == 1); - ok1(b == 2); - ok1(strcmp((char *)p, "hello world") == 0); -} -#endif - static void my_callback_postargs(char *p, int a, int b) { ok1(a == 1); @@ -84,23 +57,7 @@ static void my_callback_postargs(char *p, int a, int b) ok1(strcmp(p, "hello world") == 0); } -#if 0 /* FIXME */ -static void my_callback_postargs_const(const char *p, int a, int b) -{ - ok1(a == 1); - ok1(b == 2); - ok1(strcmp(p, "hello world") == 0); -} - -static void my_callback_postargs_volatile(volatile char *p, int a, int b) -{ - ok1(a == 1); - ok1(b == 2); - ok1(strcmp((char *)p, "hello world") == 0); -} -#endif - -/* This is simply a compile test; we promised cast_if_type can be in a +/* This is simply a compile test; we promised typesafe_cb_cast can be in a * static initializer. */ struct callback_onearg { @@ -109,7 +66,7 @@ struct callback_onearg }; struct callback_onearg cb_onearg -= { typesafe_cb(void, my_callback_onearg, (char *)(intptr_t)"hello world"), += { typesafe_cb(void, void *, my_callback_onearg, (char *)(intptr_t)"hello world"), "hello world" }; struct callback_preargs @@ -119,7 +76,7 @@ struct callback_preargs }; struct callback_preargs cb_preargs -= { typesafe_cb_preargs(void, my_callback_preargs, += { typesafe_cb_preargs(void, void *, my_callback_preargs, (char *)(intptr_t)"hi", int, int), "hi" }; struct callback_postargs @@ -129,7 +86,7 @@ struct callback_postargs }; struct callback_postargs cb_postargs -= { typesafe_cb_postargs(void, my_callback_postargs, += { typesafe_cb_postargs(void, void *, my_callback_postargs, (char *)(intptr_t)"hi", int, int), "hi" }; int main(int argc, char *argv[]) @@ -138,25 +95,15 @@ int main(int argc, char *argv[]) unsigned long l = (unsigned long)p; char str[] = "hello world"; - plan_tests(2 + 3 + 3 + 3); + plan_tests(2 + 1 + 3 + 3); set_some_value(p); set_some_value(l); callback_onearg(my_callback_onearg, str); - callback_onearg(my_callback_onearg_const, str); - callback_onearg(my_callback_onearg_volatile, str); callback_preargs(my_callback_preargs, str); -#if 0 /* FIXME */ - callback_preargs(my_callback_preargs_const, str); - callback_preargs(my_callback_preargs_volatile, str); -#endif callback_postargs(my_callback_postargs, str); -#if 0 /* FIXME */ - callback_postargs(my_callback_postargs_const, str); - callback_postargs(my_callback_postargs_volatile, str); -#endif return exit_status(); } diff --git a/ccan/typesafe_cb/typesafe_cb.h b/ccan/typesafe_cb/typesafe_cb.h index 4bc2e2da..40cfa397 100644 --- a/ccan/typesafe_cb/typesafe_cb.h +++ b/ccan/typesafe_cb/typesafe_cb.h @@ -1,159 +1,96 @@ -#ifndef CCAN_CAST_IF_TYPE_H -#define CCAN_CAST_IF_TYPE_H +#ifndef CCAN_TYPESAFE_CB_H +#define CCAN_TYPESAFE_CB_H #include "config.h" #if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P /** - * cast_if_type - only cast an expression if test matches a given type + * typesafe_cb_cast - only cast an expression if it matches a given type * @desttype: the type to cast to - * @expr: the expression to cast - * @test: the expression to test * @oktype: the type we allow + * @expr: the expression to cast * * This macro is used to create functions which allow multiple types. * The result of this macro is used somewhere that a @desttype type is - * expected: if @test is exactly of type @oktype, then @expr will be + * expected: if @expr is exactly of type @oktype, then it will be * cast to @desttype type, otherwise left alone. * * This macro can be used in static initializers. * * This is merely useful for warnings: if the compiler does not - * support the primitives required for cast_if_type(), it becomes an - * unconditional cast, and the @test and @oktype argument is not used. In - * particular, this means that @oktype can be a type which uses - * the "typeof": it will not be evaluated if typeof is not supported. + * support the primitives required for typesafe_cb_cast(), it becomes an + * unconditional cast, and the @oktype argument is not used. In + * particular, this means that @oktype can be a type which uses the + * "typeof": it will not be evaluated if typeof is not supported. * * Example: * // We can take either an unsigned long or a void *. * void _set_some_value(void *val); * #define set_some_value(e) \ - * _set_some_value(cast_if_type(void *, (e), (e), unsigned long)) + * _set_some_value(typesafe_cb_cast(void *, (e), unsigned long)) */ -#define cast_if_type(desttype, expr, test, oktype) \ - __builtin_choose_expr(__builtin_types_compatible_p(typeof(test), oktype), \ - (desttype)(expr), (expr)) +#define typesafe_cb_cast(desttype, oktype, expr) \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \ + oktype), \ + (desttype)(expr), (expr)) #else -#define cast_if_type(desttype, expr, test, oktype) ((desttype)(expr)) +#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr)) #endif /** - * cast_if_any - only cast an expression if it is one of the three given types + * typesafe_cb_cast3 - only cast an expression if it matches given types * @desttype: the type to cast to - * @expr: the expression to cast - * @test: the expression to test * @ok1: the first type we allow * @ok2: the second type we allow * @ok3: the third type we allow + * @expr: the expression to cast * - * This is a convenient wrapper for multiple cast_if_type() calls. You can - * chain them inside each other (ie. use cast_if_any() for expr) if you need - * more than 3 arguments. + * This is a convenient wrapper for multiple typesafe_cb_cast() calls. + * You can chain them inside each other (ie. use typesafe_cb_cast() + * for expr) if you need more than 3 arguments. * * Example: * // We can take either a long, unsigned long, void * or a const void *. * void _set_some_value(void *val); * #define set_some_value(expr) \ - * _set_some_value(cast_if_any(void *, (expr), (expr), \ - * long, unsigned long, const void *)) + * _set_some_value(typesafe_cb_cast3(void *,, \ + * long, unsigned long, const void *,\ + * (expr))) */ -#define cast_if_any(desttype, expr, test, ok1, ok2, ok3) \ - cast_if_type(desttype, \ - cast_if_type(desttype, \ - cast_if_type(desttype, (expr), (test), ok1), \ - (test), \ - ok2), \ - (test), \ - ok3) +#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \ + typesafe_cb_cast(desttype, ok1, \ + typesafe_cb_cast(desttype, ok2, \ + typesafe_cb_cast(desttype, ok3, \ + (expr)))) /** * typesafe_cb - cast a callback function if it matches the arg * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * If a callback function takes a single argument, this macro does - * appropriate casts to a function which takes a single void * argument if the - * callback provided matches the @arg (or a const or volatile version). - * - * It is assumed that @arg is of pointer type: usually @arg is passed - * or assigned to a void * elsewhere anyway. - * - * This will not work with a NULL @fn argument: see typesafe_cb_def or - * typesafe_cb_exact. - * - * Example: - * void _register_callback(void (*fn)(void *arg), void *arg); - * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb(void, (fn), (arg)), (arg)) - */ -#define typesafe_cb(rtype, fn, arg) \ - cast_if_type(rtype (*)(void *), (fn), (fn)(arg), rtype) - -/** - * typesafe_cb_def - cast a callback fn if it matches arg (of defined type) - * @rtype: the return type of the callback function - * @fn: the callback function to cast - * @arg: the (pointer) argument to hand to the callback function. - * - * This is typesafe_cb(), except the type must be defined (eg. if it's - * struct foo *, the definition of struct foo must be visible). For many - * applications, this is reasonable. - * - * This variant can accept @fn equal to NULL. - * - * Example: - * void _register_callback(void (*fn)(void *arg), void *arg); - * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb_def(void, (fn), (arg)), (arg)) - */ -#define typesafe_cb_def(rtype, fn, arg) \ - cast_if_any(rtype (*)(void *), (fn), 0?(fn):(fn), \ - rtype (*)(typeof(*arg)*), \ - rtype (*)(const typeof(*arg)*), \ - rtype (*)(volatile typeof(*arg)*)) - -/** - * typesafe_cb_exact - cast a callback fn if it exactly matches arg - * @rtype: the return type of the callback function - * @fn: the callback function to cast - * @arg: the (pointer) argument to hand to the callback function. - * - * This is typesafe_cb(), except the @fn can be NULL, or must exactly match - * the @arg type (no const or volatile). - * - * Example: - * void _register_callback(void (*fn)(void *arg), void *arg); - * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb_exact(void, (fn), (arg)), (arg)) - */ -#define typesafe_cb_exact(rtype, fn, arg) \ - cast_if_type(rtype (*)(void *), (fn), 0?(fn):(fn), \ - rtype (*)(typeof(arg))) - -/** - * typesafe_cb_const - cast a const callback function if it matches the arg - * @rtype: the return type of the callback function - * @fn: the callback function to cast - * @arg: the (pointer) argument to hand to the callback function. - * - * If a callback function takes a single argument, this macro does appropriate - * casts to a function which takes a single const void * argument if the + * appropriate casts to a function which takes a single atype argument if the * callback provided matches the @arg. * * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. * * Example: - * void _register_callback(void (*fn)(const void *arg), const void *arg); + * void _register_callback(void (*fn)(void *arg), void *arg); * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb_const(void, (fn), (arg)), (arg)) + * _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg)) */ -#define typesafe_cb_const(rtype, fn, arg) \ - cast_if_type(rtype (*)(const void *), (fn), (fn)(arg), rtype) +#define typesafe_cb(rtype, atype, fn, arg) \ + typesafe_cb_cast(rtype (*)(atype), \ + rtype (*)(__typeof__(arg)), \ + (fn)) /** * typesafe_cb_preargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * @@ -162,17 +99,20 @@ * * Example: * void _register_callback(void (*fn)(int, void *arg), void *arg); - * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\ + * #define register_callback(fn, arg) \ + * _register_callback(typesafe_cb_preargs(void, (fn), void *, \ + * (arg), int), \ * (arg)) */ -#define typesafe_cb_preargs(rtype, fn, arg, ...) \ - cast_if_type(rtype (*)(__VA_ARGS__, void *), (fn), 0?(fn):(fn), \ - rtype (*)(__VA_ARGS__, typeof(arg))) +#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \ + typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \ + rtype (*)(__VA_ARGS__, __typeof__(arg)), \ + (fn)) /** * typesafe_cb_postargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * @@ -182,37 +122,12 @@ * Example: * void _register_callback(void (*fn)(void *arg, int), void *arg); * #define register_callback(fn, arg) \ - * _register_callback(typesafe_cb_postargs(void, (fn), (arg), int),\ + * _register_callback(typesafe_cb_postargs(void, (fn), void *, \ + * (arg), int), \ * (arg)) */ -#define typesafe_cb_postargs(rtype, fn, arg, ...) \ - cast_if_type(rtype (*)(void *, __VA_ARGS__), (fn), 0?(fn):(fn), \ - rtype (*)(typeof(arg), __VA_ARGS__)) - -/** - * typesafe_cb_cmp - cast a compare function if it matches the arg - * @rtype: the return type of the callback function - * @fn: the callback function to cast - * @arg: the (pointer) argument(s) to hand to the compare function. - * - * If a callback function takes two matching-type arguments, this macro does - * appropriate casts to a function which takes two const void * arguments if - * the callback provided takes two a const pointers to @arg. - * - * It is assumed that @arg is of pointer type: usually @arg is passed - * or assigned to a void * elsewhere anyway. Note also that the type - * arg points to must be defined. - * - * Example: - * void _my_qsort(void *base, size_t nmemb, size_t size, - * int (*cmp)(const void *, const void *)); - * #define my_qsort(base, nmemb, cmpfn) \ - * _my_qsort((base), (nmemb), sizeof(*(base)), \ - * typesafe_cb_cmp(int, (cmpfn), (base)), (arg)) - */ -#define typesafe_cb_cmp(rtype, cmpfn, arg) \ - cast_if_type(rtype (*)(const void *, const void *), \ - (cmpfn), 0?(cmpfn):(cmpfn), \ - rtype (*)(const typeof(*arg)*, const typeof(*arg)*)) - +#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \ + typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \ + rtype (*)(__typeof__(arg), __VA_ARGS__), \ + (fn)) #endif /* CCAN_CAST_IF_TYPE_H */