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 41/73] preprocessor: Add support for __has_include and __has_include_next
Date: Mon,  9 Nov 2026 12:32:27 -0800	[thread overview]
Message-ID: <20261109203259.362845-42-bvanassche@acm.org> (raw)
In-Reply-To: <20261109203259.362845-1-bvanassche@acm.org>

Support the C23 __has_include and __has_include_next preprocessor
operators for querying the availability of header files so that code
using feature test macros can conditionally include headers portably.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 ident-list.h                                  |   2 +
 pre-process.c                                 | 303 +++++++++++++++++-
 .../preprocessor/c23-has-include-error.c      |  18 ++
 validation/preprocessor/c23-has-include.c     |  51 +++
 4 files changed, 363 insertions(+), 11 deletions(-)
 create mode 100644 validation/preprocessor/c23-has-include-error.c
 create mode 100644 validation/preprocessor/c23-has-include.c

diff --git a/ident-list.h b/ident-list.h
index 3c08e8ca9aa4..5f4d1fef5a81 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -68,6 +68,8 @@ __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
 __IDENT(__func___ident, "__func__", 0);
 __IDENT(__FUNCTION___ident, "__FUNCTION__", 0);
 __IDENT(__PRETTY_FUNCTION___ident, "__PRETTY_FUNCTION__", 0);
+__IDENT(__has_include_ident, "__has_include", 0);
+__IDENT(__has_include_next_ident, "__has_include_next", 0);
 
 /* Sparse commands */
 IDENT_RESERVED(__context__);
diff --git a/pre-process.c b/pre-process.c
index aa59dca1ae97..fbe4ba215532 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -50,6 +50,7 @@ static int false_nesting = 0;
 static int counter_macro = 0;		// __COUNTER__ expansion
 static int include_level = 0;
 static int expanding = 0;
+static int in_cond_expr = 0;
 
 #define INCLUDEPATHS 300
 const char *includepath[INCLUDEPATHS+1] = {
@@ -762,6 +763,32 @@ static struct token **substitute(struct token **list, const struct token *body,
 	return list;
 }
 
+static bool parse_has_include(struct token **list, int how);
+
+static void reject_outside_directive(struct token *token)
+{
+	struct token *next;
+
+	sparse_error(token->pos, "'%s' used outside of preprocessing directive",
+		     show_token(token));
+	next = scan_next(&token->next);
+	if (match_op(next, '(')) {
+		int depth = 1;
+
+		next = next->next;
+		while (!eof_token(next) && depth > 0) {
+			if (match_op(next, '('))
+				depth++;
+			else if (match_op(next, ')'))
+				depth--;
+			next = next->next;
+		}
+	}
+	token_type(token) = TOKEN_NUMBER;
+	token->number = "0";
+	token->next = next;
+}
+
 static int expand(struct token **list, struct symbol *sym)
 {
 	struct token *last;
@@ -777,6 +804,23 @@ static int expand(struct token **list, struct symbol *sym)
 		return 1;
 	}
 
+	if (expanding == &__has_include_ident ||
+	    expanding == &__has_include_next_ident) {
+		bool ok;
+
+		if (!in_cond_expr) {
+			reject_outside_directive(token);
+			return 0;
+		}
+		if (expanding == &__has_include_ident)
+			ok = parse_has_include(list, 0);
+		else
+			ok = parse_has_include(list, 1);
+		if (!ok)
+			replace_with_bool(token, 0);
+		return 0;
+	}
+
 	if (sym->arglist) {
 		if (!match_op(scan_next(&token->next), '('))
 			return 1;
@@ -788,6 +832,9 @@ static int expand(struct token **list, struct symbol *sym)
 	if (sym->expand)
 		return sym->expand(token, args) ? 0 : 1;
 
+	if (!expansion)
+		return 1;
+
 	expanding->tainted = 1;
 
 	last = token->next;
@@ -966,6 +1013,224 @@ static int do_include_path(const char **pptr, struct token **list, struct token
 	return 0;
 }
 
+static int test_include(const char *path, const char *filename)
+{
+	int fd;
+	struct stat st;
+	int plen = strlen(path);
+	int flen = strlen(filename);
+	char fullname[PATH_MAX];
+
+	if (plen + flen + 2 > sizeof(fullname))
+		return 0;
+	memcpy(fullname, path, plen);
+	if (plen && path[plen - 1] != '/') {
+		fullname[plen] = '/';
+		plen++;
+	}
+	memcpy(fullname + plen, filename, flen + 1);
+	if (already_tokenized(fullname))
+		return 1;
+	fd = open(fullname, O_RDONLY);
+	if (fd >= 0) {
+		if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
+			close(fd);
+			return 1;
+		}
+		close(fd);
+	}
+	return 0;
+}
+
+static int check_include(const char **pptr, const char *filename)
+{
+	const char *path;
+	while ((path = *pptr++) != NULL) {
+		if (test_include(path, filename))
+			return 1;
+	}
+	return 0;
+}
+
+static int check_has_include(struct stream *stream, const char *filename,
+			     int expect, int how)
+{
+	const char **path;
+
+	/* Absolute path? */
+	if (filename[0] == '/')
+		return test_include("", filename);
+
+	switch (how) {
+	case 1:
+		path = stream->next_path;
+		break;
+	default:
+		set_stream_include_path(stream);
+		path = expect ? angle_includepath : quote_includepath;
+		break;
+	}
+	if (!path)
+		return 0;
+	return check_include(path, filename);
+}
+
+static struct token *skip_balanced_parens(struct token *lparen)
+{
+	struct token *t;
+	int depth = 1;
+
+	if (!match_op(lparen, '('))
+		return lparen;
+	t = lparen->next;
+	while (!eof_token(t) && depth > 0) {
+		if (match_op(t, '('))
+			depth++;
+		else if (match_op(t, ')'))
+			depth--;
+		t = t->next;
+	}
+	return t;
+}
+
+static bool collect_angle_filename(struct token **next_p, char *buf,
+				   size_t size, struct position pos)
+{
+	struct token *t = *next_p;
+	char *ptr = buf;
+
+	while (!eof_token(t) && !match_op(t, '>')) {
+		const char *s = (token_type(t) == TOKEN_STRING) ?
+					t->string->data :
+					show_token(t);
+		size_t len = strlen(s);
+		size_t rem = size - (size_t)(ptr - buf);
+
+		if (len >= rem) {
+			sparse_error(t->pos, "header name too long");
+			return false;
+		}
+		memcpy(ptr, s, len);
+		ptr += len;
+		t = t->next;
+	}
+	*ptr = '\0';
+	if (!match_op(t, '>')) {
+		sparse_error(pos, "expected '>'");
+		return false;
+	}
+	if (ptr == buf) {
+		sparse_error(pos, "empty filename");
+		return false;
+	}
+	*next_p = t->next;
+	return true;
+}
+
+static bool extract_string_filename(struct token **next_p, char *buf,
+				    size_t size)
+{
+	struct token *t = *next_p;
+	const char *s = t->string->data;
+	size_t len = strlen(s);
+
+	if (!len) {
+		sparse_error(t->pos, "empty filename");
+		return false;
+	}
+	if (len >= size) {
+		sparse_error(t->pos, "header name too long");
+		return false;
+	}
+	memcpy(buf, s, len + 1);
+	*next_p = t->next;
+	return true;
+}
+
+static bool parse_has_include(struct token **list, int how)
+{
+	struct token *token = *list;
+	struct token *lparen = scan_next(&token->next);
+	struct token *next;
+	struct stream *stream = input_streams + token->pos.stream;
+	char filename[PATH_MAX];
+	int expect = 0;
+	int val = 0;
+
+	if (!match_op(lparen, '(')) {
+		sparse_error(token->pos, "expected '(' after %s",
+			     show_token(token));
+		return false;
+	}
+	next = scan_next(&lparen->next);
+	if (match_op(next, '<')) {
+		expect = '>';
+		next = next->next;
+		if (!collect_angle_filename(&next, filename, sizeof(filename),
+					    token->pos))
+			goto err;
+	} else if (token_type(next) == TOKEN_STRING) {
+		if (!extract_string_filename(&next, filename, sizeof(filename)))
+			goto err;
+	} else {
+		struct token **p = &lparen->next;
+		struct token *rparen = scan_next(p);
+		int depth = 1;
+
+		while (!eof_token(rparen)) {
+			if (match_op(rparen, '('))
+				depth++;
+			else if (match_op(rparen, ')') && !--depth)
+				break;
+			p = &rparen->next;
+			rparen = scan_next(p);
+		}
+		if (!match_op(rparen, ')')) {
+			sparse_error(rparen->pos, "expected ')'");
+			token->next = rparen;
+			return false;
+		}
+		*p = &eof_token_entry;
+		expand_list(&lparen->next);
+		p = &lparen->next;
+		while (!eof_token(*p))
+			p = &(*p)->next;
+		*p = rparen;
+		next = lparen->next;
+		if (match_op(next, '<')) {
+			expect = '>';
+			next = next->next;
+			if (!collect_angle_filename(&next, filename,
+						    sizeof(filename),
+						    token->pos))
+				goto err;
+		} else if (token_type(next) == TOKEN_STRING) {
+			if (!extract_string_filename(&next, filename,
+						     sizeof(filename)))
+				goto err;
+		} else {
+			sparse_error(next->pos,
+				     "expected \"FILENAME\" or <FILENAME>");
+			goto err;
+		}
+	}
+	next = scan_next(&next);
+	if (!match_op(next, ')')) {
+		sparse_error(next->pos, "expected ')'");
+		goto err;
+	}
+	next = next->next;
+
+	val = check_has_include(stream, filename, expect, how);
+	replace_with_bool(token, val);
+	token->next = next;
+	return true;
+
+err:
+	token->next = skip_balanced_parens(lparen);
+	return false;
+}
+
 static int free_preprocessor_line(struct token *token)
 {
 	while (token_type(token) != TOKEN_EOF) {
@@ -1645,6 +1910,7 @@ static int expression_value(struct token **where)
 	long long value;
 	int state = 0;
 
+	in_cond_expr++;
 	while (!eof_token(p = scan_next(list))) {
 		switch (state) {
 		case 0:
@@ -1655,6 +1921,18 @@ static int expression_value(struct token **where)
 				beginning = list;
 				break;
 			}
+			if (p->ident == &__has_include_ident) {
+				if (parse_has_include(list, 0))
+					continue;
+				replace_with_bool(p, 0);
+				break;
+			}
+			if (p->ident == &__has_include_next_ident) {
+				if (parse_has_include(list, 1))
+					continue;
+				replace_with_bool(p, 0);
+				break;
+			}
 			if (!expand_one_symbol(list))
 				continue;
 			if (token_type(p) != TOKEN_IDENT)
@@ -1700,6 +1978,7 @@ static int expression_value(struct token **where)
 	if (!eof_token(p))
 		sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p, 0));
 	value = get_expression_value(expr);
+	in_cond_expr--;
 	return value != 0;
 }
 
@@ -2230,17 +2509,19 @@ static void init_preprocessor(void)
 		void (*expand_simple)(struct token *);
 		bool (*expand)(struct token *, struct arg *args);
 	} dynamic[] = {
-		{ "__LINE__",		expand_line },
-		{ "__FILE__",		expand_file },
-		{ "__BASE_FILE__",	expand_basefile },
-		{ "__DATE__",		expand_date },
-		{ "__TIME__",		expand_time },
-		{ "__COUNTER__",	expand_counter },
-		{ "__INCLUDE_LEVEL__",	expand_include_level },
-		{ "__has_attribute",	NULL, expand_has_attribute },
-		{ "__has_builtin",	NULL, expand_has_builtin },
-		{ "__has_extension",	NULL, expand_has_extension },
-		{ "__has_feature",	NULL, expand_has_feature },
+		{ "__LINE__", expand_line },
+		{ "__FILE__", expand_file },
+		{ "__BASE_FILE__", expand_basefile },
+		{ "__DATE__", expand_date },
+		{ "__TIME__", expand_time },
+		{ "__COUNTER__", expand_counter },
+		{ "__INCLUDE_LEVEL__", expand_include_level },
+		{ "__has_attribute", NULL, expand_has_attribute },
+		{ "__has_builtin", NULL, expand_has_builtin },
+		{ "__has_extension", NULL, expand_has_extension },
+		{ "__has_feature", NULL, expand_has_feature },
+		{ "__has_include", NULL, NULL },
+		{ "__has_include_next", NULL, NULL },
 	};
 
 	for (i = 0; i < ARRAY_SIZE(normal); i++) {
diff --git a/validation/preprocessor/c23-has-include-error.c b/validation/preprocessor/c23-has-include-error.c
new file mode 100644
index 000000000000..931eb47998a7
--- /dev/null
+++ b/validation/preprocessor/c23-has-include-error.c
@@ -0,0 +1,18 @@
+int outside = __has_include(<stdio.h>);
+
+#if __has_include("")
+#endif
+
+#if __has_include(<>)
+#endif
+
+/*
+ * check-name: c23-has-include-error
+ * check-command: sparse -std=c23 -Wno-decl $file
+ *
+ * check-error-start
+preprocessor/c23-has-include-error.c:1:15: error: '__has_include' used outside of preprocessing directive
+preprocessor/c23-has-include-error.c:3:19: error: empty filename
+preprocessor/c23-has-include-error.c:6:5: error: empty filename
+ * check-error-end
+ */
diff --git a/validation/preprocessor/c23-has-include.c b/validation/preprocessor/c23-has-include.c
new file mode 100644
index 000000000000..fa32cc9d4992
--- /dev/null
+++ b/validation/preprocessor/c23-has-include.c
@@ -0,0 +1,51 @@
+#if defined(__has_include)
+int has_macro = 1;
+#endif
+
+#if __has_include(<stdio.h>)
+int has_stdio = 1;
+#else
+int has_stdio = 0;
+#endif
+
+#if __has_include("options.h")
+int has_options = 1;
+#endif
+
+#if __has_include(<nonexistent_header_12345.h>)
+int has_nonexistent = 1;
+#else
+int has_nonexistent = 0;
+#endif
+
+#define HEADER <stdio.h>
+#if __has_include(HEADER)
+int has_macro_header = 1;
+#endif
+
+#define HAS_INC __has_include
+#if HAS_INC(<stdio.h>) && HAS_INC("options.h")
+int has_aliased_op = 1;
+#endif
+
+#if __has_include("this_is_an_extremely_long_path_name_that_tests_bounds_checking_1234567890_abcdefghijklmnopqrstuvwxyz.h")
+int has_long = 1;
+#else
+int has_long = 0;
+#endif
+
+/*
+ * check-name: c23-has-include
+ * check-command: sparse -std=c23 -E -I.. $file
+ *
+ * check-output-start
+
+int has_macro = 1;
+int has_stdio = 1;
+int has_options = 1;
+int has_nonexistent = 0;
+int has_macro_header = 1;
+int has_aliased_op = 1;
+int has_long = 0;
+ * check-output-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 ` Bart Van Assche [this message]
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-42-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