mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
This commit is contained in:
@@ -2367,6 +2367,22 @@ class ParamClassRefDTypeRelinkVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
// A class's name before specialization (e.g. "holder" for "holder__Tz1").
|
||||
static string classOrigName(const AstClass* classp) {
|
||||
return classp->origName().empty() ? classp->name() : classp->origName();
|
||||
}
|
||||
|
||||
// Find 'name' in classp or any base class (findTypedefInModule() searches
|
||||
// only the class itself).
|
||||
static AstTypedef* findTypedefWithBases(AstClass* classp, const string& name) {
|
||||
for (AstClass* cp = classp; cp; cp = cp->extendsp() ? cp->extendsp()->classp() : nullptr) {
|
||||
if (AstTypedef* const tdp = V3LinkDotIfaceCapture::findTypedefInModule(cp, name)) {
|
||||
if (tdp->subDTypep()) return tdp;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Re-resolve REFDTYPE.typedefp/refDTypep using the containing module's
|
||||
// own resolved typedef chain. The eager retargeting in deepCloneModule
|
||||
// blindly retargets every captured entry to whichever sibling clone is
|
||||
@@ -2377,10 +2393,46 @@ class ParamClassRefDTypeRelinkVisitor final : public VNVisitor {
|
||||
// those local typedefs as ground truth.
|
||||
void retargetRefDType(AstRefDType* refp) {
|
||||
if (!m_ownerModp) return;
|
||||
|
||||
// IEEE 1800-2023 8.25.1: a bare class-qualified reference to the class
|
||||
// being compiled means the current specialization, but V3LinkDot binds
|
||||
// it to the default instance, so a typedef reached through it widens
|
||||
// with the template's defaults (#8348). Rebind it to the
|
||||
// specialization's own typedef.
|
||||
if (AstClass* const ownerClassp = VN_CAST(m_ownerModp, Class)) {
|
||||
if (!ownerClassp->hasGParam() && !refp->paramsp()) {
|
||||
// What the reference resolves to: its typedef's owner if
|
||||
// linked, else the class it is qualified by.
|
||||
const AstClass* refClassp = nullptr;
|
||||
if (AstTypedef* const tdp = refp->typedefp()) {
|
||||
refClassp = VN_CAST(V3LinkDotIfaceCapture::findOwnerModule(tdp), Class);
|
||||
} else if (const AstClassOrPackageRef* const classRefp
|
||||
= VN_CAST(refp->classOrPackageOpp(), ClassOrPackageRef)) {
|
||||
refClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class);
|
||||
}
|
||||
// Same originating class => bare self reference (another
|
||||
// specialization would carry #(), rejected above).
|
||||
if (refClassp && refClassp != ownerClassp
|
||||
&& classOrigName(refClassp) == classOrigName(ownerClassp)) {
|
||||
AstTypedef* const selfTdp = findTypedefWithBases(ownerClassp, refp->name());
|
||||
if (selfTdp) {
|
||||
UINFO(9, "post-param REFDTYPE self-reference retarget: "
|
||||
<< refp << " from " << refClassp->name() << " to "
|
||||
<< ownerClassp->name());
|
||||
refp->typedefp(selfTdp);
|
||||
refp->classOrPackagep(V3LinkDotIfaceCapture::findOwnerModule(selfTdp));
|
||||
refp->refDTypep(selfTdp->subDTypep());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstTypedef* const oldTdp = refp->typedefp();
|
||||
if (!oldTdp) return;
|
||||
AstClass* const oldOwnerp = VN_CAST(V3LinkDotIfaceCapture::findOwnerModule(oldTdp), Class);
|
||||
if (!oldOwnerp) return;
|
||||
|
||||
ensureOwnerMap();
|
||||
if (m_origNameToClone.empty()) return;
|
||||
const std::string origName
|
||||
|
||||
+18
@@ -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()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,65 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// IEEE 1800-2023 8.25.1: inside a parameterized class, a bare class name used
|
||||
// without #() denotes the current specialization. A typedef reached through
|
||||
// such a self reference must resolve against the specialization's type
|
||||
// parameters, not the template's defaults. Covers both a typedef declared in
|
||||
// the class itself and one inherited from a base class.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
package pkg;
|
||||
class item_base #(type DATA = int);
|
||||
DATA value;
|
||||
endclass
|
||||
|
||||
class holder #(type FIN = int);
|
||||
typedef item_base#(FIN) my_item_t;
|
||||
|
||||
virtual function holder::my_item_t get_bare();
|
||||
my_item_t item;
|
||||
return item;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Same, but the typedef is inherited from a base class instead.
|
||||
class base_holder #(type FIN = int);
|
||||
typedef item_base#(FIN) my_item_t;
|
||||
endclass
|
||||
|
||||
class derived #(type FIN = int) extends base_holder#(FIN);
|
||||
virtual function derived::my_item_t get_bare();
|
||||
my_item_t item;
|
||||
return item;
|
||||
endfunction
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
import pkg::*;
|
||||
|
||||
// Non-default parameters, so the specialization differs from the template
|
||||
// default and the bug is observable.
|
||||
holder#(byte) h;
|
||||
derived#(shortint) d;
|
||||
|
||||
initial begin
|
||||
automatic holder#(byte)::my_item_t got;
|
||||
automatic derived#(shortint)::my_item_t got_inherited;
|
||||
h = new;
|
||||
got = h.get_bare();
|
||||
`checkd($bits(got.value), 8);
|
||||
d = new;
|
||||
got_inherited = d.get_bare();
|
||||
`checkd($bits(got_inherited.value), 16);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Reference in New Issue
Block a user