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; }
|
VSymGraph* symsp() { return &m_syms; }
|
||||||
int stepNumber() const { return int(m_step); }
|
int stepNumber() const { return int(m_step); }
|
||||||
bool forPrimary() const { return m_step == LDS_PRIMARY; }
|
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 forPrearray() const { return m_step == LDS_PARAMED || m_step == LDS_PRIMARY; }
|
||||||
bool forScopeCreation() const { return m_step == LDS_SCOPED; }
|
bool forScopeCreation() const { return m_step == LDS_SCOPED; }
|
||||||
|
|
||||||
|
|
@ -751,6 +752,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
// METHODS
|
// METHODS
|
||||||
void makeImplicitNew(AstClass* nodep) {
|
void makeImplicitNew(AstClass* nodep) {
|
||||||
AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr};
|
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);
|
newp->isConstructor(true);
|
||||||
nodep->addMembersp(newp);
|
nodep->addMembersp(newp);
|
||||||
UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl);
|
UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl);
|
||||||
|
|
@ -2025,6 +2028,7 @@ private:
|
||||||
// (except the default instances)
|
// (except the default instances)
|
||||||
// They are added to the set only in linkDotPrimary.
|
// They are added to the set only in linkDotPrimary.
|
||||||
bool m_insideClassExtParam = false; // Inside a class from m_extendsParam
|
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 {
|
struct DotStates {
|
||||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||||
|
|
@ -2112,6 +2116,25 @@ private:
|
||||||
return nullptr;
|
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) {
|
void taskFuncSwapCheck(AstNodeFTaskRef* nodep) {
|
||||||
if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) {
|
if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) {
|
||||||
nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ());
|
nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ());
|
||||||
|
|
@ -3273,7 +3296,16 @@ private:
|
||||||
{
|
{
|
||||||
m_ftaskp = nodep;
|
m_ftaskp = nodep;
|
||||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||||
|
const bool isNew = nodep->name() == "new";
|
||||||
|
if (isNew) m_explicitSuperNew = false;
|
||||||
iterateChildren(nodep);
|
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_ds.m_dotSymp = m_curSymp = oldCurSymp;
|
||||||
m_ftaskp = nullptr;
|
m_ftaskp = nullptr;
|
||||||
|
|
@ -3389,6 +3421,7 @@ private:
|
||||||
checkNoDot(nodep);
|
checkNoDot(nodep);
|
||||||
VL_RESTORER(m_curSymp);
|
VL_RESTORER(m_curSymp);
|
||||||
VL_RESTORER(m_modSymp);
|
VL_RESTORER(m_modSymp);
|
||||||
|
VL_RESTORER(m_modp);
|
||||||
VL_RESTORER(m_ifClassImpNames);
|
VL_RESTORER(m_ifClassImpNames);
|
||||||
VL_RESTORER(m_insideClassExtParam);
|
VL_RESTORER(m_insideClassExtParam);
|
||||||
{
|
{
|
||||||
|
|
@ -3595,6 +3628,19 @@ private:
|
||||||
UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl);
|
UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl);
|
||||||
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
|
// 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 {
|
void visit(AstNode* nodep) override {
|
||||||
checkNoDot(nodep);
|
checkNoDot(nodep);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// DESCRIPTION: Verilator: Verilog Test module
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
//
|
//
|
||||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
// 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
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
`define stop $stop
|
`define stop $stop
|
||||||
|
|
@ -58,6 +58,36 @@ class Bar2Args extends Foo2Args;
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
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*/
|
module t (/*AUTOARG*/
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -80,6 +110,10 @@ module t (/*AUTOARG*/
|
||||||
BarArg barArg;
|
BarArg barArg;
|
||||||
BarExpr barExpr;
|
BarExpr barExpr;
|
||||||
Bar2Args bar2Args;
|
Bar2Args bar2Args;
|
||||||
|
NoNew noNew;
|
||||||
|
NewWithoutSuper newWithoutSuper;
|
||||||
|
NoNewParam#(2) noNewParam;
|
||||||
|
NewWithoutSuperParam#(1) newWithoutSuperParam;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
bar = new;
|
bar = new;
|
||||||
|
|
@ -94,6 +128,14 @@ module t (/*AUTOARG*/
|
||||||
`checkh(barExpr.x, 16);
|
`checkh(barExpr.x, 16);
|
||||||
bar2Args = new(2, 12);
|
bar2Args = new(2, 12);
|
||||||
`checkh(bar2Args.x, 14);
|
`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");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue