From 07b61d3745e27247a32964995cda29b49edbe02a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 23 Jan 2026 22:11:04 -0500 Subject: [PATCH] Fix internal error when fork under always expression (#6911). --- Changes | 1 + src/V3Timing.cpp | 10 +++++++++- test_regress/t/t_class_trigger_null.v | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Changes b/Changes index bf03ff5e9..0d1cf5bb9 100644 --- a/Changes +++ b/Changes @@ -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] diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 23cc9ff7e..770c2127a 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -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 diff --git a/test_regress/t/t_class_trigger_null.v b/test_regress/t/t_class_trigger_null.v index 4288a8761..d16f3952f 100644 --- a/test_regress/t/t_class_trigger_null.v +++ b/test_regress/t/t_class_trigger_null.v @@ -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