Fix static vars under member select (#6313)

This commit is contained in:
Igor Zaworski 2025-08-20 17:23:16 +02:00 committed by GitHub
parent 95c8b7bb00
commit 11667160f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 221 additions and 2 deletions

View File

@ -44,6 +44,7 @@ class WidthCommitVisitor final : public VNVisitor {
AstNodeModule* m_modp = nullptr;
std::string m_contNba; // In continuous- or non-blocking assignment
VMemberMap m_memberMap; // Member names cached for fast lookup
bool m_underSel = false; // Whether is currently under AstMemberSel or AstSel
public:
// METHODS
@ -126,7 +127,9 @@ private:
}
}
void varLifetimeCheck(AstNode* nodep, AstVar* varp) {
if (!m_contNba.empty()) {
// Skip if we are under a member select (lhs of a dot)
// We don't care about lifetime of anything else than rhs of a dot
if (!m_underSel && !m_contNba.empty()) {
std::string varType;
const AstNodeDType* const varDtp = varp->dtypep()->skipRefp();
if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType)
@ -368,7 +371,11 @@ private:
classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class));
}
void visit(AstMemberSel* nodep) override {
iterateChildren(nodep);
{
VL_RESTORER(m_underSel);
m_underSel = true;
iterateChildren(nodep);
}
editDType(nodep);
if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
classEncapCheck(nodep, nodep->varp(), classrefp->classp());
@ -388,6 +395,14 @@ private:
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}
void visit(AstSel* nodep) override {
{
VL_RESTORER(m_underSel);
m_underSel = true;
iterateChildren(nodep);
}
editDType(nodep);
}
void visit(AstNode* nodep) override {
iterateChildren(nodep);
editDType(nodep);

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(timing_loop=True, verilator_flags2=['--timing'])
test.execute()
test.passes()

View File

@ -0,0 +1,75 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
interface Iface;
bit clk;
int x;
clocking cb @(posedge clk);
default input #0 output #0;
inout x;
endclocking
endinterface
class Foo;
virtual Iface iface;
function new(virtual Iface tmp);
iface = tmp;
endfunction
task update(virtual Iface tmp);
iface = tmp;
endtask
endclass
class Bar;
Foo foo;
function new(Foo tmp);
foo = tmp;
endfunction
task update(Foo tmp);
foo = tmp;
endtask
task assignment();
foo.iface.cb.x <= 8;
endtask
endclass
module t;
Iface iface();
Iface iface2();
task clockSome();
#2;
iface.clk = ~iface.clk;
iface2.clk = ~iface2.clk;
#2;
iface.clk = ~iface.clk;
iface2.clk = ~iface2.clk;
endtask
initial begin
Foo foo = new(iface);
Foo foo2 = new(iface2);
Bar bar = new(foo);
clockSome();
if (iface.x != 0) $stop;
if (iface2.x != 0) $stop;
bar.assignment();
clockSome();
if (iface.x != 8) $stop;
if (iface2.x != 0) $stop;
foo.update(iface2);
clockSome();
if (iface.x != 8) $stop;
if (iface2.x != 0) $stop;
bar.update(foo2);
clockSome();
if (iface.x != 8) $stop;
if (iface2.x != 0) $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
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(timing_loop=True, verilator_flags2=['--timing'])
test.execute()
test.passes()

View File

@ -0,0 +1,93 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
interface Iface;
bit clk;
int x[2:0];
clocking cb @(posedge clk);
default input #0 output #0;
inout x;
endclocking
endinterface
class Foo;
virtual Iface iface;
int index = 0;
function new(virtual Iface tmp);
iface = tmp;
endfunction
task update(virtual Iface tmp);
iface = tmp;
endtask
task update_index(int i);
index = i;
endtask
endclass
class Bar;
Foo foo;
function new(Foo tmp);
foo = tmp;
endfunction
task update(Foo tmp);
foo = tmp;
endtask
task assignment();
foo.iface.cb.x[foo.index] <= 8;
endtask
endclass
module t;
Iface iface();
Iface iface2();
task clockSome();
#2;
iface.clk = ~iface.clk;
iface2.clk = ~iface2.clk;
#2;
iface.clk = ~iface.clk;
iface2.clk = ~iface2.clk;
endtask
initial begin
Foo foo = new(iface);
Foo foo2 = new(iface2);
Bar bar = new(foo);
clockSome();
if (iface.x[0] != 0) $stop;
if (iface.x[1] != 0) $stop;
if (iface2.x[0] != 0) $stop;
if (iface2.x[1] != 0) $stop;
bar.assignment();
clockSome();
if (iface.x[0] != 8) $stop;
if (iface.x[1] != 0) $stop;
if (iface2.x[0] != 0) $stop;
if (iface2.x[1] != 0) $stop;
foo.update_index(1);
clockSome();
if (iface.x[0] != 8) $stop;
if (iface.x[1] != 0) $stop;
if (iface2.x[0] != 0) $stop;
if (iface2.x[1] != 0) $stop;
foo.update(iface2);
clockSome();
if (iface.x[0] != 8) $stop;
if (iface.x[1] != 0) $stop;
if (iface2.x[0] != 0) $stop;
if (iface2.x[1] != 0) $stop;
bar.update(foo2);
clockSome();
if (iface.x[0] != 8) $stop;
if (iface.x[1] != 0) $stop;
if (iface2.x[0] != 0) $stop;
if (iface2.x[1] != 0) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule