Store lexical positions in LineInfo

Several source and netlist objects inherit `LineInfo` while separately
storing the lexical position associated with the same source location. This
requires callers to copy the file, line, and lexical position independently.

Add the lexical position to `LineInfo`. Have `set_line()` initialize it when
it is unset, so new objects inherit the complete source location while later
diagnostic location updates preserve their established declaration order.
Initialize the field to `UINT_MAX` so zero remains available as a valid
scanner position and missing initialization is distinguishable. Have
`FILE_NAME()` preserve a more precise identifier position.

Remove constructor parameters that duplicate the position supplied through
`FILE_NAME()`. Use the shared field for identifiers, wires, events, event
triggers, nets, and elaborated events. Assign static class property nets
their declaration location since they previously relied on the standalone
`NetNet` position defaulting to zero.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-07-26 12:56:45 -07:00
parent beaf44895a
commit 5f479cbad4
24 changed files with 67 additions and 77 deletions

View File

@ -22,8 +22,9 @@
# include "PEvent.h"
PEvent::PEvent(perm_string n, unsigned lexical_pos)
: name_(n), lexical_pos_(lexical_pos)
: name_(n)
{
LineInfo::lexical_pos(lexical_pos);
}
PEvent::~PEvent()

View File

@ -41,15 +41,12 @@ class PEvent : public PNamedItem {
perm_string name() const;
unsigned lexical_pos() const { return lexical_pos_; }
void elaborate_scope(Design*des, NetScope*scope) const;
SymbolType symbol_type() const override;
private:
perm_string name_;
unsigned lexical_pos_;
private: // not implemented
PEvent(const PEvent&);

View File

@ -407,18 +407,20 @@ const verireal& PEFNumber::value() const
}
PEIdent::PEIdent(const pform_name_t&that, unsigned lexical_pos)
: path_(that), lexical_pos_(lexical_pos), no_implicit_sig_(false)
: path_(that), no_implicit_sig_(false)
{
LineInfo::lexical_pos(lexical_pos);
}
PEIdent::PEIdent(perm_string s, unsigned lexical_pos, bool no_implicit_sig)
: lexical_pos_(lexical_pos), no_implicit_sig_(no_implicit_sig)
: no_implicit_sig_(no_implicit_sig)
{
LineInfo::lexical_pos(lexical_pos);
path_.name.push_back(name_component_t(s));
}
PEIdent::PEIdent(PPackage*pkg, const pform_name_t&that, unsigned lexical_pos)
: path_(pkg, that), lexical_pos_(lexical_pos), no_implicit_sig_(true)
PEIdent::PEIdent(PPackage*pkg, const pform_name_t&that)
: path_(pkg, that), no_implicit_sig_(true)
{
}
@ -469,9 +471,8 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
ss = ss->parent_scope();
}
PWire*net = new PWire(name, lexical_pos_, type, NetNet::NOT_A_PORT);
net->set_file(get_file());
net->set_lineno(get_lineno());
PWire*net = new PWire(name, lexical_pos(), type, NetNet::NOT_A_PORT);
net->set_line(*this);
scope->wires[name] = net;
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "
@ -483,7 +484,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
{
symbol_search_results sr;
if (!symbol_search(this, des, scope, path_, lexical_pos_, &sr))
if (!symbol_search(this, des, scope, path_, lexical_pos(), &sr))
return false;
// Class properties are not considered automatic since a non-blocking

View File

@ -345,7 +345,7 @@ class PEIdent : public PExpr {
public:
explicit PEIdent(perm_string, unsigned lexical_pos, bool no_implicit_sig=false);
explicit PEIdent(PPackage*pkg, const pform_name_t&name, unsigned lexical_pos);
explicit PEIdent(PPackage*pkg, const pform_name_t&name);
explicit PEIdent(const pform_name_t&, unsigned lexical_pos);
~PEIdent() override;
@ -394,11 +394,8 @@ class PEIdent : public PExpr {
const pform_scoped_name_t& path() const { return path_; }
unsigned lexical_pos() const { return lexical_pos_; }
private:
pform_scoped_name_t path_;
unsigned lexical_pos_;
bool no_implicit_sig_;
private:

View File

@ -29,10 +29,12 @@ PWire::PWire(perm_string n,
NetNet::Type t,
NetNet::PortType pt,
PWSRType rt)
: name_(n), lexical_pos_(lp), type_(t), port_type_(pt), signed_(false),
: name_(n), type_(t), port_type_(pt), signed_(false),
port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), discipline_(0)
{
lexical_pos(lp);
switch (rt) {
case SR_PORT:
port_set_ = true;

View File

@ -63,8 +63,6 @@ class PWire : public PNamedItem {
// Return a hierarchical name.
perm_string basename() const;
unsigned lexical_pos() const { return lexical_pos_; }
NetNet::Type get_wire_type() const;
bool set_wire_type(NetNet::Type);
@ -102,7 +100,6 @@ class PWire : public PNamedItem {
private:
perm_string name_;
unsigned lexical_pos_;
NetNet::Type type_;
NetNet::PortType port_type_;
bool signed_;

View File

@ -396,8 +396,8 @@ PReturn::~PReturn()
delete expr_;
}
PTrigger::PTrigger(PPackage*pkg, const pform_name_t&ev, unsigned lexical_pos)
: event_(pkg, ev), lexical_pos_(lexical_pos)
PTrigger::PTrigger(PPackage*pkg, const pform_name_t&ev)
: event_(pkg, ev)
{
}
@ -405,8 +405,8 @@ PTrigger::~PTrigger()
{
}
PNBTrigger::PNBTrigger(const pform_name_t&ev, unsigned lexical_pos, PExpr*dly)
: event_(ev), lexical_pos_(lexical_pos), dly_(dly)
PNBTrigger::PNBTrigger(const pform_name_t&ev, PExpr*dly)
: event_(ev), dly_(dly)
{
}

View File

@ -660,7 +660,7 @@ class PReturn : public Statement {
class PTrigger : public Statement {
public:
explicit PTrigger(PPackage*pkg, const pform_name_t&ev, unsigned lexical_pos);
explicit PTrigger(PPackage*pkg, const pform_name_t&ev);
~PTrigger() override;
virtual NetProc* elaborate(Design*des, NetScope*scope) const override;
@ -668,12 +668,11 @@ class PTrigger : public Statement {
private:
pform_scoped_name_t event_;
unsigned lexical_pos_;
};
class PNBTrigger : public Statement {
public:
explicit PNBTrigger(const pform_name_t&ev, unsigned lexical_pos, PExpr*dly);
explicit PNBTrigger(const pform_name_t&ev, PExpr*dly);
~PNBTrigger() override;
virtual NetProc* elaborate(Design*des, NetScope*scope) const override;
@ -681,7 +680,6 @@ class PNBTrigger : public Statement {
private:
pform_name_t event_;
unsigned lexical_pos_;
PExpr*dly_;
};

View File

@ -4973,7 +4973,7 @@ ivl_type_t PEIdent::resolve_type_(Design *des, const symbol_search_results &sr,
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{
symbol_search_results sr;
bool found_symbol = symbol_search(this, des, scope, path_, lexical_pos_, &sr);
bool found_symbol = symbol_search(this, des, scope, path_, lexical_pos(), &sr);
// If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the
@ -5129,7 +5129,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
bool need_const = NEED_CONST & flags;
symbol_search_results sr;
symbol_search(this, des, scope, path_, lexical_pos_, &sr);
symbol_search(this, des, scope, path_, lexical_pos(), &sr);
if (!sr.net) {
cerr << get_fileline() << ": error: Unable to bind variable `"
@ -5449,7 +5449,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
// a net called "b" in the scope "main.a" and with a member
// named "c". symbol_search() handles this for us.
symbol_search_results sr;
symbol_search(this, des, scope, path_, lexical_pos_, &sr);
symbol_search(this, des, scope, path_, lexical_pos(), &sr);
// If the identifier name is a parameter name, then return
// the parameter value.

View File

@ -176,7 +176,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
symbol_search_results sr;
symbol_search(this, des, scope, path_, lexical_pos_, &sr);
symbol_search(this, des, scope, path_, lexical_pos(), &sr);
NetNet *reg = sr.net;
const pform_name_t &member_path = sr.path_tail;

View File

@ -533,7 +533,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
ivl_assert(*this, scope);
symbol_search_results sr;
symbol_search(this, des, scope, path_.name, lexical_pos_, &sr);
symbol_search(this, des, scope, path_.name, lexical_pos(), &sr);
if (sr.eve != 0) {
cerr << get_fileline() << ": error: named events (" << path_
@ -1173,7 +1173,7 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const
NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const
{
symbol_search_results sr;
symbol_search(this, des, scope, path_, lexical_pos_, &sr);
symbol_search(this, des, scope, path_, lexical_pos(), &sr);
if (!sr.net) {
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
@ -1207,7 +1207,7 @@ bool PEIdent::is_collapsible_net(Design*des, NetScope*scope,
ivl_assert(*this, scope);
symbol_search_results sr;
symbol_search(this, des, scope, path_.name, lexical_pos_, &sr);
symbol_search(this, des, scope, path_.name, lexical_pos(), &sr);
if (sr.eve != 0)
return false;

View File

@ -1640,7 +1640,6 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
void PEvent::elaborate_scope(Design*, NetScope*scope) const
{
NetEvent*ev = new NetEvent(name_);
ev->lexical_pos(lexical_pos_);
ev->set_line(*this);
scope->add_event(ev);
}

View File

@ -416,8 +416,9 @@ void netclass_t::elaborate_sig(Design*des, PClass*pclass)
<< "." << endl;
}
/* NetNet*sig = */ new NetNet(class_scope_, cur->first, NetNet::REG,
use_type);
auto sig = new NetNet(class_scope_, cur->first, NetNet::REG,
use_type);
sig->set_line(cur->second);
}
for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
@ -1227,7 +1228,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope)
if (wtype == NetNet::WIRE) sig->devirtualize_pins();
sig->set_line(*this);
sig->port_type(port_type_);
sig->lexical_pos(lexical_pos_);
if (ivl_discipline_t dis = get_discipline()) {
sig->set_discipline(dis);

View File

@ -6616,7 +6616,7 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
ivl_assert(*this, scope);
symbol_search_results sr;
if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) {
if (!symbol_search(this, des, scope, event_, lexical_pos(), &sr)) {
cerr << get_fileline() << ": error: event <" << event_ << ">"
<< " not found." << endl;
if (sr.decl_after_use) {
@ -6645,7 +6645,7 @@ NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const
ivl_assert(*this, scope);
symbol_search_results sr;
if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) {
if (!symbol_search(this, des, scope, event_, lexical_pos(), &sr)) {
cerr << get_fileline() << ": error: event <" << event_ << ">"
<< " not found." << endl;
if (sr.decl_after_use) {

View File

@ -44,6 +44,8 @@ void LineInfo::set_line(const LineInfo&that)
{
file_ = that.file_;
lineno_ = that.lineno_;
if (lexical_pos_ == UINT_MAX)
lexical_pos_ = that.lexical_pos_;
}
void LineInfo::set_file(perm_string f)
@ -55,3 +57,8 @@ void LineInfo::set_lineno(unsigned n)
{
lineno_ = n;
}
void LineInfo::lexical_pos(unsigned int n)
{
lexical_pos_ = n;
}

View File

@ -20,6 +20,7 @@
*/
# include "StringHeap.h"
# include <climits>
# include <string>
/*
@ -38,18 +39,21 @@ class LineInfo {
// Get a fully formatted file/lineno
std::string get_fileline() const;
// Set the file/line from another LineInfo object.
// Set the source location from another LineInfo object.
void set_line(const LineInfo&that);
// Access parts of LineInfo data
void set_file(perm_string f);
void set_lineno(unsigned n);
void lexical_pos(unsigned int n);
perm_string get_file() const { return file_; }
unsigned get_lineno() const { return lineno_; }
unsigned int lexical_pos() const { return lexical_pos_; }
private:
perm_string file_;
unsigned lineno_;
unsigned int lexical_pos_ = UINT_MAX;
};
#endif /* IVL_LineInfo_H */

View File

@ -30,7 +30,6 @@ using namespace std;
NetEvent::NetEvent(perm_string n)
: name_(n)
{
lexical_pos_ = 0;
local_flag_ = false;
scope_ = 0;
snext_ = 0;

View File

@ -566,7 +566,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
const netranges_t&unpacked, ivl_type_t use_net_type)
: NetObj(s, n, calculate_count(unpacked)),
type_(t), port_type_(NOT_A_PORT), coerced_to_uwire_(false),
local_flag_(false), lexical_pos_(0), net_type_(use_net_type),
local_flag_(false), net_type_(use_net_type),
discipline_(0), unpacked_dims_(unpacked),
eref_count_(0), lref_count_(0)
{
@ -589,7 +589,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
NetNet::NetNet(NetScope*s, perm_string n, Type t, ivl_type_t type)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), coerced_to_uwire_(false),
local_flag_(false), lexical_pos_(0), net_type_(type),
local_flag_(false), net_type_(type),
discipline_(0),
eref_count_(0), lref_count_(0)
{

View File

@ -733,9 +733,6 @@ class NetNet : public NetObj, public PortType {
PortType port_type() const;
void port_type(PortType t);
unsigned lexical_pos() const { return lexical_pos_; }
void lexical_pos(unsigned lp) { lexical_pos_ = lp; }
// If this net net is a port (i.e. a *sub*port net of a module port)
// its port index is number of the module it connects through
int get_module_port_index() const; // -1 Not connected to port...
@ -860,7 +857,6 @@ class NetNet : public NetObj, public PortType {
PortType port_type_ : 3;
bool coerced_to_uwire_: 1;
bool local_flag_: 1;
unsigned lexical_pos_;
ivl_type_t net_type_;
netuarray_t *array_type_ = nullptr;
ivl_discipline_t discipline_;
@ -3509,9 +3505,6 @@ class NetEvent : public LineInfo {
perm_string name() const;
unsigned lexical_pos() const { return lexical_pos_; }
void lexical_pos(unsigned lp) { lexical_pos_ = lp; }
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
@ -3546,7 +3539,6 @@ class NetEvent : public LineInfo {
private:
perm_string name_;
unsigned lexical_pos_;
bool local_flag_;
// The NetScope class uses these to list the events.

20
parse.y
View File

@ -22,7 +22,6 @@
# include "config.h"
# include <climits>
# include <cstdarg>
# include "parse_misc.h"
# include "compiler.h"
@ -2194,7 +2193,6 @@ loop_statement /* IEEE1800-2005: A.6.8 */
tmp_hident.push_back(name_component_t(lex_strings.make($5)));
PEIdent*tmp_ident = pform_new_ident(@5, tmp_hident);
FILE_NAME(tmp_ident, @5);
check_for_loop(@1, $8, $10, $12);
PForStatement*tmp_for = new PForStatement(tmp_ident, $8, $10, $12, $14);
@ -3966,7 +3964,6 @@ clocking_event_opt /* */
event_control /* A.K.A. clocking_event */
: '@' hierarchy_identifier
{ PEIdent*tmpi = pform_new_ident(@2, *$2);
FILE_NAME(tmpi, @2);
PEEvent*tmpe = new PEEvent(PEEvent::ANYEDGE, tmpi);
PEventStatement*tmps = new PEventStatement(tmpe);
FILE_NAME(tmps, @1);
@ -4546,7 +4543,6 @@ expr_primary
}
| hierarchy_identifier
{ PEIdent*tmp = pform_new_ident(@1, *$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
}
@ -4555,7 +4551,6 @@ expr_primary
{ pform_name_t * nm = $1;
nm->push_back(name_component_t(lex_strings.make("and")));
PEIdent*tmp = pform_new_ident(@1, *nm);
FILE_NAME(tmp, @1);
$$ = tmp;
delete nm;
}
@ -4563,7 +4558,6 @@ expr_primary
{ pform_name_t * nm = $1;
nm->push_back(name_component_t(lex_strings.make("or")));
PEIdent*tmp = pform_new_ident(@1, *nm);
FILE_NAME(tmp, @1);
$$ = tmp;
delete nm;
}
@ -4571,7 +4565,6 @@ expr_primary
{ pform_name_t * nm = $1;
nm->push_back(name_component_t(lex_strings.make("xor")));
PEIdent*tmp = pform_new_ident(@1, *nm);
FILE_NAME(tmp, @1);
$$ = tmp;
delete nm;
}
@ -5315,7 +5308,6 @@ atom_type
lpvalue
: hierarchy_identifier
{ PEIdent*tmp = pform_new_ident(@1, *$1);
FILE_NAME(tmp, @1);
$$ = tmp;
delete $1;
}
@ -7467,35 +7459,35 @@ statement_item /* This is roughly statement_item in the LRM */
$$ = tmp;
}
| K_TRIGGER hierarchy_identifier ';'
{ PTrigger*tmp = pform_new_trigger(@2, 0, *$2, @2.lexical_pos);
{ PTrigger*tmp = pform_new_trigger(@2, nullptr, *$2);
delete $2;
$$ = tmp;
}
| K_TRIGGER package_scope hierarchy_identifier
{ lex_in_package_scope(0);
PTrigger*tmp = pform_new_trigger(@3, $2, *$3, @3.lexical_pos);
PTrigger*tmp = pform_new_trigger(@3, $2, *$3);
delete $3;
$$ = tmp;
}
/* FIXME: Does this need support for package resolution like above? */
| K_NB_TRIGGER hierarchy_identifier ';'
{ PNBTrigger*tmp = pform_new_nb_trigger(@2, 0, *$2, @2.lexical_pos);
{ PNBTrigger*tmp = pform_new_nb_trigger(@2, nullptr, *$2);
delete $2;
$$ = tmp;
}
| K_NB_TRIGGER delay1 hierarchy_identifier ';'
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, $2, *$3, @3.lexical_pos);
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, $2, *$3);
delete $3;
$$ = tmp;
}
| K_NB_TRIGGER event_control hierarchy_identifier ';'
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, 0, *$3, @3.lexical_pos);
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, nullptr, *$3);
delete $3;
$$ = tmp;
yywarn(@1, "sorry: ->> with event control is not currently supported.");
}
| K_NB_TRIGGER K_repeat '(' expression ')' event_control hierarchy_identifier ';'
{ PNBTrigger*tmp = pform_new_nb_trigger(@7, 0, *$7, @7.lexical_pos);
{ PNBTrigger*tmp = pform_new_nb_trigger(@7, nullptr, *$7);
delete $7;
$$ = tmp;
yywarn(@1, "sorry: ->> with repeat event control is not currently supported.");

View File

@ -45,6 +45,10 @@ inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
{
tmp->set_lineno(where.first_line);
tmp->set_file(filename_strings.make(where.text));
// Preserve a more precise identifier position supplied by a
// constructor instead of replacing it with the enclosing rule.
if (tmp->lexical_pos() == UINT_MAX)
tmp->lexical_pos(where.lexical_pos);
}
/* This for compatibility with new and older bison versions. */

View File

@ -744,24 +744,25 @@ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name)
if (gn_system_verilog())
check_potential_imports(loc, name.front().name, false);
return new PEIdent(name, loc.lexical_pos);
auto tmp = new PEIdent(name, loc.lexical_pos);
FILE_NAME(tmp, loc);
return tmp;
}
PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg,
const pform_name_t&name, unsigned lexical_pos)
const pform_name_t&name)
{
if (gn_system_verilog())
check_potential_imports(loc, name.front().name, false);
PTrigger*tmp = new PTrigger(pkg, name, lexical_pos);
PTrigger*tmp = new PTrigger(pkg, name);
FILE_NAME(tmp, loc);
return tmp;
}
PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
const list<PExpr*>*dly,
const pform_name_t&name,
unsigned lexical_pos)
const pform_name_t&name)
{
if (gn_system_verilog())
check_potential_imports(loc, name.front().name, false);
@ -772,7 +773,7 @@ PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
tmp_dly = dly->front();
}
PNBTrigger*tmp = new PNBTrigger(name, lexical_pos, tmp_dly);
PNBTrigger*tmp = new PNBTrigger(name, tmp_dly);
FILE_NAME(tmp, loc);
return tmp;
}

View File

@ -239,11 +239,10 @@ extern void pform_add_modport_port(const struct vlltype&loc,
extern PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name);
extern PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg,
const pform_name_t&name, unsigned lexical_pos);
const pform_name_t&name);
extern PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
const std::list<PExpr*>*dly,
const pform_name_t&name,
unsigned lexical_pos);
const pform_name_t&name);
/*
* Enter/exit name scopes. The push_scope function pushes the scope

View File

@ -232,7 +232,7 @@ PExpr* pform_package_ident(const struct vlltype&loc,
PPackage*pkg, const pform_name_t*ident_name)
{
ivl_assert(loc, ident_name);
PEIdent*tmp = new PEIdent(pkg, *ident_name, loc.lexical_pos);
PEIdent*tmp = new PEIdent(pkg, *ident_name);
FILE_NAME(tmp, loc);
return tmp;
}