Honor package import lexical order during identifier lookup
Package imports become visible from the import declaration, or for wildcard
imports, from the reference that makes an identifier locally visible. For
example:
package p;
parameter X = 2;
endpackage
parameter X = 1;
module m;
localparam A = X;
import p::X;
localparam B = X;
endmodule
Currently both `A` and `B` resolve to `p::X`. `A` should resolve to the
compilation-unit `X`, while only `B` should resolve to `p::X`.
Record the lexical position where each imported name becomes locally visible.
Pass reference positions through ordinary symbol lookup and implicit named
port connections so imports introduced later are ignored.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
eda9fdcd13
commit
3679d25e4b
14
PScope.h
14
PScope.h
|
|
@ -43,6 +43,16 @@ class PCallTask;
|
|||
class Design;
|
||||
class NetScope;
|
||||
|
||||
struct package_import_t : public LineInfo {
|
||||
package_import_t() = default;
|
||||
explicit package_import_t(PPackage *pkg) : package(pkg) { }
|
||||
|
||||
PPackage *package = nullptr;
|
||||
// LineInfo records where the imported name became locally visible.
|
||||
};
|
||||
|
||||
using package_import_map_t = std::map<perm_string, package_import_t>;
|
||||
|
||||
/*
|
||||
* The PScope class is a base representation of an object that
|
||||
* represents lexical scope. For example, a module, a function/task, a
|
||||
|
|
@ -71,7 +81,7 @@ class LexicalScope {
|
|||
// Symbols that are explicitly imported. This contains the package where
|
||||
// the symbol has been decelared. When using exports, this might not be
|
||||
// the same as the package where it has been imported from.
|
||||
std::map<perm_string,PPackage*>explicit_imports;
|
||||
package_import_map_t explicit_imports;
|
||||
// Symbols that are explicitly imported. This contains the set of
|
||||
// packages from which the symbol has been imported. When using exports
|
||||
// the same identifier can be imported via multiple packages.
|
||||
|
|
@ -86,7 +96,7 @@ class LexicalScope {
|
|||
// later in the scope. So here we stash the potential imports for
|
||||
// task and function calls. They will be added to the explicit
|
||||
// imports if we don't find a local definition.
|
||||
std::map<perm_string,PPackage*>possible_imports;
|
||||
package_import_map_t possible_imports;
|
||||
|
||||
struct range_t {
|
||||
// True if this is an exclude
|
||||
|
|
|
|||
23
net_scope.cc
23
net_scope.cc
|
|
@ -111,7 +111,6 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, NetScope*in_u
|
|||
: type_(t), name_(n), nested_module_(nest), program_block_(program),
|
||||
is_interface_(interface), is_unit_(compilation_unit), unit_(in_unit), up_(up)
|
||||
{
|
||||
imports_ = 0;
|
||||
events_ = 0;
|
||||
lcounter_ = 0;
|
||||
is_auto_ = false;
|
||||
|
|
@ -215,22 +214,26 @@ void NetScope::set_line(perm_string file, perm_string def_file,
|
|||
def_lineno_ = def_lineno;
|
||||
}
|
||||
|
||||
void NetScope::add_imports(const map<perm_string,PPackage*>*imports)
|
||||
void NetScope::add_imports(const package_import_map_t *imports)
|
||||
{
|
||||
if (!imports->empty())
|
||||
imports_ = imports;
|
||||
}
|
||||
|
||||
NetScope*NetScope::find_import(const Design*des, perm_string name)
|
||||
NetScope *NetScope::find_import(const Design *des, perm_string name,
|
||||
unsigned int lexical_pos)
|
||||
{
|
||||
if (imports_ == 0)
|
||||
return 0;
|
||||
if (!imports_)
|
||||
return nullptr;
|
||||
|
||||
map<perm_string,PPackage*>::const_iterator cur = imports_->find(name);
|
||||
if (cur != imports_->end()) {
|
||||
return des->find_package(cur->second->pscope_name());
|
||||
} else
|
||||
return 0;
|
||||
auto cur = imports_->find(name);
|
||||
if (cur == imports_->end())
|
||||
return nullptr;
|
||||
|
||||
if (cur->second.lexical_pos() > lexical_pos)
|
||||
return nullptr;
|
||||
|
||||
return des->find_package(cur->second.package->pscope_name());
|
||||
}
|
||||
|
||||
void NetScope::add_typedefs(const map<perm_string,typedef_t*>*typedefs)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
* can be passed around in this form to the various stages and design
|
||||
* processors.
|
||||
*/
|
||||
# include <climits>
|
||||
# include <string>
|
||||
# include <map>
|
||||
# include <list>
|
||||
|
|
@ -997,8 +998,9 @@ class NetScope : public Definitions, public Attrib {
|
|||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
void add_imports(const std::map<perm_string,PPackage*>*imports);
|
||||
NetScope*find_import(const Design*des, perm_string name);
|
||||
void add_imports(const package_import_map_t *imports);
|
||||
NetScope *find_import(const Design *des, perm_string name,
|
||||
unsigned int lexical_pos = UINT_MAX);
|
||||
|
||||
void add_typedefs(const std::map<perm_string,typedef_t*>*typedefs);
|
||||
|
||||
|
|
@ -1377,7 +1379,7 @@ class NetScope : public Definitions, public Attrib {
|
|||
signed char time_unit_, time_prec_;
|
||||
bool time_from_timescale_;
|
||||
|
||||
const std::map<perm_string,PPackage*>*imports_;
|
||||
const package_import_map_t *imports_ = nullptr;
|
||||
|
||||
std::map<perm_string,typedef_t*>typedefs_;
|
||||
|
||||
|
|
|
|||
17
pform.cc
17
pform.cc
|
|
@ -412,10 +412,9 @@ LexicalScope* pform_peek_scope(void)
|
|||
|
||||
static void pform_check_possible_imports(LexicalScope *scope)
|
||||
{
|
||||
map<perm_string,PPackage*>::const_iterator cur;
|
||||
for (cur = scope->possible_imports.begin(); cur != scope->possible_imports.end(); ++cur) {
|
||||
if (scope->local_symbols.find(cur->first) == scope->local_symbols.end())
|
||||
scope->explicit_imports[cur->first] = cur->second;
|
||||
for (const auto &cur : scope->possible_imports) {
|
||||
if (!scope->local_symbols.count(cur.first))
|
||||
scope->explicit_imports[cur.first] = cur.second;
|
||||
}
|
||||
scope->possible_imports.clear();
|
||||
}
|
||||
|
|
@ -473,13 +472,12 @@ static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*it
|
|||
}
|
||||
|
||||
// Check for conflict with an explicit import.
|
||||
map<perm_string,PPackage*>::const_iterator cur_pkg
|
||||
= scope->explicit_imports.find(name);
|
||||
auto cur_pkg = scope->explicit_imports.find(name);
|
||||
if (cur_pkg != scope->explicit_imports.end()) {
|
||||
cerr << item->get_fileline() << ": error: "
|
||||
"'" << name << "' has already been "
|
||||
"imported into this scope from package '"
|
||||
<< cur_pkg->second->pscope_name() << "'." << endl;
|
||||
<< cur_pkg->second.package->pscope_name() << "'." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
|
@ -931,10 +929,9 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
|
|||
// something other than a type, then give up now because
|
||||
// the name has at least shadowed any other possible
|
||||
// meaning for this name.
|
||||
map<perm_string,PPackage*>::iterator cur_pkg;
|
||||
cur_pkg = cur_scope->explicit_imports.find(name);
|
||||
auto cur_pkg = cur_scope->explicit_imports.find(name);
|
||||
if (cur_pkg != cur_scope->explicit_imports.end()) {
|
||||
PPackage*pkg = cur_pkg->second;
|
||||
auto pkg = cur_pkg->second.package;
|
||||
cur = pkg->typedefs.find(name);
|
||||
if (cur != pkg->typedefs.end())
|
||||
return cur->second;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,14 @@ static map<perm_string,PPackage*> packages_by_name;
|
|||
|
||||
static PPackage*pform_cur_package = 0;
|
||||
|
||||
static package_import_t make_package_import(PPackage *pkg,
|
||||
const struct vlltype &loc)
|
||||
{
|
||||
package_import_t import(pkg);
|
||||
FILE_NAME(&import, loc);
|
||||
return import;
|
||||
}
|
||||
|
||||
void pform_start_package_declaration(const struct vlltype&loc, const char*name,
|
||||
LexicalScope::lifetime_t lifetime)
|
||||
{
|
||||
|
|
@ -97,10 +105,12 @@ PPackage *pform_find_potential_import(const struct vlltype&loc, LexicalScope*sco
|
|||
|
||||
found_pkg = decl_pkg;
|
||||
if (make_explicit) {
|
||||
if (tf_call)
|
||||
scope->possible_imports[name] = found_pkg;
|
||||
else {
|
||||
scope->explicit_imports[name] = found_pkg;
|
||||
if (tf_call) {
|
||||
scope->possible_imports.emplace(
|
||||
name, make_package_import(found_pkg, loc));
|
||||
} else {
|
||||
scope->explicit_imports.emplace(
|
||||
name, make_package_import(found_pkg, loc));
|
||||
scope->explicit_imports_from[name].insert(search_pkg);
|
||||
}
|
||||
}
|
||||
|
|
@ -122,9 +132,9 @@ PPackage *pform_package_importable(PPackage *pkg, perm_string name)
|
|||
// *::* will match all imports, P::* will match all imports
|
||||
// from a package and P::ID will match a specific identifier
|
||||
// from a package.
|
||||
if ((!exp.pkg || exp.pkg == import_pkg->second) &&
|
||||
if ((!exp.pkg || exp.pkg == import_pkg->second.package) &&
|
||||
(exp.name.nil() || exp.name == name))
|
||||
return import_pkg->second;
|
||||
return import_pkg->second.package;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -166,19 +176,20 @@ void pform_package_import(const struct vlltype&loc, PPackage*pkg, const char*ide
|
|||
}
|
||||
|
||||
// Check for conflict with previous import.
|
||||
map<perm_string,PPackage*>::const_iterator cur_pkg
|
||||
= scope->explicit_imports.find(use_ident);
|
||||
auto cur_pkg = scope->explicit_imports.find(use_ident);
|
||||
if (cur_pkg != scope->explicit_imports.end()) {
|
||||
if (cur_pkg->second != pkg_decl) {
|
||||
if (cur_pkg->second.package != pkg_decl) {
|
||||
cerr << loc.get_fileline() << ": error: "
|
||||
"'" << use_ident << "' has already been "
|
||||
"imported into this scope from package '"
|
||||
<< cur_pkg->second->pscope_name() << "'." << endl;
|
||||
<< cur_pkg->second.package->pscope_name()
|
||||
<< "'." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
scope->explicit_imports[use_ident] = pkg_decl;
|
||||
scope->explicit_imports.emplace(
|
||||
use_ident, make_package_import(pkg_decl, loc));
|
||||
scope->explicit_imports_from[use_ident].insert(pkg);
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -372,7 +372,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
break;
|
||||
|
||||
// Imports are not visible through hierachical names
|
||||
if (NetScope*import_scope = scope->find_import(des, path_tail.name)) {
|
||||
if (auto import_scope = scope->find_import(
|
||||
des, path_tail.name, lexical_pos)) {
|
||||
scope = import_scope;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue