Correctly identify scopes for constant function calls (issue #1141)

A constant function call may be inside a named block, so we need to
search upwards to find the enclosing module before checking that the
called function is local to that module.

SystemVerilog allows constant function calls to reference functions
in (other) packages or in the $unit scope, so extend the checks to
permit that.
This commit is contained in:
Martin Whitaker 2024-06-28 22:22:16 +01:00
parent dc6f9f2049
commit f3092bba93
1 changed files with 24 additions and 2 deletions

View File

@ -2964,11 +2964,33 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope,
pfunc->elaborate(des, dscope);
}
if (dscope->parent() != scope->parent() || !dscope->is_const_func()) {
// From IEEE 1800-2023 section 13.4.3:
// A constant function call is a function call of a constant function
// wherein the constant function's declaration is local to the calling
// design element or is in a package or $unit.
bool is_const_func_call = false;
if (dscope->is_const_func()) {
NetScope*caller_scope = scope;
while (caller_scope && caller_scope->type() != NetScope::MODULE
&& caller_scope->type() != NetScope::PACKAGE) {
caller_scope = caller_scope->parent();
}
NetScope*callee_scope = dscope->parent();
while (callee_scope && callee_scope->type() != NetScope::MODULE
&& callee_scope->type() != NetScope::PACKAGE) {
callee_scope = callee_scope->parent();
}
ivl_assert(*this, caller_scope);
ivl_assert(*this, callee_scope);
is_const_func_call = (callee_scope == caller_scope) ||
(callee_scope->type() == NetScope::PACKAGE);
}
if (!is_const_func_call) {
if (scope->need_const_func()) {
cerr << get_fileline() << ": error: A function invoked by "
"a constant function must be a constant function "
"local to the current module." << endl;
"local to the current module or provided by a "
"package." << endl;
des->errors += 1;
}
scope->is_const_func(false);