Support assertion item labels shadowing type identifiers

SystemVerilog assertion item labels use ordinary identifiers. A visible
type identifier should therefore be accepted as the label on a module
level assertion item:

    typedef int CHECK;
    module test;
      CHECK: assert property (1);
    endmodule

Procedural assertion statements already accept either identifier token in
their optional label rule. Reusing that rule for module level concurrent
and deferred assertion items exposes a declaration ambiguity: module items
can also start with a typedef name followed by a variable declaration.

Keep the grammar conflict-free by parsing typedef-start variable
declarations in a single production that includes the first declarator.
This lets the parser see `:` before reducing the typedef-start declaration
path, so module and procedural assertions can share the same label rule
while preserving the existing declaration handling for typedef data types.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-06-27 12:28:24 -07:00
parent 11af9fb3b3
commit a0e5240109
1 changed files with 45 additions and 26 deletions

71
parse.y
View File

@ -936,7 +936,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
%type <statement> udp_initial udp_init_opt
%type <text> event_variable label_opt interface_port_modport_opt
%type <text> block_identifier_opt
%type <text> identifier_name
%type <identifiers> event_variable_list
%type <identifiers> genvar_identifier_list list_of_identifiers
@ -1001,6 +1000,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
%type <decl_assignments> net_decl_assigns list_of_variable_decl_assignments
%type <decl_assignments_with_type> list_of_net_decl_assignments_with_type
%type <decl_assignments_with_type> list_of_variable_decl_assignments_with_type
%type <decl_assignments_with_type> type_identifier_variable_decl_assignments_with_type
%type <data_type> data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void
%type <data_type> block_reg_data_type
@ -1156,15 +1156,8 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */
}
;
/* Some rules have a ... [ block_identifier ':' ] ... part. This
implements it in a LALR way. */
block_identifier_opt /* */
: IDENTIFIER ':'
{ $$ = $1; }
|
{ $$ = 0; }
;
/* Assertion items have an optional block identifier prefix. Consume the
label here because its spelling is not used when assertions are parsed. */
assertion_item_label_opt
: identifier_name ':'
{ delete[]$1; }
@ -1375,9 +1368,8 @@ class_new /* IEEE1800-2005 A.2.4 */
concurrent_assertion_statement and checker_instantiation rules. */
concurrent_assertion_item /* IEEE1800-2012 A.2.10 */
: block_identifier_opt concurrent_assertion_statement
{ delete $1;
delete $2;
: assertion_item_label_opt concurrent_assertion_statement
{ delete $2;
}
;
@ -1736,9 +1728,8 @@ data_type_or_implicit_or_void
;
deferred_immediate_assertion_item /* IEEE1800-2012: A.6.10 */
: block_identifier_opt deferred_immediate_assertion_statement
{ delete $1;
delete $2;
: assertion_item_label_opt deferred_immediate_assertion_statement
{ delete $2;
}
;
@ -2257,6 +2248,25 @@ list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */
}
;
type_identifier_variable_decl_assignments_with_type
: TYPE_IDENTIFIER dimensions_opt list_of_variable_decl_assignments
{ pform_set_type_referenced(@1, $1.text);
auto tmp = new typeref_t($1.type);
FILE_NAME(tmp, @1);
delete[]$1.text;
$$.decl_assignments = $3;
$$.type = pform_make_parray_type(@2, tmp, $2);
}
| package_scope TYPE_IDENTIFIER dimensions_opt list_of_variable_decl_assignments
{ lex_in_package_scope(nullptr);
auto tmp = new typeref_t($2.type, $1);
FILE_NAME(tmp, @2);
delete[]$2.text;
$$.decl_assignments = $4;
$$.type = pform_make_parray_type(@3, tmp, $3);
}
;
initializer_opt
: '=' expression { $$ = $2; }
| { $$ = nullptr; }
@ -3213,6 +3223,18 @@ attribute
rule has presumably set up the scope. */
block_item_decl
: block_item_decl_no_type_identifier_start
| type_identifier_variable_decl_assignments_with_type ';'
{ if ($1.type) pform_make_var(@1, $1.decl_assignments, $1.type, attributes_in_context, false);
var_lifetime = LexicalScope::INHERITED;
}
| ps_type_identifier_dim error ';'
{ yyerror(@1, "error: Syntax error in variable list.");
yyerrok;
}
;
block_item_decl_no_type_identifier_start
/* variable declarations. Note that data_type can be 0 if we are
recovering from an error. */
@ -3247,11 +3269,6 @@ block_item_decl
var_lifetime = LexicalScope::INHERITED;
}
| ps_type_identifier_dim list_of_variable_decl_assignments ';'
{ if ($1) pform_make_var(@1, $2, $1, attributes_in_context, false);
var_lifetime = LexicalScope::INHERITED;
}
/* The extra `reg` is not valid (System)Verilog, this is an iverilog extension. */
| K_const variable_lifetime_opt K_reg reg_prefixed_atomic_type list_of_variable_decl_assignments ';'
{ if ($4) pform_make_var(@4, $5, $4, attributes_in_context, true);
@ -3295,10 +3312,6 @@ block_item_decl
{ yyerror(@1, "error: Syntax error in variable list.");
yyerrok;
}
| ps_type_identifier_dim error ';'
{ yyerror(@1, "error: Syntax error in variable list.");
yyerrok;
}
| K_event error ';'
{ yyerror(@1, "error: Syntax error in event variable list.");
yyerrok;
@ -5613,7 +5626,13 @@ module_item
/* block_item_decl rule is shared with task blocks and named
begin/end. Careful to pass attributes to the block_item_decl. */
| attribute_list_opt { attributes_in_context = $1; } block_item_decl
| attribute_list_opt type_identifier_variable_decl_assignments_with_type ';'
{ if ($2.type) pform_make_var(@2, $2.decl_assignments, $2.type, $1, false);
var_lifetime = LexicalScope::INHERITED;
if ($1) delete $1;
}
| attribute_list_opt { attributes_in_context = $1; } block_item_decl_no_type_identifier_start
{ delete attributes_in_context;
attributes_in_context = 0;
}