From 9ec8f8e2dd0608f0f81f0f9eda8a7f8f05080241 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 3 Jul 2026 18:43:27 -0700 Subject: [PATCH] Support for and foreach identifiers shadowing type identifiers SystemVerilog allows a declaration in an inner scope to use the same name as a type identifier from an outer scope. The lexer reports such names as `TYPE_IDENTIFIER` until the new declaration has been installed. The parser previously created the synthetic loop scope and declared the loop variable only after parsing the complete `for` header. When the variable name matches a visible typedef, this is too late: the lexer can continue returning `TYPE_IDENTIFIER` for references to the variable in the initializer, condition, and step expressions. Accept `identifier_name` for the declaration name and create the loop scope and variable in a mid-rule action immediately after it, so the declaration is visible while the rest of the header is parsed. The executable foreach grammar also used to require the array expression name before the index list to be an `IDENTIFIER`. Use `identifier_name` there as well, since this position is an expression name followed by `[` and not a type name. Signed-off-by: Lars-Peter Clausen --- parse.y | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/parse.y b/parse.y index 1081bf11f..4329c7c3f 100644 --- a/parse.y +++ b/parse.y @@ -2030,7 +2030,9 @@ loop_statement /* IEEE1800-2005: A.6.8 */ // statement in a synthetic named block. We can name the block // after the variable that we are creating, that identifier is // safe in the controlling scope. - | K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression_opt ';' for_step_opt ')' + | K_for '(' K_var_opt data_type identifier_name + // Make the loop variable symbol visible while parsing the rest of + // the header. { static unsigned for_counter = 0; char for_block_name [64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); @@ -2044,6 +2046,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ assign_list.push_back(tmp_assign); pform_make_var(@5, &assign_list, $4); } + '=' expression ';' expression_opt ';' for_step_opt ')' statement_or_null { pform_name_t tmp_hident; tmp_hident.push_back(name_component_t(lex_strings.make($5))); @@ -2051,8 +2054,8 @@ loop_statement /* IEEE1800-2005: A.6.8 */ PEIdent*tmp_ident = pform_new_ident(@5, tmp_hident); FILE_NAME(tmp_ident, @5); - check_for_loop(@1, $7, $9, $11); - PForStatement*tmp_for = new PForStatement(tmp_ident, $7, $9, $11, $14); + check_for_loop(@1, $8, $10, $12); + PForStatement*tmp_for = new PForStatement(tmp_ident, $8, $10, $12, $14); FILE_NAME(tmp_for, @1); pform_pop_scope(); @@ -2091,7 +2094,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ // When matching a foreach loop, implicitly create a named block // to hold the definitions for the index variables. - | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' + | K_foreach '(' identifier_name '[' loop_variables ']' ')' { static unsigned foreach_counter = 0; char for_block_name[64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter); @@ -2143,7 +2146,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ yyerror(@1, "error: Error in do/while loop condition."); } - | K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null + | K_foreach '(' identifier_name '[' error ']' ')' statement_or_null { $$ = 0; yyerror(@4, "error: Errors in foreach loop variables list."); }