Internals: Decouple Bison class/package symbol table parsing from Link symbol table. (#5629)

Not intended to change non-error cases, but side-effects are likely.
This commit is contained in:
Wilson Snyder 2024-11-24 18:19:19 -05:00 committed by GitHub
parent 749b0345df
commit f5ee7aa0ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 32 deletions

View File

@ -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)

View File

@ -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()
: "<unresolved-object>")

View File

@ -7295,12 +7295,12 @@ packageClassScopeItem<nodeExprp>: // IEEE: package_scope or [package_scope]::[
idCC
/*mid*/ { SYMP->nextId($<scp>1); }
/*cont*/ yP_COLONCOLON
{ $$ = new AstClassOrPackageRef{$<fl>1, *$1, $<scp>1, nullptr}; $<scp>$ = $<scp>1; }
{ $$ = new AstClassOrPackageRef{$<fl>1, *$1, nullptr, nullptr}; $<scp>$ = $<scp>1; }
//
| idCC parameter_value_assignmentClass
/*mid*/ { SYMP->nextId($<scp>1); } // Change next *after* we handle parameters, not before
/*cont*/ yP_COLONCOLON
{ $$ = new AstClassOrPackageRef{$<fl>1, *$1, $<scp>1, $2}; $<scp>$ = $<scp>1; }
{ $$ = new AstClassOrPackageRef{$<fl>1, *$1, nullptr, $2}; $<scp>$ = $<scp>1; }
;
dollarUnitNextId<nodeExprp>: // $unit

View File

@ -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

View File

@ -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