Fix type_id package scope resolution (#5826)
This commit is contained in:
parent
8e87a99628
commit
b2093b513a
|
|
@ -50,7 +50,8 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// METHODS
|
// METHODS
|
||||||
const AstNodeDType* skipRefIterp(bool skipConst, bool skipEnum) const VL_MT_STABLE;
|
const AstNodeDType* skipRefIterp(bool skipConst, bool skipEnum,
|
||||||
|
bool assertOn = true) const VL_MT_STABLE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
@ -78,6 +79,15 @@ public:
|
||||||
return const_cast<AstNodeDType*>(
|
return const_cast<AstNodeDType*>(
|
||||||
static_cast<const AstNodeDType*>(this)->skipRefIterp(true, true));
|
static_cast<const AstNodeDType*>(this)->skipRefIterp(true, true));
|
||||||
}
|
}
|
||||||
|
// (Slow) Recurse over MemberDType|ParamTypeDType|RefDType|ConstDType|EnumDType to other type,
|
||||||
|
// Returns null if not resolved
|
||||||
|
const AstNodeDType* skipRefOrNullp() const VL_MT_STABLE {
|
||||||
|
return skipRefIterp(true, true, false);
|
||||||
|
}
|
||||||
|
AstNodeDType* skipRefOrNullp() VL_MT_STABLE {
|
||||||
|
return const_cast<AstNodeDType*>(
|
||||||
|
static_cast<const AstNodeDType*>(this)->skipRefIterp(true, true, false));
|
||||||
|
}
|
||||||
// (Slow) Recurse over MemberDType|ParamTypeDType|RefDType|EnumDType to ConstDType
|
// (Slow) Recurse over MemberDType|ParamTypeDType|RefDType|EnumDType to ConstDType
|
||||||
const AstNodeDType* skipRefToConstp() const { return skipRefIterp(false, true); }
|
const AstNodeDType* skipRefToConstp() const { return skipRefIterp(false, true); }
|
||||||
AstNodeDType* skipRefToConstp() {
|
AstNodeDType* skipRefToConstp() {
|
||||||
|
|
|
||||||
|
|
@ -829,7 +829,8 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) const VL_MT_STABLE {
|
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
|
||||||
|
bool assertOn) const VL_MT_STABLE {
|
||||||
const AstNodeDType* nodep = this;
|
const AstNodeDType* nodep = this;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType)
|
if (VL_UNLIKELY(VN_IS(nodep, MemberDType) || VN_IS(nodep, ParamTypeDType)
|
||||||
|
|
@ -840,7 +841,7 @@ const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum) co
|
||||||
nodep = subp;
|
nodep = subp;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type");
|
if (assertOn) nodep->v3fatalSrc(nodep->prettyTypeName() << " not linked to type");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2669,7 +2670,9 @@ AstNodeModule* AstClassOrPackageRef::classOrPackageSkipp() const {
|
||||||
AstNode* lastp = nullptr;
|
AstNode* lastp = nullptr;
|
||||||
while (foundp != lastp) {
|
while (foundp != lastp) {
|
||||||
lastp = foundp;
|
lastp = foundp;
|
||||||
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) foundp = anodep->skipRefp();
|
if (AstNodeDType* const anodep = VN_CAST(foundp, NodeDType)) {
|
||||||
|
foundp = anodep->skipRefOrNullp();
|
||||||
|
}
|
||||||
if (AstTypedef* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
if (AstTypedef* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
||||||
if (AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType))
|
if (AstClassRefDType* const anodep = VN_CAST(foundp, ClassRefDType))
|
||||||
foundp = anodep->classp();
|
foundp = anodep->classp();
|
||||||
|
|
|
||||||
|
|
@ -765,10 +765,15 @@ public:
|
||||||
if (!foundp) baddot = dotname;
|
if (!foundp) baddot = dotname;
|
||||||
return foundp;
|
return foundp;
|
||||||
}
|
}
|
||||||
VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool classOnly,
|
VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool fallback,
|
||||||
const string& forWhat) {
|
bool classOnly, const string& forWhat) {
|
||||||
if (nodep->classOrPackageSkipp()) return getNodeSym(nodep->classOrPackageSkipp());
|
if (nodep->classOrPackageSkipp()) return getNodeSym(nodep->classOrPackageSkipp());
|
||||||
VSymEnt* foundp = lookSymp->findIdFallback(nodep->name());
|
VSymEnt* foundp;
|
||||||
|
if (fallback) {
|
||||||
|
foundp = lookSymp->findIdFallback(nodep->name());
|
||||||
|
} else {
|
||||||
|
foundp = lookSymp->findIdFlat(nodep->name());
|
||||||
|
}
|
||||||
if (!foundp && v3Global.rootp()->stdPackagep()) { // Look under implied std::
|
if (!foundp && v3Global.rootp()->stdPackagep()) { // Look under implied std::
|
||||||
foundp = getNodeSym(v3Global.rootp()->stdPackagep())->findIdFlat(nodep->name());
|
foundp = getNodeSym(v3Global.rootp()->stdPackagep())->findIdFlat(nodep->name());
|
||||||
}
|
}
|
||||||
|
|
@ -1038,12 +1043,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstClassOrPackageRef* nodep) override {
|
void visit(AstClassOrPackageRef* nodep) override {
|
||||||
if (!nodep->classOrPackageNodep()) {
|
if (!nodep->classOrPackageNodep() && nodep->name() == "$unit") {
|
||||||
if (nodep->name() == "$unit") {
|
|
||||||
nodep->classOrPackageNodep(v3Global.rootp()->dollarUnitPkgAddp());
|
nodep->classOrPackageNodep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||||
} else if (nodep->name() == "std") {
|
|
||||||
nodep->classOrPackageNodep(v3Global.rootp()->stdPackagep());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
|
|
@ -1183,7 +1184,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
|
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
|
||||||
if (dotp) {
|
if (dotp) {
|
||||||
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
|
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
|
||||||
m_statep->resolveClassOrPackage(m_curSymp, lhsp, false,
|
m_statep->resolveClassOrPackage(m_curSymp, lhsp, true, false,
|
||||||
"External definition :: reference");
|
"External definition :: reference");
|
||||||
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
|
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
|
||||||
if (!lhsclassp) {
|
if (!lhsclassp) {
|
||||||
|
|
@ -1192,7 +1193,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
m_curSymp = m_statep->getNodeSym(lhsclassp);
|
m_curSymp = m_statep->getNodeSym(lhsclassp);
|
||||||
upSymp = m_curSymp;
|
upSymp = m_curSymp;
|
||||||
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
|
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
|
||||||
m_statep->resolveClassOrPackage(m_curSymp, rhsp, false,
|
m_statep->resolveClassOrPackage(m_curSymp, rhsp, true, false,
|
||||||
"External definition :: reference");
|
"External definition :: reference");
|
||||||
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
|
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
|
||||||
if (!rhsclassp) {
|
if (!rhsclassp) {
|
||||||
|
|
@ -1211,7 +1212,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
} else if (cpackagerefp) {
|
} else if (cpackagerefp) {
|
||||||
if (!cpackagerefp->classOrPackageSkipp()) {
|
if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false,
|
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, true, false,
|
||||||
"External definition :: reference");
|
"External definition :: reference");
|
||||||
}
|
}
|
||||||
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
|
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
|
||||||
|
|
@ -1338,7 +1339,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
"Unsupported: extern constraint definition with class-in-class");
|
"Unsupported: extern constraint definition with class-in-class");
|
||||||
} else {
|
} else {
|
||||||
if (!cpackagerefp->classOrPackageSkipp()) {
|
if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false,
|
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, true, false,
|
||||||
"External definition :: reference");
|
"External definition :: reference");
|
||||||
}
|
}
|
||||||
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
|
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
|
||||||
|
|
@ -2255,6 +2256,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
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
|
bool m_explicitSuperNew = false; // Hit a "super.new" call inside a "new" function
|
||||||
std::map<AstNode*, AstPin*> m_usedPins; // Pin used in this cell, map to duplicate
|
std::map<AstNode*, AstPin*> m_usedPins; // Pin used in this cell, map to duplicate
|
||||||
|
std::map<std::string, AstNodeModule*> m_modulesToRevisit; // Modules to revisit a second time
|
||||||
|
AstNode* m_lastDeferredp = nullptr; // Last node which requested a revisit of its module
|
||||||
|
|
||||||
struct DotStates final {
|
struct DotStates final {
|
||||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||||
|
|
@ -2500,6 +2503,13 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
symIterateNull(nodep, m_statep->getNodeSym(nodep));
|
symIterateNull(nodep, m_statep->getNodeSym(nodep));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marks the current module to be revisited after the initial AST iteration
|
||||||
|
void revisitLater(AstNode* deferredNodep) {
|
||||||
|
// Need to revisit entire module to build up all the necessary context
|
||||||
|
m_lastDeferredp = deferredNodep;
|
||||||
|
m_modulesToRevisit.insert(std::make_pair(m_modp->name(), m_modp));
|
||||||
|
}
|
||||||
|
|
||||||
void updateVarUse(AstVar* nodep) {
|
void updateVarUse(AstVar* nodep) {
|
||||||
// Avoid dotted.PARAM false positive when in a parameter block
|
// Avoid dotted.PARAM false positive when in a parameter block
|
||||||
// that is if ()'ed off by same dotted name as another block
|
// that is if ()'ed off by same dotted name as another block
|
||||||
|
|
@ -2744,12 +2754,58 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)
|
} else if (AstClassOrPackageRef* const lhsp
|
||||||
|| (VN_IS(nodep->lhsp(), Dot) && VN_AS(nodep->lhsp(), Dot)->colon())) {
|
= VN_CAST(nodep->lhsp(), ClassOrPackageRef)) {
|
||||||
// m_ds.m_dotText communicates the cell prefix between stages
|
// m_ds.m_dotText communicates the cell prefix between stages
|
||||||
m_ds.m_dotPos = DP_PACKAGE;
|
|
||||||
UINFO(8, indent() << "iter.lhs " << m_ds.ascii() << " " << nodep << endl);
|
UINFO(8, indent() << "iter.lhs " << m_ds.ascii() << " " << nodep << endl);
|
||||||
|
iterateAndNextNull(lhsp);
|
||||||
|
if (!lhsp->classOrPackageSkipp() && lhsp->name() != "local::") {
|
||||||
|
revisitLater(nodep);
|
||||||
|
m_ds = lastStates;
|
||||||
|
// Resolve function args before bailing
|
||||||
|
if (AstNodeFTaskRef* const ftaskrefp = VN_CAST(nodep->rhsp(), NodeFTaskRef)) {
|
||||||
|
iterateAndNextNull(ftaskrefp->pinsp());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_ds.m_dotPos = DP_PACKAGE;
|
||||||
|
// nodep->lhsp() may be a new node
|
||||||
|
if (AstClassOrPackageRef* const classOrPackageRefp
|
||||||
|
= VN_CAST(nodep->lhsp(), ClassOrPackageRef)) {
|
||||||
|
if (AstNode* const classOrPackageNodep
|
||||||
|
= classOrPackageRefp->classOrPackageSkipp()) {
|
||||||
|
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackageNodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UINFO(8, indent() << "iter.ldone " << m_ds.ascii() << " " << nodep << endl);
|
||||||
|
} else if (VN_IS(nodep->lhsp(), Dot) && VN_AS(nodep->lhsp(), Dot)->colon()) {
|
||||||
|
// m_ds.m_dotText communicates the cell prefix between stages
|
||||||
|
UINFO(8, indent() << "iter.lhs " << m_ds.ascii() << " " << nodep << endl);
|
||||||
|
m_ds.m_dotPos = DP_PACKAGE;
|
||||||
iterateAndNextNull(nodep->lhsp());
|
iterateAndNextNull(nodep->lhsp());
|
||||||
|
// nodep->lhsp() may be a new node
|
||||||
|
if (AstClassOrPackageRef* const crefp
|
||||||
|
= VN_CAST(nodep->lhsp(), ClassOrPackageRef)) {
|
||||||
|
if (!crefp->classOrPackageSkipp()) {
|
||||||
|
revisitLater(nodep);
|
||||||
|
m_ds = lastStates;
|
||||||
|
// Resolve function args before bailing
|
||||||
|
if (AstNodeFTaskRef* const ftaskrefp
|
||||||
|
= VN_CAST(nodep->rhsp(), NodeFTaskRef)) {
|
||||||
|
iterateAndNextNull(ftaskrefp->pinsp());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_lastDeferredp == nodep->lhsp()) {
|
||||||
|
// LHS got deferred, so this node won't be resolved. Defer it too
|
||||||
|
m_ds = lastStates;
|
||||||
|
// Resolve function args before bailing
|
||||||
|
if (AstNodeFTaskRef* const ftaskrefp = VN_CAST(nodep->rhsp(), NodeFTaskRef)) {
|
||||||
|
iterateAndNextNull(ftaskrefp->pinsp());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
UINFO(8, indent() << "iter.ldone " << m_ds.ascii() << " " << nodep << endl);
|
UINFO(8, indent() << "iter.ldone " << m_ds.ascii() << " " << nodep << endl);
|
||||||
} else {
|
} else {
|
||||||
m_ds.m_dotPos = DP_FIRST;
|
m_ds.m_dotPos = DP_FIRST;
|
||||||
|
|
@ -2932,10 +2988,15 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
first = true;
|
first = true;
|
||||||
} else if (!cpackagerefp->classOrPackageSkipp()) {
|
} else if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
||||||
m_ds.m_dotSymp, cpackagerefp, false, ":: reference");
|
m_ds.m_dotSymp, cpackagerefp, true, false, ":: reference");
|
||||||
if (!foundp) return;
|
if (!foundp) return;
|
||||||
classOrPackagep = cpackagerefp->classOrPackageSkipp();
|
classOrPackagep = cpackagerefp->classOrPackageSkipp();
|
||||||
|
if (classOrPackagep) {
|
||||||
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep);
|
m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep);
|
||||||
|
} else {
|
||||||
|
m_ds = lastStates;
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
classOrPackagep = cpackagerefp->classOrPackageSkipp();
|
classOrPackagep = cpackagerefp->classOrPackageSkipp();
|
||||||
UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link");
|
UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link");
|
||||||
|
|
@ -3293,12 +3354,15 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
VL_RESTORER(m_pinSymp);
|
VL_RESTORER(m_pinSymp);
|
||||||
|
|
||||||
if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") {
|
if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") {
|
||||||
m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, false, ":: reference");
|
m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, m_ds.m_dotPos != DP_PACKAGE,
|
||||||
|
false, ":: reference");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClassRef's have pins, so track
|
// ClassRef's have pins, so track
|
||||||
if (nodep->classOrPackageSkipp()) {
|
if (nodep->classOrPackageSkipp()) {
|
||||||
m_pinSymp = m_statep->getNodeSym(nodep->classOrPackageSkipp());
|
m_pinSymp = m_statep->getNodeSym(nodep->classOrPackageSkipp());
|
||||||
|
} else if (nodep->name() != "local::") {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
AstClass* const refClassp = VN_CAST(nodep->classOrPackageSkipp(), Class);
|
AstClass* const refClassp = VN_CAST(nodep->classOrPackageSkipp(), Class);
|
||||||
// Make sure any extends() are properly imported within referenced class
|
// Make sure any extends() are properly imported within referenced class
|
||||||
|
|
@ -3608,7 +3672,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
first = true;
|
first = true;
|
||||||
} else if (!cpackagerefp->classOrPackageSkipp()) {
|
} else if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
||||||
m_ds.m_dotSymp, cpackagerefp, false, ":: reference");
|
m_ds.m_dotSymp, cpackagerefp, true, false, ":: reference");
|
||||||
if (foundp) nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
if (foundp) nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
||||||
} else {
|
} else {
|
||||||
nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
||||||
|
|
@ -3968,7 +4032,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
iterate(lookNodep);
|
iterate(lookNodep);
|
||||||
cprp = dotp->rhsp();
|
cprp = dotp->rhsp();
|
||||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
||||||
lookSymp, lookNodep, false, nodep->verilogKwd());
|
lookSymp, lookNodep, true, false, nodep->verilogKwd());
|
||||||
if (!foundp) return;
|
if (!foundp) return;
|
||||||
UASSERT_OBJ(lookNodep->classOrPackageSkipp(), nodep, "Bad package link");
|
UASSERT_OBJ(lookNodep->classOrPackageSkipp(), nodep, "Bad package link");
|
||||||
lookSymp = m_statep->getNodeSym(lookNodep->classOrPackageSkipp());
|
lookSymp = m_statep->getNodeSym(lookNodep->classOrPackageSkipp());
|
||||||
|
|
@ -3984,7 +4048,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(lookSymp, cpackagerefp, true,
|
VSymEnt* const foundp = m_statep->resolveClassOrPackage(lookSymp, cpackagerefp, true,
|
||||||
nodep->verilogKwd());
|
true, nodep->verilogKwd());
|
||||||
if (foundp) {
|
if (foundp) {
|
||||||
if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) {
|
if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) {
|
||||||
AstPin* paramsp = cpackagerefp->paramsp();
|
AstPin* paramsp = cpackagerefp->paramsp();
|
||||||
|
|
@ -4151,7 +4215,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
if (!cpackagerefp->classOrPackageSkipp()) {
|
if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
VSymEnt* const foundp = m_statep->resolveClassOrPackage(
|
||||||
m_ds.m_dotSymp, cpackagerefp, false, "class/package reference");
|
m_ds.m_dotSymp, cpackagerefp, true, false, "class/package reference");
|
||||||
if (!foundp) return;
|
if (!foundp) return;
|
||||||
}
|
}
|
||||||
nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
||||||
|
|
@ -4327,6 +4391,13 @@ public:
|
||||||
: m_statep{statep} {
|
: m_statep{statep} {
|
||||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||||
iterate(rootp);
|
iterate(rootp);
|
||||||
|
std::map<std::string, AstNodeModule*> modulesToRevisit = std::move(m_modulesToRevisit);
|
||||||
|
m_lastDeferredp = nullptr;
|
||||||
|
for (auto& p : modulesToRevisit) {
|
||||||
|
AstNodeModule* const modp = p.second;
|
||||||
|
modp->foreach([](AstNode* const nodep) { nodep->user3(false); });
|
||||||
|
iterate(modp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
~LinkDotResolveVisitor() override = default;
|
~LinkDotResolveVisitor() override = default;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -712,7 +712,7 @@ void V3ParseImp::tokenPipelineSym() {
|
||||||
} else { // Not found
|
} else { // Not found
|
||||||
yylval.scp = nullptr;
|
yylval.scp = nullptr;
|
||||||
if (token == yaID__CC) {
|
if (token == yaID__CC) {
|
||||||
if (!v3Global.opt.bboxUnsup()) {
|
if (!m_afterColonColon & !v3Global.opt.bboxUnsup()) {
|
||||||
// IEEE does require this, but we may relax this as UVM breaks it, so allow
|
// IEEE does require this, but we may relax this as UVM breaks it, so allow
|
||||||
// bbox for today
|
// bbox for today
|
||||||
// We'll get a parser error eventually but might not be obvious
|
// We'll get a parser error eventually but might not be obvious
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
typedef class Bar;
|
||||||
|
typedef Bar Baz;
|
||||||
|
|
||||||
|
module t;
|
||||||
|
initial begin
|
||||||
|
Bar::Qux::boo(1);
|
||||||
|
Baz::Qux::boo(1);
|
||||||
|
if (!Bar::Qux::finish) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
class Foo #(type T);
|
||||||
|
static logic finish = 0;
|
||||||
|
static function void boo(input logic rec);
|
||||||
|
if (rec) Bar::Qux::boo(0);
|
||||||
|
finish = 1;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Goo #(type T);
|
||||||
|
function void goo();
|
||||||
|
T::Qux::boo(1);
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
typedef Foo#(Bar) Qux;
|
||||||
|
endclass
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
%Error: t/t_interface_colon_bad.v:14:7: Package/class for ':: reference' not found: 'iface'
|
%Error: t/t_interface_colon_bad.v:14:7: Package/class for ':: reference' not found: 'iface'
|
||||||
14 | iface::func();
|
14 | iface::func();
|
||||||
| ^~~~~
|
| ^~~~~
|
||||||
%Error: t/t_interface_colon_bad.v:14:14: Can't find definition of task/function: 'func'
|
|
||||||
14 | iface::func();
|
|
||||||
| ^~~~
|
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
%Error-PKGNODECL: t/t_package_identifier_bad.v:15:20: Package/class 'Bar' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
|
%Error: t/t_package_identifier_bad.v:15:20: Package/class for ':: reference' not found: 'Bar'
|
||||||
15 | int baz = Foo::Bar::baz;
|
15 | int baz = Foo::Bar::baz;
|
||||||
| ^~~
|
| ^~~
|
||||||
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
|
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
static function int get(int x);
|
||||||
|
return x;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
static function int get;
|
||||||
|
return 42;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Qux #(type Tfoo, type Tbar);
|
||||||
|
static function int get();
|
||||||
|
return Tfoo::get(Tbar::get());
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
initial begin
|
||||||
|
if (Qux#(Foo, Bar)::get() != 42) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -11,6 +11,6 @@ import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('linter')
|
test.scenarios('linter')
|
||||||
|
|
||||||
test.lint(verilator_flags2=["-DTEST_DECLARE_STD"], fails=test.vlt_all) # Issue #4705 due to ::
|
test.lint(verilator_flags2=["-DTEST_DECLARE_STD"])
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
%Error-PKGNODECL: t/t_std_identifier.v:16:20: Package/class 'std' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
|
%Error: t/t_std_identifier.v:16:20: Package/class for ':: reference' not found: 'std'
|
||||||
|
16 | int baz = foo::std::bar;
|
||||||
|
| ^~~
|
||||||
|
%Error: t/t_std_identifier.v:16:25: Can't find definition of scope/variable/func: 'bar'
|
||||||
16 | int baz = foo::std::bar;
|
16 | int baz = foo::std::bar;
|
||||||
| ^~~
|
| ^~~
|
||||||
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
|
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue