Fix internal error when fork under always expression (#6911).

This commit is contained in:
Wilson Snyder 2026-01-23 22:11:04 -05:00
parent 2737a22793
commit 07b61d3745
3 changed files with 13 additions and 4 deletions

View File

@ -41,6 +41,7 @@ Verilator 5.045 devel
* Fix signedness of packed array (#6901) (#6902). [Yutetsu TAKATSUKASA]
* Fix assignment of queue from unpacked array (#6906).
* Fix `foreach` with mid-index empty commas (#6910).
* Fix internal error when fork under always expression (#6911).
* Fix error when calling non-static method (#6916). [Artur Bieniek, Antmicro Ltd.]
* Fix memory leak in vpi_put_value and vpi_get_value (#6917). [Christian Hecken]
* Fix segfault after assignment pattern XOR error (#6928) (#6931). [emmettifelts]

View File

@ -277,6 +277,7 @@ class TimingSuspendableVisitor final : public VNVisitor {
addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC);
}
void visit(AstWait* nodep) override {
UINFO(9, "suspendable-visit " << nodep);
AstNodeExpr* const condp = V3Const::constifyEdit(nodep->condp());
if (AstConst* const constp = VN_CAST(condp, Const)) {
if (!nodep->fileline()->warnIsOff(V3ErrorCode::WAITCONST)) {
@ -365,6 +366,7 @@ class TimingSuspendableVisitor final : public VNVisitor {
iterateChildren(nodep);
}
void visit(AstFork* nodep) override {
UINFO(9, "suspendable-visit " << nodep);
VL_RESTORER(m_underFork);
v3Global.setUsesTiming(); // Even if there are no event controls, we have to set this flag
@ -1056,6 +1058,7 @@ class TimingControlVisitor final : public VNVisitor {
void visit(AstNodeAssign* nodep) override {
// Only process once to avoid infinite loops (due to the net delay)
if (nodep->user1SetOnce()) return;
UINFO(9, "control-visit " << nodep);
FileLine* const flp = nodep->fileline();
AstNode* controlp = factorOutTimingControl(nodep);
const bool inAssignDly = VN_IS(nodep, AssignDly);
@ -1063,7 +1066,10 @@ class TimingControlVisitor final : public VNVisitor {
// Transform if:
// * there's a timing control in the assignment
// * the assignment is an AssignDly and it's in a non-inlined function
if (!controlp && (!inAssignDly || m_underProcedure)) return;
if (!controlp && (!inAssignDly || m_underProcedure)) {
iterateChildren(nodep);
return;
}
// Insert new vars before the timing control if we're in a function; in a process we can't
// do that. These intra-assignment vars will later be passed to forked processes by value.
AstNode* insertBeforep = m_underProcedure ? nullptr : controlp;
@ -1232,6 +1238,7 @@ class TimingControlVisitor final : public VNVisitor {
}
void visit(AstWait* nodep) override {
// Wait on changed events related to the vars in the wait statement
UINFO(9, "control-visit " << nodep);
FileLine* const flp = nodep->fileline();
AstNode* const stmtsp = nodep->stmtsp();
if (stmtsp) stmtsp->unlinkFrBackWithNext();
@ -1290,6 +1297,7 @@ class TimingControlVisitor final : public VNVisitor {
}
void visit(AstFork* nodep) override {
if (nodep->user1SetOnce()) return;
UINFO(9, "control-visit " << nodep);
v3Global.setUsesTiming();
// Create a unique name for this fork

View File

@ -55,7 +55,7 @@ package my_pkg;
end
begin
#10;
-> h.my_event;
->h.my_event;
#10;
h.vif.sig = 1;
#10;
@ -67,7 +67,7 @@ package my_pkg;
endpackage
module t;
my_if intf();
my_if intf ();
my_pkg::my_driver drv;
virtual my_if vif;
@ -96,7 +96,7 @@ module t;
// Use #0 to ensure construction happens first in delta cycle ordering
initial begin
#0;
-> drv.my_event;
->drv.my_event;
end
// Call the task later - trigger expressions were evaluated before this