Merge pull request #1425 from larsclausen/taskfunc-type-id-shadow
Support task and function names shadowing type identifiers
This commit is contained in:
commit
b6829ab504
|
|
@ -0,0 +1,37 @@
|
|||
// Regression test for GitHub issue #670.
|
||||
// Check that a class function can have the same name as the class.
|
||||
|
||||
module test;
|
||||
|
||||
reg failed;
|
||||
|
||||
`define check(value, expected, error) \
|
||||
if ((value) !== (expected)) begin \
|
||||
$display("FAILED(%0d). %s", `__LINE__, error); \
|
||||
$display(" expected %0h, got %0h", expected, value); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
class test;
|
||||
int value;
|
||||
|
||||
function void test();
|
||||
value = 32'd42;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
initial begin
|
||||
test tst;
|
||||
|
||||
failed = 1'b0;
|
||||
tst = new;
|
||||
tst.test();
|
||||
|
||||
`check(tst.value, 32'd42, "Class function name did not hide class name");
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Check that function names can shadow visible type identifiers.
|
||||
|
||||
typedef int T;
|
||||
typedef int U;
|
||||
|
||||
module test;
|
||||
|
||||
reg failed;
|
||||
|
||||
`define check(value, expected, error) \
|
||||
if ((value) !== (expected)) begin \
|
||||
$display("FAILED(%0d). %s", `__LINE__, error); \
|
||||
$display(" expected %0h, got %0h", expected, value); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
function int T(input int value);
|
||||
return value + 32'd1;
|
||||
endfunction
|
||||
|
||||
function U;
|
||||
U = 1'b1;
|
||||
endfunction
|
||||
|
||||
class C;
|
||||
function int T(input int value);
|
||||
return value + 32'd2;
|
||||
endfunction
|
||||
|
||||
function int C(input int value);
|
||||
return value + 32'd3;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
initial begin
|
||||
C c;
|
||||
|
||||
failed = 1'b0;
|
||||
c = new;
|
||||
|
||||
`check(T(32'd41), 32'd42, "Function name did not hide typedef");
|
||||
`check(U(), 1'b1, "Implicit function name did not hide typedef");
|
||||
`check(c.T(32'd40), 32'd42, "Class function name did not hide typedef");
|
||||
`check(c.C(32'd39), 32'd42, "Class function name did not hide class name");
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Check that task names can shadow visible type identifiers.
|
||||
|
||||
typedef int T;
|
||||
typedef int U;
|
||||
|
||||
module test;
|
||||
|
||||
reg failed;
|
||||
|
||||
`define check(value, expected, error) \
|
||||
if ((value) !== (expected)) begin \
|
||||
$display("FAILED(%0d). %s", `__LINE__, error); \
|
||||
$display(" expected %0h, got %0h", expected, value); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
task T(input int value, output int result);
|
||||
result = value + 32'd1;
|
||||
endtask
|
||||
|
||||
task U;
|
||||
output int result;
|
||||
|
||||
result = 32'd33;
|
||||
endtask
|
||||
|
||||
class C;
|
||||
task T(input int value, output int result);
|
||||
result = value + 32'd2;
|
||||
endtask
|
||||
|
||||
task C(input int value, output int result);
|
||||
result = value + 32'd3;
|
||||
endtask
|
||||
endclass
|
||||
|
||||
initial begin
|
||||
C c;
|
||||
int r0;
|
||||
int r1;
|
||||
int r2;
|
||||
int r3;
|
||||
|
||||
failed = 1'b0;
|
||||
c = new;
|
||||
|
||||
T(32'd41, r0);
|
||||
U(r1);
|
||||
c.T(32'd40, r2);
|
||||
c.C(32'd39, r3);
|
||||
|
||||
`check(r0, 32'd42, "Task name did not hide typedef");
|
||||
`check(r1, 32'd33, "Non-ANSI task name did not hide typedef");
|
||||
`check(r2, 32'd42, "Class task name did not hide typedef");
|
||||
`check(r3, 32'd42, "Class task name did not hide class name");
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -37,6 +37,7 @@ br_gh440 vvp_tests/br_gh440.json
|
|||
br_gh483a vvp_tests/br_gh483a.json
|
||||
br_gh483b vvp_tests/br_gh483b.json
|
||||
br_gh552 vvp_tests/br_gh552.json
|
||||
br_gh670 vvp_tests/br_gh670.json
|
||||
br_gh687 vvp_tests/br_gh687.json
|
||||
br_gh703 vvp_tests/br_gh703.json
|
||||
br_gh710a vvp_tests/br_gh710a.json
|
||||
|
|
@ -387,6 +388,7 @@ sv_super_member_fail vvp_tests/sv_super_member_fail.json
|
|||
sv_type_identifier_ams_name_fields vvp_tests/sv_type_identifier_ams_name_fields.json
|
||||
sv_type_identifier_config_name vvp_tests/sv_type_identifier_config_name.json
|
||||
sv_type_identifier_foreach_name vvp_tests/sv_type_identifier_foreach_name.json
|
||||
sv_type_identifier_function_name vvp_tests/sv_type_identifier_function_name.json
|
||||
sv_type_identifier_genvar_name vvp_tests/sv_type_identifier_genvar_name.json
|
||||
sv_type_identifier_modport_name vvp_tests/sv_type_identifier_modport_name.json
|
||||
sv_type_identifier_module_name vvp_tests/sv_type_identifier_module_name.json
|
||||
|
|
@ -399,6 +401,7 @@ sv_type_identifier_parameter_type_param_name vvp_tests/sv_type_identifier_parame
|
|||
sv_type_identifier_port_name vvp_tests/sv_type_identifier_port_name.json
|
||||
sv_type_identifier_specparam_name vvp_tests/sv_type_identifier_specparam_name.json
|
||||
sv_type_identifier_task_function_argument_name vvp_tests/sv_type_identifier_task_function_argument_name.json
|
||||
sv_type_identifier_task_name vvp_tests/sv_type_identifier_task_name.json
|
||||
sv_type_identifier_variable_name vvp_tests/sv_type_identifier_variable_name.json
|
||||
sv_type_param_restrict_class1 vvp_tests/sv_type_param_restrict_class1.json
|
||||
sv_type_param_restrict_class2 vvp_tests/sv_type_param_restrict_class2.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "br_gh670.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "Classes are not supported",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_function_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "Classes are not supported",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_task_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "Classes are not supported",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
82
parse.y
82
parse.y
|
|
@ -1017,7 +1017,9 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
|
||||
%type <type_restrict> forward_type forward_type_without_enum
|
||||
%type <type_id_range> data_type_or_implicit_plus_id_base
|
||||
%type <type_id_range> data_type_or_implicit_plus_id
|
||||
%type <type_id_range> data_type_or_implicit_plus_id_dim
|
||||
%type <type_id_range> data_type_or_implicit_or_void_plus_id
|
||||
%type <type_id_range> partial_port_name_dim
|
||||
%type <type_id_range> partial_port_type_plus_id_dim
|
||||
%type <type_id_range> partial_port_typedef_plus_id_dim
|
||||
|
|
@ -1808,53 +1810,53 @@ for_step_opt
|
|||
definitions in the func_body to take on the scope of the function
|
||||
instead of the module. */
|
||||
function_declaration /* IEEE1800-2005: A.2.6 */
|
||||
: K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';'
|
||||
: K_function lifetime_opt data_type_or_implicit_or_void_plus_id ';'
|
||||
{ assert(current_function == 0);
|
||||
current_function = pform_push_function_scope(@1, $4, $2);
|
||||
current_function = pform_push_function_scope(@1, $3.id, $2);
|
||||
}
|
||||
tf_item_list_opt
|
||||
statement_or_null_list_opt
|
||||
K_endfunction
|
||||
{ current_function->set_ports($7);
|
||||
current_function->set_return($3);
|
||||
current_function_set_statement($8? @8 : @4, $8);
|
||||
pform_set_this_class(@4, current_function);
|
||||
{ current_function->set_ports($6);
|
||||
current_function->set_return($3.type);
|
||||
current_function_set_statement($7 ? @7 : @3, $7);
|
||||
pform_set_this_class(@3, current_function);
|
||||
pform_pop_scope();
|
||||
current_function = 0;
|
||||
}
|
||||
label_opt
|
||||
{ // Last step: check any closing name.
|
||||
check_end_label(@11, "function", $4, $11);
|
||||
delete[]$4;
|
||||
check_end_label(@10, "function", $3.id, $10);
|
||||
delete[]$3.id;
|
||||
}
|
||||
|
||||
| K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER
|
||||
| K_function lifetime_opt data_type_or_implicit_or_void_plus_id
|
||||
{ assert(current_function == 0);
|
||||
current_function = pform_push_function_scope(@1, $4, $2);
|
||||
current_function = pform_push_function_scope(@1, $3.id, $2);
|
||||
}
|
||||
'(' tf_port_list_opt ')' ';'
|
||||
block_item_decls_opt
|
||||
statement_or_null_list_opt
|
||||
K_endfunction
|
||||
{ current_function->set_ports($7);
|
||||
current_function->set_return($3);
|
||||
current_function_set_statement($11? @11 : @4, $11);
|
||||
pform_set_this_class(@4, current_function);
|
||||
{ current_function->set_ports($6);
|
||||
current_function->set_return($3.type);
|
||||
current_function_set_statement($10 ? @10 : @3, $10);
|
||||
pform_set_this_class(@3, current_function);
|
||||
pform_pop_scope();
|
||||
current_function = 0;
|
||||
if ($7 == 0) {
|
||||
pform_requires_sv(@4, "Functions with no ports");
|
||||
if ($6 == 0) {
|
||||
pform_requires_sv(@3, "Functions with no ports");
|
||||
}
|
||||
}
|
||||
label_opt
|
||||
{ // Last step: check any closing name.
|
||||
check_end_label(@14, "function", $4, $14);
|
||||
delete[]$4;
|
||||
check_end_label(@13, "function", $3.id, $13);
|
||||
delete[]$3.id;
|
||||
}
|
||||
|
||||
/* Detect and recover from some errors. */
|
||||
|
||||
| K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction
|
||||
| K_function lifetime_opt data_type_or_implicit_or_void_plus_id error K_endfunction
|
||||
{ /* */
|
||||
if (current_function) {
|
||||
pform_pop_scope();
|
||||
|
|
@ -1866,8 +1868,8 @@ function_declaration /* IEEE1800-2005: A.2.6 */
|
|||
}
|
||||
label_opt
|
||||
{ // Last step: check any closing name.
|
||||
check_end_label(@8, "function", $4, $8);
|
||||
delete[]$4;
|
||||
check_end_label(@7, "function", $3.id, $7);
|
||||
delete[]$3.id;
|
||||
}
|
||||
|
||||
;
|
||||
|
|
@ -2662,7 +2664,11 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */
|
|||
|
||||
task_declaration /* IEEE1800-2005: A.2.7 */
|
||||
|
||||
: K_task lifetime_opt IDENTIFIER ';'
|
||||
/* Tasks do not have a return type, so the leading identifier is always the
|
||||
task name. Use identifier_name so a name tokenized as TYPE_IDENTIFIER can
|
||||
still declare a task that shadows a visible type name. */
|
||||
|
||||
: K_task lifetime_opt identifier_name ';'
|
||||
{ assert(current_task == 0);
|
||||
current_task = pform_push_task_scope(@1, $3, $2);
|
||||
}
|
||||
|
|
@ -2689,7 +2695,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
|||
delete[]$3;
|
||||
}
|
||||
|
||||
| K_task lifetime_opt IDENTIFIER '('
|
||||
| K_task lifetime_opt identifier_name '('
|
||||
{ assert(current_task == 0);
|
||||
current_task = pform_push_task_scope(@1, $3, $2);
|
||||
}
|
||||
|
|
@ -2718,7 +2724,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
|||
delete[]$3;
|
||||
}
|
||||
|
||||
| K_task lifetime_opt IDENTIFIER error K_endtask
|
||||
| K_task lifetime_opt identifier_name error K_endtask
|
||||
{
|
||||
if (current_task) {
|
||||
pform_pop_scope();
|
||||
|
|
@ -2765,6 +2771,20 @@ data_type_or_implicit_plus_id_base
|
|||
}
|
||||
;
|
||||
|
||||
// Function declarations have the same type/name ambiguity as other
|
||||
// declarations. For `function T;`, T can be the function name even when the
|
||||
// lexer returns TYPE_IDENTIFIER, while `function T f;` still uses T as the
|
||||
// explicit return type. Unlike variable/net declarations, function names do
|
||||
// not allow unpacked dimensions.
|
||||
data_type_or_implicit_plus_id
|
||||
: TYPE_IDENTIFIER
|
||||
{ set_type_id_range($$, nullptr, $1.text, @1, nullptr);
|
||||
}
|
||||
| data_type_or_implicit_plus_id_base
|
||||
{ $$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
data_type_or_implicit_plus_id_dim
|
||||
: TYPE_IDENTIFIER dimensions_opt
|
||||
{ set_type_id_range($$, nullptr, $1.text, @1, $2);
|
||||
|
|
@ -2775,6 +2795,20 @@ data_type_or_implicit_plus_id_dim
|
|||
}
|
||||
;
|
||||
|
||||
// `void` is only an explicit return type. The following identifier is still a
|
||||
// function name and may be tokenized as TYPE_IDENTIFIER when it shadows a
|
||||
// visible type name.
|
||||
data_type_or_implicit_or_void_plus_id
|
||||
: data_type_or_implicit_plus_id
|
||||
{ $$ = $1;
|
||||
}
|
||||
| K_void identifier_name
|
||||
{ void_type_t*tmp = new void_type_t;
|
||||
FILE_NAME(tmp, @1);
|
||||
set_type_id_range($$, tmp, $2, @2, nullptr);
|
||||
}
|
||||
;
|
||||
|
||||
// Partial ANSI port declarations such as `input a, integer b` can redeclare
|
||||
// the data type without repeating the direction. Keep this narrower than
|
||||
// data_type_or_implicit_plus_id_dim so a bare identifier after a comma is
|
||||
|
|
|
|||
Loading…
Reference in New Issue