Fix virtual interface function calls binding to wrong instance (#7363)

This commit is contained in:
Yilou Wang 2026-04-02 16:53:01 +02:00 committed by GitHub
parent 32672deb6f
commit 1e5c93cc51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 2 deletions

View File

@ -251,6 +251,13 @@ private:
if (nodep->dpiImport()) m_curVxp->noInline(true);
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
if (nodep->recursive()) m_curVxp->noInline(true);
// V3Scope resolves virtual-interface MethodCalls via user2p (last-wins),
// so inlining would bake in the wrong instance's VarScope refs.
if (v3Global.hasVirtIfaces()) {
if (const AstScope* const scopep = VN_CAST(nodep->user3p(), Scope)) {
if (VN_IS(scopep->modp(), Iface)) m_curVxp->noInline(true);
}
}
if (nodep->isConstructor()) {
m_curVxp->noInline(true);
m_ctorp = nodep;
@ -1690,10 +1697,12 @@ class TaskVisitor final : public VNVisitor {
}
const bool noInline = m_statep->ftaskNoInline(nodep);
// Warn if not inlining an impure ftask (unless method or recursvie).
// Warn if not inlining an impure ftask (unless method, recursive,
// or interface function -- interface member access is not truly external).
// Will likely not schedule correctly.
// TODO: Why not if recursive? It will not work ...
if (noInline && !nodep->classMethod() && !nodep->recursive()) {
if (noInline && !nodep->classMethod() && !nodep->recursive()
&& !VN_IS(m_modp, Iface)) {
if (AstNode* const impurep = m_statep->checkImpure(nodep)) {
nodep->v3warn(
IMPURE,

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,41 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 PlanV GmbH
// SPDX-License-Identifier: CC0-1.0
interface my_if;
logic clk = 0;
bit clk_active = 0;
initial begin
wait (clk_active);
forever #5 clk = ~clk;
end
function void start_clk();
clk_active = 1;
endfunction
endinterface
class Driver;
virtual my_if vif;
task run();
#10;
vif.start_clk();
endtask
endclass
module t;
my_if intf();
my_if intf_unused(); // Second instance triggered the bug
initial begin
automatic Driver d = new;
d.vif = intf;
d.run();
repeat (4) @(posedge intf.clk);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule