Fix implicit calls of base class constructors with optional arguments (#4319)
This commit is contained in:
parent
51266898ec
commit
ba47c01a01
|
|
@ -215,6 +215,7 @@ public:
|
|||
VSymGraph* symsp() { return &m_syms; }
|
||||
int stepNumber() const { return int(m_step); }
|
||||
bool forPrimary() const { return m_step == LDS_PRIMARY; }
|
||||
bool forParamed() const { return m_step == LDS_PARAMED; }
|
||||
bool forPrearray() const { return m_step == LDS_PARAMED || m_step == LDS_PRIMARY; }
|
||||
bool forScopeCreation() const { return m_step == LDS_SCOPED; }
|
||||
|
||||
|
|
@ -751,6 +752,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
// METHODS
|
||||
void makeImplicitNew(AstClass* nodep) {
|
||||
AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr};
|
||||
// If needed, super.new() call is added the 2nd pass of V3LinkDotResolve,
|
||||
// because base classes are already resolved there.
|
||||
newp->isConstructor(true);
|
||||
nodep->addMembersp(newp);
|
||||
UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl);
|
||||
|
|
@ -2025,6 +2028,7 @@ private:
|
|||
// (except the default instances)
|
||||
// They are added to the set only in linkDotPrimary.
|
||||
bool m_insideClassExtParam = false; // Inside a class from m_extendsParam
|
||||
bool m_explicitSuperNew = false; // Hit a "super.new" call inside a "new" function
|
||||
|
||||
struct DotStates {
|
||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||
|
|
@ -2112,6 +2116,25 @@ private:
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
AstNodeStmt* addImplicitSuperNewCall(AstFunc* nodep) {
|
||||
// Returns the added node
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstDot* const superNewp
|
||||
= new AstDot{fl, false, new AstParseRef{fl, VParseRefExp::PX_ROOT, "super"},
|
||||
new AstNew{fl, nullptr}};
|
||||
AstNodeStmt* const superNewStmtp = superNewp->makeStmt();
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
// super.new shall be the first statement (section 8.15 of IEEE Std 1800-2017)
|
||||
// but some nodes (such as variable declarations and typedefs) should stay before
|
||||
if (VN_IS(stmtp, NodeStmt)) {
|
||||
stmtp->addHereThisAsNext(superNewStmtp);
|
||||
return superNewStmtp;
|
||||
}
|
||||
}
|
||||
// There were no statements
|
||||
nodep->addStmtsp(superNewStmtp);
|
||||
return superNewStmtp;
|
||||
}
|
||||
void taskFuncSwapCheck(AstNodeFTaskRef* nodep) {
|
||||
if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) {
|
||||
nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ());
|
||||
|
|
@ -3273,7 +3296,16 @@ private:
|
|||
{
|
||||
m_ftaskp = nodep;
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
const bool isNew = nodep->name() == "new";
|
||||
if (isNew) m_explicitSuperNew = false;
|
||||
iterateChildren(nodep);
|
||||
if (isNew && !m_explicitSuperNew && m_statep->forParamed()) {
|
||||
const AstClassExtends* const classExtendsp = VN_AS(m_modp, Class)->extendsp();
|
||||
if (classExtendsp && classExtendsp->classOrNullp()) {
|
||||
AstNodeStmt* const superNewp = addImplicitSuperNewCall(VN_AS(nodep, Func));
|
||||
iterate(superNewp);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
||||
m_ftaskp = nullptr;
|
||||
|
|
@ -3389,6 +3421,7 @@ private:
|
|||
checkNoDot(nodep);
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_ifClassImpNames);
|
||||
VL_RESTORER(m_insideClassExtParam);
|
||||
{
|
||||
|
|
@ -3595,6 +3628,19 @@ private:
|
|||
UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl);
|
||||
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
|
||||
}
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
checkNoDot(nodep);
|
||||
// Check if nodep represents a super.new call;
|
||||
if (VN_IS(nodep->exprp(), New)) {
|
||||
// in this case it was already linked, so it doesn't have a super reference
|
||||
m_explicitSuperNew = true;
|
||||
} else if (const AstDot* const dotp = VN_CAST(nodep->exprp(), Dot)) {
|
||||
if (dotp->lhsp()->name() == "super" && VN_IS(dotp->rhsp(), New)) {
|
||||
m_explicitSuperNew = true;
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
checkNoDot(nodep);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// 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.
|
||||
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
|
|
@ -58,6 +58,36 @@ class Bar2Args extends Foo2Args;
|
|||
endfunction
|
||||
endclass
|
||||
|
||||
class OptArgInNew;
|
||||
int x;
|
||||
function new (int y=1);
|
||||
x = y;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class NoNew extends OptArgInNew;
|
||||
endclass
|
||||
|
||||
class NewWithoutSuper extends OptArgInNew;
|
||||
function new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class OptArgInNewParam #(parameter int P=1);
|
||||
int x;
|
||||
function new (int y=1);
|
||||
x = y;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class NoNewParam#(parameter int R) extends OptArgInNewParam#(R);
|
||||
endclass
|
||||
|
||||
class NewWithoutSuperParam#(parameter int R) extends OptArgInNewParam#();
|
||||
function new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
);
|
||||
|
||||
|
|
@ -80,6 +110,10 @@ module t (/*AUTOARG*/
|
|||
BarArg barArg;
|
||||
BarExpr barExpr;
|
||||
Bar2Args bar2Args;
|
||||
NoNew noNew;
|
||||
NewWithoutSuper newWithoutSuper;
|
||||
NoNewParam#(2) noNewParam;
|
||||
NewWithoutSuperParam#(1) newWithoutSuperParam;
|
||||
|
||||
initial begin
|
||||
bar = new;
|
||||
|
|
@ -94,6 +128,14 @@ module t (/*AUTOARG*/
|
|||
`checkh(barExpr.x, 16);
|
||||
bar2Args = new(2, 12);
|
||||
`checkh(bar2Args.x, 14);
|
||||
noNew = new;
|
||||
`checkh(noNew.x, 1);
|
||||
newWithoutSuper = new;
|
||||
`checkh(newWithoutSuper.x, 1);
|
||||
noNewParam = new;
|
||||
`checkh(noNewParam.x, 1);
|
||||
newWithoutSuperParam = new;
|
||||
`checkh(newWithoutSuperParam.x, 1);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
|
|
|||
Loading…
Reference in New Issue