Fix implicit calls of base class constructors with optional arguments (#4319)

This commit is contained in:
Ryszard Rozak 2023-06-27 16:08:38 +02:00 committed by GitHub
parent 51266898ec
commit ba47c01a01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 1 deletions

View File

@ -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);

View File

@ -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;