mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 21:47:15 +02:00
Merge ca2a57a67d
into 3dd4d417be
This commit is contained in:
commit
0a13d89d38
|
@ -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)
|
||||
{
|
||||
uint8_t *t = (uint8_t *)label;
|
||||
const uint8_t *t = (const uint8_t *)label;
|
||||
if (!t)
|
||||
return 0;
|
||||
return (t[2] & 0x02);
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -448,6 +448,17 @@ AH_VERBATIM([OpenBSD], [
|
|||
#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
|
||||
AC_C_FLAG([-fms-extensions], [
|
||||
AC_MSG_ERROR([$CC does not support unnamed struct fields (-fms-extensions)])
|
||||
|
|
|
@ -32,11 +32,15 @@ struct ipv6_ph {
|
|||
|
||||
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)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
|
||||
iov[0].iov_base = (void *)data;
|
||||
iov[0].iov_base = unconst((char *)data);
|
||||
iov[0].iov_len = nbytes;
|
||||
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];
|
||||
|
||||
iov[0].iov_base = (void *)ph;
|
||||
iov[0].iov_base = unconst(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;
|
||||
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];
|
||||
|
||||
iov[0].iov_base = (void *)ph;
|
||||
iov[0].iov_base = unconst(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;
|
||||
return in_cksumv(iov, array_size(iov));
|
||||
}
|
||||
|
|
123
lib/compiler.h
123
lib/compiler.h
|
@ -6,7 +6,16 @@
|
|||
#ifndef _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
|
||||
#include <cstddef>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -266,7 +275,98 @@ extern "C" {
|
|||
#undef container_of
|
||||
#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))
|
||||
/* 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
|
||||
* 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, 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) \
|
||||
(__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(&((type *)0)->member), \
|
||||
typeof(ptr)) \
|
||||
|| __builtin_types_compatible_p(void *, typeof(ptr)), \
|
||||
({ \
|
||||
typeof(((type *)0)->member) *__mptr = (void *)(ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); \
|
||||
}), \
|
||||
({ \
|
||||
typeof(((const type *)0)->member) *__mptr = (ptr); \
|
||||
(const type *)((const char *)__mptr - \
|
||||
offsetof(type, member)); \
|
||||
}) \
|
||||
))
|
||||
__auto_type _p = ptr; /* avoid multiple eval */ \
|
||||
constlify(is_const_ptr2(_p, type *), typeof(((type *)0)->member) *) _mptype; \
|
||||
constlify(is_const_ptr2(_p, type *), typeof_unqual(type) *) _outtype; \
|
||||
constlify(is_const_ptr2(_p, type *), char *) _chtype; \
|
||||
typeof(_mptype) _memberptr = _p; /* input type check */ \
|
||||
(typeof(_outtype))((typeof(_chtype))_memberptr - offsetof(type, member)); \
|
||||
})
|
||||
|
||||
#else
|
||||
/* current C++ compilers don't have the builtins used above; so this version
|
||||
* of the macro doesn't do the const check. */
|
||||
|
|
|
@ -171,8 +171,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
|
|||
#define hook_call(hookname, ...) hook_call_##hookname(__VA_ARGS__)
|
||||
|
||||
/* helpers to add the void * arg */
|
||||
#ifndef __cplusplus
|
||||
#define HOOK_ADDDEF(...) (void *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 */
|
||||
#define _SKIP_10(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, ret, ...) ret
|
||||
|
|
|
@ -124,7 +124,7 @@ static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
|
|||
struct in_addr *in)
|
||||
{
|
||||
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 0;
|
||||
case IPADDR_V6:
|
||||
return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6,
|
||||
sizeof(a->ipaddr_v6));
|
||||
return memcmp(&a->ipaddr_v6, &b->ipaddr_v6, sizeof(a->ipaddr_v6));
|
||||
case IPADDR_NONE:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
uint8_t *tag = (uint8_t *)label;
|
||||
const uint8_t *tag = (const uint8_t *)label;
|
||||
vni_t vni;
|
||||
|
||||
assert(tag);
|
||||
|
|
|
@ -72,41 +72,36 @@ skiplist_new(/* encouraged: set list.del callback on new lists */
|
|||
|
||||
extern void skiplist_free(struct skiplist *);
|
||||
|
||||
extern int skiplist_insert(register struct skiplist *l, register void *key,
|
||||
register void *value);
|
||||
extern int skiplist_insert(struct skiplist *l, void *key, void *value);
|
||||
|
||||
extern int skiplist_delete(register struct skiplist *l, register void *key,
|
||||
register void *value);
|
||||
extern int skiplist_delete(struct skiplist *l, void *key, void *value);
|
||||
|
||||
extern int skiplist_search(register struct skiplist *l, register void *key,
|
||||
void **valuePointer);
|
||||
extern int skiplist_search(struct skiplist *l, void *key, void **valuePointer);
|
||||
|
||||
extern int skiplist_first_value(register struct skiplist *l, /* in */
|
||||
register const void *key, /* in */
|
||||
extern int skiplist_first_value(struct skiplist *l, /* in */
|
||||
const void *key, /* in */
|
||||
void **valuePointer, /* in/out */
|
||||
void **cursor); /* out */
|
||||
|
||||
extern int skiplist_next_value(register struct skiplist *l, /* in */
|
||||
register const void *key, /* in */
|
||||
extern int skiplist_next_value(struct skiplist *l, /* in */
|
||||
const void *key, /* in */
|
||||
void **valuePointer, /* in/out */
|
||||
void **cursor); /* in/out */
|
||||
|
||||
extern int skiplist_first(register struct skiplist *l, void **keyPointer,
|
||||
void **valuePointer);
|
||||
extern int skiplist_first(struct skiplist *l, void **keyPointer, void **valuePointer);
|
||||
|
||||
extern int skiplist_last(register struct skiplist *l, void **keyPointer,
|
||||
void **valuePointer);
|
||||
extern int skiplist_last(struct skiplist *l, void **keyPointer, 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 **valuePointer, /* 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;
|
||||
extern void skiplist_debug(struct vty *vty, struct skiplist *l);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* generic macros for all list-like types */
|
||||
|
||||
/* to iterate using the const variants of the functions, append "_const" to
|
||||
|
@ -62,40 +64,40 @@ extern "C" {
|
|||
#define TYPESAFE_FIRST_NEXT(prefix, type) \
|
||||
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) \
|
||||
{ \
|
||||
return (type *)prefix ## _const_next(h, item); \
|
||||
return unconst(prefix ## _const_next(h, item)); \
|
||||
} \
|
||||
/* ... */
|
||||
#define TYPESAFE_LAST_PREV(prefix, type) \
|
||||
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) \
|
||||
{ \
|
||||
return (type *)prefix ## _const_prev(h, item); \
|
||||
return unconst(prefix ## _const_prev(h, item)); \
|
||||
} \
|
||||
/* ... */
|
||||
#define TYPESAFE_FIND(prefix, type) \
|
||||
macro_inline type *prefix ## _find(struct prefix##_head *h, \
|
||||
const type *item) \
|
||||
{ \
|
||||
return (type *)prefix ## _const_find(h, item); \
|
||||
return unconst(prefix ## _const_find(h, item)); \
|
||||
} \
|
||||
/* ... */
|
||||
#define TYPESAFE_FIND_CMP(prefix, type) \
|
||||
macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
|
||||
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, \
|
||||
const type *item) \
|
||||
{ \
|
||||
return (type *)prefix ## _const_find_gteq(h, item); \
|
||||
return unconst(prefix ## _const_find_gteq(h, item)); \
|
||||
} \
|
||||
/* ... */
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -62,6 +62,7 @@ vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */
|
|||
#include "vtysh/vtysh.h"
|
||||
|
||||
#pragma GCC visibility push(internal)
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
|
||||
#define MAKE_VECTOR(name, len, ...) \\
|
||||
static void * name ## _vitems[] = { __VA_ARGS__ }; \\
|
||||
|
|
Loading…
Reference in a new issue