diff --git a/elab_expr.cc b/elab_expr.cc index 561f7a24e..e7a6794b8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -309,7 +309,8 @@ static const netclass_t* resolve_call_chain_prefix_class(Design*des, NetScope*sc if (link->peek_chain_prefix() == 0) { symbol_search_results sr; - if (!symbol_search(link, des, scope, link->peek_path(), UINT_MAX, &sr)) { + if (!symbol_search(link, des, scope, link->peek_path(), + link->lexical_pos(), &sr, true)) { return 0; } if (!sr.is_scope() || sr.scope->type() != NetScope::FUNC) { @@ -2100,7 +2101,8 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, // Search for the symbol. This should turn up a scope. symbol_search_results search_results; - bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results); + bool search_flag = symbol_search(this, des, scope, path_, lexical_pos(), + &search_results, true); if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::test_width: " @@ -3239,7 +3241,8 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope, // Search for the symbol. This should turn up a scope. symbol_search_results search_results; - bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results); + bool search_flag = symbol_search(this, des, scope, path_, lexical_pos(), + &search_results, true); if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::elaborate_expr: " diff --git a/netmisc.h b/netmisc.h index 8ea5f05d9..a9e9c1bb5 100644 --- a/netmisc.h +++ b/netmisc.h @@ -134,14 +134,17 @@ static inline bool test_function_return_value(const symbol_search_results&search return true; } -extern bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, - pform_name_t path, unsigned lexical_pos, - struct symbol_search_results*res, - NetScope*start_scope = nullptr, bool scope_is_bound = false); - extern bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, - const pform_scoped_name_t &path, unsigned lexical_pos, - struct symbol_search_results*res); + pform_name_t path, unsigned int lexical_pos, + struct symbol_search_results *res); + +/* The forward-reference flag applies only to the terminal name. Prefix + components still use lexical_pos. */ +extern bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, + const pform_scoped_name_t &path, + unsigned int lexical_pos, + struct symbol_search_results *res, + bool allow_terminal_forward_reference = false); extern bool check_interface_modport_access(const LineInfo *li, Design *des, const symbol_search_results &res, diff --git a/symbol_search.cc b/symbol_search.cc index afff1bb44..ce4b1d317 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -293,10 +293,11 @@ static bool symbol_search_child_scope( * the initial caller. */ -bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, - pform_name_t path, unsigned lexical_pos, - struct symbol_search_results*res, - NetScope*start_scope, bool scope_is_bound) +static bool symbol_search_(const LineInfo *li, Design *des, NetScope *scope, + pform_name_t path, unsigned int lexical_pos, + unsigned int prefix_lexical_pos, + struct symbol_search_results *res, + NetScope *start_scope, bool scope_is_bound) { assert(scope); @@ -315,21 +316,18 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, name_component_t path_tail = path.back(); path.pop_back(); - // If this is a recursive call, then we need to know that so - // that we can enable the search for scopes. Set the - // recurse_flag to true if this is a recurse. - if (start_scope==0) - start_scope = scope; - NetScope *unit_scope = start_scope->unit(); bool searched_unit_scope = false; + NetScope *instance_parent = nullptr; // If there are components ahead of the tail, symbol_search // recursively. Ideally, the result is a scope that we search // for the tail key, but there are other special cases as well. if (! path.empty()) { - bool flag = symbol_search(li, des, scope, path, lexical_pos, - res, start_scope, scope_is_bound); + bool flag = symbol_search_(li, des, scope, path, + prefix_lexical_pos, + prefix_lexical_pos, res, + start_scope, scope_is_bound); if (! flag) return false; @@ -403,6 +401,9 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, // scope or item. In this case, res->is_found() is false and we may need // to scan upwards to find the scope or item. while (scope) { + if (scope == unit_scope) + searched_unit_scope = true; + if (debug_scopes || debug_elaborate) { cerr << li->get_fileline() << ": symbol_search: " << "Looking for " << path_tail @@ -480,6 +481,21 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } + // Lookup leaves a design unit through its lexical parent, the + // compilation-unit scope, before continuing up the instance hierarchy + // (LRM 3.12.1). + const bool is_design_unit = + (scope->type() == NetScope::MODULE && !scope->nested_module()) + || scope->type() == NetScope::PACKAGE; + if (!scope_is_bound && !searched_unit_scope && is_design_unit + && unit_scope && scope != unit_scope) { + instance_parent = scope->parent(); + scope = unit_scope; + searched_unit_scope = true; + search_objects = true; + continue; + } + // If there is no prefix, then we are free to scan upwards looking // for a scope name. Note that only scopes can be searched for up // past module boundaries. Stop searching for objects after leaving @@ -489,6 +505,12 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, scope = scope->parent(); + if (scope == nullptr && instance_parent) { + scope = instance_parent; + instance_parent = nullptr; + search_objects = false; + } + // Last chance - try the compilation unit. Note that modules may // reference nets/variables in the compilation unit, even if they // cannot reference variables in containing scope. @@ -529,8 +551,17 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, - const pform_scoped_name_t &path, unsigned lexical_pos, + pform_name_t path, unsigned int lexical_pos, struct symbol_search_results *res) +{ + return symbol_search_(li, des, scope, path, lexical_pos, lexical_pos, + res, scope, false); +} + +bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, + const pform_scoped_name_t &path, unsigned int lexical_pos, + struct symbol_search_results *res, + bool allow_terminal_forward_reference) { NetScope *search_scope = scope; bool scope_is_bound = false; @@ -542,8 +573,11 @@ bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, scope_is_bound = true; } - return symbol_search(li, des, search_scope, path.name, lexical_pos, - res, search_scope, scope_is_bound); + const unsigned int terminal_lexical_pos = allow_terminal_forward_reference + ? UINT_MAX : lexical_pos; + return symbol_search_(li, des, search_scope, path.name, + terminal_lexical_pos, lexical_pos, res, + search_scope, scope_is_bound); } bool check_interface_modport_access(const LineInfo *li, Design *des,