diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index a3ae3b246..44c22b42f 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -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(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; } diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 128c70351..214d8d9b1 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -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(")"); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 5ab0211af..e19a42995 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -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 { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 73a93679d..84cf450d3 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -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()); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ab687a457..6c8578780 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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( diff --git a/test_regress/t/t_class_super_new.pl b/test_regress/t/t_class_super_new.pl new file mode 100755 index 000000000..bf4e4ce9f --- /dev/null +++ b/test_regress/t/t_class_super_new.pl @@ -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; diff --git a/test_regress/t/t_class_super_new.v b/test_regress/t/t_class_super_new.v new file mode 100644 index 000000000..5cecc1ca6 --- /dev/null +++ b/test_regress/t/t_class_super_new.v @@ -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