From b1d3d63e9f87a75aa136583bfac485c5582517e3 Mon Sep 17 00:00:00 2001 From: em2machine <92717390+em2machine@users.noreply.github.com> Date: Fri, 24 Apr 2026 04:31:57 -0400 Subject: [PATCH] Fix for unction argument expects a class refetence (#7483) (#7489) Fixes #7483. --- src/V3Width.cpp | 13 ++- test_regress/t/t_class_type_param_upcast.py | 18 ++++ test_regress/t/t_class_type_param_upcast.v | 40 +++++++++ .../t/t_class_type_param_upcast_all.py | 18 ++++ .../t/t_class_type_param_upcast_all.v | 88 +++++++++++++++++++ .../t/t_class_type_param_upcast_chain.py | 18 ++++ .../t/t_class_type_param_upcast_chain.v | 74 ++++++++++++++++ 7 files changed, 266 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_class_type_param_upcast.py create mode 100644 test_regress/t/t_class_type_param_upcast.v create mode 100755 test_regress/t/t_class_type_param_upcast_all.py create mode 100644 test_regress/t/t_class_type_param_upcast_all.v create mode 100755 test_regress/t/t_class_type_param_upcast_chain.py create mode 100644 test_regress/t/t_class_type_param_upcast_chain.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e57c891e8..34d60cf06 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7156,7 +7156,9 @@ class WidthVisitor final : public VNVisitor { } if (portp->isWritable()) V3LinkLValue::linkLValueSet(pinp); if (!portp->basicp() || portp->basicp()->isOpaque()) { - checkClassAssign(nodep, "Function Argument", pinp, portDTypep); + // Output args: at return caller = callee, reverse direction. + checkClassAssign(nodep, "Function Argument", pinp, portDTypep, + portp->direction() == VDirection::OUTPUT); userIterate(pinp, WidthVP{portDTypep, FINAL}.p()); } else { iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portDTypep); @@ -8512,14 +8514,19 @@ class WidthVisitor final : public VNVisitor { } } void checkClassAssign(const AstNode* nodep, const char* side, AstNode* rhsp, - AstNodeDType* const lhsDTypep) { + AstNodeDType* const lhsDTypep, bool isOutputArg = false) { UASSERT_OBJ(rhsp->dtypep(), rhsp, "Node has no type"); const AstNodeDType* const lhsRawDTypep = lhsDTypep->skipRefp(); const AstNodeDType* const rhsRawDTypep = rhsp->dtypep()->skipRefp(); if (const AstClassRefDType* const lhsClassRefp = VN_CAST(lhsRawDTypep, ClassRefDType)) { if (const AstClassRefDType* const rhsClassRefp = VN_CAST(rhsRawDTypep, ClassRefDType)) { - if (isBaseClassRecurse(lhsClassRefp->classp(), rhsClassRefp->classp())) return; + // Output arg swaps sides: caller actual = callee formal at return. + const AstClass* const dstp + = isOutputArg ? rhsClassRefp->classp() : lhsClassRefp->classp(); + const AstClass* const srcp + = isOutputArg ? lhsClassRefp->classp() : rhsClassRefp->classp(); + if (isBaseClassRecurse(dstp, srcp)) return; } else if (rhsp->isNull()) { return; } diff --git a/test_regress/t/t_class_type_param_upcast.py b/test_regress/t/t_class_type_param_upcast.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast.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(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_type_param_upcast.v b/test_regress/t/t_class_type_param_upcast.v new file mode 100644 index 000000000..a27df82ad --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast.v @@ -0,0 +1,40 @@ +// 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 + +// Output arg of class type-parameter accepts a base handle (upcast). + +class Fifo #(type T = int); + T m_val; + task get(output T t); + t = m_val; + endtask +endclass + +class Base; + int m_id = 10; +endclass + +class Deriv extends Base; + int m_extra = 20; +endclass + +module t; + Fifo #(Deriv) f; + Base b; + Deriv d; + initial begin + f = new; + d = new; + d.m_id = 42; + d.m_extra = 99; + f.m_val = d; + f.get(b); + if (b === null) $stop; + if (b.m_id !== 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_type_param_upcast_all.py b/test_regress/t/t_class_type_param_upcast_all.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast_all.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(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_type_param_upcast_all.v b/test_regress/t/t_class_type_param_upcast_all.v new file mode 100644 index 000000000..6e1a63677 --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast_all.v @@ -0,0 +1,88 @@ +// 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 + +// Legal upcasts on class type-parameter args, direct and multi-level. + +class Base; + int seq = 0; + int b_tag = 'hBAAD; +endclass + +class Mid extends Base; + int m_tag = 'hDEAD; +endclass + +class Leaf extends Mid; + int l_tag = 'hBEEF; +endclass + +class Unrelated; + int u_tag = 0; +endclass + +class Fifo #(type T = Unrelated); + T m_val; + task put(input T t); + m_val = t; + endtask + task get(output T t); + t = m_val; + endtask +endclass + +module t; + Fifo #(Leaf) lf; + Fifo #(Mid) mf; + Fifo #(Base) bf; + + Leaf l1, l2, l3; + Mid m1, m2; + Base b1, b2, b3; + + initial begin + lf = new; + mf = new; + bf = new; + + // Output upcast Leaf -> Mid. + l1 = new; l1.seq = 1; + lf.put(l1); + lf.get(m1); + if (m1 === null) $stop; + if (m1.seq !== 1) $stop; + + // Output upcast Leaf -> Base (two levels). + l2 = new; l2.seq = 2; + lf.put(l2); + lf.get(b1); + if (b1 === null) $stop; + if (b1.seq !== 2) $stop; + + // Output upcast Mid -> Base. + m2 = new; m2.seq = 3; + mf.put(m2); + mf.get(b2); + if (b2 === null) $stop; + if (b2.seq !== 3) $stop; + + // Input upcast Leaf -> Base. + l3 = new; l3.seq = 4; + bf.put(l3); + bf.get(b3); + if (b3 === null) $stop; + if (b3.seq !== 4) $stop; + + // Same-type sanity. + m1 = new; m1.seq = 5; + mf.put(m1); + mf.get(m2); + if (m2 === null) $stop; + if (m2.seq !== 5) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_type_param_upcast_chain.py b/test_regress/t/t_class_type_param_upcast_chain.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast_chain.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(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_type_param_upcast_chain.v b/test_regress/t/t_class_type_param_upcast_chain.v new file mode 100644 index 000000000..91e767027 --- /dev/null +++ b/test_regress/t/t_class_type_param_upcast_chain.v @@ -0,0 +1,74 @@ +// 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 + +// Output class type-parameter upcast through a 3-level extends chain. + +package x_pkg; + virtual class x_t_fifo_base #(type T = int); + T m_val; + virtual task put(input T t); + m_val = t; + endtask + virtual task get(output T t); + t = m_val; + endtask + endclass + class x_t_fifo #(type T = int) extends x_t_fifo_base #(T); + endclass + class x_t_analysis_fifo #(type T = int) extends x_t_fifo #(T); + endclass +endpackage + +package s_t_pkg; + class s_txn_base; + int id = 0; + endclass +endpackage + +package s_x_pkg; + import s_t_pkg::*; + class s_x_txn extends s_txn_base; + int x_val = 0; + endclass +endpackage + +package s_core_env_pkg; + import x_pkg::*; + import s_t_pkg::*; + import s_x_pkg::*; + class s_p_scoreboard; + x_t_analysis_fifo #(s_x_txn) x_r_fifo; + s_txn_base observed; + extern task process_r(); + endclass + task s_p_scoreboard::process_r(); + s_txn_base txn1; + x_r_fifo.get(txn1); + observed = txn1; + endtask +endpackage + +import x_pkg::*; +import s_x_pkg::*; +import s_core_env_pkg::*; + +module tb_top; + s_p_scoreboard sb; + s_x_txn tx; + initial begin + sb = new; + sb.x_r_fifo = new; + tx = new; + tx.id = 77; + tx.x_val = 99; + sb.x_r_fifo.put(tx); + sb.process_r(); + if (sb.observed === null) $stop; + if (sb.observed.id !== 77) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule