Fix extern function that returns parametrized class (#4924).
This commit is contained in:
parent
5278f42025
commit
040484cc3f
1
Changes
1
Changes
|
|
@ -41,6 +41,7 @@ Verilator 5.043 devel
|
|||
* Optimize $past delayed variable reuse (#6689). [Geza Lore, Fractile Ltd.]
|
||||
* Optimize combinational loops through sign extension (#6724). [Geza Lore]
|
||||
* Optimize trace initialization code size (#6749). [Geza Lore]
|
||||
* Fix extern function that returns parametrized class (#4924).
|
||||
* Fix expression short circuiting (#6483). [Todd Strader]
|
||||
* Fix expression coverage of system calls (#6592). [Todd Strader]
|
||||
* Fix `--timing` with `--x-initial-edge` (#6603) (#6631). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
|
|
|
|||
|
|
@ -261,6 +261,16 @@
|
|||
VL_DANGLING(var); \
|
||||
} while (false)
|
||||
|
||||
/// As with VL_DO_DANGLING, but two variables dangle.
|
||||
#define VL_DO_DANGLING2(stmt, var, var2) \
|
||||
do { \
|
||||
do { \
|
||||
stmt; \
|
||||
} while (false); \
|
||||
VL_DANGLING(var); \
|
||||
VL_DANGLING(var2); \
|
||||
} while (false)
|
||||
|
||||
/// Perform an e.g. delete, then set variable to nullptr as a requirement
|
||||
#define VL_DO_CLEAR(stmt, stmt2) \
|
||||
do { \
|
||||
|
|
|
|||
|
|
@ -966,18 +966,17 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
|
||||
void moveExternFuncDecl(AstNodeFTask* nodep, AstClass* classp) {
|
||||
// Move an 'extern function|task' to inside a class or, from an outer to inner-class
|
||||
if (!nodep->isExternDef()) {
|
||||
// Move it to proper spot under the target class
|
||||
nodep->unlinkFrBack();
|
||||
classp->addStmtsp(nodep);
|
||||
nodep->isExternDef(true); // So we check there's a matching extern
|
||||
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
||||
// Any "Type::" reference in the function's IO are really "MovedToClass::" references
|
||||
if (nodep->fvarp()) moveExternFuncDeclRefs(nodep->fvarp(), classp);
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO()) moveExternFuncDeclRefs(portp, classp);
|
||||
}
|
||||
if (nodep->isExternDef()) return;
|
||||
// Move it to proper spot under the target class
|
||||
nodep->unlinkFrBack();
|
||||
classp->addStmtsp(nodep);
|
||||
nodep->isExternDef(true); // So we check there's a matching extern
|
||||
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
||||
// Any "Type::" reference in the function's IO are really "MovedToClass::" references
|
||||
if (nodep->fvarp()) moveExternFuncDeclRefs(nodep->fvarp(), classp);
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO()) moveExternFuncDeclRefs(portp, classp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -985,7 +984,14 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
nodep->foreach([this, classp](AstClassOrPackageRef* refp) { //
|
||||
if (refp->name() == classp->name() && !refp->paramsp()) {
|
||||
UINFO(9, "Cleaning up external function type for class " << refp);
|
||||
pushDeletep(refp->unlinkFrBack());
|
||||
AstDot* const dotp = VN_CAST(refp->backp(), Dot);
|
||||
if (dotp && dotp->lhsp() == refp) {
|
||||
// If had DOT(CLASSREF this, ...) the DOT can go away
|
||||
dotp->replaceWith(dotp->rhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING2(pushDeletep(dotp), dotp, refp);
|
||||
} else {
|
||||
VL_DO_DANGLING(pushDeletep(refp->unlinkFrBack()), refp);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 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()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class One #(
|
||||
type VALUE_T = int unsigned
|
||||
);
|
||||
typedef One#(VALUE_T) self_t;
|
||||
VALUE_T value;
|
||||
extern static function self_t create(VALUE_T value);
|
||||
endclass
|
||||
|
||||
class Two #(
|
||||
type VALUE_T = int unsigned
|
||||
);
|
||||
VALUE_T value;
|
||||
extern static function Two#(VALUE_T) create(VALUE_T value);
|
||||
`ifdef NEVER
|
||||
// works ok if put function directly here
|
||||
static function Two#(VALUE_T) create(VALUE_T value);
|
||||
Two #(VALUE_T) obj = new();
|
||||
obj.value = value;
|
||||
return obj;
|
||||
endfunction
|
||||
`endif
|
||||
endclass
|
||||
|
||||
function One::self_t One::create(VALUE_T value);
|
||||
One #(VALUE_T) obj = new();
|
||||
obj.value = value;
|
||||
return obj;
|
||||
endfunction
|
||||
|
||||
function Two#(Two::VALUE_T) Two::create(VALUE_T value);
|
||||
Two #(VALUE_T) obj = new();
|
||||
obj.value = value;
|
||||
return obj;
|
||||
endfunction
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
One #(string) one;
|
||||
Two #(string) two;
|
||||
one = One#(string)::create("one");
|
||||
two = Two#(string)::create("two");
|
||||
if (one.value !== "one") $stop;
|
||||
if (two.value !== "two") $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue