mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Fix dot fallback finding wrong symbols (#5394)
This commit is contained in:
parent
48776277bd
commit
ed7040adc0
@ -577,13 +577,22 @@ private:
|
||||
return findp;
|
||||
}
|
||||
|
||||
VSymEnt* findWithAltFlat(VSymEnt* symp, const string& name, const string& altname) {
|
||||
VSymEnt* findp = symp->findIdFlat(name);
|
||||
if (findp) return findp;
|
||||
if (altname != "") {
|
||||
UINFO(8, " alt flat\n");
|
||||
findp = symp->findIdFlat(altname);
|
||||
}
|
||||
return findp;
|
||||
}
|
||||
|
||||
public:
|
||||
VSymEnt* findDotted(FileLine* refLocationp, VSymEnt* lookupSymp, const string& dotname,
|
||||
string& baddot, VSymEnt*& okSymp) {
|
||||
string& baddot, VSymEnt*& okSymp, bool firstId) {
|
||||
// Given a dotted hierarchy name, return where in scope it is
|
||||
// Note when dotname=="" we just fall through and return lookupSymp
|
||||
UINFO(8, " dottedFind se" << cvtToHex(lookupSymp) << " '" << dotname << "'" << endl);
|
||||
bool firstId = true;
|
||||
string leftname = dotname;
|
||||
okSymp = lookupSymp; // So can list bad scopes
|
||||
while (leftname != "") { // foreach dotted part of xref name
|
||||
@ -666,7 +675,7 @@ public:
|
||||
if (!lookupSymp) return nullptr; // Not found
|
||||
}
|
||||
} else { // Searching for middle submodule, must be a cell name
|
||||
if (VSymEnt* const findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) {
|
||||
if (VSymEnt* const findSymp = findWithAltFlat(lookupSymp, ident, altIdent)) {
|
||||
lookupSymp = findSymp;
|
||||
} else {
|
||||
return nullptr; // Not found
|
||||
@ -701,7 +710,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
VSymEnt* findSymPrefixed(VSymEnt* lookupSymp, const string& dotname, string& baddot) {
|
||||
VSymEnt* findSymPrefixed(VSymEnt* lookupSymp, const string& dotname, string& baddot,
|
||||
bool fallback) {
|
||||
// Find symbol in given point in hierarchy, allowing prefix (post-Inline)
|
||||
// For simplicity lookupSymp may be passed nullptr result from findDotted
|
||||
if (!lookupSymp) return nullptr;
|
||||
@ -709,11 +719,15 @@ public:
|
||||
<< dotname << " under se" << cvtToHex(lookupSymp)
|
||||
<< ((lookupSymp->symPrefix() == "") ? "" : " as ")
|
||||
<< ((lookupSymp->symPrefix() == "") ? "" : lookupSymp->symPrefix() + dotname)
|
||||
<< " at se" << lookupSymp << endl);
|
||||
<< " at se" << lookupSymp << " fallback=" << fallback << endl);
|
||||
string prefix = lookupSymp->symPrefix();
|
||||
VSymEnt* foundp = nullptr;
|
||||
while (!foundp) {
|
||||
foundp = lookupSymp->findIdFallback(prefix + dotname); // Might be nullptr
|
||||
if (fallback) {
|
||||
foundp = lookupSymp->findIdFallback(prefix + dotname); // Might be nullptr
|
||||
} else {
|
||||
foundp = lookupSymp->findIdFlat(prefix + dotname); // Might be nullptr
|
||||
}
|
||||
if (prefix.empty()) break;
|
||||
const string nextPrefix = removeLastInlineScope(prefix);
|
||||
if (prefix == nextPrefix) break;
|
||||
@ -1000,7 +1014,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
const string scope = origname.substr(0, pos);
|
||||
string baddot;
|
||||
VSymEnt* okSymp;
|
||||
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, scope, baddot, okSymp);
|
||||
aboveSymp
|
||||
= m_statep->findDotted(nodep->fileline(), aboveSymp, scope, baddot, okSymp, false);
|
||||
UASSERT_OBJ(aboveSymp, nodep,
|
||||
"Can't find instance insertion point at "
|
||||
<< AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ());
|
||||
@ -1025,7 +1040,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
const string ident = dottedname.substr(pos + std::strlen("__DOT__"));
|
||||
string baddot;
|
||||
VSymEnt* okSymp;
|
||||
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp);
|
||||
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp,
|
||||
false);
|
||||
UASSERT_OBJ(aboveSymp, nodep,
|
||||
"Can't find cellinline insertion point at "
|
||||
<< AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ());
|
||||
@ -1857,15 +1873,15 @@ class LinkDotScopeVisitor final : public VNVisitor {
|
||||
string baddot;
|
||||
VSymEnt* okSymp;
|
||||
VSymEnt* cellSymp = m_statep->findDotted(nodep->fileline(), m_modSymp, ifcellname,
|
||||
baddot, okSymp);
|
||||
baddot, okSymp, false);
|
||||
UASSERT_OBJ(
|
||||
cellSymp, nodep,
|
||||
"No symbol for interface instance: " << nodep->prettyNameQ(ifcellname));
|
||||
UINFO(5, " Found interface instance: se" << cvtToHex(cellSymp) << " "
|
||||
<< cellSymp->nodep() << endl);
|
||||
if (dtypep->modportName() != "") {
|
||||
VSymEnt* const mpSymp = m_statep->findDotted(nodep->fileline(), m_modSymp,
|
||||
ifcellname, baddot, okSymp);
|
||||
VSymEnt* const mpSymp = m_statep->findDotted(
|
||||
nodep->fileline(), m_modSymp, ifcellname, baddot, okSymp, false);
|
||||
UASSERT_OBJ(mpSymp, nodep,
|
||||
"No symbol for interface modport: "
|
||||
<< nodep->prettyNameQ(dtypep->modportName()));
|
||||
@ -1926,7 +1942,7 @@ class LinkDotScopeVisitor final : public VNVisitor {
|
||||
string baddot;
|
||||
VSymEnt* okSymp;
|
||||
symp = m_statep->findDotted(nodep->rhsp()->fileline(), m_modSymp, scopename,
|
||||
baddot, okSymp);
|
||||
baddot, okSymp, false);
|
||||
if (inl == "") break;
|
||||
inl = LinkDotState::removeLastInlineScope(inl);
|
||||
}
|
||||
@ -1952,7 +1968,7 @@ class LinkDotScopeVisitor final : public VNVisitor {
|
||||
string baddot;
|
||||
VSymEnt* okSymp;
|
||||
VSymEnt* const symp = m_statep->findDotted(nodep->lhsp()->fileline(), m_modSymp,
|
||||
scopename, baddot, okSymp);
|
||||
scopename, baddot, okSymp, false);
|
||||
UASSERT_OBJ(symp, nodep, "No symbol for interface alias lhs");
|
||||
UINFO(5, " Found a linked scope LHS: " << scopename << " se" << cvtToHex(symp)
|
||||
<< " " << symp->nodep() << endl);
|
||||
@ -2085,7 +2101,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
enum DotPosition : uint8_t {
|
||||
DP_NONE = 0, // Not under a DOT
|
||||
DP_PACKAGE, // {package}:: DOT
|
||||
DP_SCOPE, // [DOT...] {scope-or-var} DOT
|
||||
DP_FIRST, // {scope-or-var} DOT
|
||||
DP_SCOPE, // DOT... {scope-or-var} DOT
|
||||
DP_FINAL, // [DOT...] {var-or-func-or-dtype} with no following dots
|
||||
DP_MEMBER
|
||||
}; // DOT {member-name} [DOT...]
|
||||
@ -2524,7 +2541,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
m_ds.init(m_curSymp); // Start from current point
|
||||
}
|
||||
m_ds.m_dotp = nodep; // Always, not just at start
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
m_ds.m_dotPos = DP_FIRST;
|
||||
|
||||
if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") {
|
||||
VSymEnt* classSymp = getThisClassSymp();
|
||||
@ -2566,7 +2583,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
m_ds.m_dotPos = DP_PACKAGE;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
} else {
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
m_ds.m_dotPos = DP_FIRST;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
// if (debug() >= 9) nodep->dumpTree("- dot-lho: ");
|
||||
}
|
||||
@ -2578,6 +2595,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
||||
m_ds.m_unlinkedScopep = nodep->lhsp();
|
||||
}
|
||||
if (m_ds.m_dotPos == DP_FIRST) m_ds.m_dotPos = DP_SCOPE;
|
||||
if (!m_ds.m_dotErr) { // Once something wrong, give up
|
||||
// Top 'final' dot RHS is final RHS, else it's a
|
||||
// DOT(DOT(x,*here*),real-rhs) which we consider a RHS
|
||||
@ -2633,6 +2651,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
|
||||
bool first = start || m_ds.m_dotPos == DP_FIRST;
|
||||
|
||||
if (start) {
|
||||
m_ds.init(m_curSymp);
|
||||
@ -2703,11 +2722,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
if (cpackagerefp->name() == "local::") {
|
||||
m_fromSymp = nullptr;
|
||||
first = true;
|
||||
} else {
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep);
|
||||
}
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
} else if (m_ds.m_dotPos == DP_SCOPE) {
|
||||
} else if (m_ds.m_dotPos == DP_SCOPE || m_ds.m_dotPos == DP_FIRST) {
|
||||
// {a}.{b}, where {a} maybe a module name
|
||||
// or variable, where dotting into structure member
|
||||
expectWhat = "scope/variable";
|
||||
@ -2727,6 +2747,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
if (m_fromSymp) {
|
||||
foundp = m_fromSymp->findIdFlat(nodep->name());
|
||||
if (foundp) {
|
||||
if (!start) m_ds.m_dotPos = DP_MEMBER;
|
||||
if (!m_inWith) {
|
||||
UASSERT_OBJ(m_randMethodCallp, nodep, "Expected to be under randomize()");
|
||||
// This will start failing once complex expressions are allowed on the LHS
|
||||
@ -2735,15 +2756,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
"Expected simple randomize target");
|
||||
// A ParseRef is used here so that the dot RHS gets resolved
|
||||
nodep->replaceWith(new AstMemberSel{
|
||||
nodep->fileline(),
|
||||
new AstParseRef{nodep->fileline(), VParseRefExp::PX_TEXT,
|
||||
m_randMethodCallp->fromp()->name()},
|
||||
nodep->fileline(), m_randMethodCallp->fromp()->cloneTree(false),
|
||||
VFlagChildDType{}, nodep->name()});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
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,
|
||||
@ -2754,9 +2772,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
}
|
||||
if (allowScope) {
|
||||
foundp = m_statep->findDotted(nodep->fileline(), m_ds.m_dotSymp, nodep->name(),
|
||||
baddot, okSymp); // Maybe nullptr
|
||||
} else {
|
||||
baddot, okSymp, first); // Maybe nullptr
|
||||
} else if (first) {
|
||||
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
|
||||
} else {
|
||||
foundp = m_ds.m_dotSymp->findIdFlat(nodep->name());
|
||||
}
|
||||
if (foundp) {
|
||||
UINFO(9, " found=se" << cvtToHex(foundp) << " exp=" << expectWhat
|
||||
@ -2765,7 +2785,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
// What fell out?
|
||||
bool ok = false;
|
||||
// Special case: waiting on clocking event
|
||||
if (m_inSens && foundp && m_ds.m_dotPos != DP_SCOPE) {
|
||||
if (m_inSens && foundp && m_ds.m_dotPos != DP_SCOPE && m_ds.m_dotPos != DP_FIRST) {
|
||||
if (AstClocking* const clockingp = VN_CAST(foundp->nodep(), Clocking)) {
|
||||
foundp = getCreateClockingEventSymEnt(clockingp);
|
||||
}
|
||||
@ -2815,7 +2835,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
}
|
||||
nodep->replaceWith(taskrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (start) m_ds = lastStates;
|
||||
m_ds = lastStates;
|
||||
return;
|
||||
} else if (AstVar* const varp = foundToVarp(foundp, nodep, VAccess::READ)) {
|
||||
AstIfaceRefDType* const ifacerefp
|
||||
@ -2961,7 +2981,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
} else if (VN_IS(foundp->nodep(), Clocking)) {
|
||||
m_ds.m_dotSymp = foundp;
|
||||
if (m_ds.m_dotText != "") m_ds.m_dotText += "." + nodep->name();
|
||||
ok = m_ds.m_dotPos == DP_SCOPE;
|
||||
ok = m_ds.m_dotPos == DP_SCOPE || m_ds.m_dotPos == DP_FIRST;
|
||||
} else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) {
|
||||
|
||||
if (!ftaskp->isFunction() || ftaskp->classMethod()) {
|
||||
@ -2986,7 +3006,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
// Mark that the Dot statement can't be resolved.
|
||||
m_ds.m_unresolvedClass = true;
|
||||
// If the symbol was a scope name, it would be resolved.
|
||||
if (m_ds.m_dotPos == DP_SCOPE) m_ds.m_dotPos = DP_MEMBER;
|
||||
m_ds.m_dotPos = DP_MEMBER;
|
||||
} else {
|
||||
// Cells/interfaces can't be implicit
|
||||
const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false;
|
||||
@ -3128,15 +3148,16 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
// ignore (t_math_divw)
|
||||
dotSymp = m_modSymp;
|
||||
const string inl = AstNode::dedotName(nodep->inlinedDots());
|
||||
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
|
||||
dotSymp
|
||||
= m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp, false);
|
||||
UASSERT_OBJ(dotSymp, nodep,
|
||||
"Couldn't resolve inlined scope " << AstNode::prettyNameQ(baddot)
|
||||
<< " in: " << nodep->inlinedDots());
|
||||
}
|
||||
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
|
||||
okSymp); // Maybe nullptr
|
||||
okSymp, true); // Maybe nullptr
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, true);
|
||||
if (m_inSens && foundp) {
|
||||
if (AstClocking* const clockingp = VN_CAST(foundp->nodep(), Clocking)) {
|
||||
foundp = getCreateClockingEventSymEnt(clockingp);
|
||||
@ -3169,7 +3190,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
VSymEnt* const foundp
|
||||
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, true);
|
||||
AstVarScope* vscp = foundp ? VN_AS(foundp->nodep(), VarScope) : nullptr;
|
||||
if (!vscp) {
|
||||
nodep->v3error("Can't find varpin scope of "
|
||||
@ -3290,6 +3312,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
|
||||
VL_RESTORER(m_fromSymp);
|
||||
|
||||
bool first = !m_ds.m_dotp || m_ds.m_dotPos == DP_FIRST;
|
||||
bool staticAccess = false;
|
||||
if (m_ds.m_unresolvedClass) {
|
||||
// Unable to link before V3Param
|
||||
@ -3312,12 +3335,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
if (cpackagerefp->name() == "local::") {
|
||||
m_fromSymp = nullptr;
|
||||
first = true;
|
||||
} 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;
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
||||
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
||||
@ -3331,7 +3354,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_SCOPE) {
|
||||
} else if (m_ds.m_dotp && (m_ds.m_dotPos == DP_SCOPE || m_ds.m_dotPos == DP_FIRST)) {
|
||||
// HERE function() . method_called_on_function_return_value()
|
||||
m_ds.m_dotPos = DP_MEMBER;
|
||||
m_ds.m_dotText = "";
|
||||
@ -3371,8 +3394,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
dotSymp = m_modSymp;
|
||||
const string inl = AstNode::dedotName(nodep->inlinedDots());
|
||||
UINFO(8, " Inlined " << inl << endl);
|
||||
dotSymp
|
||||
= m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
|
||||
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp,
|
||||
true);
|
||||
if (!dotSymp) {
|
||||
okSymp->cellErrorScopes(nodep);
|
||||
nodep->v3fatalSrc("Couldn't resolve inlined scope "
|
||||
@ -3381,7 +3404,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
|
||||
okSymp); // Maybe nullptr
|
||||
okSymp, true); // Maybe nullptr
|
||||
}
|
||||
if (m_fromSymp) {
|
||||
VSymEnt* const foundp = m_fromSymp->findIdFlat(nodep->name());
|
||||
@ -3401,7 +3424,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
VSymEnt* const foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
VSymEnt* const foundp
|
||||
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
||||
AstNodeFTask* const taskp
|
||||
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
|
||||
if (taskp) {
|
||||
@ -3506,12 +3530,13 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
if (nodep->user3SetOnce()) return;
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
if (m_ds.m_unresolvedClass) {
|
||||
UASSERT_OBJ(m_ds.m_dotPos != DP_SCOPE, nodep,
|
||||
UASSERT_OBJ(m_ds.m_dotPos != DP_SCOPE && m_ds.m_dotPos != DP_FIRST, nodep,
|
||||
"Object of unresolved class on scope position in dotted reference");
|
||||
return;
|
||||
}
|
||||
if (m_ds.m_dotPos
|
||||
== DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
if (m_ds.m_dotPos == DP_SCOPE
|
||||
|| m_ds.m_dotPos
|
||||
== DP_FIRST) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
UINFO(9, " deferring until after a V3Param pass: " << nodep << endl);
|
||||
m_ds.m_dotText += "__BRA__??__KET__";
|
||||
m_ds.m_unresolvedCell = true;
|
||||
@ -3527,7 +3552,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
iterateAndNextNull(nodep->attrp());
|
||||
}
|
||||
}
|
||||
if (m_ds.m_unresolvedCell && m_ds.m_dotPos == DP_SCOPE) {
|
||||
if (m_ds.m_unresolvedCell && (m_ds.m_dotPos == DP_SCOPE || m_ds.m_dotPos == DP_FIRST)) {
|
||||
AstNodeExpr* const exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstCellArrayRef* const newp
|
||||
= new AstCellArrayRef{nodep->fileline(), nodep->fromp()->name(), exprp};
|
||||
@ -3538,8 +3563,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
void visit(AstNodePreSel* nodep) override {
|
||||
// Excludes simple AstSelBit, see above
|
||||
if (nodep->user3SetOnce()) return;
|
||||
if (m_ds.m_dotPos
|
||||
== DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
if (m_ds.m_dotPos == DP_SCOPE
|
||||
|| m_ds.m_dotPos
|
||||
== DP_FIRST) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
nodep->v3error("Syntax error: Range ':', '+:' etc are not allowed in the instance "
|
||||
"part of a dotted reference");
|
||||
m_ds.m_dotErr = true;
|
||||
@ -3861,7 +3887,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
|
||||
nodep->classOrPackagep(cpackagerefp->classOrPackagep());
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
m_ds.m_dotp = nullptr;
|
||||
} else {
|
||||
checkNoDot(nodep);
|
||||
}
|
||||
@ -3870,8 +3895,10 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
const VSymEnt* foundp;
|
||||
if (nodep->classOrPackagep()) {
|
||||
foundp = m_statep->getNodeSym(nodep->classOrPackagep())->findIdFlat(nodep->name());
|
||||
} else {
|
||||
} else if (m_ds.m_dotPos == DP_FIRST || m_ds.m_dotPos == DP_NONE) {
|
||||
foundp = m_curSymp->findIdFallback(nodep->name());
|
||||
} else {
|
||||
foundp = m_curSymp->findIdFlat(nodep->name());
|
||||
}
|
||||
if (AstTypedef* const defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) {
|
||||
nodep->typedefp(defp);
|
||||
|
30
test_regress/t/t_fallback_bad.out
Normal file
30
test_regress/t/t_fallback_bad.out
Normal file
@ -0,0 +1,30 @@
|
||||
%Error: t/t_fallback_bad.v:26:16: Can't find definition of task/function: 'tsk'
|
||||
26 | super.tsk;
|
||||
| ^~~
|
||||
%Error: t/t_fallback_bad.v:27:15: Can't find definition of task/function: 'tsk'
|
||||
27 | this.tsk;
|
||||
| ^~~
|
||||
%Error: t/t_fallback_bad.v:28:16: Can't find definition of variable: 'f'
|
||||
28 | super.f = 8;
|
||||
| ^
|
||||
%Error: t/t_fallback_bad.v:29:15: Can't find definition of variable: 'f'
|
||||
29 | this.f = 8;
|
||||
| ^
|
||||
%Error: t/t_fallback_bad.v:30:20: Can't find definition of 'tsk' in dotted task/function: 'sub1.sub2.tsk'
|
||||
30 | sub1.sub2.tsk;
|
||||
| ^~~
|
||||
... Known scopes under 'tsk': sub2
|
||||
%Error: t/t_fallback_bad.v:31:15: Can't find definition of scope/variable/func: 'f'
|
||||
31 | pkg::f = 8;
|
||||
| ^
|
||||
%Error: t/t_fallback_bad.v:32:15: Can't find definition of task/function: 'tsk'
|
||||
32 | pkg::tsk();
|
||||
| ^~~
|
||||
%Error: t/t_fallback_bad.v:33:20: Can't find definition of 'f' in dotted variable: 'sub1.sub2.f'
|
||||
33 | sub1.sub2.f = 8;
|
||||
| ^
|
||||
%Error: t/t_fallback_bad.v:34:20: Can't find definition of 'f' in dotted scope/variable: 'sub1.sub2.f'
|
||||
34 | sub1.sub2.f.f = 8;
|
||||
| ^
|
||||
... Known scopes under 'sub1.sub2': <no instances found>
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_fallback_bad.pl
Executable file
19
test_regress/t/t_fallback_bad.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
43
test_regress/t/t_fallback_bad.v
Normal file
43
test_regress/t/t_fallback_bad.v
Normal file
@ -0,0 +1,43 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
int f = 5;
|
||||
task tsk; endtask
|
||||
|
||||
package pkg;
|
||||
endpackage
|
||||
|
||||
module subm;
|
||||
endmodule
|
||||
|
||||
module submo;
|
||||
subm sub2;
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
submo sub1;
|
||||
|
||||
class Base;endclass
|
||||
class Cls extends Base;
|
||||
task calltsk;
|
||||
super.tsk;
|
||||
this.tsk;
|
||||
super.f = 8;
|
||||
this.f = 8;
|
||||
sub1.sub2.tsk;
|
||||
pkg::f = 8;
|
||||
pkg::tsk();
|
||||
sub1.sub2.f = 8;
|
||||
sub1.sub2.f.f = 8;
|
||||
endtask
|
||||
endclass
|
||||
|
||||
Cls obj = new;
|
||||
initial begin
|
||||
obj.calltsk;
|
||||
if (f != 5) $stop;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user