diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7965a842b..36f6fab19 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3918,6 +3918,11 @@ class LinkDotResolveVisitor final : public VNVisitor { // Primitive parameter is really a delay2 we can just ignore VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; + } else if (nodep->param() && !nodep->exprp() && !nodep->svDotName()) { + // Placeholder pin the parser makes for an empty '#()', to signal + // the user did type the '#()'. No further use, deleting. + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; } else { const std::string suggest = (nodep->param() ? m_statep->suggestSymFlat(m_pinSymp, nodep->name(), diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 1129d730a..c40c9a3a6 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1886,8 +1886,10 @@ class ParamProcessor final { std::vector pinsByIndex; pinsByIndex.resize(m_classTypeParams.size(), nullptr); for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) { - if (AstParamTypeDType* typep = pinp->modPTypep()) { - pinsByIndex[m_paramIndex[typep]] = pinp; + AstParamTypeDType* const typep = pinp->modPTypep(); + const auto it = typep ? m_paramIndex.find(typep) : m_paramIndex.end(); + if (it != m_paramIndex.end()) { + pinsByIndex[it->second] = pinp; } else { pinsByIndex.push_back(pinp); } diff --git a/test_regress/t/t_class_param_derived_noparam.py b/test_regress/t/t_class_param_derived_noparam.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_class_param_derived_noparam.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_param_derived_noparam.v b/test_regress/t/t_class_param_derived_noparam.v new file mode 100644 index 000000000..72d678f8c --- /dev/null +++ b/test_regress/t/t_class_param_derived_noparam.v @@ -0,0 +1,105 @@ +// 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 checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +// Base class with type parameter +class base_type #(type T = int); + function int width(); + T t; + return $bits(t); + endfunction +endclass + +// No type parameters of its own, inherits the base's default +class default_type extends base_type; +endclass + +// No type parameters of its own, overrides the base's parameter +class byte_type extends base_type #(byte); +endclass + +// No type parameters of its own, empty parameter list on the extends clause +class paren_type extends base_type#(); +endclass + +// Base class with value parameter +class base_val #(int N = 32); + function int val(); + return N; + endfunction +endclass + +// No parameters of its own, inherits the base's default +class default_val extends base_val; +endclass + +// No parameters of its own, overrides the base's parameter +class eight_val extends base_val #(8); +endclass + +// No parameters of its own, empty parameter list on the extends clause +class paren_val extends base_val#(); +endclass + +// Base class with no parameters at all +class base_none; + function int width(); + return 1; + endfunction +endclass + +class paren_none extends base_none#(); +endclass + +class noparen_none extends base_none; +endclass + +module t; + + // Referenced with an empty parameter list, and without one + default_type#() dp = new; + default_type dn = new; + byte_type#() bp = new; + byte_type bn = new; + paren_type#() tp = new; + paren_type tn = new; + default_val#() vp = new; + default_val vn = new; + eight_val#() ep = new; + eight_val en = new; + paren_val#() qp = new; + paren_val qn = new; + paren_none#() pp = new; + paren_none pn = new; + noparen_none#() np = new; + noparen_none nn = new; + + initial begin + `checkh(dp.width(), 32); + `checkh(dn.width(), 32); + `checkh(bp.width(), 8); + `checkh(bn.width(), 8); + `checkh(tp.width(), 32); + `checkh(tn.width(), 32); + `checkh(vp.val(), 32); + `checkh(vn.val(), 32); + `checkh(ep.val(), 8); + `checkh(en.val(), 8); + `checkh(qp.val(), 32); + `checkh(qn.val(), 32); + `checkh(pp.width(), 1); + `checkh(pn.width(), 1); + `checkh(np.width(), 1); + `checkh(nn.width(), 1); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule