diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index c98b10843..f8547b265 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -912,6 +912,7 @@ public: dtypep(nullptr); // V3Width will resolve } ASTGEN_MEMBERS_AstParamTypeDType; + void dump(std::ostream& str = std::cout) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); } AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 2a3a4d975..bb0ca080e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1719,12 +1719,25 @@ void AstTimeImport::dump(std::ostream& str) const { void AstTypedef::dump(std::ostream& str) const { this->AstNode::dump(str); if (attrPublic()) str << " [PUBLIC]"; + if (subDTypep()) { + str << " -> "; + subDTypep()->dump(str); + } } void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstRange::dump(std::ostream& str) const { this->AstNodeRange::dump(str); if (littleEndian()) str << " [LITTLE]"; } +void AstParamTypeDType::dump(std::ostream& str) const { + this->AstNodeDType::dump(str); + if (subDTypep()) { + str << " -> "; + subDTypep()->dump(str); + } else { + str << " -> UNLINKED"; + } +} void AstRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (typedefp() || subDTypep()) { @@ -2095,7 +2108,8 @@ void AstClassOrPackageRef::dump(std::ostream& str) const { } AstNodeModule* AstClassOrPackageRef::classOrPackagep() const { AstNode* foundp = m_classOrPackageNodep; - while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); + if (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); + if (auto* const anodep = VN_CAST(foundp, NodeDType)) foundp = anodep->skipRefp(); if (auto* 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 3879c918a..3ed4bd599 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2069,11 +2069,13 @@ private: } bool isParamedClassRef(const AstNode* nodep) { + // Is this a parametrized reference to a class, or a reference to class parameter if (const auto* classRefp = VN_CAST(nodep, ClassOrPackageRef)) { if (classRefp->paramsp()) return true; const auto* classp = classRefp->classOrPackageNodep(); while (const auto* typedefp = VN_CAST(classp, Typedef)) classp = typedefp->subDTypep(); - return VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp(); + return (VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp()) + || VN_IS(classp, ParamTypeDType); } return false; } @@ -2633,8 +2635,9 @@ private: // Class: Recurse inside or cleanup not founds // checkNoDot not appropriate, can be under a dot AstNode::user5ClearTree(); - UASSERT_OBJ(m_statep->forPrimary() || nodep->classOrPackagep(), nodep, - "ClassRef has unlinked class"); + UASSERT_OBJ(m_statep->forPrimary() || VN_IS(nodep->classOrPackageNodep(), ParamTypeDType) + || nodep->classOrPackagep(), + nodep, "ClassRef has unlinked class"); UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep, "class reference parameter not removed by V3Param"); VL_RESTORER(m_ds); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index baef76ddf..b1153931b 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -936,11 +936,13 @@ class ParamVisitor final : public VNVisitor { srcModp = modCellp->modp(); } else if (const auto* classRefp = VN_CAST(cellp, ClassOrPackageRef)) { srcModp = classRefp->classOrPackagep(); + if (VN_IS(classRefp->classOrPackageNodep(), ParamTypeDType)) continue; } else if (const auto* classRefp = VN_CAST(cellp, ClassRefDType)) { srcModp = classRefp->classp(); } else { cellp->v3fatalSrc("Expected module parametrization"); } + UASSERT_OBJ(srcModp, cellp, "Unlinked class ref"); // Update path string someInstanceName(modp->someInstanceName()); diff --git a/test_regress/t/t_class_param_type.pl b/test_regress/t/t_class_param_type.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_param_type.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v new file mode 100644 index 000000000..1501f0819 --- /dev/null +++ b/test_regress/t/t_class_param_type.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Arkadiusz Kozdra. +// SPDX-License-Identifier: CC0-1.0 + +// See also t_class_param.v + +class Parcls #(type T); + static function int get_p; + return T::get_p(); + endfunction +endclass + +class Cls; + static function int get_p; + return 20; + endfunction +endclass + +typedef Cls cls_t; +typedef cls_t cls2_t; + +module t (/*AUTOARG*/); + + initial begin + if (Parcls#(cls2_t)::get_p() != 20) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule