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

Support GCC machine mode attributes (such as mode(__byte__)) on both
enum declarations and enum type definitions:
- Apply prefix and postfix mode attributes on enum definitions to the
  enum's underlying type, size, alignment, and rank when no C23 fixed
  underlying type is present.
- Inspect underlying SYM_NODE and SYM_ENUM signedness in to_*_mode()
  so unsigned enums preserve unsignedness when converted to a mode.
- Expand validation/enum+mode.c and remove check-known-to-fail.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 parse.c                | 84 ++++++++++++++++++++++++++++++------------
 symbol.c               |  2 +-
 symbol.h               |  1 +
 validation/enum+mode.c | 26 ++++++++++++-
 4 files changed, 87 insertions(+), 26 deletions(-)

diff --git a/parse.c b/parse.c
index d89f60113152..b686d2d55c36 100644
--- a/parse.c
+++ b/parse.c
@@ -992,6 +992,20 @@ static struct token *struct_union_enum_specifier(enum type type,
 		else
 			warning(token->pos, "attribute __transparent_union__ applied to non-union type");
 	}
+	if (sym->type == SYM_ENUM && attr.mode && attr.mode->to_mode &&
+	    !sym->fixed_type && sym->ctype.base_type &&
+	    is_int_type(sym->ctype.base_type)) {
+		struct symbol *mtype = attr.mode->to_mode(sym);
+		if (mtype) {
+			sym->ctype.base_type = mtype;
+			sym->has_mode = 1;
+			sym->ctype.modifiers &= ~MOD_SIGNEDNESS;
+			sym->ctype.modifiers |= (mtype->ctype.modifiers & MOD_SIGNEDNESS);
+			sym->bit_size = mtype->bit_size;
+			sym->ctype.alignment = mtype->ctype.alignment;
+			sym->rank = mtype->rank;
+		}
+	}
 
 	sym->endpos = token->pos;
 
@@ -1599,62 +1613,86 @@ static struct token *attribute_address_space(struct token *token, struct symbol
 	return token;
 }
 
+static inline bool is_int_or_enum(struct symbol *ctype)
+{
+	if (!ctype)
+		return false;
+	if (ctype->type == SYM_ENUM)
+		return true;
+	if (ctype->ctype.base_type == &int_type)
+		return true;
+	if (ctype->type == SYM_NODE && ctype->ctype.base_type &&
+	    (ctype->ctype.base_type->type == SYM_ENUM ||
+	     ctype->ctype.base_type->ctype.base_type == &int_type))
+		return true;
+	return false;
+}
+
+static inline bool is_unsigned_mode_type(struct symbol *ctype)
+{
+	if (!ctype)
+		return false;
+	if (ctype->type == SYM_NODE || ctype->type == SYM_ENUM)
+		examine_symbol_type(ctype);
+	while (ctype && (ctype->type == SYM_NODE || ctype->type == SYM_ENUM)) {
+		if (ctype->ctype.modifiers & MOD_UNSIGNED)
+			return true;
+		if (ctype->ctype.modifiers & MOD_SIGNED)
+			return false;
+		ctype = ctype->ctype.base_type;
+	}
+	return ctype && (ctype->ctype.modifiers & MOD_UNSIGNED);
+}
+
 static struct symbol *to_QI_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	if (ctype == &char_ctype)
-		return ctype;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &uchar_ctype
-						     : &schar_ctype;
+	if (cbase_type(ctype) == &char_ctype)
+		return &char_ctype;
+	return is_unsigned_mode_type(ctype) ? &uchar_ctype : &schar_ctype;
 }
 
 static struct symbol *to_HI_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &ushort_ctype
-						     : &sshort_ctype;
+	return is_unsigned_mode_type(ctype) ? &ushort_ctype : &sshort_ctype;
 }
 
 static struct symbol *to_SI_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &uint_ctype
-						     : &sint_ctype;
+	return is_unsigned_mode_type(ctype) ? &uint_ctype : &sint_ctype;
 }
 
 static struct symbol *to_DI_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &ullong_ctype
-						     : &sllong_ctype;
+	return is_unsigned_mode_type(ctype) ? &ullong_ctype : &sllong_ctype;
 }
 
 static struct symbol *to_TI_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &uint128_ctype
-						     : &sint128_ctype;
+	return is_unsigned_mode_type(ctype) ? &uint128_ctype : &sint128_ctype;
 }
 
 static struct symbol *to_pointer_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? uintptr_ctype
-						     :  intptr_ctype;
+	return is_unsigned_mode_type(ctype) ? uintptr_ctype : intptr_ctype;
 }
 
 static struct symbol *to_word_mode(struct symbol *ctype)
 {
-	if (ctype->ctype.base_type != &int_type)
+	if (!is_int_or_enum(ctype))
 		return NULL;
-	return ctype->ctype.modifiers & MOD_UNSIGNED ? &ulong_ctype
-						     : &slong_ctype;
+	return is_unsigned_mode_type(ctype) ? &ulong_ctype : &slong_ctype;
 }
 
 static struct token *attribute_mode(struct token *token, struct symbol *attr, struct decl_state *ctx)
diff --git a/symbol.c b/symbol.c
index 721dd1e81ae5..d4b945d9e161 100644
--- a/symbol.c
+++ b/symbol.c
@@ -592,7 +592,7 @@ static struct symbol *examine_enum_type(struct symbol *sym)
 	struct symbol *base_type = examine_base_type(sym);
 
 	sym->ctype.modifiers |= (base_type->ctype.modifiers & MOD_SIGNEDNESS);
-	if (sym->fixed_type) {
+	if (sym->fixed_type || sym->has_mode) {
 		if (base_type == &bool_ctype)
 			sym->bit_size = bits_to_bytes(bits_in_bool) * bits_in_char;
 		else
diff --git a/symbol.h b/symbol.h
index bb063dc622e0..aa180ac4f514 100644
--- a/symbol.h
+++ b/symbol.h
@@ -214,6 +214,7 @@ struct symbol {
 			unsigned int kr_args : 1;
 			unsigned int underspecified : 1;
 			unsigned int c23_auto : 1;
+			unsigned int has_mode : 1;
 			int		rank:3;	// arithmetic's rank
 			struct expression *array_size;
 			struct ctype ctype;
diff --git a/validation/enum+mode.c b/validation/enum+mode.c
index 182af1895d49..cfd037e8617b 100644
--- a/validation/enum+mode.c
+++ b/validation/enum+mode.c
@@ -3,6 +3,7 @@ enum e { ZERO, ONE, TWO };
 struct s {
 	enum e __attribute__ ((mode(__byte__))) b;
 	enum e __attribute__ ((mode(__word__))) w;
+	enum e __attribute__ ((mode(__DI__))) d;
 	enum e __attribute__ ((mode(__TI__))) t;
 };
 
@@ -10,9 +11,30 @@ static struct s s;
 
 _Static_assert(sizeof(s.b) == 1, "");
 _Static_assert(sizeof(s.w) == sizeof(long), "");
-_Static_assert(sizeof(s.t) == sizeof(long long), "");
+_Static_assert(sizeof(s.d) == sizeof(long long), "");
+_Static_assert(sizeof(s.t) == 16, "");
+
+typedef enum { M_ZERO, M_ONE } __attribute__((mode(__byte__))) byte_enum_t;
+_Static_assert(sizeof(byte_enum_t) == 1, "typedef anon enum mode");
+_Static_assert((byte_enum_t)-1 > 0, "unsigned enum mode stays unsigned");
+
+typedef enum tagged_m { TM_0, TM_1 } __attribute__((mode(__byte__))) tagged_byte_t;
+_Static_assert(sizeof(tagged_byte_t) == 1, "typedef tagged enum mode");
+_Static_assert(sizeof(enum tagged_m) == 1, "tagged enum itself gets mode");
+
+enum __attribute__((mode(__HI__))) hi_enum { HI_0 = -1, HI_1 = 1 };
+_Static_assert(sizeof(enum hi_enum) == 2, "prefix mode on enum");
+_Static_assert((enum hi_enum)-1 < 0, "signed enum mode stays signed");
+
+enum post_qi { PQ_0 = 0, PQ_1 = 200 } __attribute__((mode(__QI__)));
+_Static_assert(sizeof(enum post_qi) == 1, "postfix mode on enum");
+_Static_assert((enum post_qi)-1 > 0, "postfix QI mode unsigned");
+
+typedef enum { UE_0 = 0, UE_1 = 1 } uenum_t;
+static uenum_t __attribute__((mode(__byte__))) ub;
+_Static_assert(sizeof(ub) == 1, "typedef var mode size");
+_Static_assert((typeof(ub))-1 > 0, "typedef var mode unsigned");
 
 /*
  * check-name: enum+mode
- * check-known-to-fail
  */

  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 ` Bart Van Assche [this message]
2026-11-09 20:32 ` [PATCH 63/73] enum: Support __attribute__((packed)) on enumeration types 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-63-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