From 0bc4ac526d41483e6e9625d156d753bb3e287a19 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Tue, 25 Oct 2022 19:33:40 +0200 Subject: [PATCH 1/4] macro: Use more correct type in IN_SET This will now catch mistakes like this: struct s { int i:2; } s = { 1 }; assert_se(IN_SET(s.i, ULLONG_MAX)); > warning: implicit conversion from 'unsigned long long' to > 'typeof (+s.i)' (aka 'int') changes value from 18446744073709551615 > to -1 [-Wconstant-conversion] --- src/fundamental/macro-fundamental.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 2536c741c62..58ffaac33cb 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -282,11 +282,9 @@ #define IN_SET(x, ...) \ ({ \ bool _found = false; \ - /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ - * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ - * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ - * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \ - static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \ + /* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \ + * here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \ + static const typeof(+x) __assert_in_set[] _unused_ = { __VA_ARGS__ }; \ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ switch (x) { \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \ From 790f4dda74d7ecdb4e57101a37cc9f2f9236bef6 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Tue, 25 Oct 2022 19:55:08 +0200 Subject: [PATCH 2/4] macro: Simply case macros for IN_SET The CASE param would normally provide the operation for the compiler to do in this macro magic. But in this case CASE_F_1 was hardcoding the operation, making the parameter moot. This just removes the somewhat pointless parameter instead of fixing the one case. These macros are used for IN_SET case labels only and not named generically anyways. --- src/fundamental/macro-fundamental.h | 43 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 58ffaac33cb..3e31d08931d 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -251,33 +251,32 @@ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ }) -#define CASE_F(X) case X: -#define CASE_F_1(CASE, X) CASE_F(X) -#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) -#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) -#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) -#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) -#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) -#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) -#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) -#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) -#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) -#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) -#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) -#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) -#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) -#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) -#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) -#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) -#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) -#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) -#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) +#define CASE_F_1(X) case X: +#define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__) +#define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__) +#define CASE_F_4(X, ...) case X: CASE_F_3( __VA_ARGS__) +#define CASE_F_5(X, ...) case X: CASE_F_4( __VA_ARGS__) +#define CASE_F_6(X, ...) case X: CASE_F_5( __VA_ARGS__) +#define CASE_F_7(X, ...) case X: CASE_F_6( __VA_ARGS__) +#define CASE_F_8(X, ...) case X: CASE_F_7( __VA_ARGS__) +#define CASE_F_9(X, ...) case X: CASE_F_8( __VA_ARGS__) +#define CASE_F_10(X, ...) case X: CASE_F_9( __VA_ARGS__) +#define CASE_F_11(X, ...) case X: CASE_F_10( __VA_ARGS__) +#define CASE_F_12(X, ...) case X: CASE_F_11( __VA_ARGS__) +#define CASE_F_13(X, ...) case X: CASE_F_12( __VA_ARGS__) +#define CASE_F_14(X, ...) case X: CASE_F_13( __VA_ARGS__) +#define CASE_F_15(X, ...) case X: CASE_F_14( __VA_ARGS__) +#define CASE_F_16(X, ...) case X: CASE_F_15( __VA_ARGS__) +#define CASE_F_17(X, ...) case X: CASE_F_16( __VA_ARGS__) +#define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__) +#define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__) +#define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__) #define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME #define FOR_EACH_MAKE_CASE(...) \ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ - (CASE_F,__VA_ARGS__) + (__VA_ARGS__) #define IN_SET(x, ...) \ ({ \ From e967926b092d8635b3da28fc4ca492009e32228f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 26 Oct 2022 03:28:08 +0900 Subject: [PATCH 3/4] macro: fix indentation --- src/fundamental/macro-fundamental.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 3e31d08931d..c11a5b15f46 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -288,7 +288,7 @@ switch (x) { \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \ _found = true; \ - break; \ + break; \ default: \ break; \ } \ From dec283e0a95517958bd77009fbcf66c89dde9a6e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 26 Oct 2022 03:32:05 +0900 Subject: [PATCH 4/4] test: add test for IN_SET() with bitfield specifier --- src/test/test-macro.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 049ea2c14e1..001166d0dcc 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -209,6 +209,16 @@ TEST(in_set) { assert_se(IN_SET(4, 1, 2, 3, 4)); assert_se(!IN_SET(0, 1)); assert_se(!IN_SET(0, 1, 2, 3, 4)); + + struct { + unsigned x:3; + } t = { 1 }; + + assert_se(IN_SET(t.x, 1)); + assert_se(IN_SET(t.x, 1, 2, 3, 4)); + assert_se(IN_SET(t.x, 2, 3, 4, 1)); + assert_se(!IN_SET(t.x, 0)); + assert_se(!IN_SET(t.x, 2, 3, 4)); } TEST(foreach_pointer) {