From 15d1751b23097af47ddd2a92531b173c04d11af8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Nov 2024 19:34:00 -0500 Subject: [PATCH] Internals: Defer `class extends` resolution until link --- src/V3LinkDot.cpp | 35 ++++++++++++++++++----- src/verilog.y | 4 +-- test_regress/t/t_class_extends_nf_bad.out | 8 ++++-- test_regress/t/t_class_extends_nf_bad.v | 10 ++++++- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index bb842f9dd..7471e755e 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -84,6 +84,12 @@ class LinkNodeMatcherClass final : public VNodeMatcher { public: bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Class); } }; +class LinkNodeMatcherClassOrPackage final : public VNodeMatcher { +public: + bool nodeMatch(const AstNode* nodep) const override { + return VN_IS(nodep, Class) || VN_IS(nodep, Package); + } +}; class LinkNodeMatcherFTask final : public VNodeMatcher { public: bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, NodeFTask); } @@ -2300,6 +2306,23 @@ 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) { @@ -3812,6 +3835,9 @@ 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()); + if (!foundp) return; UASSERT_OBJ(lookNodep->classOrPackagep(), nodep, "Bad package link"); lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); } else { @@ -3825,7 +3851,8 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE return; } - VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); + VSymEnt* const foundp + = findClassOrPackage(lookSymp, cpackagerefp, true, nodep->verilogKwd()); if (foundp) { if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) { AstPin* paramsp = cpackagerefp->paramsp(); @@ -3850,12 +3877,6 @@ class LinkDotResolveVisitor final : public VNVisitor { return; } } else { - const string suggest = m_statep->suggestSymFallback( - m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); - cpackagerefp->v3error( - "Class for '" << nodep->verilogKwd() // extends/implements - << "' not found: " << cpackagerefp->prettyNameQ() << '\n' - << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); return; } if (!nodep->childDTypep()) nodep->v3error("Attempting to extend using non-class"); diff --git a/src/verilog.y b/src/verilog.y index d795dd611..9854644fd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7227,12 +7227,12 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either ge idAny /*mid*/ { /* no nextId as not refing it above this*/ } /*cont*/ parameter_value_assignmentClassE - { $$ = new AstClassOrPackageRef{$1, *$1, $1, $3}; + { $$ = new AstClassOrPackageRef{$1, *$1, nullptr, $3}; $$ = $1; } | idCC /*mid*/ { /* no nextId as not refing it above this*/ } /*cont*/ parameter_value_assignmentClassE - { $$ = new AstClassOrPackageRef{$1, *$1, $1, $3}; + { $$ = new AstClassOrPackageRef{$1, *$1, nullptr, $3}; $$ = $1; } // // // package_sopeIdFollows expanded diff --git a/test_regress/t/t_class_extends_nf_bad.out b/test_regress/t/t_class_extends_nf_bad.out index d01cc3eea..b0aac0bf5 100644 --- a/test_regress/t/t_class_extends_nf_bad.out +++ b/test_regress/t/t_class_extends_nf_bad.out @@ -1,5 +1,9 @@ -%Error: t/t_class_extends_nf_bad.v:10:19: Class for 'extends' not found: 'IsNotFound' +%Error: t/t_class_extends_nf_bad.v:15:19: Class for 'extends' not found: 'IsNotFound' : ... Suggested alternative: 'IsFound' - 10 | class Cls extends IsNotFound; + 15 | class Cls extends IsNotFound; | ^~~~~~~~~~ +%Error: t/t_class_extends_nf_bad.v:18:25: Class for 'extends' not found: 'NotFound2' + : ... Suggested alternative: 'otFound2' + 18 | class Cls2 extends Pkg::NotFound2; + | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_nf_bad.v b/test_regress/t/t_class_extends_nf_bad.v index 2285ba8e6..533887e56 100644 --- a/test_regress/t/t_class_extends_nf_bad.v +++ b/test_regress/t/t_class_extends_nf_bad.v @@ -4,10 +4,18 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +package Pkg; +class otFound2; +endclass +endpackage + class IsFound; endclass -class Cls extends IsNotFound; +class Cls extends IsNotFound; // BAD: not found +endclass + +class Cls2 extends Pkg::NotFound2; // BAD: not found endclass module t (/*AUTOARG*/);