Internals: Disambiguate variable references under with clauses of randomize() methods (#5277)

This commit is contained in:
Krzysztof Boroński
2024-08-02 11:45:17 -04:00
committed by GitHub
parent 54f9f4b6a9
commit 45ee949cc4
10 changed files with 516 additions and 102 deletions
+66 -17
View File
@@ -65,6 +65,7 @@
#include "V3LinkDot.h"
#include "V3Global.h"
#include "V3Graph.h"
#include "V3MemberMap.h"
#include "V3Parse.h"
@@ -2046,6 +2047,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
VSymEnt* m_curSymp = nullptr; // SymEnt for current lookup point
VSymEnt* m_modSymp = nullptr; // SymEnt for current module
VSymEnt* m_pinSymp = nullptr; // SymEnt for pin lookups
VSymEnt* m_fromSymp = nullptr; // SymEnt for randomize lookups
const AstCell* m_cellp = nullptr; // Current cell
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
@@ -2465,6 +2467,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
UINFO(8, " " << nodep << endl);
const DotStates lastStates = m_ds;
const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
VL_RESTORER(m_fromSymp);
{
if (start) { // Starting dot sequence
if (debug() >= 9) nodep->dumpTree("- dot-in: ");
@@ -2580,6 +2583,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
"ParseRefs should no longer exist");
const DotStates lastStates = m_ds;
const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
if (start) {
m_ds.init(m_curSymp);
// Note m_ds.m_dot remains nullptr; this is a reference not under a dot
@@ -2648,12 +2652,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
classOrPackagep = cpackagerefp->classOrPackagep();
UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link");
if (cpackagerefp->name() == "local::") {
if (m_pinSymp) {
m_ds.m_dotSymp = m_curSymp->fallbackp();
} else {
nodep->v3error("Illegal 'local::' outside 'randomize() with'");
m_ds.m_dotErr = true;
}
m_fromSymp = nullptr;
} else {
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep);
}
@@ -2675,6 +2674,19 @@ class LinkDotResolveVisitor final : public VNVisitor {
VSymEnt* foundp;
string baddot;
VSymEnt* okSymp = nullptr;
if (m_fromSymp) {
foundp = m_fromSymp->findIdFlat(nodep->name());
if (foundp) {
UINFO(9, " randomize-with fromSym " << foundp->nodep() << endl);
if (m_ds.m_dotPos != DP_NONE) m_ds.m_dotPos = DP_MEMBER;
AstLambdaArgRef* const lambdaRefp
= new AstLambdaArgRef{nodep->fileline(), "item", false};
nodep->replaceWith(new AstMemberSel{nodep->fileline(), lambdaRefp,
VFlagChildDType{}, nodep->name()});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
}
}
if (allowScope) {
foundp = m_statep->findDotted(nodep->fileline(), m_ds.m_dotSymp, nodep->name(),
baddot, okSymp); // Maybe nullptr
@@ -2730,8 +2742,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
}
} else if (allowFTask && VN_IS(foundp->nodep(), NodeFTask)) {
AstTaskRef* const taskrefp
= new AstTaskRef{nodep->fileline(), nodep->name(), nullptr};
AstNodeFTaskRef* taskrefp;
if (VN_IS(foundp->nodep(), Task)) {
taskrefp = new AstTaskRef{nodep->fileline(), nodep->name(), nullptr};
} else {
taskrefp = new AstFuncRef{nodep->fileline(), nodep->name(), nullptr};
}
nodep->replaceWith(taskrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
if (start) m_ds = lastStates;
@@ -2979,6 +2995,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl);
iterateChildren(nodep);
if (nodep->name() == "local::") {
if (!m_fromSymp) {
nodep->v3error("Illegal 'local::' outside 'randomize() with'");
m_ds.m_dotErr = true;
}
}
AstClass* const modClassp = VN_CAST(m_modp, Class);
if (m_statep->forPrimary() && refClassp && !nodep->paramsp()
&& nodep->classOrPackagep()->hasGParam()
@@ -3124,10 +3146,10 @@ class LinkDotResolveVisitor final : public VNVisitor {
void visit(AstMethodCall* nodep) override {
// Created here so should already be resolved.
VL_RESTORER(m_ds);
VL_RESTORER(m_pinSymp);
VL_RESTORER(m_fromSymp);
{
m_ds.init(m_curSymp);
if (nodep->name() == "randomize" && VN_IS(nodep->pinsp(), With)) {
if (nodep->name() == "randomize" && nodep->pinsp()) {
const AstNodeDType* fromDtp = nodep->fromp()->dtypep();
if (!fromDtp) {
if (const AstNodeVarRef* const varRefp = VN_CAST(nodep->fromp(), NodeVarRef)) {
@@ -3157,8 +3179,16 @@ class LinkDotResolveVisitor final : public VNVisitor {
nodep->v3error("'randomize() with' on a non-class-instance "
<< fromDtp->prettyNameQ());
else
m_pinSymp = m_statep->getNodeSym(classDtp->classp());
m_fromSymp = m_statep->getNodeSym(classDtp->classp());
}
AstNode* pinsp = nodep->pinsp();
if (VN_IS(pinsp, With)) {
iterate(pinsp);
pinsp = pinsp->nextp();
}
m_fromSymp = nullptr;
iterateAndNextNull(pinsp);
return;
}
iterateChildren(nodep);
}
@@ -3191,6 +3221,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
}
}
VL_RESTORER(m_fromSymp);
bool staticAccess = false;
if (m_ds.m_unresolvedClass) {
// Unable to link before V3Param
@@ -3210,12 +3242,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
staticAccess = true;
AstClassOrPackageRef* const cpackagerefp
= VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
if (cpackagerefp->name() == "local") {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name()));
}
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
if (cpackagerefp->name() == "local::") {
m_fromSymp = nullptr;
} else {
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
}
// Class/package :: HERE function() . method_called_on_function_return_value()
m_ds.m_dotPos = DP_MEMBER;
m_ds.m_dotp = nullptr;
@@ -3284,6 +3316,24 @@ class LinkDotResolveVisitor final : public VNVisitor {
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
okSymp); // Maybe nullptr
}
if (m_fromSymp) {
VSymEnt* const foundp = m_fromSymp->findIdFlat(nodep->name());
if (foundp) {
UINFO(9, " randomize-with fromSym " << foundp->nodep() << endl);
AstNodeExpr* argsp = nullptr;
if (nodep->pinsp()) {
iterateAndNextNull(nodep->pinsp());
argsp = nodep->pinsp()->unlinkFrBackWithNext();
}
if (m_ds.m_dotPos != DP_NONE) m_ds.m_dotPos = DP_MEMBER;
AstNode* const newp = new AstMethodCall{
nodep->fileline(), new AstLambdaArgRef{nodep->fileline(), "item", false},
VFlagChildDType{}, nodep->name(), argsp};
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
}
}
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstNodeFTask* const taskp
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
@@ -3524,7 +3574,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
VL_RESTORER(m_curSymp);
{
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
if (m_pinSymp) m_curSymp->importFromClass(m_statep->symsp(), m_pinSymp);
iterateChildren(nodep);
}
m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp);