Consider lexical ordering for enum named constants

Enum named constants use the parameter lookup path, including its lexical
declaration-order check. Their declaration position is currently reported as
zero, however, so a later enum named constant can incorrectly hide a matching
constant from an outer scope.

Attach the parsed enum item's source location to the elaborated enum constant
and use its lexical position during lookup. Have the position lookup also
identify enum named constants so relaxed-mode warnings do not call them
parameters. Update the position after a warning to retain the existing warning
suppression behavior.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-08-01 23:11:23 -07:00
parent 591d2c2473
commit f6f7f9d6d7
4 changed files with 49 additions and 21 deletions

View File

@ -355,7 +355,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
} }
rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value); rc_flag = use_enum->insert_name(name_idx, cur->name, cur_value);
rc_flag &= scope->add_enumeration_name(use_enum, cur->name); rc_flag &= scope->add_enumeration_name(use_enum, cur->name, *cur);
if (! rc_flag) { if (! rc_flag) {
cerr << use_enum->get_fileline() cerr << use_enum->get_fileline()

View File

@ -52,15 +52,17 @@ void Definitions::add_enumeration_set(const enum_type_t*key, netenum_t*enum_set)
tmp = enum_set; tmp = enum_set;
} }
bool Definitions::add_enumeration_name(const netenum_t*enum_set, perm_string name) bool Definitions::add_enumeration_name(const netenum_t *enum_set,
perm_string name,
const LineInfo &location)
{ {
netenum_t::iterator enum_val = enum_set->find_name(name); auto enum_val = enum_set->find_name(name);
assert(enum_val != enum_set->end_name()); assert(enum_val != enum_set->end_name());
NetEConstEnum*val = new NetEConstEnum(name, enum_set, enum_val->second); auto val = new NetEConstEnum(name, enum_set, enum_val->second);
val->set_line(location);
pair<map<perm_string,NetEConstEnum*>::iterator, bool> cur; auto cur = enum_names_.insert(make_pair(name, val));
cur = enum_names_.insert(make_pair(name,val));
// Return TRUE if the name is added (i.e. is NOT a duplicate.) // Return TRUE if the name is added (i.e. is NOT a duplicate.)
return cur.second; return cur.second;
@ -466,23 +468,37 @@ LineInfo NetScope::get_parameter_line_info(perm_string key) const
return LineInfo(); return LineInfo();
} }
unsigned NetScope::get_parameter_lexical_pos(perm_string key) const unsigned int NetScope::get_constant_lexical_pos(perm_string key,
bool &is_enum_name) const
{ {
map<perm_string,param_expr_t>::const_iterator idx; map<perm_string,param_expr_t>::const_iterator idx;
idx = parameters.find(key); idx = parameters.find(key);
if (idx != parameters.end()) return idx->second.lexical_pos; if (idx != parameters.end()) {
is_enum_name = false;
return idx->second.lexical_pos;
}
// If we get here, assume an enumeration value. auto enum_idx = enum_names_.find(key);
return 0; assert(enum_idx != enum_names_.end());
is_enum_name = true;
return enum_idx->second->lexical_pos();
} }
void NetScope::set_parameter_lexical_pos(perm_string key, unsigned lexical_pos) void NetScope::set_constant_lexical_pos(perm_string key,
unsigned int lexical_pos)
{ {
map<perm_string,param_expr_t>::iterator idx; map<perm_string,param_expr_t>::iterator idx;
idx = parameters.find(key); idx = parameters.find(key);
if (idx != parameters.end()) idx->second.lexical_pos = lexical_pos; if (idx != parameters.end()) {
idx->second.lexical_pos = lexical_pos;
return;
}
auto enum_idx = enum_names_.find(key);
assert(enum_idx != enum_names_.end());
enum_idx->second->lexical_pos(lexical_pos);
} }
void NetScope::print_type(ostream&stream) const void NetScope::print_type(ostream&stream) const

View File

@ -945,7 +945,9 @@ class Definitions {
// up this enumeration based on the pform type. // up this enumeration based on the pform type.
void add_enumeration_set(const enum_type_t*key, netenum_t*enum_set); void add_enumeration_set(const enum_type_t*key, netenum_t*enum_set);
bool add_enumeration_name(const netenum_t*enum_set, perm_string enum_name); bool add_enumeration_name(const netenum_t *enum_set,
perm_string enum_name,
const LineInfo &location);
// Look up the enumeration set that was added with the given // Look up the enumeration set that was added with the given
// key. This is used by enum_type_t::elaborate_type to locate // key. This is used by enum_type_t::elaborate_type to locate
@ -1335,8 +1337,10 @@ class NetScope : public Definitions, public Attrib {
LineInfo get_parameter_line_info(perm_string name) const; LineInfo get_parameter_line_info(perm_string name) const;
unsigned get_parameter_lexical_pos(perm_string name) const; unsigned int get_constant_lexical_pos(perm_string name,
void set_parameter_lexical_pos(perm_string name, unsigned lexical_pos); bool &is_enum_name) const;
void set_constant_lexical_pos(perm_string name,
unsigned int lexical_pos);
/* Module instance arrays are collected here for access during /* Module instance arrays are collected here for access during
the multiple elaboration passes. */ the multiple elaboration passes. */

View File

@ -237,22 +237,30 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
} }
} }
if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->type)) { 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 = !scope_is_bound bool decl_after_use = !scope_is_bound
&& !(scope->get_parameter_lexical_pos(path_tail.name) <= lexical_pos); && !(declaration_pos <= lexical_pos);
if (!gn_strict_parameter_declaration || !decl_after_use) { if (!gn_strict_parameter_declaration || !decl_after_use) {
path.push_back(path_tail); path.push_back(path_tail);
res->scope = scope; res->scope = scope;
res->par_val = par; res->par_val = par;
res->path_head = path; res->path_head = path;
if (warn_decl_after_use && decl_after_use) { if (warn_decl_after_use && decl_after_use) {
const char *kind = is_enum_name
? "enum named constant" : "parameter";
cerr << li->get_fileline() cerr << li->get_fileline()
<< ": warning: parameter `" << path_tail.name << ": warning: " << kind << " `"
<< path_tail.name
<< "` used before declaration." << endl; << "` used before declaration." << endl;
cerr << par->get_fileline() cerr << par->get_fileline()
<< ": : the parameter is declared here." << endl; << ": : the " << kind
// suppress further warnings for this parameter << " is declared here." << endl;
scope->set_parameter_lexical_pos(path_tail.name, lexical_pos); // suppress further warnings for this constant
scope->set_constant_lexical_pos(path_tail.name, lexical_pos);
} }
return true; return true;
} else if (!res->decl_after_use) { } else if (!res->decl_after_use) {