summaryrefslogtreecommitdiff
path: root/include/libHX/defs.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/libHX/defs.h')
-rw-r--r--include/libHX/defs.h48
1 files changed, 30 insertions, 18 deletions
diff --git a/include/libHX/defs.h b/include/libHX/defs.h
index bb03f40..9ecdd32 100644
--- a/include/libHX/defs.h
+++ b/include/libHX/defs.h
@@ -22,6 +22,9 @@
# define containerof(var, type, member) reinterpret_cast<type *>( \
reinterpret_cast<char *>(var) - offsetof(type, member))
# endif
+# ifndef static_cast
+# define static_cast(T, x) static_cast<T>(x)
+# endif
template<typename new_type>
static __inline__ new_type signed_cast(const char *expr)
@@ -91,24 +94,33 @@ static __inline__ new_type signed_cast(unsigned char *expr)
((struct { type x; }){(expr)}.x)
# endif
# if defined(__GNUC__) && !defined(__clang__) && !defined(const_cast1)
-# define __const_cast_strip1(expr) \
- __typeof__(*(union { int z; __typeof__(expr) x; }){0}.x)
-# define __const_cast_strip2(expr) \
- __typeof__(**(union { int z; __typeof__(expr) x; }){0}.x)
-# define __const_cast_strip3(expr) \
- __typeof__(***(union { int z; __typeof__(expr) x; }){0}.x)
-# define const_cast1(new_type, expr) ({ \
- BUILD_BUG_ON(!__builtin_types_compatible_p(__const_cast_strip1(expr), __const_cast_strip1(new_type))); \
- (new_type)(expr); \
- })
-# define const_cast2(new_type, expr) ({ \
- BUILD_BUG_ON(!__builtin_types_compatible_p(__const_cast_strip2(expr), __const_cast_strip2(new_type))); \
- (new_type)(expr); \
- })
-# define const_cast3(new_type, expr) ({ \
- BUILD_BUG_ON(!__builtin_types_compatible_p(__const_cast_strip3(expr), __const_cast_strip3(new_type))); \
- (new_type)(expr); \
- })
+ /*
+ * The idea starts with (in abstract notation)
+ * typeof deref typeof expr
+ * To deref something, we need an object, which we can get by
+ * creating a temporary aggregate, such as a union, of which
+ * the member is accessed and dereferenced.
+ * *(union { __typeof__(expr) x; }){init}.x
+ * union has two nice properties:
+ * - with an additional dummy member, we do not have to
+ * initialize x according to its type, which, if expr is
+ * an array type, may want extra braces.
+ * - and with that dummy member, we also avoid the ugly
+ * "literal 0 is implicitly convertible to a pointer".
+ * Unfortunately, this all requires C99 compound initializers.
+ * That's ok - gcc and clang only treat it as a warning even
+ * under strict C89 - and if you still force strict C89 on
+ * yourself, you have a lot to answer for either way.
+ */
+# define __const_cast_strip(ptrs, expr) \
+ __typeof__(ptrs(union { int z; __typeof__(expr) x; }){0}.x)
+# define __const_cast_p(ptrs, new_type, expr) ((new_type)( \
+ (expr) + \
+ BUILD_BUG_ON_EXPR(!__builtin_types_compatible_p(__const_cast_strip(ptrs, expr), __const_cast_strip(ptrs, new_type))) \
+ ))
+# define const_cast1(new_type, expr) __const_cast_p(*, new_type, expr)
+# define const_cast2(new_type, expr) __const_cast_p(**, new_type, expr)
+# define const_cast3(new_type, expr) __const_cast_p(***, new_type, expr)
# endif
# ifndef signed_cast
# define signed_cast(type, expr) ((type)(expr))