Merge tag 'kbuild-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[linux-block.git] / scripts / kconfig / parser.y
index 7fb996612c966075883d945f4a8174653f025d66..ff709001b1f0268ecf475f010b95841b7fdb52db 100644 (file)
@@ -30,6 +30,8 @@ static bool zconf_endtoken(const char *tokenname,
 
 struct menu *current_menu, *current_entry;
 
+static bool inside_choice = false;
+
 %}
 
 %union
@@ -69,7 +71,6 @@ struct menu *current_menu, *current_entry;
 %token T_MODULES
 %token T_ON
 %token T_OPEN_PAREN
-%token T_OPTIONAL
 %token T_PLUS_EQUAL
 %token T_PROMPT
 %token T_RANGE
@@ -140,19 +141,25 @@ stmt_list_in_choice:
 
 config_entry_start: T_CONFIG nonconst_symbol T_EOL
 {
-       $2->flags |= SYMBOL_OPTIONAL;
        menu_add_entry($2);
        printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
 };
 
 config_stmt: config_entry_start config_option_list
 {
+       if (inside_choice) {
+               if (!current_entry->prompt) {
+                       fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
+                               current_entry->filename, current_entry->lineno);
+                       yynerrs++;
+               }
+       }
+
        printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
 };
 
 menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
 {
-       $2->flags |= SYMBOL_OPTIONAL;
        menu_add_entry($2);
        printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
 };
@@ -224,8 +231,8 @@ config_option: T_MODULES T_EOL
 
 choice: T_CHOICE T_EOL
 {
-       struct symbol *sym = sym_lookup(NULL, SYMBOL_CHOICE);
-       sym->flags |= SYMBOL_NO_WRITE;
+       struct symbol *sym = sym_lookup(NULL, 0);
+
        menu_add_entry(sym);
        menu_add_expr(P_CHOICE, NULL, NULL);
        printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
@@ -240,10 +247,14 @@ choice_entry: choice choice_option_list
        }
 
        $$ = menu_add_menu();
+
+       inside_choice = true;
 };
 
 choice_end: end
 {
+       inside_choice = false;
+
        if (zconf_endtoken($1, "choice")) {
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
@@ -272,12 +283,6 @@ choice_option: logic_type prompt_stmt_opt T_EOL
        printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
 };
 
-choice_option: T_OPTIONAL T_EOL
-{
-       current_entry->sym->flags |= SYMBOL_OPTIONAL;
-       printd(DEBUG_PARSE, "%s:%d:optional\n", cur_filename, cur_lineno);
-};
-
 choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
 {
        menu_add_symbol(P_DEFAULT, $2, $3);
@@ -471,6 +476,38 @@ assign_val:
 
 %%
 
+/**
+ * choice_check_sanity - check sanity of a choice member
+ *
+ * @menu: menu of the choice member
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int choice_check_sanity(struct menu *menu)
+{
+       struct property *prop;
+       int ret = 0;
+
+       for (prop = menu->sym->prop; prop; prop = prop->next) {
+               if (prop->type == P_DEFAULT) {
+                       fprintf(stderr, "%s:%d: error: %s",
+                               prop->filename, prop->lineno,
+                               "defaults for choice values not supported\n");
+                       ret = -1;
+               }
+
+               if (prop->menu != menu && prop->type == P_PROMPT &&
+                   prop->menu->parent != menu->parent) {
+                       fprintf(stderr, "%s:%d: error: %s",
+                               prop->filename, prop->lineno,
+                               "choice value has a prompt outside its choice group\n");
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
 void conf_parse(const char *name)
 {
        struct menu *menu;
@@ -517,20 +554,17 @@ void conf_parse(const char *name)
 
        menu_finalize();
 
-       menu = &rootmenu;
-       while (menu) {
+       menu_for_each_entry(menu) {
+               struct menu *child;
+
                if (menu->sym && sym_check_deps(menu->sym))
                        yynerrs++;
 
-               if (menu->list) {
-                       menu = menu->list;
-                       continue;
+               if (menu->sym && sym_is_choice(menu->sym)) {
+                       menu_for_each_sub_entry(child, menu)
+                               if (child->sym && choice_check_sanity(child))
+                                       yynerrs++;
                }
-
-               while (!menu->next && menu->parent)
-                       menu = menu->parent;
-
-               menu = menu->next;
        }
 
        if (yynerrs)