From 279216048b33dd5ffef06a40200aaf4613eac17d Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 16 May 2023 13:40:02 +0200 Subject: [PATCH] Fix dotted references in parameterized classes (#4206) --- src/V3LinkDot.cpp | 90 ++++++++++++++------------ test_regress/t/t_class_param_extends.v | 7 ++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index dd39277b6..72c3f762c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2772,49 +2772,57 @@ private: } } } - // Don't throw error ifthe reference is inside a class that extends a param, because - // some members can't be linked in such a case. m_insideClassExtParam may be true only - // in the first stage of linking. - if (!ok && !m_insideClassExtParam) { - // Cells/interfaces can't be implicit - const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; - const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); - const bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); - if (err) { - if (foundp) { - nodep->v3error("Found definition of '" - << m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".") - << nodep->prettyName() << "'" - << " as a " << foundp->nodep()->typeName() - << " but expected a " << expectWhat); - } else if (m_ds.m_dotText == "") { - UINFO(7, " ErrParseRef curSymp=se" << cvtToHex(m_curSymp) - << " ds=" << m_ds.ascii() << endl); - const string suggest = m_statep->suggestSymFallback( - m_ds.m_dotSymp, nodep->name(), VNodeMatcher{}); - nodep->v3error("Can't find definition of " - << expectWhat << ": " << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - } else { - nodep->v3error("Can't find definition of " - << (!baddot.empty() ? AstNode::prettyNameQ(baddot) - : nodep->prettyNameQ()) - << " in dotted " << expectWhat << ": '" - << m_ds.m_dotText + "." + nodep->prettyName() << "'"); - if (okSymp) { - okSymp->cellErrorScopes(nodep, AstNode::prettyName(m_ds.m_dotText)); + if (!ok) { + if (m_insideClassExtParam) { + // Don't throw error if the reference is inside a class that extends a param, + // because some members can't be linked in such a case. m_insideClassExtParam + // may be true only in the first stage of linking. + // Mark that the Dot statement can't be resolved. + m_ds.m_unresolvedClass = true; + } else { + // Cells/interfaces can't be implicit + const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; + const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); + const bool err + = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); + if (err) { + if (foundp) { + nodep->v3error("Found definition of '" + << m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".") + << nodep->prettyName() << "'" + << " as a " << foundp->nodep()->typeName() + << " but expected a " << expectWhat); + } else if (m_ds.m_dotText == "") { + UINFO(7, " ErrParseRef curSymp=se" + << cvtToHex(m_curSymp) << " ds=" << m_ds.ascii() << endl); + const string suggest = m_statep->suggestSymFallback( + m_ds.m_dotSymp, nodep->name(), VNodeMatcher{}); + nodep->v3error( + "Can't find definition of " + << expectWhat << ": " << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + } else { + nodep->v3error("Can't find definition of " + << (!baddot.empty() ? AstNode::prettyNameQ(baddot) + : nodep->prettyNameQ()) + << " in dotted " << expectWhat << ": '" + << m_ds.m_dotText + "." + nodep->prettyName() << "'"); + if (okSymp) { + okSymp->cellErrorScopes(nodep, + AstNode::prettyName(m_ds.m_dotText)); + } } + m_ds.m_dotErr = true; + } + if (checkImplicit) { + // Create if implicit, and also if error (so only complain once) + // Else if a scope is allowed, making a signal won't help error cascade + AstVarRef* const newp + = new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ}; + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); } - m_ds.m_dotErr = true; - } - if (checkImplicit) { - // Create if implicit, and also if error (so only complain once) - // Else if a scope is allowed, making a signal won't help error cascade - AstVarRef* const newp - = new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ}; - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); } } } diff --git a/test_regress/t/t_class_param_extends.v b/test_regress/t/t_class_param_extends.v index e63ccb0b5..5e59c09d2 100644 --- a/test_regress/t/t_class_param_extends.v +++ b/test_regress/t/t_class_param_extends.v @@ -34,8 +34,10 @@ class Getter2; endclass class Foo #(type T=Getter1); + T foo_field; int x; function new(int y); + foo_field = new; x = y; endfunction endclass @@ -50,6 +52,10 @@ class Bar #(type S=Getter2) extends Foo#(S); function int get_field_int; return field.get_int(); endfunction + + function int get_foo_field_int; + return foo_field.get_int(); + endfunction endclass // See also t_class_param_mod.v @@ -81,6 +87,7 @@ module t (/*AUTOARG*/); if (b.x != 1) $stop; if (b.get_field_int() != 2) $stop; + if (b.get_foo_field_int() != 2) $stop; $write("*-* All Finished *-*\n"); $finish;