diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 5c3b8547c..1428a6cb2 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -905,7 +905,7 @@ public: string name() const override VL_MT_STABLE { return m_name; } // * = Var name // There's no classOrPackagep(); use classOrPackageNodep() to get Node, // or iterating to package with classOrPackageSkipp() - AstNodeModule* classOrPackageSkipp() const; + AstNodeModule* classOrPackageSkipp(const bool doRefs = true) const; AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } void classOrPackagep(AstNodeModule* nodep) { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9f773e6aa..25d453933 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -3460,7 +3460,7 @@ void AstClassOrPackageRef::dump(std::ostream& str) const { } } void AstClassOrPackageRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); } -AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const { +AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp(const bool doRefs) const { AstNode* foundp = m_classOrPackageNodep; AstNode* lastp = nullptr; while (foundp != lastp) { @@ -3468,11 +3468,12 @@ AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const { if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) { foundp = anodep->skipRefOrNullp(); } - if (const AstTypedef* const anodep = VN_CAST(foundp, Typedef)) { - foundp = anodep->subDTypep(); - } - if (const AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType)) { - foundp = anodep->classp(); + if (doRefs) { + if (const AstTypedef* const anodep = VN_CAST(foundp, Typedef)) { + foundp = anodep->subDTypep(); + } else if (const AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType)) { + foundp = anodep->classp(); + } } } return VN_CAST(foundp, NodeModule); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7867c2fec..7965a842b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3173,6 +3173,7 @@ class LinkDotResolveVisitor final : public VNVisitor { bool m_replaceWithAlias = true; // Replace VarScope with an alias. Used in the handling of AstAlias bool m_isParam = false; // Specifies whether currently visiting param variable + bool m_resolvingTypedef = false; // Currently traversing a Typedef tree struct DotStates final { DotPosition m_dotPos; // Scope part of dotted resolution @@ -6063,12 +6064,14 @@ class LinkDotResolveVisitor final : public VNVisitor { iterate(cpackagep); return; } - if (!cpackagerefp->classOrPackageSkipp()) { + + const bool doDefaultTypedef = !(m_resolvingTypedef && m_statep->forPrimary()); + if (!cpackagerefp->classOrPackageSkipp(doDefaultTypedef)) { VSymEnt* const foundp = m_statep->resolveClassOrPackage( m_ds.m_dotSymp, cpackagerefp, true, false, "class/package reference"); if (!foundp) return; } - nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp()); + nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp(doDefaultTypedef)); if (!VN_IS(nodep->classOrPackagep(), Class) && !VN_IS(nodep->classOrPackagep(), Package)) { if (m_statep->forPrimary()) { @@ -6358,6 +6361,12 @@ class LinkDotResolveVisitor final : public VNVisitor { iterateChildren(nodep); } + void visit(AstTypedef* nodep) override { + VL_RESTORER(m_resolvingTypedef) + m_resolvingTypedef = true; + iterateChildren(nodep); + } + void visit(AstNode* nodep) override { VL_RESTORER(m_inPackedArray); if (VN_IS(nodep, PackArrayDType)) { diff --git a/test_regress/t/t_link_default_type_param.py b/test_regress/t/t_link_default_type_param.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_link_default_type_param.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_link_default_type_param.v b/test_regress/t/t_link_default_type_param.v new file mode 100644 index 000000000..d320ac9a3 --- /dev/null +++ b/test_regress/t/t_link_default_type_param.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class class_a; + typedef logic [31:0] type_1; +endclass + +class class_b; + typedef logic [31:0] type_1; + typedef logic [63:0] type_2; +endclass + +module top #( + parameter type class_t = class_a +) ( + input logic in_val +); + + typedef class_t::type_2 local_type_2; + local_type_2 internal_sig; + +endmodule + +module t; + + top #(.class_t(class_b)) dut (.in_val('0)); + + initial begin + dut.internal_sig = $c(1); + `checkd(dut.internal_sig, 1); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule