From f3092bba931108ca8b86850314aaedcba91e4bd8 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 28 Jun 2024 22:22:16 +0100 Subject: [PATCH] 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. --- elab_expr.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 12967412a..f7828c83c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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);