diff --git a/PScope.h b/PScope.h index 9f339a5b2..1c0760ad5 100644 --- a/PScope.h +++ b/PScope.h @@ -61,6 +61,18 @@ class LexicalScope { lifetime_t default_lifetime; + // Symbols that are defined or declared in this scope. + std::maplocal_symbols; + + // Symbols that are explicitly imported. Bind the imported name + // to the package from which the name is imported. + std::mapexplicit_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::setpotential_imports; + struct range_t { // True if this is an exclude bool exclude_flag; @@ -102,10 +114,6 @@ class LexicalScope { // Named events in the scope. mapevents; - // Symbols that are imported. Bind the imported name to the - // package from which the name is imported. - std::mapimports; - // Nets and variables (wires) in the scope mapwires; PWire* wires_find(perm_string name); diff --git a/elab_scope.cc b/elab_scope.cc index bb3592d2d..4afd4b680 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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. diff --git a/elaborate.cc b/elaborate.cc index 0185c3031..61ea115f4 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6528,7 +6528,7 @@ Design* elaborate(listroots) 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(listroots) 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(listroots) // 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 diff --git a/lexor.lex b/lexor.lex index 37c3e0207..d5cad1f7b 100644 --- a/lexor.lex +++ b/lexor.lex @@ -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; diff --git a/parse.y b/parse.y index ce8e18b3b..28154625a 100644 --- a/parse.y +++ b/parse.y @@ -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); } ; diff --git a/parse_misc.h b/parse_misc.h index 05c35fb01..58f5aea98 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -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); diff --git a/pform.cc b/pform.cc index 4b26f8c82..d6b41f3d3 100644 --- a/pform.cc +++ b/pform.cc @@ -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> 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::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::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::const_iterator cur_pkg = scope->potential_imports.begin(); + cur_pkg != scope->potential_imports.end(); ++cur_pkg) { + PPackage*search_pkg = *cur_pkg; + map::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::listtypedefs[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(data_type)) { pform_put_enum_type_in_scope(enum_type); + + list::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::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&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&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&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*names) { list::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()); } 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()); } /* @@ -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*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 (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 (scope)) && - (scope == pform_cur_module.front())) + if ((dynamic_cast(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; } diff --git a/pform.h b/pform.h index 3c9c0e9ea..cd1fb5c88 100644 --- a/pform.h +++ b/pform.h @@ -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*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 diff --git a/pform_package.cc b/pform_package.cc index 72ac9c6b3..22ec72c38 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -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::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::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::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::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::const_iterator fcur; - fcur = pkg->funcs.find(use_ident); - if (fcur != pkg->funcs.end()) { - scope->imports[fcur->first] = pkg; - return; - } - - map::const_iterator ttcur; - ttcur = pkg->tasks.find(use_ident); - if (ttcur != pkg->tasks.end()) { - scope->imports[ttcur->first] = pkg; - return; - } - - map::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::const_iterator cur = pkg->parameters.begin() - ; cur != pkg->parameters.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->localparams.begin() - ; cur != pkg->localparams.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->typedefs.begin() - ; cur != pkg->typedefs.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->funcs.begin() - ; cur != pkg->funcs.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->wires.begin() - ; cur != pkg->wires.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (set::const_iterator cur = pkg->enum_sets.begin() - ; cur != pkg->enum_sets.end() ; ++ cur) { - scope->enum_sets.insert(*cur); - } + set::const_iterator cur_pkg + = scope->potential_imports.find(pkg); + if (cur_pkg == scope->potential_imports.end()) + scope->potential_imports.insert(pkg); } }