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 <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-07-03 18:43:27 -07:00
parent 36a79568b7
commit 9ec8f8e2dd
1 changed files with 8 additions and 5 deletions

13
parse.y
View File

@ -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.");
}