From: Bart Van Assche <bvanassche@acm.org>
To: linux-sparse@vger.kernel.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Bart Van Assche <bvanassche@acm.org>
Subject: [PATCH 03/73] typeof_unqual: Strip qualifiers and address space from types and arrays
Date: Mon, 9 Nov 2026 12:31:49 -0800 [thread overview]
Message-ID: <20261109203259.362845-4-bvanassche@acm.org> (raw)
In-Reply-To: <20261109203259.362845-1-bvanassche@acm.org>
Examine the target symbol type and clear MOD_QUALIFIER, non-array
MOD_ATOMIC, and ctype.as in typeof_specifier_helper() and
examine_typeof_helper() when qual is false. Add strip_array_qualifiers()
to recursively clone SYM_ARRAY chains and strip element qualifiers and
address spaces without mutating shared typedef or declaration symbols,
while preserving MOD_ATOMIC on array element types per ISO C23 6.7.2.5p4.
Ensure that typeof_unqual() and __typeof_unqual__() remove qualifiers and
address spaces from type names, expressions, and qualified array types
instead of retaining qualifiers on the resulting type.
Fixes: dc9efe442b89 ("sparse: implement typeof_unqual()")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
parse.c | 8 +++
symbol.c | 32 +++++++++-
symbol.h | 1 +
validation/c23-typeof-unqual.c | 113 +++++++++++++++++++++++++++++++++
4 files changed, 151 insertions(+), 3 deletions(-)
create mode 100644 validation/c23-typeof-unqual.c
diff --git a/parse.c b/parse.c
index 1a889ccb6a90..f349cc75bff4 100644
--- a/parse.c
+++ b/parse.c
@@ -1070,6 +1070,14 @@ static struct token *typeof_specifier_helper(struct token *token, struct symbol
if (lookup_type(token->next)) {
struct symbol *sym;
token = typename(token->next, &sym, NULL);
+ sym = examine_symbol_type(sym);
+ if (!qual) {
+ sym->ctype.modifiers &= ~MOD_QUALIFIER;
+ if (!sym->ctype.base_type || sym->ctype.base_type->type != SYM_ARRAY)
+ sym->ctype.modifiers &= ~MOD_ATOMIC;
+ sym->ctype.as = NULL;
+ sym->ctype.base_type = strip_array_qualifiers(sym->ctype.base_type);
+ }
ctx->ctype.base_type = sym->ctype.base_type;
apply_ctype(token->pos, &ctx->ctype, &sym->ctype);
} else {
diff --git a/symbol.c b/symbol.c
index 7060acb666d9..5470880db271 100644
--- a/symbol.c
+++ b/symbol.c
@@ -541,6 +541,27 @@ static struct symbol *examine_pointer_type(struct symbol *sym)
return sym;
}
+struct symbol *strip_array_qualifiers(struct symbol *type)
+{
+ struct symbol *elem, *copy;
+ unsigned long strip;
+
+ if (!type)
+ return NULL;
+ if (type->type != SYM_ARRAY && type->type != SYM_NODE)
+ return type;
+ elem = strip_array_qualifiers(type->ctype.base_type);
+ strip = type->ctype.modifiers & MOD_QUALIFIER;
+ if (elem == type->ctype.base_type && !strip && !type->ctype.as)
+ return type;
+ copy = alloc_symbol(type->pos, type->type);
+ *copy = *type;
+ copy->ctype.base_type = elem;
+ copy->ctype.modifiers &= ~MOD_QUALIFIER;
+ copy->ctype.as = NULL;
+ return copy;
+}
+
static struct symbol *examine_typeof_helper(struct symbol *sym, bool qual)
{
struct symbol *base = evaluate_expression(sym->initializer);
@@ -548,12 +569,17 @@ static struct symbol *examine_typeof_helper(struct symbol *sym, bool qual)
if (!base)
base = &bad_ctype;
- if (base->type == SYM_NODE) {
+ while (base->type == SYM_NODE) {
mod |= base->ctype.modifiers & MOD_TYPEOF;
- if (!qual)
- mod &= ~MOD_QUALIFIER;
base = base->ctype.base_type;
}
+ if (!qual) {
+ mod &= ~MOD_QUALIFIER;
+ if (base->type != SYM_ARRAY)
+ mod &= ~MOD_ATOMIC;
+ sym->ctype.as = NULL;
+ base = strip_array_qualifiers(base);
+ }
if (base->type == SYM_BITFIELD)
warning(base->pos, "typeof applied to bitfield type");
sym->type = SYM_NODE;
diff --git a/symbol.h b/symbol.h
index 3552d4391621..9ff2733021b8 100644
--- a/symbol.h
+++ b/symbol.h
@@ -351,6 +351,7 @@ extern void add_symbol(struct symbol_list **, struct symbol *);
extern void bind_symbol(struct symbol *, struct ident *, enum namespace);
extern void bind_symbol_with_scope(struct symbol *, struct ident *, enum namespace, struct scope *);
+extern struct symbol *strip_array_qualifiers(struct symbol *);
extern struct symbol *examine_symbol_type(struct symbol *);
extern struct symbol *examine_pointer_target(struct symbol *);
extern const char *show_as(struct ident *as);
diff --git a/validation/c23-typeof-unqual.c b/validation/c23-typeof-unqual.c
new file mode 100644
index 000000000000..5738fafd2fca
--- /dev/null
+++ b/validation/c23-typeof-unqual.c
@@ -0,0 +1,113 @@
+/* Test typeof_unqual on type names */
+typedef const int const_int;
+typedef typeof_unqual(const_int) unqual_int;
+
+typedef volatile int vol_int;
+typedef typeof_unqual(vol_int) nonvol_int;
+
+typedef int * const const_ptr;
+typedef typeof_unqual(const_ptr) mod_ptr;
+
+typedef _Atomic int atomic_int;
+typedef typeof_unqual(atomic_int) nonatomic_int;
+
+typedef const int ca[3];
+typedef typeof_unqual(ca) unqual_ca;
+
+typedef const int cmatrix[2][3];
+typedef typeof_unqual(cmatrix) unqual_matrix;
+
+typedef const _Atomic int const_atomic_arr[2];
+typedef typeof_unqual(const_atomic_arr) unqual_atomic_arr;
+
+typedef const int *cip_arr_t[2];
+typedef int * const cpi_arr_t[2];
+
+#ifdef __CHECKER__
+typedef int __attribute__((address_space(1))) as1_int;
+typedef typeof_unqual(as1_int) as0_int;
+typedef int __attribute__((address_space(1))) as1_arr[2];
+typedef typeof_unqual(as1_arr) as0_arr;
+#endif
+
+_Static_assert(!__builtin_types_compatible_p(ca *, int (*)[3]), "ca stays const");
+_Static_assert(__builtin_types_compatible_p(ca *, const int (*)[3]), "ca is const int[3]");
+_Static_assert(__builtin_types_compatible_p(unqual_ca *, int (*)[3]), "unqual_ca strips const");
+_Static_assert(!__builtin_types_compatible_p(cmatrix *, int (*)[2][3]), "cmatrix stays const");
+_Static_assert(__builtin_types_compatible_p(unqual_matrix *, int (*)[2][3]), "unqual_matrix strips const");
+_Static_assert(!__builtin_types_compatible_p(const_atomic_arr *, _Atomic int (*)[2]), "const_atomic_arr stays const");
+_Static_assert(__builtin_types_compatible_p(unqual_atomic_arr *, _Atomic int (*)[2]), "unqual_atomic_arr strips const, keeps _Atomic");
+_Static_assert(__builtin_types_compatible_p(typeof_unqual(cip_arr_t) *, const int *(*)[2]), "pointee const kept");
+_Static_assert(!__builtin_types_compatible_p(typeof_unqual(cip_arr_t) *, int *(*)[2]), "pointee const not stripped");
+_Static_assert(__builtin_types_compatible_p(typeof_unqual(cpi_arr_t) *, int *(*)[2]), "element ptr const stripped");
+
+static void test_types(void)
+{
+ unqual_int a = 1;
+ a = 2;
+
+ mod_ptr p = (void *)0;
+ p = (int *)0;
+
+ unqual_ca b;
+ b[0] = 1;
+
+ unqual_matrix u;
+ u[0][0] = 1;
+
+ unqual_atomic_arr na;
+ na[0] = 1;
+
+ typeof_unqual(cpi_arr_t) ucpi;
+ ucpi[0] = (int *)0;
+
+#ifdef __CHECKER__
+ as0_int x = 0;
+ int *px = &x;
+ (void)px;
+
+ as0_arr ax;
+ int *pax = ax;
+ (void)pax;
+#endif
+}
+
+/* Test typeof_unqual on expressions */
+static void test_exprs(const int c, _Atomic int a)
+{
+ typeof_unqual(c) uc = 10;
+ uc = 20;
+
+ typeof_unqual(a) ua = 30;
+ ua = 40;
+
+ const int arr[3] = { 0 };
+ typeof_unqual(arr) uarr;
+ uarr[0] = 1;
+ _Static_assert(!__builtin_types_compatible_p(typeof(&arr), int (*)[3]), "arr stays const");
+ _Static_assert(__builtin_types_compatible_p(typeof(&uarr), int (*)[3]), "uarr is int[3]");
+
+ const int m[2][3] = { { 0 } };
+ typeof_unqual(m) um;
+ um[0][0] = 1;
+ _Static_assert(!__builtin_types_compatible_p(typeof(&m), int (*)[2][3]), "m stays const");
+ _Static_assert(__builtin_types_compatible_p(typeof(&um), int (*)[2][3]), "um is int[2][3]");
+
+ const _Atomic int aa[2] = { 0 };
+ typeof_unqual(aa) uaa;
+ uaa[0] = 1;
+ _Static_assert(!__builtin_types_compatible_p(typeof(&aa), _Atomic int (*)[2]), "aa stays const");
+ _Static_assert(__builtin_types_compatible_p(typeof(&uaa), _Atomic int (*)[2]), "uaa is _Atomic int[2]");
+
+#ifdef __CHECKER__
+ static int __attribute__((address_space(1))) asa[2];
+ typeof_unqual(asa) uasa;
+ int *p = uasa;
+ (void)p;
+#endif
+}
+
+/*
+ * check-name: c23-typeof-unqual
+ * check-command: sparse $file
+ */
next prev parent reply other threads:[~2026-11-09 20:33 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 20:31 Bart Van Assche
2026-11-09 20:31 ` [PATCH 01/73] Makefile: Pass '--' to rm in clean target to handle dash-prefixed files Bart Van Assche
2026-11-09 20:31 ` [PATCH 02/73] sparse-llvm: Use LLVMCreateBuilderForModule() with LLVM 24 and later Bart Van Assche
2026-11-09 20:31 ` Bart Van Assche [this message]
2026-11-09 20:31 ` [PATCH 04/73] bitfield: Pack consecutive _Bool bitfields into byte containers Bart Van Assche
2026-11-09 20:31 ` [PATCH 05/73] allocate: Harden slab allocation bounds, zeroing, and mmap checks Bart Van Assche
2026-11-09 20:31 ` [PATCH 06/73] tokenize: Support 4096-byte identifiers and fix escape bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 07/73] pre-process: Fix macro expansion and include directive handling Bart Van Assche
2026-11-09 20:31 ` [PATCH 08/73] options, lib: Harden warning buffers and command-line option parsing Bart Van Assche
2026-11-09 20:31 ` [PATCH 09/73] builtin: Fix atomic builtin type checking and object_size bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 10/73] parse, show-parse: Fix attribute propagation, enum overflow, and bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 11/73] target-openrisc: Set target_openrisc.mach to MACH_OPENRISC Bart Van Assche
2026-11-09 20:31 ` [PATCH 12/73] evaluate: Fix pointer arithmetic, incomplete types, and qualifiers Bart Van Assche
2026-11-09 20:31 ` [PATCH 13/73] expand: Fix static initializer folding and floating-point casts Bart Van Assche
2026-11-09 20:32 ` [PATCH 14/73] inline: Copy union cast types and VLA bounds when inlining Bart Van Assche
2026-11-09 20:32 ` [PATCH 15/73] linearize, flow: Fix asm operands, switch case bounds, and DSE Bart Van Assche
2026-11-09 20:32 ` [PATCH 16/73] memops, ssa: Walk parent insns in reverse and skip mixed-size SSA Bart Van Assche
2026-11-09 20:32 ` [PATCH 17/73] simplify: Prevent overflow on LLONG_MIN negation and fix simplifications Bart Van Assche
2026-11-09 20:32 ` [PATCH 18/73] sparse: Gate context failure warning on Wcontext and catch underflow Bart Van Assche
2026-11-09 20:32 ` [PATCH 19/73] ast-model: Return AST_N_COLUMNS and inspect child nodes lazily Bart Van Assche
2026-11-09 20:32 ` [PATCH 20/73] c2xml: Guard against recursive symbols and free xmlGetProp() string Bart Van Assche
2026-11-09 20:32 ` [PATCH 21/73] compile-i386: Fix buffer bounds, unsigned '<=' codegen, and null checks Bart Van Assche
2026-11-09 20:32 ` [PATCH 22/73] ctags: Fix line comparison order and handle SYM_RESTRICT and SYM_LABEL Bart Van Assche
2026-11-09 20:32 ` [PATCH 23/73] dissect: Unwrap array element type via base_type() Bart Van Assche
2026-11-09 20:32 ` [PATCH 24/73] example: Fix show_op() rotating buffer dimensions Bart Van Assche
2026-11-09 20:32 ` [PATCH 25/73] graph: Check PSEUDO_SYM before dereferencing insn->func->sym Bart Van Assche
2026-11-09 20:32 ` [PATCH 26/73] scheck: Fix slice() upper bit index calculation Bart Van Assche
2026-11-09 20:32 ` [PATCH 27/73] sparse-llvm: Support arbitrary struct member counts and fix operand types Bart Van Assche
2026-11-09 20:32 ` [PATCH 28/73] inline: Duplicate generic expressions instead of evaluating them Bart Van Assche
2026-11-09 20:32 ` [PATCH 29/73] lib: Avoid mutating fmt before va_start() in warning() Bart Van Assche
2026-11-09 20:32 ` [PATCH 30/73] cse, canon: Cast pointers to uintptr_t before relational comparison Bart Van Assche
2026-11-09 20:32 ` [PATCH 31/73] context: Add "conditional context increment" model Bart Van Assche
2026-11-09 20:32 ` [PATCH 32/73] expand: Simplify signed constants early Bart Van Assche
2026-11-09 20:32 ` [PATCH 33/73] bitwise: Allow all-bits-set as a restricted value Bart Van Assche
2026-11-09 20:32 ` [PATCH 34/73] bitwise: Allow restricted ordered compares with unrestricted values Bart Van Assche
2026-11-09 20:32 ` [PATCH 35/73] bitwise: Keep unrestricted values unrestricted after a cast Bart Van Assche
2026-11-09 20:32 ` [PATCH 36/73] bitwise: Don't remove MOD_SPECIFIER from 'bitwise' types Bart Van Assche
2026-11-09 20:32 ` [PATCH 37/73] bitwise: Allow both regular casts and forced casts for restricted values Bart Van Assche
2026-11-09 20:32 ` [PATCH 38/73] clang-format: Add .clang-format configuration file Bart Van Assche
2026-11-09 20:32 ` [PATCH 39/73] options: Add support for -std=c23, -std=c2x and -std=gnu23 Bart Van Assche
2026-11-09 20:32 ` [PATCH 40/73] preprocessor: Add support for #elifdef and #elifndef Bart Van Assche
2026-11-09 20:32 ` [PATCH 41/73] preprocessor: Add support for __has_include and __has_include_next Bart Van Assche
2026-11-09 20:32 ` [PATCH 42/73] c23: Add support for static_assert, alignas, alignof, thread_local Bart Van Assche
2026-11-09 20:32 ` [PATCH 43/73] c23: Add support for bool, true, and false keywords Bart Van Assche
2026-11-09 20:32 ` [PATCH 44/73] c23: Add support for nullptr and nullptr_t Bart Van Assche
2026-11-09 20:32 ` [PATCH 45/73] c23: Add support for digit separators in numeric literals Bart Van Assche
2026-11-09 20:32 ` [PATCH 46/73] c23: Support unnamed parameters in function definitions Bart Van Assche
2026-11-09 20:32 ` [PATCH 47/73] c23: Support variadic functions without named parameters Bart Van Assche
2026-11-09 20:32 ` [PATCH 48/73] c23: Support labels before declarations and at block ends Bart Van Assche
2026-11-09 20:32 ` [PATCH 49/73] c23: Support auto type inference Bart Van Assche
2026-11-09 20:32 ` [PATCH 50/73] c23: Support constexpr object specifier Bart Van Assche
2026-11-09 20:32 ` [PATCH 51/73] c23: Support enumerations with fixed underlying types Bart Van Assche
2026-11-09 20:32 ` [PATCH 52/73] c23: Support standard [[]] attribute syntax Bart Van Assche
2026-11-09 20:32 ` [PATCH 53/73] preprocessor: Add support for __has_c_attribute Bart Van Assche
2026-11-09 20:32 ` [PATCH 54/73] c23: Support empty initializer braces {} Bart Van Assche
2026-11-09 20:32 ` [PATCH 55/73] preprocessor: Add support for __has_embed Bart Van Assche
2026-11-09 20:32 ` [PATCH 56/73] preprocessor: Add support for #embed directive Bart Van Assche
2026-11-09 20:32 ` [PATCH 57/73] c23: Add support for u8 character constants and string literals Bart Van Assche
2026-11-09 20:32 ` [PATCH 58/73] preprocessor: Add support for __VA_OPT__ Bart Van Assche
2026-11-09 20:32 ` [PATCH 59/73] c23: Treat empty parameter list () as (void) and reject K&R functions Bart Van Assche
2026-11-09 20:32 ` [PATCH 60/73] c23: Support storage-class specifiers in compound literals Bart Van Assche
2026-11-09 20:32 ` [PATCH 61/73] c23: Add support for _BitInt(N) Bart Van Assche
2026-11-09 20:32 ` [PATCH 62/73] enum: Support machine mode attributes on enumeration types Bart Van Assche
2026-11-09 20:32 ` [PATCH 63/73] enum: Support __attribute__((packed)) " Bart Van Assche
2026-11-09 20:32 ` [PATCH 64/73] expand: Ignore top-level non-array address space in compare_types() Bart Van Assche
2026-11-09 20:32 ` [PATCH 65/73] builtin: Support __builtin_infer_alloc_token() as a size_t ICE Bart Van Assche
2026-11-09 20:32 ` [PATCH 66/73] builtin: Add support for Linux kernel compiler builtins Bart Van Assche
2026-11-09 20:32 ` [PATCH 67/73] builtin: Add support for __builtin_has_attribute() Bart Van Assche
2026-11-09 20:32 ` [PATCH 68/73] cleanup: Support __attribute__((cleanup(...))) in linearize and -Wcontext Bart Van Assche
2026-11-09 20:32 ` [PATCH 69/73] builtin: Do not evaluate __builtin_clz(0) and __builtin_ctz(0) Bart Van Assche
2026-11-09 20:32 ` [PATCH 70/73] pre-process: Support long token and string expansions dynamically Bart Van Assche
2026-11-09 20:32 ` [PATCH 71/73] x86: Undefine conflicting bitness macros when parsing -m flags Bart Van Assche
2026-11-09 20:32 ` [PATCH 72/73] evaluate: Accept conditional expressions with only one void side Bart Van Assche
2026-11-09 20:32 ` [PATCH 73/73] ci: Add Linux kernel GitHub Actions workflow and build script Bart Van Assche
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261109203259.362845-4-bvanassche@acm.org \
--to=bvanassche@acm.org \
--cc=linux-sparse@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox