Correctly handle explicit and wildcard package imports.

Explicit imports should always conflict with local declarations using
the same name. Wildcard imports only conflict if they are referenced
before a local declaration with the same name.

This also unifies the detection of identifier conflicts.
This commit is contained in:
Martin Whitaker 2019-09-26 23:35:57 +01:00
parent b88d91c617
commit d3bced57cc
9 changed files with 278 additions and 313 deletions

View File

@ -61,6 +61,18 @@ class LexicalScope {
lifetime_t default_lifetime;
// Symbols that are defined or declared in this scope.
std::map<perm_string,PNamedItem*>local_symbols;
// Symbols that are explicitly imported. Bind the imported name
// to the package from which the name is imported.
std::map<perm_string,PPackage*>explicit_imports;
// Packages that are wildcard imported. When identifiers from
// these packages are referenced, they will be added to the
// explicit imports (IEEE 1800-2012 26.3).
std::set<PPackage*>potential_imports;
struct range_t {
// True if this is an exclude
bool exclude_flag;
@ -102,10 +114,6 @@ class LexicalScope {
// Named events in the scope.
map<perm_string,PEvent*>events;
// Symbols that are imported. Bind the imported name to the
// package from which the name is imported.
std::map<perm_string,PPackage*>imports;
// Nets and variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);

View File

@ -542,7 +542,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
// Task methods are always automatic...
method_scope->is_auto(true);
method_scope->set_line(cur->second);
method_scope->add_imports(&cur->second->imports);
method_scope->add_imports(&cur->second->explicit_imports);
if (debug_scopes) {
cerr << cur->second->get_fileline() << ": elaborate_scope_class: "
@ -561,7 +561,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
// Function methods are always automatic...
method_scope->is_auto(true);
method_scope->set_line(cur->second);
method_scope->add_imports(&cur->second->imports);
method_scope->add_imports(&cur->second->explicit_imports);
if (debug_scopes) {
cerr << cur->second->get_fileline() << ": elaborate_scope_class: "
@ -632,7 +632,7 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task)
NetScope*task_scope = new NetScope(scope, use_name, NetScope::TASK);
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);
task_scope->add_imports(&task->imports);
task_scope->add_imports(&task->explicit_imports);
if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_task: "
@ -695,7 +695,7 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task)
NetScope*task_scope = new NetScope(scope, use_name, NetScope::FUNC);
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);
task_scope->add_imports(&task->imports);
task_scope->add_imports(&task->explicit_imports);
if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_func: "
@ -1069,7 +1069,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
NetScope*scope = new NetScope(container, use_name,
NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
scope->add_imports(&imports);
scope->add_imports(&explicit_imports);
// Set in the scope a localparam for the value of the
// genvar within this instance of the generate
@ -1205,7 +1205,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
// for myself. That is what I will pass to the subscope.
NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
scope->add_imports(&imports);
scope->add_imports(&explicit_imports);
elaborate_subscope_(des, scope);
@ -1346,7 +1346,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
NetScope*scope = new NetScope(container, use_name,
NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
scope->add_imports(&imports);
scope->add_imports(&explicit_imports);
item->elaborate_subscope_(des, scope);
@ -1403,7 +1403,7 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
NetScope*scope = new NetScope(container, use_name,
NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
scope->add_imports(&imports);
scope->add_imports(&explicit_imports);
elaborate_subscope_(des, scope);
@ -1709,7 +1709,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
my_scope->set_line(get_file(), mod->get_file(),
get_lineno(), mod->get_lineno());
my_scope->set_module_name(mod->mod_name());
my_scope->add_imports(&mod->imports);
my_scope->add_imports(&mod->explicit_imports);
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val);
@ -1934,7 +1934,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
: NetScope::BEGIN_END);
my_scope->set_line(get_file(), get_lineno());
my_scope->is_auto(scope->is_auto());
my_scope->add_imports(&imports);
my_scope->add_imports(&explicit_imports);
// Scan the parameters in the scope, and store the information
// needed to evaluate the parameter expressions.

View File

@ -6528,7 +6528,7 @@ Design* elaborate(list<perm_string>roots)
PPackage*unit = pform_units[i];
NetScope*scope = des->make_package_scope(unit->pscope_name(), 0, true);
scope->set_line(unit);
scope->add_imports(&unit->imports);
scope->add_imports(&unit->explicit_imports);
set_scope_timescale(des, scope, unit);
elaborator_work_item_t*es = new elaborate_package_t(des, scope, unit);
@ -6553,7 +6553,7 @@ Design* elaborate(list<perm_string>roots)
NetScope*unit_scope = unit_scopes[pac->second->parent_scope()];
NetScope*scope = des->make_package_scope(pac->first, unit_scope, false);
scope->set_line(pac->second);
scope->add_imports(&pac->second->imports);
scope->add_imports(&pac->second->explicit_imports);
set_scope_timescale(des, scope, pac->second);
elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second);
@ -6595,7 +6595,7 @@ Design* elaborate(list<perm_string>roots)
// Collect some basic properties of this scope from the
// Module definition.
scope->set_line(rmod);
scope->add_imports(&rmod->imports);
scope->add_imports(&rmod->explicit_imports);
set_scope_timescale(des, scope, rmod);
// Save this scope, along with its definition, in the

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -362,7 +362,7 @@ TU [munpf]
/* If this identifier names a previously declared type, then
return this as a TYPE_IDENTIFIER instead. */
if (rc == IDENTIFIER && gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
rc = TYPE_IDENTIFIER;
@ -383,7 +383,7 @@ TU [munpf]
}
}
if (gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) {
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
return TYPE_IDENTIFIER;

20
parse.y
View File

@ -1428,7 +1428,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */
{ pform_name_t tmp_hident;
tmp_hident.push_back(name_component_t(lex_strings.make($4)));
PEIdent*tmp_ident = pform_new_ident(tmp_hident);
PEIdent*tmp_ident = pform_new_ident(@4, tmp_hident);
FILE_NAME(tmp_ident, @4);
PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13);
@ -3604,7 +3604,7 @@ expr_primary
indexed arrays and part selects */
| hierarchy_identifier
{ PEIdent*tmp = pform_new_ident(*$1);
{ PEIdent*tmp = pform_new_ident(@1, *$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
@ -4500,7 +4500,7 @@ atom2_type
rule to reflect the rules for assignment l-values. */
lpvalue
: hierarchy_identifier
{ PEIdent*tmp = pform_new_ident(*$1);
{ PEIdent*tmp = pform_new_ident(@1, *$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
@ -5040,24 +5040,24 @@ module_item
IDENTIFIER '=' expression ')'
{ pform_start_generate_for(@1, $3, $5, $7, $9, $11); }
generate_block
{ pform_endgenerate(); }
{ pform_endgenerate(false); }
| generate_if
generate_block_opt
K_else
{ pform_start_generate_else(@1); }
generate_block
{ pform_endgenerate(); }
{ pform_endgenerate(true); }
| generate_if
generate_block_opt %prec less_than_K_else
{ pform_endgenerate(); }
{ pform_endgenerate(true); }
| K_case '(' expression ')'
{ pform_start_generate_case(@1, $3); }
generate_case_items
K_endcase
{ pform_endgenerate(); }
{ pform_endgenerate(true); }
| modport_declaration
@ -5154,9 +5154,9 @@ generate_case_items
generate_case_item
: expression_list_proper ':' { pform_generate_case_item(@1, $1); } generate_block_opt
{ pform_endgenerate(); }
{ pform_endgenerate(false); }
| K_default ':' { pform_generate_case_item(@1, 0); } generate_block_opt
{ pform_endgenerate(); }
{ pform_endgenerate(false); }
;
generate_item
@ -5177,7 +5177,7 @@ generate_item
warn_count += 1;
cerr << @1 << ": warning: Anachronistic use of named begin/end to surround generate schemes." << endl;
}
pform_endgenerate();
pform_endgenerate(false);
}
;

View File

@ -1,7 +1,7 @@
#ifndef IVL_parse_misc_H
#define IVL_parse_misc_H
/*
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -88,7 +88,7 @@ extern void lex_in_package_scope(PPackage*pkg);
* parser detects typedefs and marks the typedef'ed identifiers as
* type names.
*/
extern data_type_t* pform_test_type_identifier(const char*txt);
extern data_type_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt);
extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt);
extern bool pform_test_type_identifier_local(perm_string txt);

403
pform.cc
View File

@ -349,6 +349,13 @@ static unsigned scope_generate_counter = 1;
always within a module. */
static PGenerate*pform_cur_generate = 0;
/* Blocks within the same conditional generate construct may have
the same name. Here we collect the set of names used in each
construct, so they can be added to the local scope without
conflicting with each other. Generate constructs may nest, so
we need a stack. */
static list<set<perm_string>> conditional_block_names;
/* This tracks the current modport list being processed. This is
always within an interface. */
static PModport*pform_cur_modport = 0;
@ -423,6 +430,87 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
return scopex;
}
static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*item)
{
assert(scope);
// Check for conflict with another local symbol.
map<perm_string,PNamedItem*>::const_iterator cur_sym
= scope->local_symbols.find(name);
if (cur_sym != scope->local_symbols.end()) {
cerr << item->get_fileline() << ": error: "
"'" << name << "' has already been declared "
"in this scope." << endl;
cerr << cur_sym->second->get_fileline() << ": : "
"It was declared here as "
<< cur_sym->second->symbol_type() << "." << endl;
error_count += 1;
return;
}
// Check for conflict with an explicit import.
map<perm_string,PPackage*>::const_iterator 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;
error_count += 1;
return;
}
scope->local_symbols[name] = item;
}
static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*scope,
perm_string name, PNamedItem::SymbolType st)
{
assert(scope);
PPackage*found_pkg = 0;
for (set<PPackage*>::const_iterator cur_pkg = scope->potential_imports.begin();
cur_pkg != scope->potential_imports.end(); ++cur_pkg) {
PPackage*search_pkg = *cur_pkg;
map<perm_string,PNamedItem*>::const_iterator cur_sym
= search_pkg->local_symbols.find(name);
if (cur_sym != search_pkg->local_symbols.end()) {
if (st != PNamedItem::ANY && st != cur_sym->second->symbol_type())
continue;
if (found_pkg) {
cerr << loc.get_fileline() << ": error: "
"Ambiguous use of '" << name << "'. "
"It is exported by both '"
<< found_pkg->pscope_name()
<< "' and by '"
<< search_pkg->pscope_name()
<< "'." << endl;
error_count += 1;
} else {
found_pkg = search_pkg;
scope->explicit_imports[name] = found_pkg;
}
}
}
return found_pkg;
}
static void check_potential_imports(const struct vlltype&loc, perm_string name)
{
LexicalScope*scope = lexical_scope;
while (scope) {
if (scope->local_symbols.find(name) != scope->local_symbols.end())
return;
if (scope->explicit_imports.find(name) != scope->explicit_imports.end())
return;
if (find_potential_import(loc, scope, name, PNamedItem::ANY))
return;
scope = scope->parent_scope();
}
}
/*
* Set the local time unit/precision. This version is used for setting
* the time scale for design elements (modules, packages, etc.) and is
@ -516,12 +604,6 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
pform_set_scope_timescale(class_scope, scopex);
if (scopex->classes.find(name) != scopex->classes.end()) {
cerr << class_scope->get_fileline() << ": error: duplicate "
"definition for class '" << name << "' in '"
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
scopex->classes[name] = class_scope;
scopex->classes_lexical .push_back(class_scope);
@ -566,25 +648,11 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name,
pform_set_scope_timescale(task, scopex);
if (pform_cur_generate) {
// Check if the task is already in the dictionary.
if (pform_cur_generate->tasks.find(task->pscope_name()) !=
pform_cur_generate->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate "
"definition for task '" << name << "' in '"
<< pform_cur_module.front()->mod_name() << "' (generate)."
<< endl;
error_count += 1;
}
pform_cur_generate->tasks[task->pscope_name()] = task;
add_local_symbol(pform_cur_generate, task_name, task);
pform_cur_generate->tasks[task_name] = task;
} else {
// Check if the task is already in the dictionary.
if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate "
"definition for task '" << name << "' in '"
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
scopex->tasks[task->pscope_name()] = task;
add_local_symbol(scopex, task_name, task);
scopex->tasks[task_name] = task;
}
lexical_scope = task;
@ -615,26 +683,12 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
pform_set_scope_timescale(func, scopex);
if (pform_cur_generate) {
// Check if the function is already in the dictionary.
if (pform_cur_generate->funcs.find(func->pscope_name()) !=
pform_cur_generate->funcs.end()) {
cerr << func->get_fileline() << ": error: duplicate "
"definition for function '" << name << "' in '"
<< pform_cur_module.front()->mod_name() << "' (generate)."
<< endl;
error_count += 1;
}
pform_cur_generate->funcs[func->pscope_name()] = func;
add_local_symbol(pform_cur_generate, func_name, func);
pform_cur_generate->funcs[func_name] = func;
} else {
// Check if the function is already in the dictionary.
if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) {
cerr << func->get_fileline() << ": error: duplicate "
"definition for function '" << name << "' in '"
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
scopex->funcs[func->pscope_name()] = func;
add_local_symbol(scopex, func_name, func);
scopex->funcs[func_name] = func;
}
lexical_scope = func;
@ -657,6 +711,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
PBlock*block = new PBlock(block_name, lexical_scope, bt);
block->default_lifetime = find_lifetime(LexicalScope::INHERITED);
if (name) add_local_symbol(lexical_scope, block_name, block);
lexical_scope = block;
return block;
@ -665,8 +720,11 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
/*
* Create a new identifier.
*/
PEIdent* pform_new_ident(const pform_name_t&name)
PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name)
{
if (gn_system_verilog() && name.size() == 1)
check_potential_imports(loc, name.back().name);
return new PEIdent(name);
}
@ -721,6 +779,7 @@ PWire*pform_get_wire_in_scope(perm_string name)
static void pform_put_wire_in_scope(perm_string name, PWire*net)
{
add_local_symbol(lexical_scope, name, net);
lexical_scope->wires[name] = net;
}
@ -729,7 +788,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set)
lexical_scope->enum_sets.insert(enum_set);
}
PWire*pform_get_make_wire_in_scope(const struct vlltype&li, perm_string name,
PWire*pform_get_make_wire_in_scope(const struct vlltype&, perm_string name,
NetNet::Type net_type, NetNet::PortType port_type,
ivl_variable_type_t vt_type)
{
@ -737,15 +796,11 @@ PWire*pform_get_make_wire_in_scope(const struct vlltype&li, perm_string name,
// If the wire already exists and is fully defined, this
// must be a redeclaration. Start again with a new wire.
if (cur && cur->get_data_type() != IVL_VT_NO_TYPE) {
LineInfo tloc;
FILE_NAME(&tloc, li);
cerr << tloc.get_fileline() << ": error: duplicate declaration "
"for net or variable '" << name << "'." << endl;
error_count += 1;
delete cur;
// The error will be reported when we add the new wire
// to the scope. Do not delete the old wire - it will
// remain in the local symbol map.
if (cur && cur->get_data_type() != IVL_VT_NO_TYPE)
cur = 0;
}
if (cur == 0) {
cur = new PWire(name, net_type, port_type, vt_type);
@ -765,6 +820,8 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list<pform_
if(unp_ranges)
data_type = new uarray_type_t(data_type, unp_ranges);
add_local_symbol(lexical_scope, name, data_type);
data_type_t*&ref = lexical_scope->typedefs[name];
ivl_assert(*data_type, ref == 0);
@ -772,10 +829,14 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list<pform_
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(data_type)) {
pform_put_enum_type_in_scope(enum_type);
list<named_pexpr_t>::const_iterator cur;
for (cur = enum_type->names->begin(); cur != enum_type->names->end(); ++cur)
add_local_symbol(lexical_scope, cur->name, enum_type);
}
}
data_type_t* pform_test_type_identifier(const char*txt)
data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
{
perm_string name = lex_strings.make(txt);
@ -790,8 +851,8 @@ data_type_t* pform_test_type_identifier(const char*txt)
// the name has at least shadowed any other possible
// meaning for this name.
map<perm_string,PPackage*>::iterator cur_pkg;
cur_pkg = cur_scope->imports.find(name);
if (cur_pkg != cur_scope->imports.end()) {
cur_pkg = cur_scope->explicit_imports.find(name);
if (cur_pkg != cur_scope->explicit_imports.end()) {
PPackage*pkg = cur_pkg->second;
cur = pkg->typedefs.find(name);
if (cur != pkg->typedefs.end())
@ -805,6 +866,13 @@ data_type_t* pform_test_type_identifier(const char*txt)
if (cur != cur_scope->typedefs.end())
return cur->second;
PPackage*pkg = find_potential_import(loc, cur_scope, name, PNamedItem::TYPE);
if (pkg) {
cur = pkg->typedefs.find(name);
if (cur != cur_scope->typedefs.end())
return cur->second;
}
cur_scope = cur_scope->parent_scope();
} while (cur_scope);
@ -833,6 +901,9 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)
{
if (gn_system_verilog() && name.size() == 1)
check_potential_imports(loc, name.back().name);
PECallFunction*tmp = new PECallFunction(name, parms);
FILE_NAME(tmp, loc);
return tmp;
@ -842,6 +913,9 @@ PCallTask* pform_make_call_task(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)
{
if (gn_system_verilog() && name.size() == 1)
check_potential_imports(loc, name.back().name);
PCallTask*tmp = new PCallTask(name, parms);
FILE_NAME(tmp, loc);
return tmp;
@ -1224,6 +1298,8 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
allow_timeunit_decl = true;
allow_timeprec_decl = true;
add_local_symbol(lexical_scope, lex_name, cur_module);
lexical_scope = cur_module;
/* The generate scheme numbering starts with *1*, not
@ -1307,31 +1383,20 @@ void pform_endmodule(const char*name, bool inside_celldefine,
pform_pop_scope();
}
static void pform_add_genvar(const struct vlltype&li, const perm_string&name,
map<perm_string,LineInfo*>&genvars)
{
LineInfo*lni = new LineInfo();
FILE_NAME(lni, li);
if (genvars.find(name) != genvars.end()) {
cerr << lni->get_fileline() << ": error: genvar '"
<< name << "' has already been declared." << endl;
cerr << genvars[name]->get_fileline()
<< ": the previous declaration is here." << endl;
error_count += 1;
delete lni;
} else {
genvars[name] = lni;
}
}
void pform_genvars(const struct vlltype&li, list<perm_string>*names)
{
list<perm_string>::const_iterator cur;
for (cur = names->begin(); cur != names->end() ; *cur++) {
if (pform_cur_generate)
pform_add_genvar(li, *cur, pform_cur_generate->genvars);
else
pform_add_genvar(li, *cur, pform_cur_module.front()->genvars);
PGenvar*genvar = new PGenvar();
FILE_NAME(genvar, li);
if (pform_cur_generate) {
add_local_symbol(pform_cur_generate, *cur, genvar);
pform_cur_generate->genvars[*cur] = genvar;
} else {
add_local_symbol(pform_cur_module.front(), *cur, genvar);
pform_cur_module.front()->genvars[*cur] = genvar;
}
}
delete names;
@ -1374,6 +1439,8 @@ void pform_start_generate_if(const struct vlltype&li, PExpr*test)
pform_cur_generate->loop_init = 0;
pform_cur_generate->loop_test = test;
pform_cur_generate->loop_step = 0;
conditional_block_names.push_front(set<perm_string>());
}
void pform_start_generate_else(const struct vlltype&li)
@ -1382,7 +1449,7 @@ void pform_start_generate_else(const struct vlltype&li)
assert(pform_cur_generate->scheme_type == PGenerate::GS_CONDIT);
PGenerate*cur = pform_cur_generate;
pform_endgenerate();
pform_endgenerate(false);
PGenerate*gen = new PGenerate(lexical_scope, scope_generate_counter++);
lexical_scope = gen;
@ -1416,6 +1483,8 @@ void pform_start_generate_case(const struct vlltype&li, PExpr*expr)
pform_cur_generate->loop_init = 0;
pform_cur_generate->loop_test = expr;
pform_cur_generate->loop_step = 0;
conditional_block_names.push_front(set<perm_string>());
}
/*
@ -1438,6 +1507,10 @@ void pform_start_generate_nblock(const struct vlltype&li, char*name)
pform_cur_generate->scope_name = lex_strings.make(name);
delete[]name;
add_local_symbol(pform_cur_generate->parent_scope(),
pform_cur_generate->scope_name,
pform_cur_generate);
}
/*
@ -1479,14 +1552,31 @@ void pform_generate_block_name(char*name)
{
assert(pform_cur_generate != 0);
assert(pform_cur_generate->scope_name == 0);
pform_cur_generate->scope_name = lex_strings.make(name);
perm_string scope_name = lex_strings.make(name);
pform_cur_generate->scope_name = scope_name;
if (pform_cur_generate->scheme_type == PGenerate::GS_CONDIT
|| pform_cur_generate->scheme_type == PGenerate::GS_ELSE
|| pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM) {
if (conditional_block_names.front().count(scope_name))
return;
conditional_block_names.front().insert(scope_name);
}
add_local_symbol(pform_cur_generate->parent_scope(),
scope_name, pform_cur_generate);
}
void pform_endgenerate()
void pform_endgenerate(bool end_conditional)
{
assert(pform_cur_generate != 0);
assert(! pform_cur_module.empty());
if (end_conditional)
conditional_block_names.pop_front();
// If there is no explicit block name then generate a temporary
// name. This will be replaced by the correct name later, once
// we know all the explicit names in the surrounding scope. If
@ -1975,18 +2065,10 @@ static void pform_set_net_range(list<perm_string>*names,
*/
static void pform_make_event(perm_string name, const char*fn, unsigned ln)
{
// Check if the named event is already in the dictionary.
if (lexical_scope->events.find(name) != lexical_scope->events.end()) {
LineInfo tloc;
FILE_NAME(&tloc, fn, ln);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for named event '" << name << "' in '"
<< pform_cur_module.front()->mod_name() << "'." << endl;
error_count += 1;
}
PEvent*event = new PEvent(name);
FILE_NAME(event, fn, ln);
add_local_symbol(lexical_scope, name, event);
lexical_scope->events[name] = event;
}
@ -2040,10 +2122,13 @@ static void pform_makegate(PGBuiltin::Type type,
cur->strength1(str.str1);
FILE_NAME(cur, info.file, info.lineno);
if (pform_cur_generate)
if (pform_cur_generate) {
if (dev_name != "") add_local_symbol(pform_cur_generate, dev_name, cur);
pform_cur_generate->add_gate(cur);
else
} else {
if (dev_name != "") add_local_symbol(pform_cur_module.front(), dev_name, cur);
pform_cur_module.front()->add_gate(cur);
}
}
void pform_makegates(const struct vlltype&loc,
@ -2120,10 +2205,13 @@ static void pform_make_modgate(perm_string type,
cur->set_parameters(overrides->by_order);
}
if (pform_cur_generate)
if (pform_cur_generate) {
if (name != "") add_local_symbol(pform_cur_generate, name, cur);
pform_cur_generate->add_gate(cur);
else
} else {
if (name != "") add_local_symbol(pform_cur_module.front(), name, cur);
pform_cur_module.front()->add_gate(cur);
}
pform_bind_attributes(cur->attributes, attr);
}
@ -2165,11 +2253,13 @@ static void pform_make_modgate(perm_string type,
cur->set_parameters(overrides->by_order);
}
if (pform_cur_generate)
if (pform_cur_generate) {
add_local_symbol(pform_cur_generate, name, cur);
pform_cur_generate->add_gate(cur);
else
} else {
add_local_symbol(pform_cur_module.front(), name, cur);
pform_cur_module.front()->add_gate(cur);
}
pform_bind_attributes(cur->attributes, attr);
}
@ -2505,20 +2595,15 @@ static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name,
// If the wire already exists and is fully defined, this
// must be a redeclaration. Start again with a new wire.
if (cur) {
LineInfo tloc;
FILE_NAME(&tloc, li);
cerr << tloc.get_fileline() << ": error: duplicate declaration "
"for net or variable '" << name << "' in '"
<< pform_cur_module.front()->mod_name() << "'." << endl;
error_count += 1;
delete cur;
}
// The error will be reported when we add the new wire
// to the scope. Do not delete the old wire - it will
// remain in the local symbol map.
cur = new PWire(name, type, ptype, dtype);
FILE_NAME(cur, li.text, li.first_line);
pform_put_wire_in_scope(name, cur);
return cur;
}
@ -2972,38 +3057,6 @@ void pform_set_parameter(const struct vlltype&loc,
VLerror("parameter declarations are not permitted in generate blocks");
return;
}
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
assert(scopex);
// Check if the parameter name is already in the dictionary.
if (scope->parameters.find(name) != scope->parameters.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for parameter '" << name << "' in '"
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
if (scope->localparams.find(name) != scope->localparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: localparam and "
<< "parameter in '" << scopex->pscope_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
// Only a Module scope has specparams.
if ((dynamic_cast<Module*> (scope)) &&
(scope == pform_cur_module.front()) &&
(pform_cur_module.front()->specparams.find(name) !=
pform_cur_module.front()->specparams.end())) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: specparam and "
"parameter in '" << scopex->pscope_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
assert(expr);
Module::param_expr_t&parm = scope->parameters[name];
@ -3026,9 +3079,10 @@ void pform_set_parameter(const struct vlltype&loc,
parm.signed_flag = signed_flag;
parm.range = value_range;
add_local_symbol(scope, name, &parm);
// Only a Module keeps the position of the parameter.
if ((dynamic_cast<Module*> (scope)) &&
(scope == pform_cur_module.front()))
if ((dynamic_cast<Module*>(scope)) && (scope == pform_cur_module.front()))
pform_cur_module.front()->param_names.push_back(name);
}
@ -3041,37 +3095,6 @@ void pform_set_localparam(const struct vlltype&loc,
VLerror(loc, "error: localparam declarations must be contained within a module.");
return;
}
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
assert(scopex);
// Check if the localparam name is already in the dictionary.
if (scope->localparams.find(name) != scope->localparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for localparam '" << name << "' in '"
<< scopex->pscope_name() << "'." << endl;
error_count += 1;
}
if (scope->parameters.find(name) != scope->parameters.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: parameter and "
<< "localparam in '" << scopex->pscope_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
if ((! pform_cur_module.empty()) &&
(scope == pform_cur_module.front()) &&
(pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: specparam and "
"localparam in '" << scopex->pscope_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
assert(expr);
Module::param_expr_t&parm = scope->localparams[name];
@ -3093,6 +3116,8 @@ void pform_set_localparam(const struct vlltype&loc,
}
parm.signed_flag = signed_flag;
parm.range = 0;
add_local_symbol(scope, name, &parm);
}
void pform_set_specparam(const struct vlltype&loc, perm_string name,
@ -3102,35 +3127,7 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name,
Module*scope = pform_cur_module.front();
assert(scope == lexical_scope);
// Check if the specparam name is already in the dictionary.
if (pform_cur_module.front()->specparams.find(name) !=
pform_cur_module.front()->specparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for specparam '" << name << "' in '"
<< pform_cur_module.front()->mod_name() << "'." << endl;
error_count += 1;
}
if (scope->parameters.find(name) != scope->parameters.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: parameter and "
"specparam in '" << pform_cur_module.front()->mod_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
if (scope->localparams.find(name) != scope->localparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: localparam and "
"specparam in '" << pform_cur_module.front()->mod_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
assert(expr);
Module::param_expr_t&parm = pform_cur_module.front()->specparams[name];
FILE_NAME(&parm, loc);
@ -3151,6 +3148,8 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name,
}
parm.signed_flag = false;
parm.range = 0;
add_local_symbol(scope, name, &parm);
}
void pform_set_defparam(const pform_name_t&name, PExpr*expr)
@ -3572,12 +3571,10 @@ void pform_start_modport_item(const struct vlltype&loc, const char*name)
perm_string use_name = lex_strings.make(name);
pform_cur_modport = new PModport(use_name);
FILE_NAME(pform_cur_modport, loc);
if (scope->modports.find(use_name) != scope->modports.end()) {
cerr << loc << ": error: duplicate declaration for modport '"
<< name << "' in '" << scope->mod_name() << "'." << endl;
error_count += 1;
}
add_local_symbol(scope, use_name, pform_cur_modport);
scope->modports[use_name] = pform_cur_modport;
delete[] name;
}

View File

@ -246,7 +246,7 @@ extern void pform_add_modport_port(const struct vlltype&loc,
* This creates an identifier aware of names that may have been
* imported from other packages.
*/
extern PEIdent* pform_new_ident(const pform_name_t&name);
extern PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name);
/*
* Enter/exit name scopes. The push_scope function pushes the scope
@ -299,7 +299,7 @@ extern void pform_start_generate_case(const struct vlltype&lp, PExpr*test);
extern void pform_start_generate_nblock(const struct vlltype&lp, char*name);
extern void pform_generate_case_item(const struct vlltype&lp, list<PExpr*>*test);
extern void pform_generate_block_name(char*name);
extern void pform_endgenerate();
extern void pform_endgenerate(bool end_conditional);
/*
* This function returns the lexically containing generate scheme, if

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2019 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -72,98 +72,58 @@ void pform_end_package_declaration(const struct vlltype&loc)
* package is declared in pform ahead of time (it is) and that we can
* simply transfer definitions to the current scope (we can).
*/
void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident)
void pform_package_import(const struct vlltype&loc, PPackage*pkg, const char*ident)
{
LexicalScope*scope = pform_peek_scope();
if (ident) {
perm_string use_ident = lex_strings.make(ident);
map<perm_string,LexicalScope::param_expr_t>::const_iterator cur
= pkg->parameters.find(use_ident);
if (cur != pkg->parameters.end()) {
scope->imports[cur->first] = pkg;
// Check that the requested symbol is available.
map<perm_string,PNamedItem*>::const_iterator cur_sym
= pkg->local_symbols.find(use_ident);
if (cur_sym == pkg->local_symbols.end()) {
cerr << loc.get_fileline() << ": error: "
"'" << use_ident << "' is not exported by '"
<< pkg->pscope_name() << "'." << endl;
error_count += 1;
return;
}
cur = pkg->localparams.find(use_ident);
if (cur != pkg->localparams.end()) {
scope->imports[cur->first] = pkg;
// Check for conflict with local symbol.
cur_sym = scope->local_symbols.find(use_ident);
if (cur_sym != scope->local_symbols.end()) {
cerr << loc.get_fileline() << ": error: "
"'" << use_ident << "' has already been declared "
"in this scope." << endl;
cerr << cur_sym->second->get_fileline() << ": : "
"It was declared here as "
<< cur_sym->second->symbol_type() << "." << endl;
error_count += 1;
return;
}
map<perm_string,data_type_t*>::const_iterator tcur;
tcur = pkg->typedefs.find(use_ident);
if (tcur != pkg->typedefs.end()) {
scope->imports[tcur->first] = pkg;
// Check for conflict with previous import.
map<perm_string,PPackage*>::const_iterator cur_pkg
= scope->explicit_imports.find(use_ident);
if (cur_pkg != scope->explicit_imports.end()) {
if (cur_pkg->second != pkg) {
cerr << loc.get_fileline() << ": error: "
"'" << use_ident << "' has already been "
"imported into this scope from package '"
<< cur_pkg->second->pscope_name() << "'." << endl;
error_count += 1;
}
return;
}
map<perm_string,PFunction*>::const_iterator fcur;
fcur = pkg->funcs.find(use_ident);
if (fcur != pkg->funcs.end()) {
scope->imports[fcur->first] = pkg;
return;
}
map<perm_string,PTask*>::const_iterator ttcur;
ttcur = pkg->tasks.find(use_ident);
if (ttcur != pkg->tasks.end()) {
scope->imports[ttcur->first] = pkg;
return;
}
map<perm_string,PWire*>::const_iterator wcur;
wcur = pkg->wires.find(use_ident);
if (wcur != pkg->wires.end()) {
scope->imports[wcur->first] = pkg;
return;
}
ostringstream msg;
msg << "Symbol " << use_ident
<< " not found in package " << pkg->pscope_name() << "." << ends;
VLerror(msg.str().c_str());
return;
scope->explicit_imports[use_ident] = pkg;
} else {
// Handle the pkg::* case by importing everything from
// the package.
for (map<perm_string,LexicalScope::param_expr_t>::const_iterator cur = pkg->parameters.begin()
; cur != pkg->parameters.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,LexicalScope::param_expr_t>::const_iterator cur = pkg->localparams.begin()
; cur != pkg->localparams.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,data_type_t*>::const_iterator cur = pkg->typedefs.begin()
; cur != pkg->typedefs.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,PFunction*>::const_iterator cur = pkg->funcs.begin()
; cur != pkg->funcs.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,PWire*>::const_iterator cur = pkg->wires.begin()
; cur != pkg->wires.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (set<enum_type_t*>::const_iterator cur = pkg->enum_sets.begin()
; cur != pkg->enum_sets.end() ; ++ cur) {
scope->enum_sets.insert(*cur);
}
set<PPackage*>::const_iterator cur_pkg
= scope->potential_imports.find(pkg);
if (cur_pkg == scope->potential_imports.end())
scope->potential_imports.insert(pkg);
}
}