From 061e63028390bc27db749c75a3689c2888f00f57 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 15 Jun 2010 19:32:55 +0930 Subject: [PATCH] typesafe_cb: expose _exact and _def variants. We can't allow NULL with the new variant (needed by talloc's set_destructor for example), so document that and expose all three variants for different uses. --- .../test/compile_fail-typesafe_cb_exact.c | 33 ++++++++++++++ .../test/compile_ok-typesafe_cb-NULL.c | 21 +++++++++ .../test/compile_ok-typesafe_cb-const.c | 4 ++ .../test/compile_ok-typesafe_cb_def-const.c | 45 +++++++++++++++++++ ccan/typesafe_cb/typesafe_cb.h | 43 ++++++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c create mode 100644 ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c create mode 100644 ccan/typesafe_cb/test/compile_ok-typesafe_cb_def-const.c diff --git a/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c new file mode 100644 index 00000000..0f61d5de --- /dev/null +++ b/ccan/typesafe_cb/test/compile_fail-typesafe_cb_exact.c @@ -0,0 +1,33 @@ +#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_ok-typesafe_cb-NULL.c b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c new file mode 100644 index 00000000..e3dceb24 --- /dev/null +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-NULL.c @@ -0,0 +1,21 @@ +#include +#include + +/* NULL args for callback function should be OK for _exact and _def. */ + +static void _register_callback(void (*cb)(void *arg), 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)) + +int main(int argc, char *argv[]) +{ + register_callback_def(NULL, "hello world"); + register_callback_exact(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 index 5017928a..1e4a77b2 100644 --- a/ccan/typesafe_cb/test/compile_ok-typesafe_cb-const.c +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb-const.c @@ -10,6 +10,9 @@ 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) { } @@ -39,6 +42,7 @@ static void my_callback_post(/*const*/ char *p, int x) int main(int argc, char *argv[]) { register_callback(my_callback, "hello world"); + register_callback_def(my_callback, "hello world"); register_callback_pre(my_callback_pre, "hello world"); register_callback_post(my_callback_post, "hello world"); 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 new file mode 100644 index 00000000..5017928a --- /dev/null +++ b/ccan/typesafe_cb/test/compile_ok-typesafe_cb_def-const.c @@ -0,0 +1,45 @@ +#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[]) +{ + register_callback(my_callback, "hello world"); + register_callback_pre(my_callback_pre, "hello world"); + register_callback_post(my_callback_post, "hello world"); + return 0; +} diff --git a/ccan/typesafe_cb/typesafe_cb.h b/ccan/typesafe_cb/typesafe_cb.h index 39b03124..e48741a9 100644 --- a/ccan/typesafe_cb/typesafe_cb.h +++ b/ccan/typesafe_cb/typesafe_cb.h @@ -78,6 +78,9 @@ * 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) \ @@ -86,6 +89,46 @@ #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), &*(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), &*(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 -- 2.39.2