Add support for void cast function call

SystemVerilog has explicit support for calling a function
as a statement. This is allowed when the function call is encapsulated in
`void'(...)`. E.g. `void'(f(1, 2, 3));`

We already support calling function calls as statements without the void
cast and emit a warning when doing so.

Adding support for void casts only requires to update the parser to handle
the void cast and then do not emit the warning if a function is called as
a statement as part of a void cast.

Void casting a task or void function call is not allowed and will generate
an elaboration error.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-10-12 11:05:57 +02:00
parent 54956f0f29
commit 0e62ff153d
3 changed files with 70 additions and 35 deletions

View File

@ -226,6 +226,8 @@ class PCallTask : public Statement {
bool elaborate_elab(Design*des, NetScope*scope) const;
void void_cast() { void_cast_ = true; }
private:
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
@ -257,6 +259,7 @@ class PCallTask : public Statement {
PPackage*package_;
pform_name_t path_;
std::vector<PExpr*> parms_;
bool void_cast_ = false;
};
class PCase : public Statement {

View File

@ -3390,10 +3390,14 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
{
if (peek_tail_name(path_)[0] == '$')
return elaborate_sys(des, scope);
if (peek_tail_name(path_)[0] == '$') {
if (void_cast_)
return elaborate_non_void_function_(des, scope);
else
return elaborate_sys(des, scope);
} else {
return elaborate_usr(des, scope);
}
}
/*
@ -3690,8 +3694,10 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
perm_string method_name,
const char*sys_task_name) const
{
if (!void_cast_) {
cerr << get_fileline() << ": warning: method function '"
<< method_name << "' is being called as a task." << endl;
}
// Generate the function.
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
@ -3906,8 +3912,11 @@ NetProc *PCallTask::elaborate_non_void_function_(Design *des, NetScope *scope) c
PAssign*tmp = new PAssign(0, rval);
tmp->set_file(get_file());
tmp->set_lineno(get_lineno());
if (!void_cast_) {
cerr << get_fileline() << ": warning: User function '"
<< peek_tail_name(path_) << "' is being called as a task." << endl;
}
// Elaborate the assignment to a dummy variable.
return tmp->elaborate(des, scope);
}
@ -3962,11 +3971,23 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
// that we can catch more errors.
test_task_calls_ok_(des, scope);
if (void_cast_) {
cerr << get_fileline() << ": error: void casting user task '"
<< peek_tail_name(path_) << "' is not allowed." << endl;
des->errors++;
}
} else if (task->type() == NetScope::FUNC) {
NetFuncDef*tmp = task->func_def();
if (!tmp->is_void())
return elaborate_non_void_function_(des, scope);
def = tmp;
if (void_cast_) {
cerr << get_fileline() << ": error: void casting user void function '"
<< peek_tail_name(path_) << "' is not allowed." << endl;
des->errors++;
}
}
/* The caller has checked the parms_ size to make sure it

65
parse.y
View File

@ -420,6 +420,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
PWire*wire;
std::vector<PWire*>*wires;
PCallTask *subroutine_call;
PEventStatement*event_statement;
Statement*statement;
std::vector<Statement*>*statement_list;
@ -685,6 +687,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <statement> analog_statement
%type <subroutine_call> subroutine_call
%type <join_keyword> join_keyword
%type <letter> spec_polarity
@ -6241,6 +6245,35 @@ spec_notifier
{ args_after_notifier = 0; delete[]$1; }
;
subroutine_call
: hierarchy_identifier argument_list_parens_opt
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
delete $1;
delete $2;
$$ = tmp;
}
| class_hierarchy_identifier argument_list_parens_opt
{ PCallTask*tmp = new PCallTask(*$1, *$2);
FILE_NAME(tmp, @1);
delete $1;
delete $2;
$$ = tmp;
}
| SYSTEM_IDENTIFIER argument_list_parens_opt
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
FILE_NAME(tmp,@1);
delete[]$1;
delete $2;
$$ = tmp;
}
| hierarchy_identifier '(' error ')'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
}
;
statement_item /* This is roughly statement_item in the LRM */
@ -6592,19 +6625,13 @@ statement_item /* This is roughly statement_item in the LRM */
FILE_NAME(tmp,@1);
$$ = tmp;
}
| SYSTEM_IDENTIFIER argument_list_parens_opt ';'
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
FILE_NAME(tmp,@1);
delete[]$1;
delete $2;
$$ = tmp;
| K_void '\'' '(' subroutine_call ')' ';'
{ $4->void_cast();
$$ = $4;
}
| hierarchy_identifier argument_list_parens_opt ';'
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
delete $1;
delete $2;
$$ = tmp;
| subroutine_call ';'
{ $$ = $1;
}
| hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';'
@ -6622,14 +6649,6 @@ statement_item /* This is roughly statement_item in the LRM */
$$ = tmp;
}
| class_hierarchy_identifier argument_list_parens_opt ';'
{ PCallTask*tmp = new PCallTask(*$1, *$2);
FILE_NAME(tmp, @1);
delete $1;
delete $2;
$$ = tmp;
}
/* IEEE1800 A.1.8: class_constructor_declaration with a call to
parent constructor. Note that the implicit_class_handle must
be K_super ("this.new" makes little sense) but that would
@ -6646,14 +6665,6 @@ statement_item /* This is roughly statement_item in the LRM */
delete $1;
$$ = tmp;
}
| hierarchy_identifier '(' error ')' ';'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
}
| error ';'
{ yyerror(@2, "error: malformed statement");
yyerrok;