Fix issue #298: elaborate types in the scope where they were declared.

The compiler elaborates types on the fly as they are used. For user-
defined types (typedefs) we must do the elaboration in the scope where
the type was declared, not in the scope where it is used.
This commit is contained in:
Martin Whitaker 2019-12-22 17:29:23 +00:00
parent e8e2c35df0
commit 8dc395940d
6 changed files with 74 additions and 7 deletions

View File

@ -490,6 +490,8 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
use_class->set_definition_scope(scope);
set_scope_timescale(des, class_scope, pclass);
class_scope->add_typedefs(&pclass->typedefs);
// Elaborate enum types declared in the class. We need these
// now because enumeration constants can be used during scope
// elaboration.
@ -708,6 +710,8 @@ bool PPackage::elaborate_scope(Design*des, NetScope*scope)
<< "Elaborate package " << scope_path(scope) << "." << endl;
}
scope->add_typedefs(&typedefs);
collect_scope_parameters_(des, scope, parameters);
collect_scope_localparams_(des, scope, localparams);
@ -734,6 +738,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
<< "Elaborate " << scope_path(scope) << "." << endl;
}
scope->add_typedefs(&typedefs);
// Add the genvars to the scope.
typedef map<perm_string,LineInfo*>::const_iterator genvar_it_t;
for (genvar_it_t cur = genvars.begin(); cur != genvars.end(); ++ cur ) {
@ -1192,6 +1198,8 @@ void PGenerate::elaborate_subscope_direct_(Design*des, NetScope*scope)
void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
{
scope->add_typedefs(&typedefs);
// Add the genvars to this scope.
typedef map<perm_string,LineInfo*>::const_iterator genvar_it_t;
for (genvar_it_t cur = genvars.begin(); cur != genvars.end(); ++ cur ) {
@ -1545,6 +1553,8 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const
// find otherwise.
scope->is_const_func(true);
scope->add_typedefs(&typedefs);
// Scan the parameters in the function, and store the information
// needed to evaluate the parameter expressions.
@ -1563,6 +1573,8 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
scope->add_typedefs(&typedefs);
// Scan the parameters in the task, and store the information
// needed to evaluate the parameter expressions.
@ -1611,6 +1623,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
my_scope->set_line(get_file(), get_lineno());
my_scope->is_auto(scope->is_auto());
my_scope->add_imports(&explicit_imports);
my_scope->add_typedefs(&typedefs);
// Scan the parameters in the scope, and store the information
// needed to evaluate the parameter expressions.

View File

@ -955,6 +955,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
unsigned wid = 1;
vector<netrange_t>packed_dimensions;
NetScope*base_type_scope = scope;
if (set_data_type_ && !set_data_type_->name.nil())
base_type_scope = scope->find_typedef_scope(des, set_data_type_);
des->errors += error_cnt_;
if (port_set_ || net_set_) {
@ -997,7 +1001,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Evaluate ranges for net " << basename() << endl;
}
dimensions_ok &= evaluate_ranges(des, scope, this, nlist, net_);
dimensions_ok &= evaluate_ranges(des, base_type_scope, this, nlist, net_);
}
assert(net_set_ || net_.empty());
@ -1068,6 +1072,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
list<netrange_t>unpacked_dimensions;
netdarray_t*netdarray = 0;
NetScope*array_type_scope = scope;
if (uarray_type_ && !uarray_type_->name.nil())
array_type_scope = scope->find_typedef_scope(des, uarray_type_);
for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
; cur != unpacked_.end() ; ++cur) {
PExpr*use_lidx = cur->first;
@ -1100,7 +1108,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
ivl_assert(*this, netdarray==0);
long index_l, index_r;
evaluate_range(des, scope, this, *cur, index_l, index_r);
evaluate_range(des, array_type_scope, this, *cur, index_l, index_r);
if (abs(index_r - index_l) > warn_dimension_size) {
cerr << get_fileline() << ": warning: Array dimension "
@ -1191,7 +1199,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
} else if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(set_data_type_)) {
list<named_pexpr_t>::const_iterator sample_name = enum_type->names->begin();
const netenum_t*use_enum = scope->find_enumeration_for_name(des, sample_name->name);
const netenum_t*use_enum = base_type_scope->find_enumeration_for_name(des, sample_name->name);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype

View File

@ -78,6 +78,11 @@ static void elaborate_array_ranges(Design*des, NetScope*scope,
*/
ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope)
{
// User-defined types must be elaborated in the context
// where they were defined.
if (!name.nil())
scope = scope->find_typedef_scope(des, this);
ivl_assert(*this, scope);
Definitions*use_definitions = scope;

View File

@ -119,6 +119,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, NetScope*in_u
is_interface_(interface), is_unit_(compilation_unit), unit_(in_unit), up_(up)
{
imports_ = 0;
typedefs_ = 0;
events_ = 0;
lcounter_ = 0;
is_auto_ = false;
@ -224,6 +225,35 @@ NetScope*NetScope::find_import(const Design*des, perm_string name)
return 0;
}
void NetScope::add_typedefs(const map<perm_string,data_type_t*>*typedefs)
{
if (!typedefs->empty())
typedefs_ = typedefs;
}
NetScope*NetScope::find_typedef_scope(const Design*des, data_type_t*type)
{
assert(type);
NetScope *cur_scope = this;
while (cur_scope) {
if (cur_scope->typedefs_ && cur_scope->typedefs_->find(type->name) != cur_scope->typedefs_->end())
return cur_scope;
NetScope*import_scope = cur_scope->find_import(des, type->name);
if (import_scope)
cur_scope = import_scope;
else if (cur_scope == unit_)
return 0;
else
cur_scope = cur_scope->parent();
if (cur_scope == 0)
cur_scope = unit_;
}
return 0;
}
/*
* Look for the enumeration in the current scope and any parent scopes.
*/
@ -235,9 +265,12 @@ const netenum_t*NetScope::find_enumeration_for_name(const Design*des, perm_strin
if (tmp) break;
NetScope*import_scope = cur_scope->find_import(des, name);
if (import_scope)
cur_scope = import_scope;
cur_scope = import_scope;
else if (cur_scope == unit_)
return 0;
else
cur_scope = cur_scope->parent();
cur_scope = cur_scope->parent();
if (cur_scope == 0)
cur_scope = unit_;
}

View File

@ -946,6 +946,11 @@ class NetScope : public Definitions, public Attrib {
void add_imports(const map<perm_string,PPackage*>*imports);
NetScope*find_import(const Design*des, perm_string name);
void add_typedefs(const map<perm_string,data_type_t*>*typedefs);
/* Search the scope hierarchy for the scope where 'type' was defined. */
NetScope*find_typedef_scope(const Design*des, data_type_t*type);
/* Routine to search for the enumeration given a name. It basically
* does what enumeration_for_name() does but searched the hierarchy. */
const netenum_t*find_enumeration_for_name(const Design*des, perm_string name);
@ -1275,6 +1280,8 @@ class NetScope : public Definitions, public Attrib {
const map<perm_string,PPackage*>*imports_;
const map<perm_string,data_type_t*>*typedefs_;
NetEvent *events_;
map<perm_string,LineInfo*> genvars_;

View File

@ -3520,8 +3520,9 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type,
// Add the file and line information to the enumeration type.
FILE_NAME(&(enum_type->li), li);
// Attach the enumeration to the current scope.
pform_put_enum_type_in_scope(enum_type);
// If this is an anonymous enumeration, attach it to the current scope.
if (enum_type->name.nil())
pform_put_enum_type_in_scope(enum_type);
// Now apply the checked enumeration type to the variables
// that are being declared with this type.