Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kconfig: do not reparent the menu inside a choice block

The boolean 'choice' is used to list exclusively selected config
options.

You must not add a dependency between choice members, because such a
dependency would create an invisible entry.

In the following test case, it is impossible to choose 'C'.

[Test Case 1]

choice
prompt "Choose one, but how to choose C?"

config A
bool "A"

config B
bool "B"

config C
bool "C"
depends on A

endchoice

Hence, Kconfig shows the following error message:

Kconfig:1:error: recursive dependency detected!
Kconfig:1: choice <choice> contains symbol C
Kconfig:10: symbol C is part of choice A
Kconfig:4: symbol A is part of choice <choice>
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"

However, Kconfig does not report anything for the following similar code:

[Test Case 2]

choice
prompt "Choose one, but how to choose B?"

config A
bool "A"

config B
bool "B"
depends on A

config C
bool "C"

endchoice

This is because menu_finalize() reparents the menu tree when an entry
depends on the preceding one.

With reparenting, the menu tree:

choice
|- A
|- B
\- C

... will be transformed into the following structure:

choice
|- A
| \- B
\- C

Consequently, Kconfig considers only 'A' and 'C' as choice members.
This behavior is awkward. The second test case should be an error too.

This commit stops reparenting inside a choice.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>

+18 -13
-5
scripts/kconfig/conf.c
··· 552 552 continue; 553 553 } 554 554 sym_set_tristate_value(child->sym, yes); 555 - for (child = child->list; child; child = child->next) { 556 - indent += 2; 557 - conf(child); 558 - indent -= 2; 559 - } 560 555 return 1; 561 556 } 562 557 }
+1 -1
scripts/kconfig/lkc.h
··· 89 89 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); 90 90 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); 91 91 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); 92 - void menu_finalize(struct menu *parent); 92 + void menu_finalize(void); 93 93 void menu_set_type(int type); 94 94 95 95 extern struct menu rootmenu;
+16 -6
scripts/kconfig/menu.c
··· 282 282 } 283 283 } 284 284 285 - void menu_finalize(struct menu *parent) 285 + static void _menu_finalize(struct menu *parent, bool inside_choice) 286 286 { 287 287 struct menu *menu, *last_menu; 288 288 struct symbol *sym; ··· 296 296 * and propagate parent dependencies before moving on. 297 297 */ 298 298 299 - if (sym && sym_is_choice(sym)) { 299 + bool is_choice = false; 300 + 301 + if (sym && sym_is_choice(sym)) 302 + is_choice = true; 303 + 304 + if (is_choice) { 300 305 if (sym->type == S_UNKNOWN) { 301 306 /* find the first choice value to find out choice type */ 302 307 current_entry = parent; ··· 399 394 } 400 395 } 401 396 402 - if (sym && sym_is_choice(sym)) 397 + if (is_choice) 403 398 expr_free(parentdep); 404 399 405 400 /* ··· 407 402 * moving on 408 403 */ 409 404 for (menu = parent->list; menu; menu = menu->next) 410 - menu_finalize(menu); 411 - } else if (sym) { 405 + _menu_finalize(menu, is_choice); 406 + } else if (!inside_choice && sym) { 412 407 /* 413 408 * Automatic submenu creation. If sym is a symbol and A, B, C, 414 409 * ... are consecutive items (symbols, menus, ifs, etc.) that ··· 468 463 /* Superset, put in submenu */ 469 464 expr_free(dep2); 470 465 next: 471 - menu_finalize(menu); 466 + _menu_finalize(menu, false); 472 467 menu->parent = parent; 473 468 last_menu = menu; 474 469 } ··· 585 580 expr_alloc_and(parent->prompt->visible.expr, 586 581 expr_alloc_symbol(&symbol_mod))); 587 582 } 583 + } 584 + 585 + void menu_finalize(void) 586 + { 587 + _menu_finalize(&rootmenu, false); 588 588 } 589 589 590 590 bool menu_has_prompt(struct menu *menu)
+1 -1
scripts/kconfig/parser.y
··· 515 515 menu_add_prompt(P_MENU, "Main menu", NULL); 516 516 } 517 517 518 - menu_finalize(&rootmenu); 518 + menu_finalize(); 519 519 520 520 menu = &rootmenu; 521 521 while (menu) {