shared: rework _NM_GET_PRIVATE() to use _Generic()

_NM_GET_PRIVATE() used typeof() to propagate constness of the @self
pointer. However, that means, it could only be used with a self pointer
of the exact type. That means, you explicitly had to cast from (GObject *)
or from (void *).
The requirement is cumbersome, and often led us to either create @self
pointer we didn't need:

    NMDeviceVlan *self = NM_DEVICE_VLAN (device);
    NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);

or casting:

    NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDevice *) device);

In both cases we forcefully cast the source variable, loosing help from
the compiler to detect a bug.

For "nm-linux-platform.c", instead we commonly have a pointer of type
NMPlatform. Hence, we always forcefully cast the type via _NM_GET_PRIVATE_VOID().

Rework the macro to use _Generic(). If compiler supports _Generic(), then we
will get all compile time checks as desired. If the compiler doesn't support
_Generic(), it will still work. You don't get the compile-time checking of course,
but you'd notice that something is wrong once you build with a suitable
compiler.
This commit is contained in:
Thomas Haller
2017-11-09 10:05:00 +01:00
parent f02df2c2ca
commit b1810d7a68
3 changed files with 57 additions and 47 deletions

View File

@@ -270,26 +270,65 @@ NM_G_ERROR_MSG (GError *error)
#endif #endif
#if _NM_CC_SUPPORT_GENERIC #if _NM_CC_SUPPORT_GENERIC
#define _NM_CONSTCAST(type, obj) \ #define _NM_CONSTCAST_FULL(type, obj_expr, obj) \
(_Generic ((obj), \ (_Generic ((obj_expr), \
void * : ((type *) (obj)), \
void *const : ((type *) (obj)), \
const void * : ((const type *) (obj)), \ const void * : ((const type *) (obj)), \
const void *const: ((const type *) (obj)), \ void * : (( type *) (obj)), \
const type * : (obj), \ const type * : ((const type *) (obj)), \
const type *const: (obj), \ type * : (( type *) (obj))))
type * : (obj), \ #define _NM_CONSTCAST2_FULL(type, obj_expr, obj, alias_type2) \
type *const : (obj))) (_Generic ((obj_expr), \
const void *: ((const type *) (obj)), \
void *: (( type *) (obj)), \
const alias_type2 *: ((const type *) (obj)), \
alias_type2 *: (( type *) (obj)), \
const type *: ((const type *) (obj)), \
type *: (( type *) (obj))))
#define _NM_CONSTCAST3_FULL(type, obj_expr, obj, alias_type2, alias_type3) \
(_Generic ((obj_expr), \
const void *: ((const type *) (obj)), \
void *: (( type *) (obj)), \
const alias_type2 *: ((const type *) (obj)), \
alias_type2 *: (( type *) (obj)), \
const alias_type3 *: ((const type *) (obj)), \
alias_type3 *: (( type *) (obj)), \
const type *: ((const type *) (obj)), \
type *: (( type *) (obj))))
#else #else
/* _NM_CONSTCAST() is there to preserve constness of a pointer. /* _NM_CONSTCAST() is there to preserve constness of a pointer.
* It uses C11's _Generic(). If that is not supported, we fall back * It uses C11's _Generic(). If that is not supported, we fall back
* to casting away constness. So, with _Generic, we get some additional * to casting away constness. So, with _Generic, we get some additional
* static type checking by preserving constness, without, we cast it * static type checking by preserving constness, without, we cast it
* to a non-const pointer. */ * to a non-const pointer. */
#define _NM_CONSTCAST(type, obj) \ #define _NM_CONSTCAST_FULL(type, obj_expr, obj) \
((type *) (obj))
#define _NM_CONSTCAST2_FULL(type, obj_expr, obj, alias_type2) \
((type *) (obj))
#define _NM_CONSTCAST3_FULL(type, obj_expr, obj, alias_type2, alias_type2) \
((type *) (obj)) ((type *) (obj))
#endif #endif
#define _NM_CONSTCAST(type, obj) \
_NM_CONSTCAST_FULL(type, (obj), (obj))
#define _NM_CONSTCAST2(type, obj, alias_type2) \
_NM_CONSTCAST2_FULL(type, (obj), (obj), alias_type2)
#define _NM_GOBJECT_CAST(type, obj, is_check) \
({ \
const void *_obj = (obj); \
\
nm_assert (is_check (_obj)); \
_NM_CONSTCAST2_FULL (type, (obj), _obj, GObject); \
})
#define _NM_GOBJECT_CAST2(type, obj, is_check, alias_type2) \
({ \
const void *_obj = (obj); \
\
nm_assert (is_check (_obj)); \
_NM_CONSTCAST3_FULL (type, (obj), _obj, GObject, alias_type2); \
})
#if _NM_CC_SUPPORT_GENERIC #if _NM_CC_SUPPORT_GENERIC
/* returns @value, if the type of @value matches @type. /* returns @value, if the type of @value matches @type.
* This requires support for C11 _Generic(). If no support is * This requires support for C11 _Generic(). If no support is
@@ -581,39 +620,10 @@ _notify (obj_type *obj, _PropertyEnums prop) \
/*****************************************************************************/ /*****************************************************************************/
/* these are implemented as a macro, because they accept self #define _NM_GET_PRIVATE( self, type, is_check) (&(_NM_GOBJECT_CAST (type, (self), is_check )->_priv))
* as both (type*) and (const type*), and return a const #define _NM_GET_PRIVATE_PTR( self, type, is_check) ( (_NM_GOBJECT_CAST (type, (self), is_check )->_priv))
* private pointer accordingly. */ #define _NM_GET_PRIVATE2( self, type, is_check, alias_type2) (&(_NM_GOBJECT_CAST2 (type, (self), is_check, alias_type2)->_priv))
#define __NM_GET_PRIVATE(self, type, is_check, addrop) \ #define _NM_GET_PRIVATE2_PTR(self, type, is_check, alias_type2) ( (_NM_GOBJECT_CAST2 (type, (self), is_check, alias_type2)->_priv))
({ \
/* preserve the const-ness of self. Unfortunately, that
* way, @self cannot be a void pointer */ \
typeof (self) _self = (self); \
\
/* Get compiler error if variable is of wrong type */ \
_nm_unused const type *const _self2 = (_self); \
\
nm_assert (is_check (_self)); \
( addrop ( _NM_CONSTCAST (type, _self)->_priv) ); \
})
#define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &)
#define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, )
#define __NM_GET_PRIVATE_VOID(self, type, is_check, result_cmd) \
({ \
/* (self) can be any non-const pointer. It will be cast to "type *".
* We don't explicitly cast but assign first to (void *) which
* will fail if @self is pointing to const. */ \
void *const _self1 = (self); \
type *const _self = _self1; \
\
nm_assert (is_check (_self)); \
( result_cmd ); \
})
#define _NM_GET_PRIVATE_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, &_self->_priv)
#define _NM_GET_PRIVATE_PTR_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, _self->_priv)
/*****************************************************************************/ /*****************************************************************************/

View File

@@ -66,7 +66,7 @@ struct _NMDeviceVlanClass {
G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE)
#define NM_DEVICE_VLAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceVlan, NM_IS_DEVICE_VLAN) #define NM_DEVICE_VLAN_GET_PRIVATE(self) _NM_GET_PRIVATE2 (self, NMDeviceVlan, NM_IS_DEVICE_VLAN, NMDevice)
/*****************************************************************************/ /*****************************************************************************/
@@ -418,7 +418,7 @@ complete_connection (NMDevice *device,
static void static void
update_connection (NMDevice *device, NMConnection *connection) update_connection (NMDevice *device, NMConnection *connection)
{ {
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection); NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
int ifindex = nm_device_get_ifindex (device); int ifindex = nm_device_get_ifindex (device);
const char *setting_parent, *new_parent; const char *setting_parent, *new_parent;
@@ -558,7 +558,7 @@ static void
get_property (GObject *object, guint prop_id, get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec) GValue *value, GParamSpec *pspec)
{ {
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) object); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
switch (prop_id) { switch (prop_id) {
case PROP_VLAN_ID: case PROP_VLAN_ID:

View File

@@ -2867,7 +2867,7 @@ struct _NMLinuxPlatformClass {
G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_VOID(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM) #define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE2(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform)
NMPlatform * NMPlatform *
nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support)