This commit is contained in:
Mateusz Gancarz 2026-07-14 21:52:28 -04:00 committed by GitHub
commit 4f9dc73040
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 129 additions and 17 deletions

View File

@ -3136,6 +3136,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
bool m_inPackedArray = false; // Currently traversing a packed array tree bool m_inPackedArray = false; // Currently traversing a packed array tree
bool m_replaceWithAlias bool m_replaceWithAlias
= true; // Replace VarScope with an alias. Used in the handling of AstAlias = true; // Replace VarScope with an alias. Used in the handling of AstAlias
bool m_isParam = false; // Specifies whether currently visiting param variable
struct DotStates final { struct DotStates final {
DotPosition m_dotPos; // Scope part of dotted resolution DotPosition m_dotPos; // Scope part of dotted resolution
@ -5092,6 +5093,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
checkNoDot(nodep); checkNoDot(nodep);
VL_RESTORER(m_isParam);
m_isParam = nodep->varType().isParam();
iterateChildren(nodep); iterateChildren(nodep);
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) { if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
nodep->v3error( nodep->v3error(
@ -5273,27 +5276,32 @@ class LinkDotResolveVisitor final : public VNVisitor {
// which may find std::randomize and overwrite classOrPackagep // which may find std::randomize and overwrite classOrPackagep
return; return;
} }
if (m_insideClassExtParam) { VSymEnt* const foundp
// The reference may point to a method declared in a super class, which is proved = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
// by a parameter. In such a case, it can't be linked at the first stage. AstNodeFTask* const taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr;
// Must not do any linking, because e.g. might find an extends of an upper class AstNodeModule* const taskModulep = foundp ? foundp->classOrPackagep() : nullptr;
// because the current class (under parent) isn't yet importing it's extended class // Ignore deferring linking of functions inside params of classes extending
// symbols // parametric classes if referenced function can be linked in the first pass.
return; if (!m_isParam || !taskp
} || (taskp->classMethod() && taskModulep && taskModulep->hasParameterList())) {
if (AstClass* const targetClassp = VN_CAST(dotSymp->nodep(), Class)) { if (m_insideClassExtParam) {
if (m_extendsParam.count(targetClassp)) { // The reference may point to a method declared in a super class, which is
// Target class has parameterized extends not yet resolved. // proved by a parameter. In such a case, it can't be linked at the first
// Its inherited symbols (e.g. static functions from the base class) // stage. Must not do any linking, because e.g. might find an extends of an
// aren't imported yet - defer to linkDotParamed. // upper class because the current class (under parent) isn't yet importing
// it's extended class symbols.
return; return;
} }
if (AstClass* const targetClassp = VN_CAST(dotSymp->nodep(), Class)) {
if (m_extendsParam.count(targetClassp)) {
// Target class has parameterized extends not yet resolved.
// Its inherited symbols (e.g. static functions from the base class)
// aren't imported yet - defer to linkDotParamed.
return;
}
}
} }
VSymEnt* const foundp
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
AstNodeFTask* const taskp
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
if (taskp) { if (taskp) {
if (staticAccess && !taskp->isStatic()) { if (staticAccess && !taskp->isStatic()) {
// TODO bug4077 // TODO bug4077

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('vlt')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,86 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
`define stop $stop
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
function automatic int align(input int a, input int b);
return a - (a % b);
endfunction
class Foo;
static function int mul(input int a, input int b);
return a * b;
endfunction
endclass : Foo
class FooParam #(parameter int param = 5);
static function int mul(input int a);
return a * param;
endfunction
endclass : FooParam
class Base #(parameter int param = 5);
function int get_base_param();
return param;
endfunction
static function int alignUp(input int a);
return ((a + param - 1) / param) * param;
endfunction
endclass : Base
class Derived #(
parameter int a = 17,
parameter int b = 8,
parameter int c = align(a, b),
parameter int d = Base#(b)::alignUp(a),
parameter int e = Foo::mul(a, b),
parameter int f = FooParam#()::mul(a)
) extends Base #(
.param (a)
);
function int get_third_param();
return c;
endfunction
function int get_fourth_param();
return d;
endfunction
function int get_fifth_param();
return e;
endfunction
function int get_sixth_param();
return f;
endfunction
endclass : Derived
module t (clk);
input clk;
Derived inst = new;
always @(posedge clk) begin
`checkh(inst.get_base_param(), 17)
`checkh(inst.get_third_param(), 16)
`checkh(inst.get_fourth_param(), 24)
`checkh(inst.get_fifth_param(), 136)
`checkh(inst.get_sixth_param(), 85)
$write("*-* All Finished *-*\n");
$finish;
end
endmodule