diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 27a8457ac..4643a5e10 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1191,6 +1191,8 @@ class AstDot final : public AstNodeExpr { // These are eliminated in the link stage // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr + // + // We don't have a list of elements as it's probably legal to do '(foo.bar).(baz.bap)' const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) public: AstDot(FileLine* fl, bool colon, AstNodeExpr* lhsp, AstNodeExpr* rhsp) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 722bf54f8..40aa0a413 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -765,6 +765,25 @@ public: if (!foundp) baddot = dotname; return foundp; } + VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool classOnly, + const string& forWhat) { + if (nodep->classOrPackagep()) return getNodeSym(nodep->classOrPackagep()); + VSymEnt* foundp = lookSymp->findIdFallback(nodep->name()); + if (!foundp && v3Global.rootp()->stdPackagep()) { // Look under implied std:: + foundp = getNodeSym(v3Global.rootp()->stdPackagep())->findIdFlat(nodep->name()); + } + if (foundp) { + nodep->classOrPackageNodep(foundp->nodep()); + return foundp; + } + const string suggest + = suggestSymFallback(lookSymp, nodep->name(), LinkNodeMatcherClassOrPackage{}); + nodep->v3error((classOnly ? "Class" : "Package/class") + << " for '" << forWhat // extends/implements + << "' not found: " << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + return nullptr; + } string suggestSymFallback(VSymEnt* lookupSymp, const string& name, const VNodeMatcher& matcher) { // Suggest alternative symbol in given point in hierarchy @@ -1163,6 +1182,10 @@ class LinkDotFindVisitor final : public VNVisitor { nodep->v3warn(E_UNSUPPORTED, "Unsupported: extern function definition with class-in-class"); } else { + if (!cpackagerefp->classOrPackagep()) { + m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false, + "External definition :: reference"); + } AstClass* const classp = VN_CAST(cpackagerefp->classOrPackagep(), Class); if (!classp) { nodep->v3error("Extern declaration's scope is not a defined class"); @@ -2309,23 +2332,6 @@ class LinkDotResolveVisitor final : public VNVisitor { UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName); return ifaceTopVarp; } - VSymEnt* findClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool classOnly, - const string& forWhat) { - if (nodep->classOrPackagep()) return m_statep->getNodeSym(nodep->classOrPackagep()); - VSymEnt* const foundp = lookSymp->findIdFallback(nodep->name()); - if (foundp) { - nodep->classOrPackageNodep(foundp->nodep()); - return foundp; - } else { - const string suggest = m_statep->suggestSymFallback(lookSymp, nodep->name(), - LinkNodeMatcherClassOrPackage{}); - nodep->v3error((classOnly ? "Class" : "Package/Class") - << " for '" << forWhat // extends/implements - << "' not found: " << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - return nullptr; - } - } void markAndCheckPinDup(AstPin* nodep, AstNode* refp, const char* whatp) { const auto pair = m_usedPins.emplace(refp, nodep); if (!pair.second) { @@ -2839,6 +2845,7 @@ class LinkDotResolveVisitor final : public VNVisitor { allowVar = true; allowFTask = true; staticAccess = true; + UINFO(9, "chk pkg " << m_ds.ascii() << " lhsp=" << m_ds.m_dotp->lhsp() << endl); UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); AstClassOrPackageRef* const cpackagerefp @@ -2846,6 +2853,12 @@ class LinkDotResolveVisitor final : public VNVisitor { if (cpackagerefp->name() == "local::") { m_randSymp = nullptr; first = true; + } else if (!cpackagerefp->classOrPackagep()) { + VSymEnt* const foundp = m_statep->resolveClassOrPackage( + m_ds.m_dotSymp, cpackagerefp, false, ":: reference"); + if (!foundp) return; + classOrPackagep = cpackagerefp->classOrPackagep(); + m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep); } else { classOrPackagep = cpackagerefp->classOrPackagep(); UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link"); @@ -3197,12 +3210,15 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep, "ClassRef has unlinked class"); UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep, "class reference parameter not removed by V3Param"); - { - // ClassRef's have pins, so track VL_RESTORER(m_ds); VL_RESTORER(m_pinSymp); + if (!nodep->classOrPackagep() && nodep->name() != "local::") { + m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, false, ":: reference"); + } + + // ClassRef's have pins, so track if (nodep->classOrPackagep()) { m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep()); } @@ -3237,6 +3253,10 @@ class LinkDotResolveVisitor final : public VNVisitor { return; } } + if (m_ds.m_dotPos == DP_PACKAGE && nodep->classOrPackagep()) { + m_ds.m_dotSymp = m_statep->getNodeSym(nodep->classOrPackagep()); + UINFO(9, indent() << "set sym " << m_ds.ascii() << endl); + } } void visit(AstConstraintRef* nodep) override { if (nodep->user3SetOnce()) return; @@ -3485,9 +3505,11 @@ class LinkDotResolveVisitor final : public VNVisitor { if (cpackagerefp->name() == "local::") { m_randSymp = nullptr; first = true; + } else if (!cpackagerefp->classOrPackagep()) { + VSymEnt* const foundp = m_statep->resolveClassOrPackage( + m_ds.m_dotSymp, cpackagerefp, false, ":: reference"); + if (foundp) nodep->classOrPackagep(cpackagerefp->classOrPackagep()); } else { - UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), - "Bad package link"); nodep->classOrPackagep(cpackagerefp->classOrPackagep()); } // Class/package :: HERE function() . method_called_on_function_return_value() @@ -3860,8 +3882,8 @@ class LinkDotResolveVisitor final : public VNVisitor { if (AstClassOrPackageRef* lookNodep = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { iterate(lookNodep); cprp = dotp->rhsp(); - VSymEnt* const foundp - = findClassOrPackage(lookSymp, lookNodep, false, nodep->verilogKwd()); + VSymEnt* const foundp = m_statep->resolveClassOrPackage( + lookSymp, lookNodep, false, nodep->verilogKwd()); if (!foundp) return; UASSERT_OBJ(lookNodep->classOrPackagep(), nodep, "Bad package link"); lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); @@ -3876,8 +3898,8 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE return; } - VSymEnt* const foundp - = findClassOrPackage(lookSymp, cpackagerefp, true, nodep->verilogKwd()); + VSymEnt* const foundp = m_statep->resolveClassOrPackage(lookSymp, cpackagerefp, true, + nodep->verilogKwd()); if (foundp) { if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) { AstPin* paramsp = cpackagerefp->paramsp(); @@ -4036,10 +4058,16 @@ class LinkDotResolveVisitor final : public VNVisitor { iterate(cpackagep); return; } + if (!cpackagerefp->classOrPackagep()) { + VSymEnt* const foundp = m_statep->resolveClassOrPackage( + m_ds.m_dotSymp, cpackagerefp, false, "class/package reference"); + if (!foundp) return; + } nodep->classOrPackagep(cpackagerefp->classOrPackagep()); if (!VN_IS(nodep->classOrPackagep(), Class) && !VN_IS(nodep->classOrPackagep(), Package)) { - cpackagerefp->v3error( + // Likely impossible, as error thrown earlier + cpackagerefp->v3error( // LCOV_EXCL_LINE "'::' expected to reference a class/package but referenced '" << (nodep->classOrPackagep() ? nodep->classOrPackagep()->prettyTypeName() : "") diff --git a/src/verilog.y b/src/verilog.y index 47741bcfc..2ce3e4b08 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7295,12 +7295,12 @@ packageClassScopeItem: // IEEE: package_scope or [package_scope]::[ idCC /*mid*/ { SYMP->nextId($1); } /*cont*/ yP_COLONCOLON - { $$ = new AstClassOrPackageRef{$1, *$1, $1, nullptr}; $$ = $1; } + { $$ = new AstClassOrPackageRef{$1, *$1, nullptr, nullptr}; $$ = $1; } // | idCC parameter_value_assignmentClass /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before /*cont*/ yP_COLONCOLON - { $$ = new AstClassOrPackageRef{$1, *$1, $1, $2}; $$ = $1; } + { $$ = new AstClassOrPackageRef{$1, *$1, nullptr, $2}; $$ = $1; } ; dollarUnitNextId: // $unit diff --git a/test_regress/t/t_class_mod_bad.out b/test_regress/t/t_class_mod_bad.out index 08ae3c20d..359343923 100644 --- a/test_regress/t/t_class_mod_bad.out +++ b/test_regress/t/t_class_mod_bad.out @@ -1,5 +1,7 @@ -%Error: t/t_class_mod_bad.v:21:7: '::' expected to reference a class/package but referenced 'MODULE 'M'' - : ... Suggest '.' instead of '::' +%Error: t/t_class_mod_bad.v:21:7: Package/class for ':: reference' not found: 'M' + 21 | M::Cls p; + | ^ +%Error: t/t_class_mod_bad.v:21:7: Package/class for 'class/package reference' not found: 'M' 21 | M::Cls p; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_ref_bad.out b/test_regress/t/t_class_ref_bad.out index d11276ec2..e675eef7e 100644 --- a/test_regress/t/t_class_ref_bad.out +++ b/test_regress/t/t_class_ref_bad.out @@ -1,4 +1,5 @@ -%Error: Internal Error: t/t_class_ref_bad.v:15:11: ../V3LinkDot.cpp:#: Bad package link +%Error: t/t_class_ref_bad.v:15:11: Package/class for ':: reference' not found: 'ClsRigh' + : ... Suggested alternative: 'ClsRight' 15 | s = ClsRigh::m_s; | ^~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html for more assistance. +%Error: Exiting due to