Fix enum item references in class extends with parameters.

This commit is contained in:
Wilson Snyder 2025-12-07 15:26:52 -05:00
parent 8130fed777
commit ae480c5f76
7 changed files with 83 additions and 7 deletions

View File

@ -84,6 +84,7 @@ Verilator 5.043 devel
* Fix DFG assertion on out-of-bounds selects. [Geza Lore]
* Fix crash when super.new() called without a base class (#6772). [Matthew Ballance]
* Fix class-in-class extends with parameters (#6773).
* Fix enum item references in class extends with parameters.
Verilator 5.042 2025-11-02

View File

@ -1285,11 +1285,13 @@ public:
bool cleanOut() const override { return true; }
};
class AstEnumItemRef final : public AstNodeExpr {
// @astgen ptr := m_itemp : AstEnumItem // [AfterLink] Pointer to item
// @astgen ptr := m_itemp : Optional[AstEnumItem] // [AfterLink] Pointer to item
// @astgen ptr := m_classOrPackagep : Optional[AstNodeModule] // Class/package defined in
string m_name; // Name of enum (for param relink)
public:
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep)
: ASTGEN_SUPER_EnumItemRef(fl)
, m_name{itemp->name()}
, m_itemp{itemp}
, m_classOrPackagep{classOrPackagep} {
dtypeFrom(m_itemp);
@ -1297,13 +1299,14 @@ public:
ASTGEN_MEMBERS_AstEnumItemRef;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string name() const override VL_MT_STABLE { return itemp() ? itemp()->name() : "<null>"; }
string name() const override VL_MT_STABLE { return itemp() ? itemp()->name() : m_name; }
int instrCount() const override { return 0; }
bool sameNode(const AstNode* samep) const override {
const AstEnumItemRef* const sp = VN_DBG_AS(samep, EnumItemRef);
return itemp() == sp->itemp();
}
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
void itemp(AstEnumItem* nodep) { m_itemp = nodep; }
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
@ -1691,8 +1694,6 @@ class AstLambdaArgRef final : public AstNodeExpr {
// Lambda argument usage
// These are not AstVarRefs because we need to be able to delete/clone lambdas during
// optimizations and AstVar's are painful to remove.
private:
string m_name; // Name of variable
bool m_index; // Index, not value

View File

@ -4370,8 +4370,25 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
}
void visit(AstEnumItemRef* nodep) override {
// EnumItemRef may be under a dot. Should already be resolved.
// Resolve its reference
// EnumItemRefs are created by the first pass, but V3Param may regenerate due to
// a parameterized class/module, so we shouldn't get can't find errors.
// No checkNoDot; created and iterated from a parseRef
LINKDOT_VISIT_START();
if (!nodep->itemp()) {
UINFO(9, indent() << "linkEnumRef se" << cvtToHex(m_curSymp) << " n=" << nodep);
UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table");
VSymEnt* const foundp = m_curSymp->findIdFallback(nodep->name());
if (AstEnumItem* const itemp = foundp ? VN_CAST(foundp->nodep(), EnumItem) : nullptr) {
nodep->itemp(itemp);
nodep->classOrPackagep(foundp->classOrPackagep());
UINFO(9, indent() << " resolved " << nodep);
}
if (VL_UNCOVERABLE(!nodep->itemp())) {
nodep->v3error("Can't find definition of enum item, again: " // LCOV_EXCL_LINE
<< nodep->prettyNameQ());
}
}
iterateChildren(nodep);
}
void visit(AstMethodCall* nodep) override {

View File

@ -2032,8 +2032,12 @@ public:
}
// Set all links pointing to a user3 (deleting) node as null
netlistp->foreach([](AstNode* const nodep) {
nodep->foreachLink([](AstNode** const linkpp, const char*) {
if (*linkpp && (*linkpp)->user3()) *linkpp = nullptr;
nodep->foreachLink([&](AstNode** const linkpp, const char*) {
if (*linkpp && (*linkpp)->user3()) {
UINFO(9, "clear link " << nodep);
*linkpp = nullptr;
UINFO(9, "cleared link " << nodep);
}
});
});
}

View File

@ -2817,6 +2817,7 @@ class WidthVisitor final : public VNVisitor {
}
}
void visit(AstEnumItemRef* nodep) override {
UASSERT_OBJ(nodep->itemp(), nodep, "Unlinked");
if (!nodep->itemp()->didWidth()) {
// We need to do the whole enum en masse
AstNode* enump = nodep->itemp();

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,34 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package uvm_pkg;
class uvm_reg_sequence #(
type BASE = int
);
typedef enum {
LOCAL = 2,
UPSTREAM = 3
} seq_parent_e;
endclass
endpackage
module t;
import uvm_pkg::*;
class test_seq extends uvm_reg_sequence;
endclass
initial begin
test_seq c;
c = new;
`checkd(c.LOCAL, 2);
`checkd(c.UPSTREAM, 3);
$finish;
end
endmodule