Fix resolving default/nondefault type parameters (#7171) (#7346)

Fixes #7171
This commit is contained in:
em2machine 2026-04-02 10:51:11 -04:00 committed by GitHub
parent d7c484ae85
commit 32672deb6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 91 additions and 4 deletions

View File

@ -1235,6 +1235,32 @@ class ParamProcessor final {
}
}
// Check if exprp is a ClassRefDType whose class is the default-parameter clone
// of origp's template class. This catches the case where an explicit type parameter
// like Holder#(W#(int)) resolves to the same specialization as the implicit default
// Holder#(), because W#(int) deparameterizes to W_ (the all-default clone of W).
// Uses the user4p link set at line ~1658 when defaultsResolved is true.
static bool classTypeMatchesDefaultClone(const AstNodeDType* exprp,
const AstNodeDType* origp) {
exprp = exprp->skipRefp();
origp = origp->skipRefp();
const auto* const exprClassRefp = VN_CAST(exprp, ClassRefDType);
const auto* const origClassRefp = VN_CAST(origp, ClassRefDType);
UINFO(9, "classTypeMatchesDefaultClone: exprClassRef="
<< exprClassRefp << " origClassRef=" << origClassRefp);
if (!exprClassRefp || !origClassRefp) return false;
const AstNodeModule* const defaultClonep
= VN_CAST(origClassRefp->classp()->user4p(), Class);
const bool result = defaultClonep && defaultClonep == exprClassRefp->classp();
UINFO(9, " origClass=" << origClassRefp->classp()->prettyNameQ()
<< " origClassp=" << cvtToHex(origClassRefp->classp())
<< " user4p=" << (defaultClonep ? cvtToHex(defaultClonep) : "null")
<< " exprClass=" << exprClassRefp->classp()->prettyNameQ()
<< " exprClassp=" << cvtToHex(exprClassRefp->classp())
<< " result=" << result);
return result;
}
void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer,
bool& any_overridesr) {
if (!pinp->exprp()) return; // No-connect
@ -1358,7 +1384,7 @@ class ParamProcessor final {
<< " violates parameter's forwarding type '"
<< modvarp->fwdType().ascii() << "'");
}
if (exprp->similarDType(origp)) {
if (exprp->similarDType(origp) || classTypeMatchesDefaultClone(exprp, origp)) {
// Setting parameter to its default value. Just ignore it.
// This prevents making additional modules, and makes coverage more
// obvious as it won't show up under a unique module page name.
@ -1620,11 +1646,14 @@ class ParamProcessor final {
cellInterfaceCleanup(pinsp, srcModp, longname /*ref*/, any_overrides /*ref*/,
ifaceRefRefs /*ref*/);
// Classes/modules with type parameters need specialization even when types match defaults.
// This is required for UVM parameterized classes. However, interfaces should NOT
// Template classes with type parameters need specialization even when types match
// defaults. This is required for UVM parameterized classes. However, interfaces should NOT
// be specialized when type params match defaults (needed for nested interface ports).
// Already-specialized clones (hasGParam=false) must not be re-cloned, otherwise
// nested class type parameters cause unbounded re-deparameterization (Holder_ ->
// Holder__).
bool defaultsResolved = false;
if (!any_overrides && !VN_IS(srcModp, Iface)) {
if (!any_overrides && !VN_IS(srcModp, Iface) && srcModp->hasGParam()) {
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
if (pinp->modPTypep()) {
any_overrides = true;

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: 2025 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: Verify that implicit-default and explicit-equivalent
// class type parameters resolve to the same specialization.
//
// 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
package p;
class W #(type T = int);
T v;
endclass
class Holder #(type U = W#());
U u;
endclass
typedef Holder#() H_imp_t; // implicit default
typedef Holder#(W#(int)) H_exp_t; // explicit equivalent default
endpackage
module t;
p::H_imp_t imp;
p::H_exp_t exp;
initial begin
imp = new;
// verilator lint_off CASTCONST
// verilator lint_off WIDTHTRUNC
if (!$cast(exp, imp)) begin
// verilator lint_on WIDTHTRUNC
// verilator lint_on CASTCONST
$display("WRONG_TYPE");
$fatal;
end
$write("*-* All Coverage Coverage *-*\n");
$finish;
end
endmodule