[PATCH 1/4] kconfig: promote invalid numeric reference from warning to error

From: Julian Braha

Date: Sat Aug 29 2026 - 13:20:35 EST


The Kconfig interpreter already warns if a numeric option attempts to use
a non-numeric option (bool, tristate, or string) to set its value (for
example, with a 'default' or 'range').

Since there is nowhere in the tree that attempts this, we can safely
promote this check from warning to error.

Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Julian Braha <julianbraha@xxxxxxxxx>
---
scripts/kconfig/lkc.h | 2 +-
scripts/kconfig/menu.c | 39 ++++++----
scripts/kconfig/parser.y | 2 +-
.../tests/err_num_non_numeric_ref/Kconfig | 75 +++++++++++++++++++
.../tests/err_num_non_numeric_ref/__init__.py | 9 +++
.../err_num_non_numeric_ref/expected_stderr | 14 ++++
6 files changed, 126 insertions(+), 15 deletions(-)
create mode 100644 scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig
create mode 100644 scripts/kconfig/tests/err_num_non_numeric_ref/__init__.py
create mode 100644 scripts/kconfig/tests/err_num_non_numeric_ref/expected_stderr

diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 7e6f6ca299cf..bbc99f75b416 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -89,7 +89,7 @@ struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
-void menu_finalize(void);
+int menu_finalize(void);
void menu_set_type(int type);

extern struct menu rootmenu;
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 9c079e92a9ed..99a57ce0fdc9 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -240,11 +240,12 @@ static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
}

-static void sym_check_prop(struct symbol *sym)
+static int sym_check_prop(struct symbol *sym)
{
struct property *prop;
struct symbol *sym2;
char *use;
+ int errors = 0;

for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
@@ -258,10 +259,13 @@ static void sym_check_prop(struct symbol *sym)
break;
sym2 = prop_get_symbol(prop);
if (sym->type == S_HEX || sym->type == S_INT) {
- if (!menu_validate_number(sym, sym2))
- prop_warn(prop,
- "'%s': number is invalid",
- sym->name);
+ if (!menu_validate_number(sym, sym2)) {
+ fprintf(stderr,
+ "%s:%d: error: '%s': number is invalid\n",
+ prop->filename, prop->lineno,
+ sym->name);
+ errors++;
+ }
}
if (sym_is_choice(sym)) {
struct menu *choice = sym_get_choice_menu(sym2);
@@ -293,21 +297,28 @@ static void sym_check_prop(struct symbol *sym)
prop_warn(prop, "range is only allowed "
"for int or hex symbols");
if (!menu_validate_number(sym, prop->expr->left.sym) ||
- !menu_validate_number(sym, prop->expr->right.sym))
- prop_warn(prop, "range is invalid");
+ !menu_validate_number(sym, prop->expr->right.sym)) {
+ fprintf(stderr,
+ "%s:%d: error: range is invalid\n",
+ prop->filename, prop->lineno);
+ errors++;
+ }
break;
default:
;
}
}
+
+ return errors;
}

-static void _menu_finalize(struct menu *parent, bool inside_choice)
+static int _menu_finalize(struct menu *parent, bool inside_choice)
{
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *basedep, *dep, *dep2;
+ int errors = 0;

sym = parent->sym;
if (parent->list) {
@@ -393,7 +404,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
* moving on
*/
for (menu = parent->list; menu; menu = menu->next)
- _menu_finalize(menu, sym && sym_is_choice(sym));
+ errors += _menu_finalize(menu, sym && sym_is_choice(sym));
} else if (!inside_choice && sym) {
/*
* Automatic submenu creation. If sym is a symbol and A, B, C,
@@ -461,7 +472,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
}
/* Superset, put in submenu */
next:
- _menu_finalize(menu, false);
+ errors += _menu_finalize(menu, false);
menu->parent = parent;
last_menu = menu;
}
@@ -519,14 +530,16 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
menu_warn(parent, "config symbol defined without type");

/* Check properties connected to this symbol */
- sym_check_prop(sym);
+ errors += sym_check_prop(sym);
sym->flags |= SYMBOL_WARNED;
}
+
+ return errors;
}

-void menu_finalize(void)
+int menu_finalize(void)
{
- _menu_finalize(&rootmenu, false);
+ return _menu_finalize(&rootmenu, false);
}

bool menu_has_prompt(const struct menu *menu)
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index 5fb6f07b6ad2..40ceb9908c6f 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -587,7 +587,7 @@ void conf_parse(const char *name)
menu_add_prompt(P_MENU, "Main menu", NULL);
}

- menu_finalize();
+ yynerrs += menu_finalize();

menu_for_each_entry(menu) {
struct menu *child;
diff --git a/scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig b/scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig
new file mode 100644
index 000000000000..0ca7a4a460f6
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+# Test non-numeric symbol references from numeric symbols
+
+config BOOL_SOURCE
+ bool
+
+config TRISTATE_SOURCE
+ tristate
+
+config STRING_SOURCE
+ string
+
+# Invalid int defaults
+
+config INT_DEFAULT_BOOL
+ int
+ default BOOL_SOURCE
+
+config INT_DEFAULT_TRISTATE
+ int
+ default TRISTATE_SOURCE
+
+config INT_DEFAULT_STRING
+ int
+ default STRING_SOURCE
+
+# Invalid hex defaults
+
+config HEX_DEFAULT_BOOL
+ hex
+ default BOOL_SOURCE
+
+config HEX_DEFAULT_TRISTATE
+ hex
+ default TRISTATE_SOURCE
+
+config HEX_DEFAULT_STRING
+ hex
+ default STRING_SOURCE
+
+# Invalid int ranges
+
+config INT_RANGE_BOOL
+ int
+ range BOOL_SOURCE 1
+
+config INT_RANGE_TRISTATE
+ int
+ range TRISTATE_SOURCE 1
+
+config INT_RANGE_STRING
+ int
+ range STRING_SOURCE 1
+
+config INT_RANGE_MULTIPLE
+ int
+ range BOOL_SOURCE TRISTATE_SOURCE
+
+# Invalid hex ranges
+
+config HEX_RANGE_BOOL
+ hex
+ range BOOL_SOURCE 0x1
+
+config HEX_RANGE_TRISTATE
+ hex
+ range TRISTATE_SOURCE 0x1
+
+config HEX_RANGE_STRING
+ hex
+ range STRING_SOURCE 0x1
+
+config HEX_RANGE_MULTIPLE
+ hex
+ range BOOL_SOURCE TRISTATE_SOURCE
diff --git a/scripts/kconfig/tests/err_num_non_numeric_ref/__init__.py b/scripts/kconfig/tests/err_num_non_numeric_ref/__init__.py
new file mode 100644
index 000000000000..9632907abead
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_non_numeric_ref/__init__.py
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Reject nonnumeric symbol references from int and hex properties.
+"""
+
+
+def test(conf):
+ assert conf.olddefconfig() == 1
+ assert conf.stderr_matches('expected_stderr')
diff --git a/scripts/kconfig/tests/err_num_non_numeric_ref/expected_stderr b/scripts/kconfig/tests/err_num_non_numeric_ref/expected_stderr
new file mode 100644
index 000000000000..4974ba2fcd9c
--- /dev/null
+++ b/scripts/kconfig/tests/err_num_non_numeric_ref/expected_stderr
@@ -0,0 +1,14 @@
+Kconfig:17: error: 'INT_DEFAULT_BOOL': number is invalid
+Kconfig:21: error: 'INT_DEFAULT_TRISTATE': number is invalid
+Kconfig:25: error: 'INT_DEFAULT_STRING': number is invalid
+Kconfig:31: error: 'HEX_DEFAULT_BOOL': number is invalid
+Kconfig:35: error: 'HEX_DEFAULT_TRISTATE': number is invalid
+Kconfig:39: error: 'HEX_DEFAULT_STRING': number is invalid
+Kconfig:45: error: range is invalid
+Kconfig:49: error: range is invalid
+Kconfig:53: error: range is invalid
+Kconfig:57: error: range is invalid
+Kconfig:63: error: range is invalid
+Kconfig:67: error: range is invalid
+Kconfig:71: error: range is invalid
+Kconfig:75: error: range is invalid
--
2.55.0