This commit is contained in:
David Lamparter 2025-04-29 16:20:43 +00:00 committed by GitHub
commit 0a13d89d38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 173 additions and 58 deletions

View file

@ -74,7 +74,7 @@ static inline int bgp_is_withdraw_label(mpls_label_t *label)
static inline int bgp_is_valid_label(const mpls_label_t *label) static inline int bgp_is_valid_label(const mpls_label_t *label)
{ {
uint8_t *t = (uint8_t *)label; const uint8_t *t = (const uint8_t *)label;
if (!t) if (!t)
return 0; return 0;
return (t[2] & 0x02); return (t[2] & 0x02);

View file

@ -448,6 +448,17 @@ AH_VERBATIM([OpenBSD], [
#endif #endif
]) ])
dnl Debian 8.3.0-6 has a broken -Wdiscarded-qualifiers
dnl Gentoo 7.5.0 and 8.4.0 are both fine, so either it's gcc 8.3 or Debian's
dnl meddling. I'm guessing the latter. (2025-01-27 equinox)
AC_MSG_CHECKING([whether $CC is a broken Debian GCC 8.3])
if $CC -v 2>&1 | grep -q -E '^gcc.*Debian 8\.3\.'; then
AC_MSG_RESULT([yes])
CFLAGS="$CFLAGS -Wno-discarded-qualifiers"
else
AC_MSG_RESULT([no])
fi
dnl always want these CFLAGS dnl always want these CFLAGS
AC_C_FLAG([-fms-extensions], [ AC_C_FLAG([-fms-extensions], [
AC_MSG_ERROR([$CC does not support unnamed struct fields (-fms-extensions)]) AC_MSG_ERROR([$CC does not support unnamed struct fields (-fms-extensions)])

View file

@ -32,11 +32,15 @@ struct ipv6_ph {
extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len); extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len);
/* note the (char *) in the casts below is needed to make this header work
* when compiled as C++ as it behaves differently with const qualification
*/
static inline uint16_t in_cksum(const void *data, size_t nbytes) static inline uint16_t in_cksum(const void *data, size_t nbytes)
{ {
struct iovec iov[1]; struct iovec iov[1];
iov[0].iov_base = (void *)data; iov[0].iov_base = unconst((char *)data);
iov[0].iov_len = nbytes; iov[0].iov_len = nbytes;
return in_cksumv(iov, array_size(iov)); return in_cksumv(iov, array_size(iov));
} }
@ -46,9 +50,9 @@ static inline uint16_t in_cksum_with_ph4(const struct ipv4_ph *ph,
{ {
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = (void *)ph; iov[0].iov_base = unconst(ph);
iov[0].iov_len = sizeof(*ph); iov[0].iov_len = sizeof(*ph);
iov[1].iov_base = (void *)data; iov[1].iov_base = unconst((char *)data);
iov[1].iov_len = nbytes; iov[1].iov_len = nbytes;
return in_cksumv(iov, array_size(iov)); return in_cksumv(iov, array_size(iov));
} }
@ -58,9 +62,9 @@ static inline uint16_t in_cksum_with_ph6(const struct ipv6_ph *ph,
{ {
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = (void *)ph; iov[0].iov_base = unconst(ph);
iov[0].iov_len = sizeof(*ph); iov[0].iov_len = sizeof(*ph);
iov[1].iov_base = (void *)data; iov[1].iov_base = unconst((char *)data);
iov[1].iov_len = nbytes; iov[1].iov_len = nbytes;
return in_cksumv(iov, array_size(iov)); return in_cksumv(iov, array_size(iov));
} }

View file

@ -6,7 +6,16 @@
#ifndef _FRR_COMPILER_H #ifndef _FRR_COMPILER_H
#define _FRR_COMPILER_H #define _FRR_COMPILER_H
#if defined(__cplusplus) || defined(test__cplusplus)
/* -Wcast-qual is not supported in the FRR codebase with C++, since the macros
* don't work
*/
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
#ifdef __cplusplus #ifdef __cplusplus
#include <cstddef>
extern "C" { extern "C" {
#endif #endif
@ -266,7 +275,98 @@ extern "C" {
#undef container_of #undef container_of
#endif #endif
#ifdef __cplusplus
#define typeof(x) decltype(x)
#endif
/* strip qualifiers of a type */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
/* nothing - typeof_unqual is in ISO C23. note that that is normally
* 202311L, but gcc 14 claims 202000L for -std=gnu23 and that works too
*/
#elif !defined(__cplusplus) && (__GNUC__ >= 14 || (defined(__clang__) && __clang_major__ >= 19))
/* __typeof_unqual__ is available as an alias for the C23 feature for use
* outside C23 mode in GCC >= 14 and clang >= 19
*/
#define typeof_unqual(_t) __typeof_unqual__(_t)
#else
/* this works because a function return value can't have qualifiers attached.
* unfortunately there is a warning about the very thing we're intentionally
* doing here (ignoring the qualifiers), so mute that
*
* declaring a variable with this type would also do it, except that'll barf
* if we try to declare a variable of type "void"; a function pointer is fine
*
* turn off clang-format because it wrecks the _Pragma formatting
*/
/* clang-format off */
#define typeof_unqual(_t) \
typeof(({ \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"") \
typeof(_t) (*_v)(void); \
_Pragma("GCC diagnostic pop") \
_v(); \
}))
/* clang-format on */
#endif
#if !defined(__cplusplus)
/* cast val (pointer type) into the same type but without const
* this is built to work with -Wcast-qual, hence the cast via uintptr_t
*
* the type is automatically determined to help against accidentally changing
* into some other type while intending to only remove the const
*/
#define unconst(_val) \
({ \
__auto_type _v = _val; \
typeof_unqual(*_v) * d; \
(typeof(d))(uintptr_t)_v; \
})
#else
#define unconst(_val) \
({ \
auto _v = _val; \
const_cast<decltype(({ \
auto _t = *_v; \
&_t; \
}))>(_v); \
})
#endif
#if !(defined(__cplusplus) || defined(test__cplusplus)) #if !(defined(__cplusplus) || defined(test__cplusplus))
/* returns 1 if v is a pointer to const (e.g. "const char *x; is_const_ptr(x)")
* or bare type specification (e.g. "is_const_ptr(const char *)")
* (supporting the latter is the reason for some extra hoops to jump through)
* "w" exists only to avoid a "duplicate use of const" warning on clang
*/
#define is_const_ptr(_v) \
__builtin_types_compatible_p(typeof(_v), typeof(({ \
typeof(_v) _w; \
const typeof(*_w) *_x; \
_x; \
})))
/* shortcut */
#define is_const_ptr2(_v1, _v2) is_const_ptr(_v1) || is_const_ptr(_v2)
/* conditionally add const. It is intentional that the combination of "const"
* and "typ" happens on the preprocessor level here, which is not quite the
* same thing as doing "const typeof(x)".
*/
#define constlify(cond, typ) \
typeof(__builtin_choose_expr(cond, ({ \
const typ _x; \
_x; \
}), \
({ \
typ _x; \
_x; \
})))
/* this variant of container_of() retains 'const' on pointers without needing /* this variant of container_of() retains 'const' on pointers without needing
* to be told to do so. The following will all work without warning: * to be told to do so. The following will all work without warning:
* *
@ -284,22 +384,19 @@ extern "C" {
* struct cont *x = container_of(cp, struct cont, member); * struct cont *x = container_of(cp, struct cont, member);
* struct cont *x = container_of(cp, const struct cont, member); * struct cont *x = container_of(cp, const struct cont, member);
* struct cont *x = container_of(p, const struct cont, member); * struct cont *x = container_of(p, const struct cont, member);
*
* _mptype, _outtype and _chtype are here to make compiler warnings better.
*/ */
#define container_of(ptr, type, member) \ #define container_of(ptr, type, member) \
(__builtin_choose_expr( \ ({ \
__builtin_types_compatible_p(typeof(&((type *)0)->member), \ __auto_type _p = ptr; /* avoid multiple eval */ \
typeof(ptr)) \ constlify(is_const_ptr2(_p, type *), typeof(((type *)0)->member) *) _mptype; \
|| __builtin_types_compatible_p(void *, typeof(ptr)), \ constlify(is_const_ptr2(_p, type *), typeof_unqual(type) *) _outtype; \
({ \ constlify(is_const_ptr2(_p, type *), char *) _chtype; \
typeof(((type *)0)->member) *__mptr = (void *)(ptr); \ typeof(_mptype) _memberptr = _p; /* input type check */ \
(type *)((char *)__mptr - offsetof(type, member)); \ (typeof(_outtype))((typeof(_chtype))_memberptr - offsetof(type, member)); \
}), \ })
({ \
typeof(((const type *)0)->member) *__mptr = (ptr); \
(const type *)((const char *)__mptr - \
offsetof(type, member)); \
}) \
))
#else #else
/* current C++ compilers don't have the builtins used above; so this version /* current C++ compilers don't have the builtins used above; so this version
* of the macro doesn't do the const check. */ * of the macro doesn't do the const check. */

View file

@ -171,8 +171,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
#define hook_call(hookname, ...) hook_call_##hookname(__VA_ARGS__) #define hook_call(hookname, ...) hook_call_##hookname(__VA_ARGS__)
/* helpers to add the void * arg */ /* helpers to add the void * arg */
#ifndef __cplusplus
#define HOOK_ADDDEF(...) (void *hookarg , ## __VA_ARGS__) #define HOOK_ADDDEF(...) (void *hookarg , ## __VA_ARGS__)
#define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__) #define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__)
#else
/* apparently the preprocessor behaves differently in C++ mode... */
#define HOOK_ADDDEF(...) (void *hookarg __VA_OPT__(, )##__VA_ARGS__)
#define HOOK_ADDARG(...) (hookarg __VA_OPT__(, )##__VA_ARGS__)
#endif
/* and another helper to convert () into (void) to get a proper prototype */ /* and another helper to convert () into (void) to get a proper prototype */
#define _SKIP_10(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, ret, ...) ret #define _SKIP_10(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, ret, ...) ret

View file

@ -124,7 +124,7 @@ static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
struct in_addr *in) struct in_addr *in)
{ {
memset(in, 0, sizeof(struct in_addr)); memset(in, 0, sizeof(struct in_addr));
memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); memcpy(in, (const char *)in6 + 12, sizeof(struct in_addr));
} }
/* /*
@ -145,8 +145,7 @@ static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b)
return (va < vb) ? -1 : 1; return (va < vb) ? -1 : 1;
return 0; return 0;
case IPADDR_V6: case IPADDR_V6:
return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6, return memcmp(&a->ipaddr_v6, &b->ipaddr_v6, sizeof(a->ipaddr_v6));
sizeof(a->ipaddr_v6));
case IPADDR_NONE: case IPADDR_NONE:
return 0; return 0;
} }

View file

@ -133,7 +133,7 @@ static inline void vni2label(vni_t vni, mpls_label_t *label)
static inline vni_t label2vni(const mpls_label_t *label) static inline vni_t label2vni(const mpls_label_t *label)
{ {
uint8_t *tag = (uint8_t *)label; const uint8_t *tag = (const uint8_t *)label;
vni_t vni; vni_t vni;
assert(tag); assert(tag);

View file

@ -72,41 +72,36 @@ skiplist_new(/* encouraged: set list.del callback on new lists */
extern void skiplist_free(struct skiplist *); extern void skiplist_free(struct skiplist *);
extern int skiplist_insert(register struct skiplist *l, register void *key, extern int skiplist_insert(struct skiplist *l, void *key, void *value);
register void *value);
extern int skiplist_delete(register struct skiplist *l, register void *key, extern int skiplist_delete(struct skiplist *l, void *key, void *value);
register void *value);
extern int skiplist_search(register struct skiplist *l, register void *key, extern int skiplist_search(struct skiplist *l, void *key, void **valuePointer);
void **valuePointer);
extern int skiplist_first_value(register struct skiplist *l, /* in */ extern int skiplist_first_value(struct skiplist *l, /* in */
register const void *key, /* in */ const void *key, /* in */
void **valuePointer, /* in/out */ void **valuePointer, /* in/out */
void **cursor); /* out */ void **cursor); /* out */
extern int skiplist_next_value(register struct skiplist *l, /* in */ extern int skiplist_next_value(struct skiplist *l, /* in */
register const void *key, /* in */ const void *key, /* in */
void **valuePointer, /* in/out */ void **valuePointer, /* in/out */
void **cursor); /* in/out */ void **cursor); /* in/out */
extern int skiplist_first(register struct skiplist *l, void **keyPointer, extern int skiplist_first(struct skiplist *l, void **keyPointer, void **valuePointer);
void **valuePointer);
extern int skiplist_last(register struct skiplist *l, void **keyPointer, extern int skiplist_last(struct skiplist *l, void **keyPointer, void **valuePointer);
void **valuePointer);
extern int skiplist_delete_first(register struct skiplist *l); extern int skiplist_delete_first(struct skiplist *l);
extern int skiplist_next(register struct skiplist *l, /* in */ extern int skiplist_next(struct skiplist *l, /* in */
void **keyPointer, /* out */ void **keyPointer, /* out */
void **valuePointer, /* out */ void **valuePointer, /* out */
void **cursor); /* in/out */ void **cursor); /* in/out */
extern int skiplist_empty(register struct skiplist *l); /* in */ extern int skiplist_empty(struct skiplist *l); /* in */
extern unsigned int skiplist_count(register struct skiplist *l); /* in */ extern unsigned int skiplist_count(struct skiplist *l); /* in */
struct vty; struct vty;
extern void skiplist_debug(struct vty *vty, struct skiplist *l); extern void skiplist_debug(struct vty *vty, struct skiplist *l);

View file

@ -17,6 +17,8 @@
extern "C" { extern "C" {
#endif #endif
/* clang-format off */
/* generic macros for all list-like types */ /* generic macros for all list-like types */
/* to iterate using the const variants of the functions, append "_const" to /* to iterate using the const variants of the functions, append "_const" to
@ -62,40 +64,40 @@ extern "C" {
#define TYPESAFE_FIRST_NEXT(prefix, type) \ #define TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _first(struct prefix##_head *h) \ macro_pure type *prefix ## _first(struct prefix##_head *h) \
{ \ { \
return (type *)prefix ## _const_first(h); \ return unconst(prefix ## _const_first(h)); \
} \ } \
macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \ macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
{ \ { \
return (type *)prefix ## _const_next(h, item); \ return unconst(prefix ## _const_next(h, item)); \
} \ } \
/* ... */ /* ... */
#define TYPESAFE_LAST_PREV(prefix, type) \ #define TYPESAFE_LAST_PREV(prefix, type) \
macro_pure type *prefix ## _last(struct prefix##_head *h) \ macro_pure type *prefix ## _last(struct prefix##_head *h) \
{ \ { \
return (type *)prefix ## _const_last(h); \ return unconst(prefix ## _const_last(h)); \
} \ } \
macro_pure type *prefix ## _prev(struct prefix##_head *h, type *item) \ macro_pure type *prefix ## _prev(struct prefix##_head *h, type *item) \
{ \ { \
return (type *)prefix ## _const_prev(h, item); \ return unconst(prefix ## _const_prev(h, item)); \
} \ } \
/* ... */ /* ... */
#define TYPESAFE_FIND(prefix, type) \ #define TYPESAFE_FIND(prefix, type) \
macro_inline type *prefix ## _find(struct prefix##_head *h, \ macro_inline type *prefix ## _find(struct prefix##_head *h, \
const type *item) \ const type *item) \
{ \ { \
return (type *)prefix ## _const_find(h, item); \ return unconst(prefix ## _const_find(h, item)); \
} \ } \
/* ... */ /* ... */
#define TYPESAFE_FIND_CMP(prefix, type) \ #define TYPESAFE_FIND_CMP(prefix, type) \
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
const type *item) \ const type *item) \
{ \ { \
return (type *)prefix ## _const_find_lt(h, item); \ return unconst(prefix ## _const_find_lt(h, item)); \
} \ } \
macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
const type *item) \ const type *item) \
{ \ { \
return (type *)prefix ## _const_find_gteq(h, item); \ return unconst(prefix ## _const_find_gteq(h, item)); \
} \ } \
/* ... */ /* ... */

View file

@ -147,7 +147,7 @@ static inline int pim_sgaddr_cmp(const pim_sgaddr a, const pim_sgaddr b)
static inline uint32_t pim_sgaddr_hash(const pim_sgaddr a, uint32_t initval) static inline uint32_t pim_sgaddr_hash(const pim_sgaddr a, uint32_t initval)
{ {
return jhash2((uint32_t *)&a, sizeof(a) / sizeof(uint32_t), initval); return jhash2((const uint32_t *)&a, sizeof(a) / sizeof(uint32_t), initval);
} }
#ifdef _FRR_ATTRIBUTE_PRINTFRR #ifdef _FRR_ATTRIBUTE_PRINTFRR

View file

@ -62,6 +62,7 @@ vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */
#include "vtysh/vtysh.h" #include "vtysh/vtysh.h"
#pragma GCC visibility push(internal) #pragma GCC visibility push(internal)
#pragma GCC diagnostic ignored "-Wcast-qual"
#define MAKE_VECTOR(name, len, ...) \\ #define MAKE_VECTOR(name, len, ...) \\
static void * name ## _vitems[] = { __VA_ARGS__ }; \\ static void * name ## _vitems[] = { __VA_ARGS__ }; \\