mirror of
https://github.com/verilator/verilator.git
synced 2025-07-31 07:56:10 +00:00
Support super.new calls (#3789)
This commit is contained in:
parent
468a33b61c
commit
073dc03adc
@ -550,7 +550,7 @@ private:
|
||||
string m_cname; // C name, for dpiExports
|
||||
string m_rtnType; // void, bool, or other return type
|
||||
string m_argTypes; // Argument types
|
||||
string m_ctorInits; // Constructor sub-class inits
|
||||
string m_baseCtors; // Base class constructor
|
||||
string m_ifdef; // #ifdef symbol around this function
|
||||
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
|
||||
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
|
||||
@ -611,7 +611,7 @@ public:
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCFunc* const asamep = static_cast<const AstCFunc*>(samep);
|
||||
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
|
||||
&& (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits())
|
||||
&& (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors())
|
||||
&& isLoose() == asamep->isLoose()
|
||||
&& (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name()));
|
||||
}
|
||||
@ -644,8 +644,8 @@ public:
|
||||
void funcPublic(bool flag) { m_funcPublic = flag; }
|
||||
void argTypes(const string& str) { m_argTypes = str; }
|
||||
string argTypes() const { return m_argTypes; }
|
||||
void ctorInits(const string& str) { m_ctorInits = str; }
|
||||
string ctorInits() const { return m_ctorInits; }
|
||||
void baseCtors(const string& str) { m_baseCtors = str; }
|
||||
string baseCtors() const { return m_baseCtors; }
|
||||
void ifdef(const string& str) { m_ifdef = str; }
|
||||
string ifdef() const { return m_ifdef; }
|
||||
bool isConstructor() const { return m_isConstructor; }
|
||||
|
@ -422,11 +422,7 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint
|
||||
puts(nodep->argTypes());
|
||||
comma = true;
|
||||
}
|
||||
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (comma) puts(", ");
|
||||
iterate(subnodep);
|
||||
comma = true;
|
||||
}
|
||||
putCommaIterateNext(nodep->argsp(), comma);
|
||||
puts(")");
|
||||
}
|
||||
|
||||
|
@ -205,6 +205,13 @@ public:
|
||||
m_emitConstInit = true;
|
||||
iterate(initp);
|
||||
}
|
||||
void putCommaIterateNext(AstNode* nodep, bool comma = false) {
|
||||
for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) {
|
||||
if (comma) puts(", ");
|
||||
iterate(subnodep);
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
using EmitCConstInit::visit;
|
||||
@ -221,11 +228,24 @@ public:
|
||||
if (nodep->isInline()) puts("VL_INLINE_OPT ");
|
||||
emitCFuncHeader(nodep, m_modp, /* withScope: */ true);
|
||||
|
||||
// TODO perhaps better to have a new AstCCtorInit so we can pass arguments
|
||||
// rather than requiring a string here
|
||||
if (!nodep->ctorInits().empty()) {
|
||||
if (!nodep->baseCtors().empty()) {
|
||||
puts(": ");
|
||||
puts(nodep->ctorInits());
|
||||
puts(nodep->baseCtors());
|
||||
puts("(vlSymsp");
|
||||
// Find call to super.new to get the arguments
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
AstNode* exprp;
|
||||
if (VN_IS(stmtp, StmtExpr)) {
|
||||
exprp = VN_CAST(stmtp, StmtExpr)->exprp();
|
||||
} else {
|
||||
exprp = stmtp;
|
||||
}
|
||||
if (AstCNew* const newRefp = VN_CAST(exprp, CNew)) {
|
||||
putCommaIterateNext(newRefp->argsp(), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
puts(" {\n");
|
||||
|
||||
@ -417,15 +437,13 @@ public:
|
||||
iterate(nodep->exprp());
|
||||
}
|
||||
void visit(AstCNew* nodep) override {
|
||||
bool comma = false;
|
||||
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", ");
|
||||
puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary
|
||||
if (nodep->argsp()) comma = true;
|
||||
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (comma) puts(", ");
|
||||
iterate(subnodep);
|
||||
comma = true;
|
||||
if (VN_IS(nodep->dtypep(), VoidDType)) {
|
||||
// super.new case
|
||||
return;
|
||||
}
|
||||
// assignment case
|
||||
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", vlSymsp");
|
||||
putCommaIterateNext(nodep->argsp(), true);
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
|
@ -1181,8 +1181,8 @@ private:
|
||||
cfuncp->isConstructor(true);
|
||||
AstClass* const classp = m_statep->getClassp(nodep);
|
||||
if (classp->extendsp()) {
|
||||
cfuncp->ctorInits(EmitCBaseVisitor::prefixNameProtect(classp->extendsp()->classp())
|
||||
+ "(vlSymsp)");
|
||||
cfuncp->baseCtors(
|
||||
EmitCBaseVisitor::prefixNameProtect(classp->extendsp()->classp()));
|
||||
}
|
||||
}
|
||||
if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname());
|
||||
|
@ -3555,22 +3555,32 @@ private:
|
||||
|
||||
void visit(AstNew* nodep) override {
|
||||
if (nodep->didWidth()) return;
|
||||
AstClassRefDType* const refp
|
||||
= m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr;
|
||||
if (!refp) { // e.g. int a = new;
|
||||
nodep->v3error("new() not expected in this context");
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(refp);
|
||||
AstClass* classp = nullptr;
|
||||
if (VN_IS(nodep->backp(), Assign)) { // assignment case
|
||||
AstClassRefDType* const refp
|
||||
= m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr;
|
||||
if (!refp) { // e.g. int a = new;
|
||||
nodep->v3error("new() not expected in this context");
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(refp);
|
||||
|
||||
AstClass* const classp = refp->classp();
|
||||
UASSERT_OBJ(classp, nodep, "Unlinked");
|
||||
if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) {
|
||||
nodep->taskp(ftaskp);
|
||||
nodep->classOrPackagep(classp);
|
||||
} else {
|
||||
// Either made explicitly or V3LinkDot made implicitly
|
||||
classp->v3fatalSrc("Can't find class's new");
|
||||
classp = refp->classp();
|
||||
UASSERT_OBJ(classp, nodep, "Unlinked");
|
||||
if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) {
|
||||
nodep->taskp(ftaskp);
|
||||
nodep->classOrPackagep(classp);
|
||||
} else {
|
||||
// Either made explicitly or V3LinkDot made implicitly
|
||||
classp->v3fatalSrc("Can't find class's new");
|
||||
}
|
||||
} else { // super.new case
|
||||
// in this case class and taskp() should be properly linked in V3LinkDot.cpp during
|
||||
// "super" reference resolution
|
||||
classp = VN_CAST(nodep->classOrPackagep(), Class);
|
||||
UASSERT_OBJ(classp, nodep, "Unlinked classOrPackagep()");
|
||||
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked taskp()");
|
||||
nodep->dtypeFrom(nodep->taskp());
|
||||
}
|
||||
if (classp->isVirtual()) {
|
||||
nodep->v3error(
|
||||
|
20
test_regress/t/t_class_super_new.pl
Executable file
20
test_regress/t/t_class_super_new.pl
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2022 by Antmicro Ltd. 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile();
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
101
test_regress/t/t_class_super_new.v
Normal file
101
test_regress/t/t_class_super_new.v
Normal file
@ -0,0 +1,101 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
class Foo;
|
||||
int x;
|
||||
function new;
|
||||
this.x = 10;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Bar extends Foo;
|
||||
function new;
|
||||
super.new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class BarUnusedArg extends Foo;
|
||||
function new (int a);
|
||||
super.new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class FooArg;
|
||||
int x;
|
||||
function new (int a);
|
||||
this.x = a;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class BarArg extends FooArg;
|
||||
function new (int a);
|
||||
super.new(a);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class BarExpr extends FooArg;
|
||||
function new (int a, string b);
|
||||
super.new(a + b.len());
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Foo2Args;
|
||||
int x;
|
||||
function new (int a, int b);
|
||||
this.x = a + b;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Bar2Args extends Foo2Args;
|
||||
function new (int a, int b);
|
||||
super.new(a, b);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
);
|
||||
|
||||
class FooInModule;
|
||||
int x;
|
||||
function new;
|
||||
this.x = 15;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class BarInModule extends FooInModule;
|
||||
function new;
|
||||
super.new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
Bar bar;
|
||||
BarInModule barInModule;
|
||||
BarUnusedArg barUnusedArg;
|
||||
BarArg barArg;
|
||||
BarExpr barExpr;
|
||||
Bar2Args bar2Args;
|
||||
|
||||
initial begin
|
||||
bar = new;
|
||||
`checkh(bar.x, 10);
|
||||
barInModule = new;
|
||||
`checkh(barInModule.x, 15);
|
||||
barUnusedArg = new(2);
|
||||
`checkh(barUnusedArg.x, 10);
|
||||
barArg = new(2);
|
||||
`checkh(barArg.x, 2);
|
||||
barExpr = new (7, "ABCDEFGHI");
|
||||
`checkh(barExpr.x, 16);
|
||||
bar2Args = new(2, 12);
|
||||
`checkh(bar2Args.x, 14);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user