From 7c5c1acf027540e48ecbfed3466cf1af402cf15f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 11 Aug 2026 08:15:24 -0700 Subject: [PATCH] Use `symbol_search()` for task and function calls Task and function calls used as statements currently use `Design::find_task()` and `Design::find_function()`, which only search for scopes of the requested type. A closer variable, named event, or parameter is skipped. This can call a hidden task or function, and can make the non-void discarded-return path resolve a different symbol and abort. Use one `symbol_search()` for both task lookup and the function fallback so all declarations in the shared name space participate in lookup. Accept a function scope or the return variable of a recursive function call, while preserving the existing method fallback. Allow the terminal task or function name to be declared later while resolving a receiver prefix at the call position. Use the call position when the method fallback searches for the receiver as well. Remove the now unused `Design::find_task()` and `Design::find_function()` helpers. Signed-off-by: Lars-Peter Clausen --- Statement.h | 3 ++- elaborate.cc | 51 ++++++++++++++++++++++++++++++++++----------------- net_design.cc | 32 -------------------------------- netlist.h | 6 ------ 4 files changed, 36 insertions(+), 56 deletions(-) diff --git a/Statement.h b/Statement.h index b1f77678e..831853bbf 100644 --- a/Statement.h +++ b/Statement.h @@ -251,7 +251,8 @@ class PCallTask : public Statement { NetProc*elaborate_method_(Design*des, NetScope*scope, bool add_this_flag = false) const; - NetProc*elaborate_function_(Design*des, NetScope*scope) const; + NetProc *elaborate_function_( + Design *des, NetScope *scope, NetScope *func_scope) const; NetProc*elaborate_void_function_(Design*des, NetScope*scope, NetFuncDef*def) const; NetProc *elaborate_non_void_function_(Design *des, NetScope *scope, diff --git a/elaborate.cc b/elaborate.cc index fd195c606..32e600ed5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3950,25 +3950,35 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const { ivl_assert(*this, scope); - NetScope*pscope = scope; - if (package_) { - pscope = des->find_package(package_->pscope_name()); - ivl_assert(*this, pscope); + symbol_search_results search_results; + pform_scoped_name_t call_path(package_, path_); + NetScope *task = nullptr; + NetScope *func_scope = nullptr; + if (symbol_search(this, des, scope, call_path, lexical_pos(), + &search_results, true)) { + if (search_results.is_scope()) { + if (search_results.scope->type() == NetScope::TASK) + task = search_results.scope; + else if (search_results.scope->type() == NetScope::FUNC) + func_scope = search_results.scope; + } else if (test_function_return_value(search_results)) { + // A recursive function call resolves to the function return + // variable. Its containing scope is the function being called. + func_scope = search_results.scope; + } } - NetScope*task = des->find_task(pscope, path_); - if (task == 0) { + if (!task) { // For SystemVerilog this may be a few other things. if (gn_system_verilog()) { - NetProc *tmp; // This could be a method attached to a signal // or defined in this object? bool try_implicit_this = scope->get_class_scope() && path_.size() == 1; - tmp = elaborate_method_(des, scope, try_implicit_this); + NetProc *tmp = elaborate_method_(des, scope, try_implicit_this); if (tmp) return tmp; // Or it could be a function call ignoring the return? - tmp = elaborate_function_(des, scope); - if (tmp) return tmp; + if (func_scope) + return elaborate_function_(des, scope, func_scope); } cerr << get_fileline() << ": error: Enable of unknown task " @@ -4307,7 +4317,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, // (internally represented as "@") is handled by there being a // "this" object in the instance scope. symbol_search_results sr; - symbol_search(this, des, scope, use_path, UINT_MAX, &sr); + symbol_search(this, des, scope, use_path, lexical_pos(), &sr); NetNet*net = sr.net; if (net == 0) @@ -4631,14 +4641,21 @@ NetProc *PCallTask::elaborate_non_void_function_(Design *des, NetScope *scope, return tmp->elaborate(des, scope); } -NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const +NetProc *PCallTask::elaborate_function_( + Design *des, NetScope *scope, NetScope *func_scope) const { - NetFuncDef*func = des->find_function(scope, path_); + ivl_assert(*this, func_scope); + ivl_assert(*this, func_scope->type() == NetScope::FUNC); - // This is not a function, so this task call cannot be a function - // call with a missing return assignment. - if (!func) - return nullptr; + // The function signals might not have been elaborated yet. + if (func_scope->elab_stage() < 2) { + func_scope->need_const_func(true); + const PFunction *pfunc = func_scope->func_pform(); + ivl_assert(*this, pfunc); + pfunc->elaborate_sig(des, func_scope); + } + NetFuncDef *func = func_scope->func_def(); + ivl_assert(*this, func); if (gn_system_verilog() && func->is_void()) return elaborate_void_function_(des, scope, func); diff --git a/net_design.cc b/net_design.cc index 0491457b9..8ea4bf7be 100644 --- a/net_design.cc +++ b/net_design.cc @@ -1030,38 +1030,6 @@ NetNet* Design::find_signal(NetScope*scope, pform_name_t path) return 0; } -NetFuncDef* Design::find_function(NetScope*scope, const pform_name_t&name) -{ - assert(scope); - - std::list eval_path = eval_scope_path(this, scope, name); - NetScope*func = find_scope(scope, eval_path, NetScope::FUNC); - if (func && (func->type() == NetScope::FUNC)) { - // If a function is used in a parameter definition or in - // a signal declaration, it is possible to get here before - // the function's signals have been elaborated. If this is - // the case, elaborate them now. - if (func->elab_stage() < 2) { - func->need_const_func(true); - const PFunction*pfunc = func->func_pform(); - assert(pfunc); - pfunc->elaborate_sig(this, func); - } - return func->func_def(); - } - return 0; -} - -NetScope* Design::find_task(NetScope*scope, const pform_name_t&name) -{ - std::list eval_path = eval_scope_path(this, scope, name); - NetScope*task = find_scope(scope, eval_path, NetScope::TASK); - if (task && (task->type() == NetScope::TASK)) - return task; - - return 0; -} - void Design::add_node(NetNode*net) { assert(net->design_ == 0); diff --git a/netlist.h b/netlist.h index f64a97246..7812fcb79 100644 --- a/netlist.h +++ b/netlist.h @@ -5215,12 +5215,6 @@ class Design { NetNet*find_signal(NetScope*scope, pform_name_t path); - // Functions - NetFuncDef* find_function(NetScope*scope, const pform_name_t&key); - - // Tasks - NetScope* find_task(NetScope*scope, const pform_name_t&name); - // NODES void add_node(NetNode*); void del_node(NetNode*);