Re: [PATCH tip/locking/core] compiler-context-analysis: Bump required Clang version to 23
From: Nathan Chancellor
Date: Mon Mar 30 2026 - 10:32:08 EST
On Mon, Mar 30, 2026 at 04:09:50PM +0200, Marco Elver wrote:
> Clang 23 introduces support for multiple arguments in the `guarded_by`
> and `pt_guarded_by` attributes [1]. This allows defining variables
> protected by multiple context locks, where read access requires holding
> at least one lock (shared or exclusive), and write access requires
> holding all of them exclusively.
>
> Clang 23 also provides a few other improvements (such as being able to
> deal with arrays of locks [2]) that make it worthwhile bumping the
> compiler version instead of trying to make both Clang 22 and later work
> while supporting these new features.
>
> Link: https://github.com/llvm/llvm-project/pull/186838 [1]
> Link: https://github.com/llvm/llvm-project/pull/148551 [2]
> Requested-by: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> Signed-off-by: Marco Elver <elver@xxxxxxxxxx>
Fair enough. I will upload a new main snapshot to kernel.org to make it
more accessible to folks for testing.
Reviewed-by: Nathan Chancellor <nathan@xxxxxxxxxx>
> ---
> v2:
> * Bump version instead of __guarded_by_any workaround.
> ---
> Documentation/dev-tools/context-analysis.rst | 2 +-
> include/linux/compiler-context-analysis.h | 30 ++++++++++++++------
> lib/Kconfig.debug | 4 +--
> lib/test_context-analysis.c | 24 ++++++++++++++++
> 4 files changed, 49 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/dev-tools/context-analysis.rst b/Documentation/dev-tools/context-analysis.rst
> index 54d9ee28de98..8e71e1e75b5b 100644
> --- a/Documentation/dev-tools/context-analysis.rst
> +++ b/Documentation/dev-tools/context-analysis.rst
> @@ -17,7 +17,7 @@ features. To enable for Clang, configure the kernel with::
>
> CONFIG_WARN_CONTEXT_ANALYSIS=y
>
> -The feature requires Clang 22 or later.
> +The feature requires Clang 23 or later.
>
> The analysis is *opt-in by default*, and requires declaring which modules and
> subsystems should be analyzed in the respective `Makefile`::
> diff --git a/include/linux/compiler-context-analysis.h b/include/linux/compiler-context-analysis.h
> index 00c074a2ccb0..1ab2622621c3 100644
> --- a/include/linux/compiler-context-analysis.h
> +++ b/include/linux/compiler-context-analysis.h
> @@ -39,12 +39,14 @@
> # define __assumes_shared_ctx_lock(...) __attribute__((assert_shared_capability(__VA_ARGS__)))
>
> /**
> - * __guarded_by - struct member and globals attribute, declares variable
> - * only accessible within active context
> + * __guarded_by() - struct member and globals attribute, declares variable
> + * only accessible within active context
> + * @...: context lock instance pointer(s)
> *
> * Declares that the struct member or global variable is only accessible within
> - * the context entered by the given context lock. Read operations on the data
> - * require shared access, while write operations require exclusive access.
> + * the context entered by the given context lock(s). Read operations on the data
> + * require shared access to at least one of the context locks, while write
> + * operations require exclusive access to all listed context locks.
> *
> * .. code-block:: c
> *
> @@ -52,17 +54,24 @@
> * spinlock_t lock;
> * long counter __guarded_by(&lock);
> * };
> + *
> + * struct some_state {
> + * spinlock_t lock1, lock2;
> + * long counter __guarded_by(&lock1, &lock2);
> + * };
> */
> # define __guarded_by(...) __attribute__((guarded_by(__VA_ARGS__)))
>
> /**
> - * __pt_guarded_by - struct member and globals attribute, declares pointed-to
> - * data only accessible within active context
> + * __pt_guarded_by() - struct member and globals attribute, declares pointed-to
> + * data only accessible within active context
> + * @...: context lock instance pointer(s)
> *
> * Declares that the data pointed to by the struct member pointer or global
> * pointer is only accessible within the context entered by the given context
> - * lock. Read operations on the data require shared access, while write
> - * operations require exclusive access.
> + * lock(s). Read operations on the data require shared access to at least one
> + * of the context locks, while write operations require exclusive access to all
> + * listed context locks.
> *
> * .. code-block:: c
> *
> @@ -70,6 +79,11 @@
> * spinlock_t lock;
> * long *counter __pt_guarded_by(&lock);
> * };
> + *
> + * struct some_state {
> + * spinlock_t lock1, lock2;
> + * long *counter __pt_guarded_by(&lock1, &lock2);
> + * };
> */
> # define __pt_guarded_by(...) __attribute__((pt_guarded_by(__VA_ARGS__)))
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 93f356d2b3d9..09e9bd003c70 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -630,7 +630,7 @@ config DEBUG_FORCE_WEAK_PER_CPU
>
> config WARN_CONTEXT_ANALYSIS
> bool "Compiler context-analysis warnings"
> - depends on CC_IS_CLANG && CLANG_VERSION >= 220100
> + depends on CC_IS_CLANG && CLANG_VERSION >= 230000
> # Branch profiling re-defines "if", which messes with the compiler's
> # ability to analyze __cond_acquires(..), resulting in false positives.
> depends on !TRACE_BRANCH_PROFILING
> @@ -641,7 +641,7 @@ config WARN_CONTEXT_ANALYSIS
> and releasing user-definable "context locks".
>
> Clang's name of the feature is "Thread Safety Analysis". Requires
> - Clang 22.1.0 or later.
> + Clang 23 or later.
>
> Produces warnings by default. Select CONFIG_WERROR if you wish to
> turn these warnings into errors.
> diff --git a/lib/test_context-analysis.c b/lib/test_context-analysis.c
> index 06b4a6a028e0..316f4dfcda65 100644
> --- a/lib/test_context-analysis.c
> +++ b/lib/test_context-analysis.c
> @@ -159,6 +159,10 @@ TEST_SPINLOCK_COMMON(read_lock,
> struct test_mutex_data {
> struct mutex mtx;
> int counter __guarded_by(&mtx);
> +
> + struct mutex mtx2;
> + int anyread __guarded_by(&mtx, &mtx2);
> + int *anyptr __pt_guarded_by(&mtx, &mtx2);
> };
>
> static void __used test_mutex_init(struct test_mutex_data *d)
> @@ -219,6 +223,26 @@ static void __used test_mutex_cond_guard(struct test_mutex_data *d)
> }
> }
>
> +static void __used test_mutex_multiguard(struct test_mutex_data *d)
> +{
> + mutex_lock(&d->mtx);
> + (void)d->anyread;
> + (void)*d->anyptr;
> + mutex_unlock(&d->mtx);
> +
> + mutex_lock(&d->mtx2);
> + (void)d->anyread;
> + (void)*d->anyptr;
> + mutex_unlock(&d->mtx2);
> +
> + mutex_lock(&d->mtx);
> + mutex_lock(&d->mtx2);
> + d->anyread++;
> + (*d->anyptr)++;
> + mutex_unlock(&d->mtx2);
> + mutex_unlock(&d->mtx);
> +}
> +
> struct test_seqlock_data {
> seqlock_t sl;
> int counter __guarded_by(&sl);
> --
> 2.53.0.1018.g2bb0e51243-goog