symbol_search(): Search compilation-unit scope before instance hierarchy
`symbol_search()` currently searches the enclosing instance hierarchy before the compilation-unit scope for ordinary names. An enclosing instance scope can therefore hide an earlier compilation-unit variable or object, including when the object is the prefix of a dotted reference. The LRM section 3.12.1 requires a common lookup order. First search the local lexical scopes through the design unit. Next search the compilation-unit scope up to the reference position. If there is no match, resume at the saved instantiation parent and continue through the instance hierarchy. Disable data object lookup when resuming so only enclosing scope names can match. Task and function names follow the same traversal, but the LRM section 23.8.1 lets the terminal subroutine name search the complete compilation unit. Use a separate terminal lexical limit for this. Resolve a prefix such as `object` in `object.func()` at the reference position while allowing a forward declaration of `func`. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
f35515ac65
commit
9d7e8e67ab
|
|
@ -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: "
|
||||
|
|
|
|||
17
netmisc.h
17
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue