From 7f3e178b68375a07604e98374e6926a372caedcf Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 31 Jan 2023 04:20:56 +0100 Subject: [PATCH] Fix paramaterized class function linkage (#3917) * Visit function arguments even if the function is unlinkable * Don't use m_unlinedScopep in AstLambdaArgRef handling --- src/V3LinkDot.cpp | 71 +++++++++++++++++++--------------- test_regress/t/t_class_param.v | 25 ++++++++++++ 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7eb296357..13825a9f9 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2350,6 +2350,7 @@ private: // Dot(Dot(Dot(ParseRef(text), ... if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); + bool replaceWithRhs = true; const DotStates lastStates = m_ds; const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed { @@ -2401,14 +2402,13 @@ private: } if (m_statep->forPrimary() && isParamedClassRef(nodep->lhsp())) { // Dots of paramed classes will be linked after deparameterization - m_ds.m_dotPos = DP_NONE; - return; + m_ds.m_unresolved = true; + replaceWithRhs = false; } if (m_ds.m_unresolved && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScopep = nodep->lhsp(); } - if (VN_IS(nodep->lhsp(), LambdaArgRef)) m_ds.m_unlinkedScopep = nodep->lhsp(); if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS @@ -2417,16 +2417,17 @@ private: // if (debug() >= 9) nodep->dumpTree("- dot-rho: "); } if (start) { - AstNode* newp; - if (m_ds.m_dotErr) { - newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}}; - } else { - // RHS is what we're left with - newp = nodep->rhsp()->unlinkFrBack(); + if (replaceWithRhs) { + AstNode* newp; + if (m_ds.m_dotErr) { + newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}}; + } else { + newp = nodep->rhsp()->unlinkFrBack(); + } + if (debug() >= 9) newp->dumpTree("- dot-out: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - if (debug() >= 9) newp->dumpTree("- dot-out: "); - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { // Dot midpoint AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack(); if (m_ds.m_unresolved) { @@ -2452,6 +2453,7 @@ private: void visit(AstParseRef* nodep) override { if (nodep->user3SetOnce()) return; UINFO(9, " linkPARSEREF " << m_ds.ascii() << " n=" << nodep << endl); + if (m_ds.m_unresolved && !m_ds.m_unlinkedScopep) return; // m_curSymp is symbol table of outer expression // m_ds.m_dotSymp is symbol table relative to "."'s above now UASSERT_OBJ(m_ds.m_dotSymp, nodep, "nullptr lookup symbol table"); @@ -2492,7 +2494,7 @@ private: // If not, treat it as normal member select iterateChildren(nodep); const auto newp = new AstLambdaArgRef{ - nodep->fileline(), m_ds.m_unlinkedScopep->name() + "__DOT__index", true}; + nodep->fileline(), m_ds.m_dotp->lhsp()->name() + "__DOT__index", true}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; @@ -2941,7 +2943,29 @@ private: if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); UINFO(8, " " << m_ds.ascii() << endl); - if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { + { + // Visit arguments at the beginning. + // They may be visitted even if the current node can't be linked now. + VL_RESTORER(m_ds); + m_ds.init(m_curSymp); + iterateChildren(nodep); + } + + if (m_ds.m_unresolved) { + // Unable to link before V3Param + if (m_ds.m_dotPos == DP_FINAL && m_ds.m_unlinkedScopep) { + AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false); + newftaskp->dotted(m_ds.m_dotText); + AstNode* const newp + = new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(), + m_ds.m_unlinkedScopep->unlinkFrBack()}; + m_ds.m_unlinkedScopep = nullptr; + m_ds.m_unresolved = false; + nodep->replaceWith(newp); + } + // else: AstDot wasn't replaced and it will be linked after V3Param + return; + } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); AstClassOrPackageRef* const cpackagerefp @@ -2955,19 +2979,7 @@ private: m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { - if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) { - AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false); - newftaskp->dotted(m_ds.m_dotText); - AstNode* const newp - = new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(), - m_ds.m_unlinkedScopep->unlinkFrBack()}; - m_ds.m_unlinkedScopep = nullptr; - m_ds.m_unresolved = false; - nodep->replaceWith(newp); - return; - } else { - nodep->dotted(m_ds.m_dotText); // Maybe "" - } + nodep->dotted(m_ds.m_dotText); // Maybe "" } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is method call. // {scope}.{var}.HERE {method} ( ARGS ) @@ -3098,11 +3110,6 @@ private: } taskFuncSwapCheck(nodep); } - { - VL_RESTORER(m_ds); - m_ds.init(m_curSymp); - iterateChildren(nodep); - } } void visit(AstSelBit* nodep) override { if (nodep->user3SetOnce()) return; diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v index 5dfa4ee20..17fb452fb 100644 --- a/test_regress/t/t_class_param.v +++ b/test_regress/t/t_class_param.v @@ -54,6 +54,22 @@ class SelfRefClassIntParam #(int P=1); typedef SelfRefClassIntParam #(10) self_int_t; endclass +class Sum #(type T); + static int sum; + static function void add(T element); + sum += int'(element); + endfunction +endclass + +class IntQueue; + int q[$]; + function int getSum(); + foreach(q[i]) + Sum#(int)::add(q[i]); + return Sum#(int)::sum; + endfunction +endclass + module t (/*AUTOARG*/); Cls c12; @@ -65,6 +81,8 @@ module t (/*AUTOARG*/); SelfRefClassTypeParam::self_int_t src_int; SelfRefClassIntParam src1; SelfRefClassIntParam::self_int_t src10; + IntQueue qi; + int arr [1:0] = '{1, 2}; initial begin c12 = new; c4 = new; @@ -75,6 +93,7 @@ module t (/*AUTOARG*/); src_logic = new; src1 = new; src10 = new; + qi = new; if (Cls#()::PBASE != 12) $stop; if (Cls#(4)::PBASE != 4) $stop; if (Cls8_t::PBASE != 8) $stop; @@ -114,6 +133,12 @@ module t (/*AUTOARG*/); if (src1.P != 1) $stop; if (src10.P != 10) $stop; + qi.q = '{2, 4, 6, 0, 2}; + if (qi.getSum() != 14) $stop; + Sum#(int)::add(arr[0]); + if(Sum#(int)::sum != 16) $stop; + if(Sum#(real)::sum != 0) $stop; + $write("*-* All Finished *-*\n"); $finish; end