The recent changes to get_unaligned() resulted in a new sparse warning: net/rds/ib_cm.c:96:35: sparse: sparse: incorrect type in argument 1 (different modifiers) @@ expected void * @@ got restricted __be64 const * @@ net/rds/ib_cm.c:96:35: sparse: expected void * net/rds/ib_cm.c:96:35: sparse: got restricted __be64 const * The updated get_unaligned_t() uses __unqual_scalar_typeof() to get an unqualified type. This works correctly for the compilers, but fails for sparse when the data type is __be64 (or any other __beNN variant). On sparse runs (C=[12]) __beNN types are annotated with __attribute__((bitwise)). That annotation allows sparse to detect incompatible operations on __beNN variables, but it also prevents sparse from evaluating the _Generic() in __unqual_scalar_typeof() and map __beNN to a unqualified scalar type, so it ends up with the default, i.e. the original qualified type of a 'const __beNN' pointer. That then ends up as the first pointer argument to builtin_memcpy(), which obviously causes the above sparse warnings. The sparse git tree supports typeof_unqual() now, which allows to use it instead of the _Generic() based __unqual_scalar_typeof(). With that sparse correctly evaluates the unqualified type and keeps the __beNN logic intact. The downside is that this requires a top of tree sparse build and an old sparse version will emit a metric ton of incomprehensible error messages before it dies with a segfault. Therefore implement a sanity check which validates that the checker is available and capable of handling typeof_unqual(). Emit a warning if not so the user can take informed action. [ tglx: Move the evaluation of USE_TYPEOF_UNQUAL to compiler_types.h so it is set before use and implement the sanity checker ]
Unified · Split
| @@ -1187,6 +1187,14 @@ CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian) · 1186 unmodified lines | |||
| 1187 | # the checker needs the correct machine size | 1187 | # the checker needs the correct machine size |
| 1188 | CHECKFLAGS += $(if $(CONFIG_64BIT),-m64,-m32) | 1188 | CHECKFLAGS += $(if $(CONFIG_64BIT),-m64,-m32) |
| 1189 | 1189 | ||
| 1190 | # Validate the checker is available and functional | ||
| 1191 | ifneq ($(KBUILD_CHECKSRC), 0) | ||
| 1192 | ifneq ($(shell $(srctree)/scripts/checker-valid.sh $(CHECK) $(CHECKFLAGS)), 1) | ||
| 1193 | $(warning C=$(KBUILD_CHECKSRC) specified, but $(CHECK) is not available or not up to date) | ||
| 1194 | KBUILD_CHECKSRC = 0 | ||
| 1195 | endif | ||
| 1196 | endif | ||
| 1197 | |||
| 1190 | # Default kernel image to build when no specific target is given. | 1198 | # Default kernel image to build when no specific target is given. |
| 1191 | # KBUILD_IMAGE may be overruled on the command line or | 1199 | # KBUILD_IMAGE may be overruled on the command line or |
| 1192 | # set in the environment | 1200 | # set in the environment |
| @@ -230,16 +230,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 229 unmodified lines | |||
| 230 | __BUILD_BUG_ON_ZERO_MSG(!__is_noncstr(p), \ | 230 | __BUILD_BUG_ON_ZERO_MSG(!__is_noncstr(p), \ |
| 231 | "must be non-C-string (not NUL-terminated)") | 231 | "must be non-C-string (not NUL-terminated)") |
| 232 | 232 | ||
| 233 | /* | ||
| 234 | * Use __typeof_unqual__() when available. | ||
| 235 | * | ||
| 236 | * XXX: Remove test for __CHECKER__ once | ||
| 237 | * sparse learns about __typeof_unqual__(). | ||
| 238 | */ | ||
| 239 | #if CC_HAS_TYPEOF_UNQUAL && !defined(__CHECKER__) | ||
| 240 | # define USE_TYPEOF_UNQUAL 1 | ||
| 241 | #endif | ||
| 242 | |||
| 243 | /* | 233 | /* |
| 244 | * Define TYPEOF_UNQUAL() to use __typeof_unqual__() as typeof | 234 | * Define TYPEOF_UNQUAL() to use __typeof_unqual__() as typeof |
| 245 | * operator when available, to return an unqualified type of the exp. | 235 | * operator when available, to return an unqualified type of the exp. |
| @@ -562,6 +562,14 @@ struct ftrace_likely_data { · 561 unmodified lines | |||
| 562 | #define asm_inline asm | 562 | #define asm_inline asm |
| 563 | #endif | 563 | #endif |
| 564 | 564 | ||
| 565 | #ifndef __ASSEMBLY__ | ||
| 566 | /* | ||
| 567 | * Use __typeof_unqual__() when available. | ||
| 568 | */ | ||
| 569 | #if CC_HAS_TYPEOF_UNQUAL || defined(__CHECKER__) | ||
| 570 | # define USE_TYPEOF_UNQUAL 1 | ||
| 571 | #endif | ||
| 572 | |||
| 565 | /* Are two types/vars the same type (ignoring qualifiers)? */ | 573 | /* Are two types/vars the same type (ignoring qualifiers)? */ |
| 566 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) | 574 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) |
| 567 | 575 | ||
| @@ -569,6 +577,7 @@ struct ftrace_likely_data { · 1 unmodified line | |||
| 569 | * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving | 577 | * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving |
| 570 | * non-scalar types unchanged. | 578 | * non-scalar types unchanged. |
| 571 | */ | 579 | */ |
| 580 | #ifndef USE_TYPEOF_UNQUAL | ||
| 572 | /* | 581 | /* |
| 573 | * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' | 582 | * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' |
| 574 | * is not type-compatible with 'signed char', and we define a separate case. | 583 | * is not type-compatible with 'signed char', and we define a separate case. |
| @@ -586,6 +595,10 @@ struct ftrace_likely_data { · 11 unmodified lines | |||
| 586 | __scalar_type_to_expr_cases(long), \ | 595 | __scalar_type_to_expr_cases(long), \ |
| 587 | __scalar_type_to_expr_cases(long long), \ | 596 | __scalar_type_to_expr_cases(long long), \ |
| 588 | default: (x))) | 597 | default: (x))) |
| 598 | #else | ||
| 599 | #define __unqual_scalar_typeof(x) __typeof_unqual__(x) | ||
| 600 | #endif | ||
| 601 | #endif /* !__ASSEMBLY__ */ | ||
| 589 | 602 | ||
| 590 | /* Is this type a native word size -- useful for atomic operations */ | 603 | /* Is this type a native word size -- useful for atomic operations */ |
| 591 | #define __native_word(t) \ | 604 | #define __native_word(t) \ |
| @@ -0,0 +1,19 @@ | |||
| 1 | #!/bin/sh -eu | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | [ ! -x "$(command -v "$1")" ] && exit 1 | ||
| 5 | |||
| 6 | tmp_file=$(mktemp) | ||
| 7 | trap "rm -f $tmp_file" EXIT | ||
| 8 | |||
| 9 | cat << EOF >$tmp_file | ||
| 10 | static inline int u(const int *q) | ||
| 11 | { | ||
| 12 | __typeof_unqual__(*q) v = *q; | ||
| 13 | return v; | ||
| 14 | } | ||
| 15 | EOF | ||
| 16 | |||
| 17 | # sparse happily exits with 0 on error so validate | ||
| 18 | # there is none on stderr. Use awk as grep is a pain with sh -e | ||
| 19 | $@ $tmp_file 2>&1 | awk -v c=1 '/error/{c=0}END{print c}' | ||