Re: [PATCH] compiler: Use __typeof_unqual__() for __unqual_scalar_typeof()
Ian Rogers <[email protected]> Fri, 16 Jan 2026 21:25:19 -0800
| Newsgroups | org.kernel.vger.linux-sparse,dev.linux.lists.oe-kbuild-all,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAP-5=fUDQ6NTLWVfA2B+3022D6fZjvAksKH5EJ9Agnd1Qzvobw@mail.gmail.com> |
On Fri, Jan 16, 2026 at 10:18 AM Thomas Gleixner <[email protected]> wrote: > > From: Peter Zijlstra <[email protected]> > > 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. Wow, that's painful. Congratulations on finding the root case. Acked-by: Ian Rogers <[email protected]> Thanks, Ian > 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 ] > > Reported-by: kernel test robot <[email protected]> > Signed-off-by: Peter Zijlstra <[email protected]> > Signed-off-by: Thomas Gleixner <[email protected]> > Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/ > --- > Makefile | 8 ++++++++ > include/linux/compiler.h | 10 ---------- > include/linux/compiler_types.h | 11 +++++++++++ > scripts/checker-valid.sh | 19 +++++++++++++++++++ > 4 files changed, 38 insertions(+), 10 deletions(-) > > --- a/Makefile > +++ b/Makefile > @@ -1178,6 +1178,14 @@ ifdef CONFIG_CC_IS_CLANG > KBUILD_USERLDFLAGS += --ld-path=$(LD) > endif > > +# Validate the checker is available and functional > +ifneq ($(KBUILD_CHECKSRC), 0) > + ifneq ($(shell $(srctree)/scripts/checker-valid.sh $(CHECK)), 1) > + $(warning C=$(KBUILD_CHECKSRC) specified, but $(CHECK) is not available or not up to date) > + KBUILD_CHECKSRC = 0 > + endif > +endif > + > # make the checker run with the right architecture > CHECKFLAGS += --arch=$(ARCH) > > --- a/include/linux/compiler.h > +++ b/include/linux/compiler.h > @@ -231,16 +231,6 @@ void ftrace_likely_update(struct ftrace_ > "must be non-C-string (not NUL-terminated)") > > /* > - * Use __typeof_unqual__() when available. > - * > - * XXX: Remove test for __CHECKER__ once > - * sparse learns about __typeof_unqual__(). > - */ > -#if CC_HAS_TYPEOF_UNQUAL && !defined(__CHECKER__) > -# define USE_TYPEOF_UNQUAL 1 > -#endif > - > -/* > * Define TYPEOF_UNQUAL() to use __typeof_unqual__() as typeof > * operator when available, to return an unqualified type of the exp. > */ > --- a/include/linux/compiler_types.h > +++ b/include/linux/compiler_types.h > @@ -562,6 +562,13 @@ struct ftrace_likely_data { > #define asm_inline asm > #endif > > +/* > + * Use __typeof_unqual__() when available. > + */ > +#if CC_HAS_TYPEOF_UNQUAL || defined(__CHECKER__) > +# define USE_TYPEOF_UNQUAL 1 > +#endif > + > /* Are two types/vars the same type (ignoring qualifiers)? */ > #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) > > @@ -569,6 +576,7 @@ struct ftrace_likely_data { > * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving > * non-scalar types unchanged. > */ > +#ifndef USE_TYPEOF_UNQUAL > /* > * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' > * is not type-compatible with 'signed char', and we define a separate case. > @@ -586,6 +594,9 @@ struct ftrace_likely_data { > __scalar_type_to_expr_cases(long), \ > __scalar_type_to_expr_cases(long long), \ > default: (x))) > +#else > +#define __unqual_scalar_typeof(x) __typeof_unqual__(x) > +#endif > > /* Is this type a native word size -- useful for atomic operations */ > #define __native_word(t) \ > --- /dev/null > +++ b/scripts/checker-valid.sh > @@ -0,0 +1,19 @@ > +#!/bin/sh -eu > +# SPDX-License-Identifier: GPL-2.0 > + > +[ ! -x "$(command -v "$1")" ] && exit 1 > + > +tmp_file=$(mktemp) > +trap "rm -f $tmp_file" EXIT > + > +cat << EOF >$tmp_file > +static inline int u(const int *q) > +{ > + __typeof_unqual__(*q) v = *q; > + return v; > +} > +EOF > + > +# sparse happily exits with 0 on error so validate > +# there is none on stderr. Use awk as grep is a pain with sh -e > +$1 $tmp_file 2>&1 | awk -v c=1 '/error/{c=0}END{print c}'