Fix for unction argument expects a class refetence (#7483) (#7489)

Fixes #7483.
This commit is contained in:
em2machine 2026-04-24 04:31:57 -04:00 committed by GitHub
parent 2cd9b8df66
commit b1d3d63e9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 266 additions and 3 deletions

View File

@ -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;
}

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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