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:
parent
54956f0f29
commit
0e62ff153d
|
|
@ -226,6 +226,8 @@ class PCallTask : public Statement {
|
||||||
|
|
||||||
bool elaborate_elab(Design*des, NetScope*scope) const;
|
bool elaborate_elab(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
|
void void_cast() { void_cast_ = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
|
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
|
||||||
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
|
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
|
||||||
|
|
@ -257,6 +259,7 @@ class PCallTask : public Statement {
|
||||||
PPackage*package_;
|
PPackage*package_;
|
||||||
pform_name_t path_;
|
pform_name_t path_;
|
||||||
std::vector<PExpr*> parms_;
|
std::vector<PExpr*> parms_;
|
||||||
|
bool void_cast_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PCase : public Statement {
|
class PCase : public Statement {
|
||||||
|
|
|
||||||
25
elaborate.cc
25
elaborate.cc
|
|
@ -3390,10 +3390,14 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
|
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
if (peek_tail_name(path_)[0] == '$')
|
if (peek_tail_name(path_)[0] == '$') {
|
||||||
return elaborate_sys(des, scope);
|
if (void_cast_)
|
||||||
|
return elaborate_non_void_function_(des, scope);
|
||||||
else
|
else
|
||||||
|
return elaborate_sys(des, scope);
|
||||||
|
} else {
|
||||||
return elaborate_usr(des, scope);
|
return elaborate_usr(des, scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -3690,8 +3694,10 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
||||||
perm_string method_name,
|
perm_string method_name,
|
||||||
const char*sys_task_name) const
|
const char*sys_task_name) const
|
||||||
{
|
{
|
||||||
|
if (!void_cast_) {
|
||||||
cerr << get_fileline() << ": warning: method function '"
|
cerr << get_fileline() << ": warning: method function '"
|
||||||
<< method_name << "' is being called as a task." << endl;
|
<< method_name << "' is being called as a task." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the function.
|
// Generate the function.
|
||||||
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
|
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);
|
PAssign*tmp = new PAssign(0, rval);
|
||||||
tmp->set_file(get_file());
|
tmp->set_file(get_file());
|
||||||
tmp->set_lineno(get_lineno());
|
tmp->set_lineno(get_lineno());
|
||||||
|
if (!void_cast_) {
|
||||||
cerr << get_fileline() << ": warning: User function '"
|
cerr << get_fileline() << ": warning: User function '"
|
||||||
<< peek_tail_name(path_) << "' is being called as a task." << endl;
|
<< peek_tail_name(path_) << "' is being called as a task." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Elaborate the assignment to a dummy variable.
|
// Elaborate the assignment to a dummy variable.
|
||||||
return tmp->elaborate(des, scope);
|
return tmp->elaborate(des, scope);
|
||||||
}
|
}
|
||||||
|
|
@ -3962,11 +3971,23 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
|
||||||
// that we can catch more errors.
|
// that we can catch more errors.
|
||||||
test_task_calls_ok_(des, scope);
|
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) {
|
} else if (task->type() == NetScope::FUNC) {
|
||||||
NetFuncDef*tmp = task->func_def();
|
NetFuncDef*tmp = task->func_def();
|
||||||
if (!tmp->is_void())
|
if (!tmp->is_void())
|
||||||
return elaborate_non_void_function_(des, scope);
|
return elaborate_non_void_function_(des, scope);
|
||||||
def = tmp;
|
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
|
/* The caller has checked the parms_ size to make sure it
|
||||||
|
|
|
||||||
65
parse.y
65
parse.y
|
|
@ -420,6 +420,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
|
||||||
PWire*wire;
|
PWire*wire;
|
||||||
std::vector<PWire*>*wires;
|
std::vector<PWire*>*wires;
|
||||||
|
|
||||||
|
PCallTask *subroutine_call;
|
||||||
|
|
||||||
PEventStatement*event_statement;
|
PEventStatement*event_statement;
|
||||||
Statement*statement;
|
Statement*statement;
|
||||||
std::vector<Statement*>*statement_list;
|
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 <statement> analog_statement
|
||||||
|
|
||||||
|
%type <subroutine_call> subroutine_call
|
||||||
|
|
||||||
%type <join_keyword> join_keyword
|
%type <join_keyword> join_keyword
|
||||||
|
|
||||||
%type <letter> spec_polarity
|
%type <letter> spec_polarity
|
||||||
|
|
@ -6241,6 +6245,35 @@ spec_notifier
|
||||||
{ args_after_notifier = 0; delete[]$1; }
|
{ 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 */
|
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);
|
FILE_NAME(tmp,@1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| SYSTEM_IDENTIFIER argument_list_parens_opt ';'
|
| K_void '\'' '(' subroutine_call ')' ';'
|
||||||
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
|
{ $4->void_cast();
|
||||||
FILE_NAME(tmp,@1);
|
$$ = $4;
|
||||||
delete[]$1;
|
|
||||||
delete $2;
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
| hierarchy_identifier argument_list_parens_opt ';'
|
| subroutine_call ';'
|
||||||
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
|
{ $$ = $1;
|
||||||
delete $1;
|
|
||||||
delete $2;
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
| hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';'
|
| hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';'
|
||||||
|
|
@ -6622,14 +6649,6 @@ statement_item /* This is roughly statement_item in the LRM */
|
||||||
$$ = tmp;
|
$$ = 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
|
/* IEEE1800 A.1.8: class_constructor_declaration with a call to
|
||||||
parent constructor. Note that the implicit_class_handle must
|
parent constructor. Note that the implicit_class_handle must
|
||||||
be K_super ("this.new" makes little sense) but that would
|
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;
|
delete $1;
|
||||||
$$ = tmp;
|
$$ = 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 ';'
|
| error ';'
|
||||||
{ yyerror(@2, "error: malformed statement");
|
{ yyerror(@2, "error: malformed statement");
|
||||||
yyerrok;
|
yyerrok;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue