mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support class new.
This commit is contained in:
parent
d4b6e2b2b5
commit
dba88bae3c
@ -3567,8 +3567,8 @@ path.
|
||||
|
||||
Verilator class support is very limited and in active development.
|
||||
Verilator supports members, and methods. Verilator doe not support initial
|
||||
values on class members, class static members, class new methods, class
|
||||
extend, or class parameters.
|
||||
values on class members, class static members, class extend, or class
|
||||
parameters.
|
||||
|
||||
=head2 Dotted cross-hierarchy references
|
||||
|
||||
|
@ -4066,24 +4066,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class AstNew : public AstNodeMath {
|
||||
class AstNew : public AstNodeFTaskRef {
|
||||
// New as constructor
|
||||
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
public:
|
||||
AstNew(FileLine* fl, AstNode* argsp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
addNOp2p(argsp);
|
||||
}
|
||||
AstNew(FileLine* fl, AstNode* pinsp)
|
||||
: ASTGEN_SUPER(fl, false, "new", pinsp) {}
|
||||
ASTNODE_NODE_FUNCS(New)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual string emitVerilog() { return "new"; }
|
||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const { return true; }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
AstNode* argsp() const { return op2p(); }
|
||||
};
|
||||
|
||||
class AstNewCopy : public AstNodeMath {
|
||||
@ -7040,6 +7038,23 @@ public:
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
};
|
||||
|
||||
class AstCNew : public AstNodeCCall {
|
||||
// C++ new() call
|
||||
// Parents: Anything above an expression
|
||||
// Children: Args to the function
|
||||
public:
|
||||
AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = NULL)
|
||||
: ASTGEN_SUPER(fl, funcp, argsp) {
|
||||
statement(false);
|
||||
}
|
||||
// Replacement form for V3Combine
|
||||
// Note this removes old attachments from the oldp
|
||||
AstCNew(AstCCall* oldp, AstCFunc* funcp)
|
||||
: ASTGEN_SUPER(oldp, funcp) {}
|
||||
virtual bool hasDType() const { return true; }
|
||||
ASTNODE_NODE_FUNCS(CNew)
|
||||
};
|
||||
|
||||
class AstCReturn : public AstNodeStmt {
|
||||
// C++ return from a function
|
||||
// Parents: CFUNC/statement
|
||||
|
@ -149,8 +149,13 @@ void V3CCtors::cctorsAll() {
|
||||
// Process each module in turn
|
||||
AstCFunc* varResetFuncp;
|
||||
{
|
||||
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
|
||||
V3CCtorsVisitor var_reset(
|
||||
modp, "_ctor_var_reset",
|
||||
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
|
||||
(VN_IS(modp, Class) ? "vlSymsp" : ""),
|
||||
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
|
||||
varResetFuncp = var_reset.builtFuncp();
|
||||
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(np, Var)) {
|
||||
if (!varp->isIfaceParent() && !varp->isIfaceRef()
|
||||
@ -164,7 +169,8 @@ void V3CCtors::cctorsAll() {
|
||||
if (v3Global.opt.coverage()) {
|
||||
V3CCtorsVisitor configure_coverage(
|
||||
modp, "_configure_coverage",
|
||||
EmitCBaseVisitor::symClassVar() + ", bool first", "vlSymsp, first",
|
||||
EmitCBaseVisitor::symClassVar() + ", bool first",
|
||||
"vlSymsp, first",
|
||||
"if (false && vlSymsp && first) {} // Prevent unused\n");
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) {
|
||||
@ -175,14 +181,6 @@ void V3CCtors::cctorsAll() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VN_IS(modp, Class)) {
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "new", NULL, "");
|
||||
funcp->isConstructor(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->slow(false);
|
||||
modp->addStmtp(funcp);
|
||||
funcp->addStmtsp(new AstCCall(varResetFuncp->fileline(), varResetFuncp));
|
||||
}
|
||||
if (VN_IS(modp, Class)) {
|
||||
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, "");
|
||||
funcp->isDestructor(true);
|
||||
|
@ -223,6 +223,10 @@ private:
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
operandTriop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
|
@ -850,8 +850,10 @@ public:
|
||||
puts(cvtToStr(nodep->fileline()->lineno()));
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstNew* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">(");
|
||||
puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary
|
||||
if (nodep->argsp()) puts(", ");
|
||||
iterateAndNextNull(nodep->argsp());
|
||||
puts(")");
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||
v3Global.needHeavy(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNew* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
@ -643,10 +643,9 @@ public:
|
||||
VSymEnt* foundp = NULL;
|
||||
while (!foundp) {
|
||||
foundp = lookupSymp->findIdFallback(prefix + dotname); // Might be NULL
|
||||
if (prefix == "") {
|
||||
break;
|
||||
}
|
||||
prefix = removeLastInlineScope(prefix);
|
||||
if (prefix.empty()) break;
|
||||
string nextPrefix = removeLastInlineScope(prefix);
|
||||
if (prefix == nextPrefix) break;
|
||||
}
|
||||
if (!foundp) baddot = dotname;
|
||||
return foundp;
|
||||
@ -686,7 +685,8 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
bool m_inRecursion; // Inside a recursive module
|
||||
int m_paramNum; // Parameter number, for position based connection
|
||||
int m_beginNum; // Begin block number, 0=none seen
|
||||
int m_modBeginNum; // Begin block number in module, 0=none seen
|
||||
bool m_explicitNew; // Hit a "new" function
|
||||
int m_modBeginNum; // Begin block number in module, 0=none seen
|
||||
|
||||
// METHODS
|
||||
int debug() { return LinkDotState::debug(); }
|
||||
@ -723,6 +723,13 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void makeImplicitNew(AstClass* nodep) {
|
||||
AstFunc* newp = new AstFunc(nodep->fileline(), "new", NULL, NULL);
|
||||
newp->isConstructor(true);
|
||||
nodep->addMembersp(newp);
|
||||
UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl);
|
||||
m_statep->insertBlock(m_curSymp, newp->name(), newp, m_packagep);
|
||||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
@ -842,10 +849,13 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
m_paramNum = 0;
|
||||
m_beginNum = 0;
|
||||
m_modBeginNum = 0;
|
||||
m_explicitNew = false;
|
||||
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
|
||||
// Iterate
|
||||
iterateChildren(nodep);
|
||||
nodep->user4(true);
|
||||
// Implicit new needed?
|
||||
if (!m_explicitNew && m_statep->forPrimary()) makeImplicitNew(nodep);
|
||||
}
|
||||
m_scope = oldscope;
|
||||
m_modSymp = oldModSymp;
|
||||
@ -971,6 +981,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Function/Task not under module?");
|
||||
if (nodep->name() == "new") m_explicitNew = true;
|
||||
// Remember the existing symbol table scope
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
{
|
||||
@ -1232,6 +1243,7 @@ public:
|
||||
m_inRecursion = false;
|
||||
m_paramNum = 0;
|
||||
m_beginNum = 0;
|
||||
m_explicitNew = false;
|
||||
m_modBeginNum = 0;
|
||||
//
|
||||
iterate(rootp);
|
||||
@ -2423,6 +2435,8 @@ private:
|
||||
<<nodep->prettyName()
|
||||
<<"'"<<" as a "<<foundp->nodep()->typeName()
|
||||
<<" but expected a task/function");
|
||||
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
||||
// Resolved in V3Width
|
||||
} else if (nodep->dotted() == "") {
|
||||
string suggest = m_statep->suggestSymFallback(
|
||||
dotSymp, nodep->name(), LinkNodeMatcherFTask());
|
||||
|
@ -126,6 +126,7 @@ private:
|
||||
if (nodep->valuep()) clearOptimizable(nodep, "HasInitValue");
|
||||
if (!VarFlags(nodep).m_stdFuncAsn) clearStdOptimizable(nodep, "NoStdAssign");
|
||||
VarFlags flags (nodep);
|
||||
|
||||
if ((nodep->isMovableToBlock() // Blocktemp
|
||||
|| !flags.m_notStd) // Or used only in block
|
||||
&& !flags.m_notOpt // Optimizable
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
string newname = string("__PVT__")+nodep->name();
|
||||
nodep->name(newname);
|
||||
nodep->editCountInc();
|
||||
} else if (VN_IS(nodep, CFunc) && VN_CAST(nodep, CFunc)->isConstructor()) {
|
||||
} else {
|
||||
string rsvd = m_words.isKeyword(nodep->name());
|
||||
if (rsvd != "") {
|
||||
|
@ -501,6 +501,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
||||
{
|
||||
m_contextp = nodep;
|
||||
AstNodeFTask* ftaskp = nodep->taskp();
|
||||
UASSERT_OBJ(ftaskp, nodep, "Unlinked");
|
||||
// Iterate arguments of a function/task.
|
||||
for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp;
|
||||
argp = argp->nextp(), paramp = paramp ? paramp->nextp() : NULL) {
|
||||
|
@ -186,7 +186,7 @@ private:
|
||||
m_assignwp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// Includes handling AstMethodCall
|
||||
// Includes handling AstMethodCall, AstNew
|
||||
if (m_assignwp) {
|
||||
// Wire assigns must become always statements to deal with insertion
|
||||
// of multiple statements. Perhaps someday make all wassigns into always's?
|
||||
@ -204,6 +204,7 @@ private:
|
||||
m_curVxp = getFTaskVertex(nodep);
|
||||
if (nodep->dpiImport()) m_curVxp->noInline(true);
|
||||
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
|
||||
if (nodep->isConstructor()) m_curVxp->noInline(true);
|
||||
iterateChildren(nodep);
|
||||
m_curVxp = lastVxp;
|
||||
}
|
||||
@ -474,7 +475,7 @@ private:
|
||||
}
|
||||
|
||||
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix,
|
||||
AstVarScope* outvscp) {
|
||||
AstVarScope* outvscp, AstCNew*& cnewpr) {
|
||||
// outvscp is the variable for functions only, if NULL, it's a task
|
||||
UASSERT_OBJ(refp->taskp(), refp, "Unlinked?");
|
||||
AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp());
|
||||
@ -483,12 +484,19 @@ private:
|
||||
AstNode* beginp = new AstComment(refp->fileline(),
|
||||
string("Function: ")+refp->name(), true);
|
||||
AstNodeCCall* ccallp;
|
||||
if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) {
|
||||
if (AstNew* mrefp = VN_CAST(refp, New)) {
|
||||
AstCNew* cnewp = new AstCNew(refp->fileline(), cfuncp);
|
||||
cnewp->dtypep(refp->dtypep());
|
||||
ccallp = cnewp;
|
||||
// Parent AstNew will replace with this CNew
|
||||
cnewpr = cnewp;
|
||||
} else if (AstMethodCall* mrefp = VN_CAST(refp, MethodCall)) {
|
||||
ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp);
|
||||
beginp->addNext(ccallp);
|
||||
} else {
|
||||
ccallp = new AstCCall(refp->fileline(), cfuncp);
|
||||
beginp->addNext(ccallp);
|
||||
}
|
||||
beginp->addNext(ccallp);
|
||||
|
||||
// Convert complicated outputs to temp signals
|
||||
V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
|
||||
@ -988,8 +996,10 @@ private:
|
||||
// so make it unique now.
|
||||
string suffix; // So, make them unique
|
||||
if (!nodep->taskPublic()) suffix = "_"+m_scopep->nameDotless();
|
||||
string name = ((nodep->name() == "new") ? "new"
|
||||
: prefix + nodep->name() + suffix);
|
||||
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
|
||||
prefix + nodep->name() + suffix,
|
||||
name,
|
||||
m_scopep,
|
||||
((nodep->taskPublic() && rtnvarp)
|
||||
? rtnvarp->cPubArgType(true, true)
|
||||
@ -1003,6 +1013,7 @@ private:
|
||||
cfuncp->dpiImportWrapper(nodep->dpiImport());
|
||||
cfuncp->isStatic(!(nodep->dpiImport() || nodep->taskPublic() || nodep->classMethod()));
|
||||
cfuncp->pure(nodep->pure());
|
||||
cfuncp->isConstructor(nodep->name() == "new");
|
||||
//cfuncp->dpiImport // Not set in the wrapper - the called function has it set
|
||||
if (cfuncp->dpiExport()) cfuncp->cname(nodep->cname());
|
||||
|
||||
@ -1017,6 +1028,10 @@ private:
|
||||
} else {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
if (cfuncp->name() == "new") {
|
||||
cfuncp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(), "_ctor_var_reset(vlSymsp);\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->dpiContext()) {
|
||||
@ -1157,6 +1172,7 @@ private:
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// Includes handling AstMethodCall, AstNew
|
||||
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked?");
|
||||
iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs
|
||||
UINFO(4," FTask REF "<<nodep<<endl);
|
||||
@ -1173,15 +1189,21 @@ private:
|
||||
}
|
||||
// Create cloned statements
|
||||
AstNode* beginp;
|
||||
AstCNew* cnewp = NULL;
|
||||
if (m_statep->ftaskNoInline(nodep->taskp())) {
|
||||
// This may share VarScope's with a public task, if any. Yuk.
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp);
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp, cnewp /*ref*/);
|
||||
} else {
|
||||
beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
}
|
||||
// Replace the ref
|
||||
AstNode* visitp = NULL;
|
||||
if (!nodep->isStatement()) {
|
||||
if (VN_IS(nodep, New)) {
|
||||
UASSERT_OBJ(!nodep->isStatement(), nodep, "new is non-stmt");
|
||||
UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new");
|
||||
nodep->replaceWith(cnewp);
|
||||
visitp = insertBeforeStmt(nodep, beginp);
|
||||
} else if (!nodep->isStatement()) {
|
||||
UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function");
|
||||
AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false);
|
||||
nodep->replaceWith(outrefp);
|
||||
|
@ -1895,7 +1895,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
|
||||
UINFO(5," METHODSEL "<<nodep<<endl);
|
||||
UINFO(5, " METHODCALL " << nodep << endl);
|
||||
if (nodep->didWidth()) return;
|
||||
if (debug()>=9) nodep->dumpTree("-mts-in: ");
|
||||
// Should check types the method requires, but at present we don't do much
|
||||
@ -2431,12 +2431,20 @@ private:
|
||||
return;
|
||||
}
|
||||
nodep->dtypep(refp);
|
||||
if (nodep->argsp()) {
|
||||
nodep->v3error("Unsupported: new with arguments");
|
||||
pushDeletep(nodep->argsp()->unlinkFrBackWithNext());
|
||||
//TODO code similar to AstNodeFTaskRef
|
||||
//userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
|
||||
|
||||
AstClass* classp = refp->classp();
|
||||
UASSERT_OBJ(classp, nodep, "Unlinked");
|
||||
if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember("new"), Func)) {
|
||||
nodep->taskp(ftaskp);
|
||||
nodep->packagep(classp);
|
||||
} else {
|
||||
// Either made explicitly or V3LinkDot made implicitly
|
||||
classp->v3fatalSrc("Can't find class's new");
|
||||
}
|
||||
|
||||
userIterate(nodep->taskp(), NULL);
|
||||
userIterateChildren(nodep, NULL);
|
||||
processFTaskRefArgs(nodep);
|
||||
}
|
||||
virtual void visit(AstNewCopy* nodep) VL_OVERRIDE {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
@ -3406,7 +3414,6 @@ private:
|
||||
userIterateChildren(nodep, NULL);
|
||||
if (nodep->isConstructor()) {
|
||||
// Pretend it's void so less special casing needed when look at dtypes
|
||||
nodep->v3error("Unsupported: new constructor");
|
||||
nodep->dtypeSetVoid();
|
||||
} else if (nodep->fvarp()) {
|
||||
m_funcp = VN_CAST(nodep, Func);
|
||||
|
@ -1,13 +0,0 @@
|
||||
%Error: t/t_class_new.v:9:13: Unsupported: new constructor
|
||||
: ... In instance t
|
||||
9 | function new();
|
||||
| ^~~
|
||||
%Error: t/t_class_new.v:16:13: Unsupported: new constructor
|
||||
: ... In instance t
|
||||
16 | function new(int i);
|
||||
| ^~~
|
||||
%Error: t/t_class_new.v:27:12: Unsupported: new with arguments
|
||||
: ... In instance t
|
||||
27 | c2 = new(2);
|
||||
| ^~~
|
||||
%Error: Exiting due to
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
#execute(
|
||||
# check_finished => 1,
|
||||
# );
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -16,16 +16,22 @@ class ClsArg;
|
||||
function new(int i);
|
||||
imembera = i + 1;
|
||||
endfunction
|
||||
function int geta;
|
||||
return imembera;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
ClsNoArg c1;
|
||||
ClsArg c2;
|
||||
|
||||
c1 = new;
|
||||
if (c1.imembera != 5) $stop;
|
||||
|
||||
c2 = new(2);
|
||||
if (c2.imembera != 3) $stop;
|
||||
if (c2.geta() != 3) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
@ -1,13 +1,12 @@
|
||||
%Error: t/t_class_new_bad.v:10:13: Unsupported: new constructor
|
||||
: ... In instance t
|
||||
10 | function new();
|
||||
| ^~~
|
||||
%Error: t/t_class_new_bad.v:17:13: Unsupported: new constructor
|
||||
: ... In instance t
|
||||
17 | function new(int i);
|
||||
| ^~~
|
||||
%Error: t/t_class_new_bad.v:26:12: Unsupported: new with arguments
|
||||
: ... In instance t
|
||||
26 | c1 = new(3);
|
||||
%Error: t/t_class_new_bad.v:31:16: Too many arguments in function call to FUNC 'new'
|
||||
31 | c1 = new(3);
|
||||
| ^
|
||||
%Error: t/t_class_new_bad.v:32:16: Too many arguments in function call to FUNC 'new'
|
||||
32 | c2 = new(3);
|
||||
| ^
|
||||
%Error: t/t_class_new_bad.v:33:12: Missing argument on non-defaulted argument 'i' in function call to FUNC 'new'
|
||||
33 | c3 = new();
|
||||
| ^~~
|
||||
%Error: Internal Error: t/t_class_new_bad.v:33:12: ../V3Broken.cpp:#: Width != WidthMin
|
||||
33 | c3 = new();
|
||||
| ^~~
|
||||
%Error: Exiting due to
|
||||
|
@ -12,6 +12,10 @@ class ClsNoArg;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class ClsNoNew;
|
||||
int imembera;
|
||||
endclass
|
||||
|
||||
class ClsArg;
|
||||
int imembera;
|
||||
function new(int i);
|
||||
@ -22,9 +26,11 @@ endclass
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
ClsNoArg c1;
|
||||
ClsArg c2;
|
||||
ClsNoNew c2;
|
||||
ClsArg c3;
|
||||
c1 = new(3); // Bad, called with arg
|
||||
c2 = new(); // Bad, called without arg
|
||||
c2 = new(3); // Bad, called with arg
|
||||
c3 = new(); // Bad, called without arg
|
||||
$stop;
|
||||
end
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user