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 63/73] enum: Support __attribute__((packed)) on enumeration types
Date: Mon,  9 Nov 2026 12:32:49 -0800	[thread overview]
Message-ID: <20261109203259.362845-64-bvanassche@acm.org> (raw)
In-Reply-To: <20261109203259.362845-1-bvanassche@acm.org>

Support GCC/Clang __attribute__((packed)) on enumeration types so
packed enums select the narrowest integer type fitting their range:
- Define get_enum_base_type() and record the enumerator range on the
  enum symbol so prefix and postfix packed attributes shrink the enum
  size and alignment.
- Preserve sym->packed across subsequent tag lookups with '|=' instead
  of '='.
- Warn when both 'packed' and 'aligned' attributes are applied to an
  enum type since Clang and GCC treat that combination differently, and
  diagnose array element types whose size is not a multiple of their
  alignment in examine_array_type().
- Avoid overwriting invalid (&bad_ctype), incomplete, bitwise
  (SYM_RESTRICT), mode-attributed, or C23 fixed-underlying-type enums.
- Add regression tests in validation/enum-packed.c.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 parse.c                  | 92 +++++++++++++++++-----------------------
 symbol.c                 | 87 ++++++++++++++++++++++++++++++++++---
 symbol.h                 | 10 +++++
 validation/enum-packed.c | 85 +++++++++++++++++++++++++++++++++++++
 4 files changed, 214 insertions(+), 60 deletions(-)
 create mode 100644 validation/enum-packed.c

diff --git a/parse.c b/parse.c
index b686d2d55c36..3235274e6659 100644
--- a/parse.c
+++ b/parse.c
@@ -891,6 +891,8 @@ static struct token *struct_union_enum_specifier(enum type type,
 				sym->rank = underlying->rank;
 			}
 			token = handle_attributes(token, &attr);
+			sym->packed |= attr.packed;
+			sym->has_aligned |= attr.has_aligned;
 			if (!match_op(token, '{')) {
 				ctx->opaque_fixed_enum = 1;
 				ctx->opaque_fixed_enum_pos = colon_pos;
@@ -972,6 +974,8 @@ static struct token *struct_union_enum_specifier(enum type type,
 		return token;
 	}
 
+	sym->packed |= attr.packed;
+	sym->has_aligned |= attr.has_aligned;
 	token = parse(token->next, sym);
 	token = expect(token, '}', "at end of specifier");
 	sym->defined = 1;
@@ -979,7 +983,11 @@ static struct token *struct_union_enum_specifier(enum type type,
 	attr.ctype.base_type = sym;
 	token = handle_attributes(token, &attr);
 	apply_ctype(token->pos, &sym->ctype, &attr.ctype);
-	sym->packed = attr.packed;
+	sym->packed |= attr.packed;
+	sym->has_aligned |= attr.has_aligned;
+	if (sym->type == SYM_ENUM && sym->packed && sym->has_aligned)
+		warning(sym->pos,
+			"Clang and GCC treat 'packed' and 'aligned' attributes on enum types differently");
 	if (attr.designated_init) {
 		if (sym->type == SYM_STRUCT)
 			sym->designated_init = 1;
@@ -1006,6 +1014,16 @@ static struct token *struct_union_enum_specifier(enum type type,
 			sym->rank = mtype->rank;
 		}
 	}
+	if (sym->type == SYM_ENUM && sym->packed && !sym->fixed_type &&
+	    !sym->has_mode && sym->ctype.base_type &&
+	    is_int_type(sym->ctype.base_type)) {
+		struct symbol *base = get_enum_base_type(sym->range, 1);
+		if (base && base != &bad_ctype) {
+			sym->ctype.base_type = base;
+			sym->ctype.modifiers &= ~MOD_SIGNEDNESS;
+			sym->ctype.modifiers |= (base->ctype.modifiers & MOD_SIGNEDNESS);
+		}
+	}
 
 	sym->endpos = token->pos;
 
@@ -1045,24 +1063,6 @@ static struct token *union_specifier(struct token *token, struct symbol *sym, st
 	return struct_union_enum_specifier(SYM_UNION, token, ctx, parse_union_declaration);
 }
 
-///
-// safe right shift
-//
-// This allow to use a shift amount as big (or bigger)
-// than the width of the value to be shifted, in which case
-// the result is, of course, 0.
-static unsigned long long rshift(unsigned long long val, unsigned int n)
-{
-	if (n >= (sizeof(val) * 8))
-		return 0;
-	return val >> n;
-}
-
-struct range {
-	long long		neg;
-	unsigned long long	pos;
-};
-
 static void update_range(struct range *range, unsigned long long uval, struct symbol *vtype)
 {
 	long long sval = uval;
@@ -1076,24 +1076,6 @@ static void update_range(struct range *range, unsigned long long uval, struct sy
 	}
 }
 
-static int type_is_ok(struct symbol *type, struct range range)
-{
-	int shift = type->bit_size;
-	int is_unsigned = type->ctype.modifiers & MOD_UNSIGNED;
-
-	if (!is_unsigned)
-		shift--;
-	if (rshift(range.pos, shift))
-		return 0;
-	if (range.neg == 0)
-		return 1;
-	if (is_unsigned)
-		return 0;
-	if (rshift(~range.neg, shift))
-		return 0;
-	return 1;
-}
-
 static struct range type_range(struct symbol *type)
 {
 	struct range range;
@@ -1315,20 +1297,9 @@ static struct token *parse_enum_declaration(struct token *token, struct symbol *
 			base_type = &bad_ctype;
 		} else if (!is_int_type(base_type))
 			;
-		else if (type_is_ok(&uint_ctype, range))
-			base_type = &uint_ctype;
-		else if (type_is_ok(&int_ctype, range))
-			base_type = &int_ctype;
-		else if (type_is_ok(&ulong_ctype, range))
-			base_type = &ulong_ctype;
-		else if (type_is_ok(&long_ctype, range))
-			base_type = &long_ctype;
-		else if (type_is_ok(&ullong_ctype, range))
-			base_type = &ullong_ctype;
-		else if (type_is_ok(&llong_ctype, range))
-			base_type = &llong_ctype;
 		else
-			base_type = &bad_ctype;
+			base_type = get_enum_base_type(range, parent->packed);
+		parent->range = range;
 		parent->ctype.base_type = base_type;
 		parent->ctype.modifiers |=
 			(base_type->ctype.modifiers & MOD_UNSIGNED);
@@ -1491,10 +1462,9 @@ static struct token *ignore_attribute(struct token *token, struct symbol *attr,
 
 static struct token *attribute_packed(struct token *token, struct symbol *attr, struct decl_state *ctx)
 {
-	if (!ctx->ctype.alignment) {
+	if (!ctx->ctype.alignment)
 		ctx->ctype.alignment = 1;
-		ctx->packed = 1;
-	}
+	ctx->packed = 1;
 	return token;
 }
 
@@ -1513,6 +1483,7 @@ static struct token *attribute_aligned(struct token *token, struct symbol *attr,
 		return token;
 	} else if (alignment > ctx->ctype.alignment)
 		ctx->ctype.alignment = alignment;
+	ctx->has_aligned = 1;
 	return token;
 }
 
@@ -2004,6 +1975,8 @@ static struct token *declaration_specifiers(struct token *token, struct decl_sta
 			seen |= Set_S | Set_T;
 			ctx->ctype.base_type = s->ctype.base_type;
 			apply_ctype(token->pos, &ctx->ctype, &s->ctype);
+			if (s->ctype.alignment > ctx->typedef_alignment)
+				ctx->typedef_alignment = s->ctype.alignment;
 			token = token->next;
 			continue;
 		}
@@ -2422,12 +2395,14 @@ static struct token *direct_declarator(struct token *token, struct decl_state *c
 	} else if (match_op(token, '(') &&
 	    is_nested(token, &next, ctx->prefer_abstract)) {
 		struct symbol *base_type = ctype->base_type;
+		unsigned int saved_td_align = ctx->typedef_alignment;
 		if (token->next != next)
 			next = handle_attributes(token->next, ctx);
 		token = declarator(next, ctx);
 		token = expect(token, ')', "in nested declarator");
 		while (ctype->base_type != base_type)
 			ctype = &ctype->base_type->ctype;
+		ctx->typedef_alignment = saved_td_align;
 		p = NULL;
 	}
 
@@ -2459,6 +2434,7 @@ static struct token *direct_declarator(struct token *token, struct decl_state *c
 		return token;
 	}
 
+	bool saw_array = false;
 	while (match_op(token, '[') && !match_c23_attribute(token)) {
 		struct symbol *array;
 		array = alloc_indirect_symbol(token->pos, ctype, SYM_ARRAY);
@@ -2466,9 +2442,12 @@ static struct token *direct_declarator(struct token *token, struct decl_state *c
 		token = expect(token, ']', "in abstract_array_declarator");
 		array->endpos = token->pos;
 		ctype = &array->ctype;
+		saw_array = true;
 		if (match_c23_attribute(token))
 			token = handle_attributes(token, ctx);
 	}
+	if (saw_array && ctx->typedef_alignment > ctype->alignment)
+		ctype->alignment = ctx->typedef_alignment;
 	return token;
 }
 
@@ -2485,6 +2464,7 @@ static struct token *pointer(struct token *token, struct decl_state *ctx)
 		ctx->ctype.as = NULL;
 		ctx->ctype.contexts = NULL;
 		ctx->ctype.alignment = 0;
+		ctx->typedef_alignment = 0;
 
 		token = handle_qualifiers(token->next, ctx);
 		ctx->ctype.base_type->endpos = token->pos;
@@ -2553,6 +2533,7 @@ static struct token *declaration_list(struct token *token, struct symbol_list **
 	struct decl_state ctx = {.prefer_abstract = 0};
 	struct ctype saved;
 	unsigned long mod;
+	unsigned int saved_td_align;
 
 	token = declaration_specifiers(token, &ctx);
 	if (ctx.opaque_fixed_enum)
@@ -2560,10 +2541,12 @@ static struct token *declaration_list(struct token *token, struct symbol_list **
 			     "'enum' underlying type may not be specified here");
 	mod = decl_modifiers(&ctx);
 	saved = ctx.ctype;
+	saved_td_align = ctx.typedef_alignment;
 	for (;;) {
 		struct symbol *decl = alloc_symbol(token->pos, SYM_NODE);
 		ctx.cleanup = NULL;
 		ctx.ident_modifiers = 0;
+		ctx.typedef_alignment = saved_td_align;
 		ctx.ident = &decl->ident;
 
 		token = declarator(token, &ctx);
@@ -3801,6 +3784,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
 	struct decl_state ctx = { .ident = &ident };
 	struct ctype saved;
 	unsigned long saved_f_modifiers;
+	unsigned int saved_td_align;
 	struct symbol *base_type;
 	unsigned long mod;
 	int is_typedef;
@@ -3840,6 +3824,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
 
 	saved = ctx.ctype;
 	saved_f_modifiers = ctx.f_modifiers;
+	saved_td_align = ctx.typedef_alignment;
 	token = declarator(token, &ctx);
 	token = handle_asm_name(token, &ctx);
 	token = handle_attributes(token, &ctx);
@@ -4108,6 +4093,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
 		ctx.cleanup = NULL;
 		ctx.ident_modifiers = 0;
 		ctx.f_modifiers = saved_f_modifiers;
+		ctx.typedef_alignment = saved_td_align;
 		token = handle_attributes(token, &ctx);
 		token = declarator(token, &ctx);
 		token = handle_asm_name(token, &ctx);
diff --git a/symbol.c b/symbol.c
index d4b945d9e161..69fb0670c341 100644
--- a/symbol.c
+++ b/symbol.c
@@ -352,6 +352,7 @@ static struct symbol * examine_array_type(struct symbol *sym)
 	struct symbol *base_type = examine_base_type(sym);
 	unsigned long bit_size = -1, alignment;
 	struct expression *array_size = sym->array_size;
+	int elem_size;
 
 	if (!base_type)
 		return sym;
@@ -376,8 +377,13 @@ static struct symbol * examine_array_type(struct symbol *sym)
 	if (has_flexible_array(base_type) && Wflexible_array_array)
 		warning(sym->pos, "array of flexible structures");
 	alignment = base_type->ctype.alignment;
-	if (!sym->ctype.alignment)
+	if (!sym->ctype.alignment || sym->ctype.alignment < alignment)
 		sym->ctype.alignment = alignment;
+	elem_size = bits_to_bytes(base_type->bit_size);
+	if (elem_size > 0 && sym->ctype.alignment &&
+	    (elem_size % sym->ctype.alignment))
+		sparse_error(sym->pos,
+			     "size of array element is not a multiple of its alignment");
 	sym->bit_size = bit_size;
 	return sym;
 }
@@ -587,25 +593,92 @@ static struct symbol * examine_node_type(struct symbol *sym)
 	return sym;
 }
 
+static unsigned long long rshift(unsigned long long val, unsigned int n)
+{
+	if (n >= (sizeof(val) * 8))
+		return 0;
+	return val >> n;
+}
+
+static int type_is_ok(struct symbol *type, struct range range)
+{
+	int shift = type->bit_size;
+	int is_unsigned = type->ctype.modifiers & MOD_UNSIGNED;
+
+	if (!is_unsigned)
+		shift--;
+	if (rshift(range.pos, shift))
+		return 0;
+	if (range.neg == 0)
+		return 1;
+	if (is_unsigned)
+		return 0;
+	if (rshift(~range.neg, shift))
+		return 0;
+	return 1;
+}
+
+struct symbol *get_enum_base_type(struct range range, int packed)
+{
+	if (packed) {
+		if (type_is_ok(&uchar_ctype, range))
+			return &uchar_ctype;
+		if (type_is_ok(&schar_ctype, range))
+			return &schar_ctype;
+		if (type_is_ok(&ushort_ctype, range))
+			return &ushort_ctype;
+		if (type_is_ok(&short_ctype, range))
+			return &short_ctype;
+	}
+	if (type_is_ok(&uint_ctype, range))
+		return &uint_ctype;
+	if (type_is_ok(&int_ctype, range))
+		return &int_ctype;
+	if (type_is_ok(&ulong_ctype, range))
+		return &ulong_ctype;
+	if (type_is_ok(&long_ctype, range))
+		return &long_ctype;
+	if (type_is_ok(&ullong_ctype, range))
+		return &ullong_ctype;
+	if (type_is_ok(&llong_ctype, range))
+		return &llong_ctype;
+	return &bad_ctype;
+}
+
 static struct symbol *examine_enum_type(struct symbol *sym)
 {
-	struct symbol *base_type = examine_base_type(sym);
+	struct symbol *base_type;
+	unsigned long alignment;
+
+	if (sym->packed && !sym->fixed_type && !sym->has_mode &&
+	    sym->ctype.base_type && is_int_type(sym->ctype.base_type) &&
+	    sym->ctype.base_type != &incomplete_ctype) {
+		base_type = get_enum_base_type(sym->range, 1);
+		if (base_type && base_type != &bad_ctype) {
+			sym->ctype.base_type = base_type;
+			sym->ctype.modifiers &= ~MOD_SIGNEDNESS;
+			sym->ctype.modifiers |= (base_type->ctype.modifiers & MOD_SIGNEDNESS);
+		}
+	}
+	base_type = examine_base_type(sym);
 
 	sym->ctype.modifiers |= (base_type->ctype.modifiers & MOD_SIGNEDNESS);
-	if (sym->fixed_type || sym->has_mode) {
+	if (sym->fixed_type || sym->packed || sym->has_mode) {
 		if (base_type == &bool_ctype)
 			sym->bit_size = bits_to_bytes(bits_in_bool) * bits_in_char;
 		else
 			sym->bit_size = base_type->bit_size;
-		sym->ctype.alignment = base_type->ctype.alignment;
+		alignment = base_type->ctype.alignment;
 	} else {
 		sym->bit_size = bits_in_enum;
 		if (base_type->bit_size > sym->bit_size)
 			sym->bit_size = base_type->bit_size;
-		sym->ctype.alignment = enum_alignment;
-		if (base_type->ctype.alignment > sym->ctype.alignment)
-			sym->ctype.alignment = base_type->ctype.alignment;
+		alignment = enum_alignment;
+		if (base_type->ctype.alignment > alignment)
+			alignment = base_type->ctype.alignment;
 	}
+	if (sym->ctype.alignment < alignment)
+		sym->ctype.alignment = alignment;
 	sym->rank = base_type->rank;
 	return sym;
 }
diff --git a/symbol.h b/symbol.h
index aa180ac4f514..691213a0b454 100644
--- a/symbol.h
+++ b/symbol.h
@@ -87,6 +87,11 @@ enum keyword {
 	KW_EXACT	= 1 << 9,
 };
 
+struct range {
+	long long		neg;
+	unsigned long long	pos;
+};
+
 struct context {
 	struct expression *context;
 	unsigned int in, out;
@@ -112,10 +117,12 @@ struct decl_state {
 	unsigned long f_modifiers;		// function attributes
 	unsigned long ident_modifiers;		// declarator-id C23 attributes
 	unsigned long storage_class;
+	unsigned int typedef_alignment;
 	unsigned char prefer_abstract;
 	unsigned char autotype;
 	unsigned char forced;
 	unsigned char packed;
+	unsigned char has_aligned;
 	unsigned char has_auto;
 	unsigned char has_alignas;
 	unsigned char is_constexpr;
@@ -215,6 +222,7 @@ struct symbol {
 			unsigned int underspecified : 1;
 			unsigned int c23_auto : 1;
 			unsigned int has_mode : 1;
+			unsigned int has_aligned : 1;
 			int		rank:3;	// arithmetic's rank
 			struct expression *array_size;
 			struct ctype ctype;
@@ -225,6 +233,7 @@ struct symbol {
 			struct symbol_list *inline_symbol_list;
 			struct expression *initializer;
 			struct expression *cleanup;
+			struct range range;
 			struct entrypoint *ep;
 			struct symbol *definition;
 		};
@@ -373,6 +382,7 @@ extern void bind_symbol_with_scope(struct symbol *, struct ident *, enum namespa
 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 struct symbol *get_enum_base_type(struct range range, int packed);
 extern const char *show_as(struct ident *as);
 extern const char *show_typename(struct symbol *sym);
 extern const char *builtin_typename(struct symbol *sym);
diff --git a/validation/enum-packed.c b/validation/enum-packed.c
new file mode 100644
index 000000000000..4d1ba40a2781
--- /dev/null
+++ b/validation/enum-packed.c
@@ -0,0 +1,85 @@
+/*
+ * Check that __attribute__((packed)) on enums selects the smallest
+ * integer type that can hold all enumerator values.
+ */
+
+enum e_u8 {
+	U8_0 = 0,
+	U8_1 = 200,
+} __attribute__((packed));
+
+enum e_s8 {
+	S8_0 = -10,
+	S8_1 = 100,
+} __attribute__((packed));
+
+enum __attribute__((packed)) e_u16 {
+	U16_0 = 0,
+	U16_1 = 1000,
+};
+
+enum e_s16 {
+	S16_0 = -1000,
+	S16_1 = 50,
+} __attribute__((__packed__));
+
+enum e_u32 {
+	U32_0 = 0,
+	U32_1 = 70000,
+} __attribute__((packed));
+
+_Static_assert(sizeof(enum e_u8) == 1, "e_u8 size");
+_Static_assert(_Alignof(enum e_u8) == 1, "e_u8 align");
+_Static_assert(sizeof(enum e_s8) == 1, "e_s8 size");
+_Static_assert(_Alignof(enum e_s8) == 1, "e_s8 align");
+
+_Static_assert(sizeof(enum e_u16) == 2, "e_u16 size");
+_Static_assert(_Alignof(enum e_u16) == 2, "e_u16 align");
+_Static_assert(sizeof(enum e_s16) == 2, "e_s16 size");
+_Static_assert(_Alignof(enum e_s16) == 2, "e_s16 align");
+
+_Static_assert(sizeof(enum e_u32) == 4, "e_u32 size");
+
+/* Subsequent tag lookups must not clear the packed flag */
+static enum e_u8 var_u8;
+static enum e_u16 var_u16;
+_Static_assert(sizeof(var_u8) == 1, "var_u8 size");
+_Static_assert(sizeof(var_u16) == 2, "var_u16 size");
+
+enum __attribute__((aligned(2), packed)) e_aligned_packed {
+	AP_0 = 0,
+};
+_Static_assert(sizeof(enum e_aligned_packed) == 1, "e_aligned_packed size");
+_Static_assert(_Alignof(enum e_aligned_packed) == 2, "e_aligned_packed align");
+
+static enum e_aligned_packed bad_enum_arr[2];
+typedef char __attribute__((aligned(2))) aligned_char;
+static aligned_char bad_char_arr[2];
+static aligned_char *ok_char_ptr_arr[2];
+__attribute__((aligned(16))) static char ok_aligned_arr[2];
+static enum e_u8 ok_u8_arr[4];
+
+enum __attribute__((packed, mode(__SI__))) e_packed_si {
+	PSI_0 = 0,
+};
+_Static_assert(sizeof(enum e_packed_si) == 4, "mode overrides packed");
+
+enum __attribute__((packed)) e_fixed_packed : int {
+	EFP_0 = 0,
+};
+_Static_assert(sizeof(enum e_fixed_packed) == sizeof(int),
+	       "fixed type overrides packed");
+
+_Static_assert(sizeof(U8_0) == sizeof(int), "enumerator has int size");
+_Static_assert(sizeof(S8_0) == sizeof(int), "enumerator has int size");
+
+/*
+ * check-name: packed enum support
+ * check-command: sparse $file
+ *
+ * check-error-start
+enum-packed.c:49:42: warning: Clang and GCC treat 'packed' and 'aligned' attributes on enum types differently
+enum-packed.c:55:42: error: size of array element is not a multiple of its alignment
+enum-packed.c:57:33: error: size of array element is not a multiple of its alignment
+ * 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 ` [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 ` Bart Van Assche [this message]
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-64-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