diff --git a/PExpr.cc b/PExpr.cc index ebb98449a..8e22bd950 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -488,6 +488,9 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const if (!symbol_search(this, des, scope, path_, lexical_pos(), &sr)) return false; + if (sr.type_def) + return false; + // Class properties are not considered automatic since a non-blocking // assignment to an object stored in an automatic variable is supposed to // capture a reference to the object, not the variable. diff --git a/elab_expr.cc b/elab_expr.cc index e7a6794b8..50e8937a6 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3271,6 +3271,9 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope, return 0; } + if (!search_results.require_non_type(this, des, "in a function call")) + return 0; + // If the symbol is found, but is not a scope... if (! search_results.is_scope() && !test_function_return_value(search_results)) { @@ -5146,6 +5149,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, symbol_search_results sr; symbol_search(this, des, scope, path_, lexical_pos(), &sr); + if (!sr.require_non_type(this, des, "in an expression")) + return nullptr; + if (!sr.net) { cerr << get_fileline() << ": error: Unable to bind variable `" << path_ << "' in `" << scope_path(scope) << "'" << endl; @@ -5466,6 +5472,9 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, symbol_search_results sr; symbol_search(this, des, scope, path_, lexical_pos(), &sr); + if (!sr.require_non_type(this, des, "in an expression")) + return 0; + // If the identifier name is a parameter name, then return // the parameter value. if (sr.par_val != 0) { diff --git a/elab_lval.cc b/elab_lval.cc index c12250d6b..4b1b30651 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -178,6 +178,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, symbol_search_results sr; symbol_search(this, des, scope, path_, lexical_pos(), &sr); + if (!sr.require_non_type(this, des, "as a procedural l-value")) + return nullptr; + NetNet *reg = sr.net; const pform_name_t &member_path = sr.path_tail; diff --git a/elaborate.cc b/elaborate.cc index 5c5906837..95dc0ce34 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1274,7 +1274,7 @@ bool PGModule::match_module_ports_(Design*des, const Module*rmod, wildcard.lexical_pos(), &sr); if (sr.net != 0 || (rmod->ports[j]->is_interface_port() && - sr.scope != 0 && sr.scope->is_interface())) { + sr.is_scope() && sr.scope->is_interface())) { pins[j] = new PEIdent( rmod->ports[j]->name, wildcard.lexical_pos(), true); @@ -1450,7 +1450,8 @@ static bool resolve_interface_actual_scope(const PExpr*actual, symbol_search_results sr; symbol_search(actual, des, parent_scope, actual_ident->path(), actual_ident->lexical_pos(), &sr); - res.scope = sr.scope; + if (sr.is_scope()) + res.scope = sr.scope; if (sr.through_interface_alias()) res.modport = sr.interface_alias_modport; } @@ -1462,7 +1463,8 @@ static bool resolve_interface_actual_scope(const PExpr*actual, symbol_search(actual, des, parent_scope, actual_ident->path(), actual_ident->lexical_pos(), &sr); - res.scope = sr.scope; + if (sr.is_scope()) + res.scope = sr.scope; if (sr.through_interface_alias()) res.modport = sr.interface_alias_modport; else if (NetScope*child = parent_scope->child(hname_t(res.display_name))) @@ -3956,6 +3958,10 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const NetScope *func_scope = nullptr; if (symbol_search(this, des, scope, call_path, lexical_pos(), &search_results, true)) { + if (!search_results.require_non_type( + this, des, "in a task or function call")) + return nullptr; + if (search_results.is_scope()) { if (search_results.scope->type() == NetScope::TASK) task = search_results.scope; @@ -5264,6 +5270,10 @@ NetProc* PDisable::elaborate(Design*des, NetScope*scope) const des->errors += 1; return 0; } + if (!search_results.require_non_type(this, des, + "as a disable target")) + return nullptr; + if (!search_results.is_scope()) { cerr << get_fileline() << ": error: Cannot disable " << search_results.result_type() << " `" << scope_ << "'." @@ -6669,6 +6679,8 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const des->errors += 1; return 0; } + if (!sr.require_non_type(this, des, "as a named event")) + return nullptr; if (!sr.eve) { cerr << get_fileline() << ": error: <" << event_ << ">" @@ -6698,6 +6710,8 @@ NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const des->errors += 1; return 0; } + if (!sr.require_non_type(this, des, "as a named event")) + return nullptr; if (sr.eve == 0) { cerr << get_fileline() << ": error: <" << event_ << ">" diff --git a/net_scope.cc b/net_scope.cc index 607c51a8d..3bf768138 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -244,6 +244,19 @@ void NetScope::add_typedefs(const map*typedefs) typedefs_ = *typedefs; } +typedef_t *NetScope::lookup_typedef(perm_string name, + unsigned int lexical_pos) const +{ + auto type = typedefs_.find(name); + if (type == typedefs_.end()) + return nullptr; + + if (type->second->lexical_pos() > lexical_pos) + return nullptr; + + return type->second; +} + /* * Type names are resolved to typedef_t objects during parsing. Locate the * scope that owns that exact object instead of resolving its name again diff --git a/netlist.h b/netlist.h index 7812fcb79..741af445b 100644 --- a/netlist.h +++ b/netlist.h @@ -1006,6 +1006,11 @@ class NetScope : public Definitions, public Attrib { void add_typedefs(const std::map*typedefs); + /* Find a type declared in this scope and visible at the given source + position. */ + typedef_t *lookup_typedef(perm_string name, + unsigned int lexical_pos) const; + /* Locate the scope that owns the resolved typedef object. */ NetScope*find_typedef_scope(const Design*des, const typedef_t*type_i); diff --git a/netmisc.h b/netmisc.h index a9e9c1bb5..0f958f885 100644 --- a/netmisc.h +++ b/netmisc.h @@ -48,6 +48,7 @@ struct symbol_search_results { net = 0; par_val = 0; type = 0; + type_def = nullptr; eve = 0; decl_after_use = 0; interface_alias_scope = 0; @@ -59,6 +60,7 @@ struct symbol_search_results { if (net) return false; if (eve) return false; if (par_val) return false; + if (type_def) return false; if (scope) return true; return false; } @@ -67,6 +69,7 @@ struct symbol_search_results { if (net) return true; if (eve) return true; if (par_val) return true; + if (type_def) return true; if (scope) return true; return false; } @@ -75,10 +78,14 @@ struct symbol_search_results { if (net) return "net"; if (eve) return "named event"; if (par_val) return "parameter"; + if (type_def) return "type"; if (scope) return "scope"; return "nothing found"; } + bool require_non_type(const LineInfo *li, Design *des, + const char *use) const; + inline bool through_interface_alias() const { return interface_alias_target != 0; } @@ -92,6 +99,8 @@ struct symbol_search_results { // optional value dimensions. const NetExpr*par_val; ivl_type_t type; + // If this is a type, the parsed type declaration. + typedef_t *type_def; // If this is a named event, ... NetEvent*eve; // If a symbol was located but skipped because its lexical position diff --git a/symbol_search.cc b/symbol_search.cc index ce4b1d317..7e829c382 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -30,6 +30,21 @@ using namespace std; +bool symbol_search_results::require_non_type(const LineInfo *li, + Design *des, + const char *use) const +{ + if (!type_def) + return true; + + cerr << li->get_fileline() << ": error: Type name `" << path_head + << "' cannot be used " << use << "." << endl; + cerr << type_def->get_fileline() << ": : The type was declared here." + << endl; + des->errors += 1; + return false; +} + enum class scope_object_search_result_t { not_found, found, @@ -39,8 +54,8 @@ enum class scope_object_search_result_t { static scope_object_search_result_t symbol_search_scope_objects( const LineInfo *li, Design *des, NetScope *scope, NetScope *start_scope, const pform_name_t &path, - const name_component_t &path_tail, unsigned int lexical_pos, - bool check_lexical_order, struct symbol_search_results *res) + const name_component_t &path_tail, unsigned int visibility_pos, + struct symbol_search_results *res) { // Special case `super` keyword. Return the `this` object, but // with the type of the base class. @@ -70,8 +85,7 @@ static scope_object_search_result_t symbol_search_scope_objects( } if (NetNet *net = scope->find_signal(path_tail.name)) { - bool decl_after_use = check_lexical_order - && !(net->lexical_pos() <= lexical_pos); + bool decl_after_use = !(net->lexical_pos() <= visibility_pos); if (!gn_strict_net_var_declaration || !decl_after_use) { pform_name_t path_head = path; path_head.push_back(path_tail); @@ -87,7 +101,7 @@ static scope_object_search_result_t symbol_search_scope_objects( << ": : the net/variable is declared here." << endl; // suppress further warnings for this net - net->lexical_pos(lexical_pos); + net->lexical_pos(visibility_pos); } return scope_object_search_result_t::found; } else if (!res->decl_after_use) { @@ -96,8 +110,7 @@ static scope_object_search_result_t symbol_search_scope_objects( } if (NetEvent *eve = scope->find_event(path_tail.name)) { - bool decl_after_use = check_lexical_order - && !(eve->lexical_pos() <= lexical_pos); + bool decl_after_use = !(eve->lexical_pos() <= visibility_pos); if (!gn_strict_net_var_declaration || !decl_after_use) { pform_name_t path_head = path; path_head.push_back(path_tail); @@ -111,7 +124,7 @@ static scope_object_search_result_t symbol_search_scope_objects( cerr << eve->get_fileline() << ": : the event is declared here." << endl; // suppress further warnings for this event - eve->lexical_pos(lexical_pos); + eve->lexical_pos(visibility_pos); } return scope_object_search_result_t::found; } else if (!res->decl_after_use) { @@ -119,14 +132,26 @@ static scope_object_search_result_t symbol_search_scope_objects( } } + // Types and data objects share a namespace. Return a visible + // type even when the caller requires a value so it cannot + // incorrectly continue searching an outer scope. + if (auto type_def = scope->lookup_typedef( + path_tail.name, visibility_pos)) { + pform_name_t path_head = path; + path_head.push_back(path_tail); + res->scope = scope; + res->type_def = type_def; + res->path_head = path_head; + return scope_object_search_result_t::found; + } + if (const NetExpr *par = scope->get_parameter( des, path_tail.name, res->type)) { bool is_enum_name; unsigned int declaration_pos = scope->get_constant_lexical_pos(path_tail.name, is_enum_name); - bool decl_after_use = check_lexical_order - && !(declaration_pos <= lexical_pos); + bool decl_after_use = !(declaration_pos <= visibility_pos); if (!gn_strict_parameter_declaration || !decl_after_use) { pform_name_t path_head = path; path_head.push_back(path_tail); @@ -145,7 +170,7 @@ static scope_object_search_result_t symbol_search_scope_objects( << " is declared here." << endl; // suppress further warnings for this constant scope->set_constant_lexical_pos( - path_tail.name, lexical_pos); + path_tail.name, visibility_pos); } return scope_object_search_result_t::found; } else if (!res->decl_after_use) { @@ -180,7 +205,7 @@ static scope_object_search_result_t symbol_search_scope_objects( // Finally check the rare case of a signal that hasn't // been elaborated yet. if (PWire *wire = scope->find_signal_placeholder(path_tail.name)) { - if (!check_lexical_order || (wire->lexical_pos() <= lexical_pos)) { + if (wire->lexical_pos() <= visibility_pos) { NetNet *net = wire->elaborate_sig(des, scope); if (!net) return scope_object_search_result_t::failed; @@ -413,8 +438,8 @@ static bool symbol_search_(const LineInfo *li, Design *des, NetScope *scope, // An explicit $unit:: prefix only disambiguates the name and does // not allow forward references (LRM 3.12.1). - const bool check_lexical_order = - !scope_is_bound || scope->is_unit(); + const unsigned int visibility_pos = + (!scope_is_bound || scope->is_unit()) ? lexical_pos : UINT_MAX; if (scope->genvar_tmp.str() && path_tail.name == scope->genvar_tmp) return false; @@ -435,7 +460,7 @@ static bool symbol_search_(const LineInfo *li, Design *des, NetScope *scope, scope_object_search_result_t object_result = symbol_search_scope_objects( li, des, scope, start_scope, path, path_tail, - lexical_pos, check_lexical_order, res); + visibility_pos, res); if (object_result == scope_object_search_result_t::found) return true; if (object_result == scope_object_search_result_t::failed)