Linux SPARSE checker discussions
 help / color / mirror / Atom feed
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 12/73] evaluate: Fix pointer arithmetic, incomplete types, and qualifiers
Date: Mon,  9 Nov 2026 12:31:58 -0800	[thread overview]
Message-ID: <20261109203259.362845-13-bvanassche@acm.org> (raw)
In-Reply-To: <20261109203259.362845-1-bvanassche@acm.org>

Fix type checking and qualifier handling across evaluate.c, parse.c,
symbol.c, and symbol.h:
- Distinguish forward-declared incomplete structs and unions
  (bit_size = -1) from complete GNU empty structs (bit_size = 0) via
  sym->defined, and preserve bit_size = -1 on arrays of incomplete types.
- Preserve unsigned integer index offsets in evaluate_ptr_add() and
  diagnose pointer addition and subtraction on incomplete types.
- Diagnose incomplete types in evaluate_alignof() and incomplete array or
  multi-dimensional VLA types in evaluate_generic_selection().
- Guard null index types in evaluate_offsetof(), null current_fn in
  check_label_declaration(), and symbolic '[...]' asm constraints.
- Preserve noderef and nocast qualifiers across conditional pointer
  targets and check pointee MOD_NOCAST on pointer casts.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 evaluate.c                    | 104 ++++++++++++++++++++++++++++------
 parse.c                       |   2 +
 symbol.c                      |  12 +++-
 symbol.h                      |   2 +-
 validation/eval-type-checks.c |  89 +++++++++++++++++++++++++++++
 5 files changed, 187 insertions(+), 22 deletions(-)
 create mode 100644 validation/eval-type-checks.c

diff --git a/evaluate.c b/evaluate.c
index 40778f4e8a63..0e4e64d33192 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -246,6 +246,8 @@ static struct symbol *base_type(struct symbol *node, unsigned long *modp, struct
 	return node;
 }
 
+#define MOD_IGN (MOD_QUALIFIER | MOD_FUN_ATTR)
+
 static int is_same_type(struct expression *expr, struct symbol *new)
 {
 	struct symbol *old = expr->ctype;
@@ -273,6 +275,13 @@ static int is_same_type(struct expression *expr, struct symbol *new)
 		if (difmod == MOD_CONST)
 			return 0;
 	}
+	if (old->type == SYM_PTR && new->type == SYM_PTR && oldas == newas &&
+	    (oldmod & MOD_NOCAST) == (newmod & MOD_NOCAST)) {
+		if (!type_difference(&old->ctype, &new->ctype,
+				     MOD_IGN | MOD_NODEREF, MOD_IGN | MOD_NODEREF) ||
+		    ((oldmod & MOD_NOCAST) && is_void_type(new->ctype.base_type)))
+			return 0;
+	}
 	if ((oldmod | newmod) & MOD_NOCAST) {
 		const char *tofrom = "to/from";
 		if (!(newmod & MOD_NOCAST))
@@ -588,6 +597,10 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
 		expression_error(expr, "arithmetics on pointers to functions");
 		return NULL;
 	}
+	if (!is_void_type(base) && base->bit_size < 0) {
+		expression_error(expr, "arithmetics on pointers to incomplete type");
+		return NULL;
+	}
 
 	/* Get the size of whatever the pointer points to */
 	multiply = is_void_type(base) ? 1 : bits_to_bytes(base->bit_size);
@@ -603,10 +616,10 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
 		struct expression *val = alloc_expression(expr->pos, EXPR_VALUE);
 		unsigned long long v = index->value, mask;
 		mask = sign_bit(itype->bit_size);
-		if (v & mask)
+		if (!(itype->ctype.modifiers & MOD_UNSIGNED) && (v & mask))
 			v |= -mask;
 		else
-			v &= mask - 1;
+			v &= mask | (mask - 1);
 		v *= multiply;
 		v &= bits_mask(bits_in_pointer);
 		val->value = v;
@@ -638,8 +651,6 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
 
 static void examine_fn_arguments(struct symbol *fn);
 
-#define MOD_IGN (MOD_QUALIFIER | MOD_FUN_ATTR)
-
 const char *type_difference(struct ctype *c1, struct ctype *c2,
 	unsigned long mod1, unsigned long mod2)
 {
@@ -812,6 +823,14 @@ static unsigned long target_qualifiers(struct symbol *type)
 	return mod;
 }
 
+static unsigned long cond_target_qualifiers(struct symbol *type)
+{
+	unsigned long mod = type->ctype.modifiers & (MOD_IGN | MOD_NODEREF | MOD_NOCAST);
+	if (type->ctype.base_type && type->ctype.base_type->type == SYM_ARRAY)
+		mod = 0;
+	return mod;
+}
+
 static struct symbol *evaluate_ptr_sub(struct expression *expr)
 {
 	const char *typediff;
@@ -835,6 +854,10 @@ static struct symbol *evaluate_ptr_sub(struct expression *expr)
 		expression_error(expr, "subtraction of functions? Share your drugs");
 		return NULL;
 	}
+	if (!is_void_type(lbase) && lbase->bit_size < 0) {
+		expression_error(expr, "subtraction of pointers to incomplete type");
+		return NULL;
+	}
 
 	expr->ctype = ssize_t_ctype;
 	if (lbase->bit_size > bits_in_char) {
@@ -1222,7 +1245,7 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
 		/* need to be lazier here */
 		lbase = examine_pointer_target(ltype);
 		rbase = examine_pointer_target(rtype);
-		qual = target_qualifiers(ltype) | target_qualifiers(rtype);
+		qual = cond_target_qualifiers(ltype) | cond_target_qualifiers(rtype);
 
 		if (lbase == &void_ctype) {
 			/* XXX: pointers to function should warn here */
@@ -1433,8 +1456,8 @@ static int check_assignment_types(struct symbol *target, struct expression **rp,
 		}
 		b1 = examine_pointer_target(t);
 		b2 = examine_pointer_target(s);
-		mod1 = t->ctype.modifiers & MOD_IGN;
-		mod2 = s->ctype.modifiers & MOD_IGN;
+		mod1 = t->ctype.modifiers & (MOD_IGN | MOD_NODEREF);
+		mod2 = s->ctype.modifiers & (MOD_IGN | MOD_NODEREF);
 		if (whitelist_pointers(b1, b2)) {
 			/*
 			 * assignments to/from void * are OK, provided that
@@ -2310,14 +2333,32 @@ static struct symbol *evaluate_ptrsizeof(struct expression *expr)
 	return size_t_ctype;
 }
 
+static bool is_incomplete_alignof_type(struct symbol *type, bool is_type)
+{
+	while (type && type->type == SYM_NODE)
+		type = type->ctype.base_type;
+	while (type && type->type == SYM_ARRAY) {
+		if (is_type && !type->array_size)
+			return true;
+		type = type->ctype.base_type;
+		while (type && type->type == SYM_NODE)
+			type = type->ctype.base_type;
+	}
+	return !type || (type->bit_size < 0 && type->type != SYM_FN);
+}
+
 static struct symbol *evaluate_alignof(struct expression *expr)
 {
 	struct symbol *type;
+	bool is_type = expr->cast_type != NULL;
 
 	type = evaluate_type_information(expr);
 	if (!type)
 		return NULL;
 
+	if (is_incomplete_alignof_type(type, is_type))
+		expression_error(expr, "cannot size alignment of incomplete type");
+
 	expr->type = EXPR_VALUE;
 	expr->value = type->ctype.alignment;
 	expr->taint = 0;
@@ -3268,7 +3309,11 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
 			struct expression *idx = expr->index, *m;
 			struct symbol *i_type = evaluate_expression(idx);
 			unsigned old_idx_flags;
-			int i_class = classify_type(i_type, &i_type);
+			int i_class;
+
+			if (!i_type)
+				return NULL;
+			i_class = classify_type(i_type, &i_type);
 
 			if (!is_int(i_class)) {
 				expression_error(expr, "non-integer index");
@@ -3316,7 +3361,8 @@ static void check_label_declaration(struct position pos, struct symbol *label)
 		sparse_error(pos, "label '%s' was not declared", show_ident(label->ident));
 		/* fallthrough */
 	case NS_NONE:
-		current_fn->bogus_linear = 1;
+		if (current_fn)
+			current_fn->bogus_linear = 1;
 	default:
 		break;
 	}
@@ -3337,10 +3383,14 @@ static struct symbol *evaluate_generic_selection(struct expression *expr)
 	struct symbol source;
 	struct symbol *ctrl;
 
-	if (!evaluate_expression(expr->control))
+	if (!evaluate_expression(expr->control)) {
+		expr->ctype = &bad_ctype;
 		return NULL;
-	if (!(ctrl = degenerate(expr->control)))
+	}
+	if (!(ctrl = degenerate(expr->control))) {
+		expr->ctype = &bad_ctype;
 		return NULL;
+	}
 
 	source = *ctrl;
 	source.ctype.modifiers &= ~(MOD_QUALIFIER|MOD_ATOMIC);
@@ -3352,18 +3402,31 @@ static struct symbol *evaluate_generic_selection(struct expression *expr)
 			continue;
 
 		base = stype->ctype.base_type;
-		if (base->type == SYM_ARRAY && base->array_size) {
-			get_expression_value_silent(base->array_size);
-			if (base->array_size->type == EXPR_VALUE)
+		if (base && base->type == SYM_ARRAY) {
+			bool is_vla = false;
+			struct symbol *arr = base;
+			while (arr && arr->type == SYM_ARRAY) {
+				if (arr->array_size) {
+					get_expression_value_silent(arr->array_size);
+					if (arr->array_size->type != EXPR_VALUE) {
+						is_vla = true;
+						break;
+					}
+				}
+				arr = arr->ctype.base_type;
+				while (arr && arr->type == SYM_NODE)
+					arr = arr->ctype.base_type;
+			}
+			if (is_vla) {
+				sparse_error(stype->pos, "variable length array type in generic selection");
 				continue;
-			sparse_error(stype->pos, "variable length array type in generic selection");
-			continue;
+			}
 		}
 		if (is_func_type(stype)) {
 			sparse_error(stype->pos, "function type in generic selection");
 			continue;
 		}
-		if (stype->bit_size <= 0 || is_void_type(stype)) {
+		if (stype->bit_size < 0 || is_void_type(stype)) {
 			sparse_error(stype->pos, "incomplete type in generic selection");
 			continue;
 		}
@@ -3376,6 +3439,7 @@ static struct symbol *evaluate_generic_selection(struct expression *expr)
 	res = expr->def;
 	if (!res) {
 		sparse_error(expr->pos, "no generic selection for '%s'", show_typename(ctrl));
+		expr->ctype = &bad_ctype;
 		return NULL;
 	}
 
@@ -3682,7 +3746,11 @@ static void parse_asm_constraint(struct asm_operand *op)
 			break;
 		case '[':
 			// FIXME: symbolic matching constraint
-			return;
+			while (*str && *str != ']')
+				str++;
+			if (*str == ']')
+				str++;
+			break;
 
 		default:
 			if (arch_target->asm_constraint)
diff --git a/parse.c b/parse.c
index ea90d088a244..2675a3976099 100644
--- a/parse.c
+++ b/parse.c
@@ -791,6 +791,8 @@ static struct token *struct_union_enum_specifier(enum type type,
 
 	token = parse(token->next, sym);
 	token = expect(token, '}', "at end of specifier");
+	sym->defined = 1;
+	sym->examined = 0;
 	attr.ctype.base_type = sym;
 	token = handle_attributes(token, &attr);
 	apply_ctype(token->pos, &sym->ctype, &attr.ctype);
diff --git a/symbol.c b/symbol.c
index abf3a198acc8..06cd8ca2ede7 100644
--- a/symbol.c
+++ b/symbol.c
@@ -215,6 +215,11 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance
 	void (*fn)(struct symbol *, struct struct_union_info *);
 	struct symbol *member;
 
+	if (!sym->defined) {
+		sym->bit_size = -1;
+		return sym;
+	}
+
 	fn = advance ? lay_out_struct : lay_out_union;
 	FOR_EACH_PTR(sym->symbol_list, member) {
 		if (member->ctype.base_type == &autotype_ctype) {
@@ -298,9 +303,10 @@ static struct symbol * examine_array_type(struct symbol *sym)
 	if (!base_type)
 		return sym;
 
-	if (array_size) {	
-		bit_size = array_element_offset(base_type->bit_size,
-						get_expression_value_silent(array_size));
+	if (array_size) {
+		unsigned long count = get_expression_value_silent(array_size);
+		if (base_type->bit_size >= 0)
+			bit_size = array_element_offset(base_type->bit_size, count);
 		if (array_size->type != EXPR_VALUE) {
 			if (Wvla)
 				warning(array_size->pos, "Variable length array is used.");
diff --git a/symbol.h b/symbol.h
index 9a8e58d5da28..a14686fe863b 100644
--- a/symbol.h
+++ b/symbol.h
@@ -149,7 +149,7 @@ struct symbol_op {
 struct symbol {
 	enum type type:8;
 	enum namespace namespace:9;
-	unsigned char used:1, attr:2, enum_member:1, bound:1;
+	unsigned char used:1, attr:2, enum_member:1, bound:1, defined:1;
 	struct position pos;		/* Where this symbol was declared */
 	struct position endpos;		/* Where this symbol ends*/
 	struct ident *ident;		/* What identifier this symbol is associated with */
diff --git a/validation/eval-type-checks.c b/validation/eval-type-checks.c
new file mode 100644
index 000000000000..13b3ff22210d
--- /dev/null
+++ b/validation/eval-type-checks.c
@@ -0,0 +1,89 @@
+#define __noderef __attribute__((noderef))
+#define __nocast __attribute__((nocast))
+
+struct empty {};
+struct inc;
+struct __attribute__((aligned(16))) inc_aligned;
+
+extern struct empty es;
+extern int ext_arr[];
+
+_Static_assert(_Generic(es, struct empty: 1, default: 0) == 1, "empty struct generic");
+_Static_assert(_Generic(0, int[4]: 1, default: 2) == 2, "fixed array assoc");
+_Static_assert(_Alignof(struct empty) == 1, "empty struct alignof");
+
+static unsigned long valid_alignof(int n)
+{
+	return _Alignof(int[n]) + _Alignof(void(void)) + __alignof__(ext_arr);
+}
+
+static void *valid_void_ptr_add(void *p)
+{
+	return p + 1;
+}
+
+static void test_incomplete_errors(struct inc *pi, int (*pa)[], int n)
+{
+	(void)(pi + 1);
+	(void)(pa + 1);
+	(void)_Alignof(void);
+	(void)_Alignof(int[]);
+	(void)_Alignof(struct inc);
+	(void)_Alignof(struct inc_aligned);
+	(void)_Alignof(struct inc[2]);
+	(void)_Generic(0, int[2][n]: 1, default: 0);
+	(void)_Generic(0, struct inc[2]: 1, default: 0);
+}
+
+static long test_qualifiers(int c, void *vp, void __nocast *vp_nc, int *p,
+			    int __noderef *p_nd, int __nocast *p_nc)
+{
+	void __nocast *ok_both_nc = c ? vp_nc : p_nc;
+	void __nocast *ok_one_nc = c ? vp : p_nc;
+	void __noderef *ok_nd = c ? vp : p_nd;
+	int *bad_nc = c ? vp_nc : p_nc;
+	int *bad_nd = c ? vp : p_nd;
+	long r = 0;
+
+	(void)ok_both_nc;
+	(void)ok_one_nc;
+	(void)ok_nd;
+	(void)bad_nc;
+	(void)bad_nd;
+
+	r += (p_nd == p);
+	r += (p_nd - p);
+	r += (p_nc == p);
+	r += (p_nc - p);
+	return r;
+}
+
+/*
+ * check-name: eval-type-checks
+ * check-command: sparse -Wno-vla $file
+ *
+ * check-error-start
+eval-type-checks.c:27:19: error: arithmetics on pointers to incomplete type
+eval-type-checks.c:28:19: error: arithmetics on pointers to incomplete type
+eval-type-checks.c:29:15: error: cannot size alignment of incomplete type
+eval-type-checks.c:30:15: error: cannot size alignment of incomplete type
+eval-type-checks.c:31:15: error: cannot size alignment of incomplete type
+eval-type-checks.c:32:15: error: cannot size alignment of incomplete type
+eval-type-checks.c:33:15: error: cannot size alignment of incomplete type
+eval-type-checks.c:34:27: error: variable length array type in generic selection
+eval-type-checks.c:35:27: error: incomplete type in generic selection
+eval-type-checks.c:42:40: warning: implicit cast to nocast type
+eval-type-checks.c:44:25: warning: implicit cast from nocast type
+eval-type-checks.c:45:25: warning: incorrect type in initializer (different modifiers)
+eval-type-checks.c:45:25:    expected int *bad_nd
+eval-type-checks.c:45:25:    got void [noderef] *
+eval-type-checks.c:54:20: error: incompatible types in comparison expression (different modifiers):
+eval-type-checks.c:54:20:    int [noderef] *
+eval-type-checks.c:54:20:    int *
+eval-type-checks.c:55:20: error: subtraction of different types can't work (different modifiers)
+eval-type-checks.c:56:20: error: incompatible types in comparison expression (different modifiers):
+eval-type-checks.c:56:20:    int [nocast] *
+eval-type-checks.c:56:20:    int *
+eval-type-checks.c:57:20: error: subtraction of different types can't work (different modifiers)
+ * check-error-end
+ */

  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 ` [PATCH 03/73] typeof_unqual: Strip qualifiers and address space from types and arrays Bart Van Assche
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 ` Bart Van Assche [this message]
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-13-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