Fix class scope '::' reference through an inherited type parameter (#7844)

This commit is contained in:
Sergey Chusov 2026-07-01 22:58:35 +03:00 committed by GitHub
parent 6b3e2ce971
commit 1ea10ba71c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 5 deletions

View File

@ -258,6 +258,7 @@ Samuel Riedel
Sean Cross
Sebastien Van Cauwenberghe
Secturion
Sergey Chusov
Sergey Fedorov
Sergi Granell
Seth Pellegrino

View File

@ -1013,18 +1013,23 @@ public:
if (checkUnresolvedRef(VN_CAST(dtypep, RefDType))) return true;
} else if (const AstParamTypeDType* const paramTypep
= VN_CAST(symp->nodep(), ParamTypeDType)) {
// ParamTypeDType child may be wrapped in RequireDType or unwrapped
// Before V3Param the declared default is in childDTypep (possibly
// wrapped in a RequireDType); after V3Param it is consumed and the
// bound type is the resolved data type, e.g. a type parameter
// inherited from a specialized base class (REQ #(Item) -> class Item).
AstNode* childp = paramTypep->childDTypep();
if (const AstRequireDType* const reqp = VN_CAST(childp, RequireDType)) {
childp = reqp->lhsp();
}
if (isValidTypeNode(childp)) return true;
if (checkUnresolvedRef(VN_CAST(childp, RefDType))) return true;
const AstNode* const checkp = childp ? childp : paramTypep->skipRefp();
if (isValidTypeNode(checkp)) return true;
if (checkUnresolvedRef(VN_CAST(checkp, RefDType))) return true;
}
return false;
}
VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool fallback,
bool classOnly, const string& forWhat) {
bool classOnly, const string& forWhat,
bool deferIfUnresolved = false) {
if (nodep->classOrPackageSkipp()) return getNodeSym(nodep->classOrPackageSkipp());
VSymEnt* foundp;
VSymEnt* searchSymp = lookSymp;
@ -1050,6 +1055,7 @@ public:
nodep->classOrPackageNodep(foundp->nodep());
return foundp;
}
if (deferIfUnresolved) return nullptr;
const string suggest
= suggestSymFallback(lookSymp, nodep->name(), LinkNodeMatcherClassOrPackage{});
nodep->v3error((classOnly ? "Class" : "Package/class")
@ -4758,8 +4764,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
VL_RESTORER(m_pinSymp);
if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") {
const bool deferIfUnresolved = m_statep->forPrimary() && m_insideClassExtParam;
m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, m_ds.m_dotPos != DP_PACKAGE,
false, ":: reference");
false, ":: reference", deferIfUnresolved);
}
// ClassRef's have pins, so track

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: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,47 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Sergey Chusov
// SPDX-License-Identifier: CC0-1.0
// A factory-like static method, as used by UVM's type_id::create().
class registry #(type T = int);
static function T create();
T r = new;
return r;
endfunction
endclass
class item;
int val;
typedef registry#(item) type_id;
function new();
val = 42;
endfunction
endclass
class seq_base #(type REQ = int, type RSP = REQ);
REQ req;
endclass
// Non-parameterized class extending a parameterized base.
// REQ is a type parameter inherited from the (specialized) base class and is
// here used as a '::' class scope: REQ::type_id::create(). Resolving REQ in
// this position requires deferring until after V3Param has bound REQ to item.
class seq extends seq_base #(item);
function int make();
REQ r;
r = REQ::type_id::create();
return r.val;
endfunction
endclass
module t;
seq s;
initial begin
s = new;
if (s.make() != 42) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule