Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: preliminary fixes for -Wcast-qual #17936

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bgpd/bgp_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,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);
Expand Down
14 changes: 9 additions & 5 deletions lib/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@ struct ipv6_ph {

extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len);
mjstapp marked this conversation as resolved.
Show resolved Hide resolved

/* 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));
}
Expand All @@ -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));
}
Expand All @@ -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));
}
Expand Down
127 changes: 112 additions & 15 deletions lib/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
*
Expand All @@ -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)); \
}) \
))
#define container_of(ptr, 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. */
Expand Down
6 changes: 6 additions & 0 deletions lib/hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions lib/ipaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,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));
}

/*
Expand All @@ -144,8 +144,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;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/mpls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
45 changes: 20 additions & 25 deletions lib/skiplist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
void **valuePointer, /* in/out */
void **cursor); /* out */
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 */
void **valuePointer, /* in/out */
void **cursor); /* in/out */
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 */
void **keyPointer, /* out */
void **valuePointer, /* out */
void **cursor); /* in/out */
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);
Expand Down
16 changes: 9 additions & 7 deletions lib/typesafe.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)); \
} \
/* ... */

Expand Down
2 changes: 1 addition & 1 deletion pimd/pim_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions python/xref2vtysh.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#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__ }; \\
Expand Down
Loading