From 651f2233876cc2c6b7fce5d19ee186042cad0081 Mon Sep 17 00:00:00 2001 From: Alex Zhou <126853855+aexzhou@users.noreply.github.com> Date: Mon, 16 Mar 2026 04:31:35 -0700 Subject: [PATCH] Fix false recursive definition error (#6769) (#7118) --- src/V3Param.cpp | 51 ++++++++++++++++++++++++ test_regress/t/t_recursive_definition.py | 18 +++++++++ test_regress/t/t_recursive_definition.v | 30 ++++++++++++++ 3 files changed, 99 insertions(+) create mode 100755 test_regress/t/t_recursive_definition.py create mode 100644 test_regress/t/t_recursive_definition.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 3882b8a3d..db786047e 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1913,6 +1913,55 @@ public: void visit(AstNode* nodep) override { iterateChildren(nodep); } }; +//###################################################################### +// Relink RefDType nodes to point to parameterized classes' type parameters + +class ParamClassRefDTypeRelinkVisitor final : public VNVisitor { + + AstClass* m_classp = nullptr; + std::unordered_map m_paramTypeClassMap; + +public: + explicit ParamClassRefDTypeRelinkVisitor(AstNetlist* netlistp) { iterate(netlistp); } + void visit(AstClass* nodep) override { + VL_RESTORER(m_classp); + m_classp = nodep; + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstParamTypeDType* const ptp = VN_CAST(stmtp, ParamTypeDType)) { + m_paramTypeClassMap[ptp] = nodep; + } + } + iterateChildren(nodep); + } + void visit(AstRefDType* nodep) override { + iterateChildren(nodep); + AstParamTypeDType* const paramtypep = VN_CAST(nodep->refDTypep(), ParamTypeDType); + if (!paramtypep) return; + const auto it = m_paramTypeClassMap.find(paramtypep); + if (it == m_paramTypeClassMap.end()) return; + AstClass* const origClassp = it->second; + if (!origClassp->hasGParam()) return; // only relink refs to original param classes + if (origClassp->user3p()) return; // will not get removed, no need to relink + AstClass* const parametrizedClassp = VN_CAST(origClassp->user4p(), Class); + if (!parametrizedClassp) return; + const string paramName = paramtypep->name(); + AstParamTypeDType* newParamTypep = nullptr; + for (AstNode* stmtp = parametrizedClassp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstParamTypeDType* const ptp = VN_CAST(stmtp, ParamTypeDType)) { + if (ptp->name() == paramName) { + newParamTypep = ptp; + break; + } + } + } + if (newParamTypep) { + nodep->refDTypep(newParamTypep); + nodep->classOrPackagep(parametrizedClassp); + } + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } +}; + //###################################################################### // Process parameter top state @@ -2784,6 +2833,8 @@ public: } }); + ParamClassRefDTypeRelinkVisitor paramClassDTypeRelinkVisitor{netlistp}; + relinkDots(); resortNetlistModules(netlistp); diff --git a/test_regress/t/t_recursive_definition.py b/test_regress/t/t_recursive_definition.py new file mode 100755 index 000000000..3cc73805c --- /dev/null +++ b/test_regress/t/t_recursive_definition.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: 2024 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_recursive_definition.v b/test_regress/t/t_recursive_definition.v new file mode 100644 index 000000000..15e2fca90 --- /dev/null +++ b/test_regress/t/t_recursive_definition.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2023 Antmicro Ltd +// SPDX-License-Identifier: CC0-1.0 + +module t; + class uvm_built_in_comp #( + type T = int + ); + endclass + + class uvm_in_order_comparator #( + type T = int, + type comp_type = uvm_built_in_comp#(T) + ); + endclass + + class uvm_in_order_built_in_comparator #( + type T = int + ) extends uvm_in_order_comparator #(T); + endclass + + initial begin + uvm_in_order_built_in_comparator #(int) sb; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule