diff --git a/src/V3Task.cpp b/src/V3Task.cpp index f6968107c..9a04fa5e5 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -291,18 +291,23 @@ private: iterateChildren(nodep); } UASSERT_OBJ(m_ctorp, nodep, "class constructor missing"); // LinkDot always makes it + AstNode* insertp = nullptr; for (AstInitialAutomatic* initialp : m_initialps) { - if (AstNode* const newp = initialp->stmtsp()) { - newp->unlinkFrBackWithNext(); - if (!m_ctorp->stmtsp()) { - m_ctorp->addStmtsp(newp); - } else { - m_ctorp->stmtsp()->addHereThisAsNext(newp); - } + if (AstNode* const movep = initialp->stmtsp()) { + movep->unlinkFrBackWithNext(); + // Next InitialAutomatic must go in order after what we inserted + insertp = AstNode::addNextNull(insertp, movep); } VL_DO_DANGLING(pushDeletep(initialp->unlinkFrBack()), initialp); } m_initialps.clear(); + if (insertp) { + if (!m_ctorp->stmtsp()) { + m_ctorp->addStmtsp(insertp); + } else { + m_ctorp->stmtsp()->addHereThisAsNext(insertp); + } + } } void visit(AstInitialAutomatic* nodep) override { m_initialps.push_back(nodep); diff --git a/test_regress/t/t_class_init_order.py b/test_regress/t/t_class_init_order.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_class_init_order.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_init_order.v b/test_regress/t/t_class_init_order.v new file mode 100644 index 000000000..13a7b6fad --- /dev/null +++ b/test_regress/t/t_class_init_order.v @@ -0,0 +1,68 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +module t; + + class uvm_coreservice; + static uvm_coreservice inst; + + function new(string name); + endfunction + + static function uvm_coreservice get(); + if (inst == null) begin + inst = new("cs-base"); + end + return inst; + endfunction + + virtual function string get_factory(); + return "factory"; + endfunction + endclass + + class uvm_test; + string m_name; + string s0 = {m_name, "0"}; // Before new(); this must get "0" not "name0" + function new(string name); + m_name = name; + endfunction + endclass + + class test extends uvm_test; + + string s1 = {s0, "1"}; + string s2 = {s1, "2"}; + + uvm_coreservice cs = uvm_coreservice::get(); + // Below assumes that the above 'cs' executes first. + // Most simulators require this ordering, but some allow arbitrary order + // This would require dataflow analysis, so for now Verilator requires user ordering + string factory = cs.get_factory(); + + function new(string name); + super.new(name); + endfunction + endclass + initial begin + test t; + string s; + + t = new("test"); + `checks(t.s0, "0"); + `checks(t.s1, "01"); + `checks(t.s2, "012"); + s = t.factory; + `checks(s, "factory"); + + $finish; + end +endmodule