clang++ errors out on g_atomic_pointer_compare_and_exchange
We have a C and C++ mixed codebase, where the C++ parts are compiled with clang++ including some C based headers in extern "C"
mode. In such a case g_atomic_pointer_compare_and_exchange() errors out with this error message:
.../lib/atomic-gssize.h:118:10: error: cannot initialize a parameter of type 'gssize *' (aka 'long *') with an rvalue of type 'void *'
return g_atomic_pointer_compare_and_exchange(&a->value, oldval, newval);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gatomic.h:258:44: note: expanded from macro 'g_atomic_pointer_compare_and_exchange'
__atomic_compare_exchange_n ((atomic), (void *) (&(gapcae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
^~~~~~~~~~~~~~~~~~~~~~~~~~~
The triggering function looks like this:
static inline gboolean
atomic_gssize_compare_and_exchange(atomic_gssize *a, gssize oldval, gssize newval)
{
return g_atomic_pointer_compare_and_exchange(&a->value, oldval, newval);
}
and the struct:
typedef struct
{
gssize value;
} atomic_gssize;
The issue is that the 2nd argument to __atomic_compare_exchange_n() is cast to (void *) whereas the rest are not.
My workaround is here: https://github.com/syslog-ng/syslog-ng/pull/4739/commits/a33b9c10f288640f46a577bdc2a56d169ffd0d8f
The important part is just adding extra (void **) casts for every argument to __atomic_compare_exchange_n() and remove the (void *) cast from the oldvalue.
#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
(G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer)); \
gpointer gapcae_oldval = (gpointer)(oldval); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \
__atomic_compare_exchange_n ((void **) (atomic), (&(gapcae_oldval)), (void **) (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
^^^^^^^^^ ^^^^^^^^^
}))
#endif