From f1396fbced361b8a8d3339372cc0aa863eb8928a Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 10 Sep 2025 22:42:45 +0100 Subject: [PATCH] Fix memory leaks - batch 2 (#6417) --- src/V3Ast.h | 3 +- src/V3Broken.cpp | 4 +- src/V3Const.cpp | 2 - src/V3Control.cpp | 1 + src/V3DfgRegularize.cpp | 1 + src/V3LinkDot.cpp | 12 +- src/V3Param.cpp | 6 +- src/V3ParseGrammar.cpp | 36 +++-- src/V3ParseGrammar.h | 15 +- src/V3Simulate.h | 10 +- src/V3Task.cpp | 6 +- src/verilog.y | 245 ++++++++++++++++--------------- test_regress/t/t_fuzz_eof_bad.py | 3 + 13 files changed, 188 insertions(+), 156 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 88d295549..8a1f24e75 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2131,6 +2131,7 @@ public: protected: // CONSTRUCTORS AstNode(VNType t, FileLine* fl); + virtual ~AstNode() = default; // Use 'deleteTree' instead virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead virtual void cloneRelink() { cloneRelinkGen(); } virtual void cloneRelinkGen() {}; // Overrides generated by 'astgen' @@ -2208,8 +2209,6 @@ public: bool brokeExists() const { return V3Broken::isLinkable(this); } bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); } - // CONSTRUCTORS - virtual ~AstNode() = default; #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index f34c2b7cc..fa00fc436 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -371,12 +371,12 @@ void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = void V3Broken::selfTest() { // Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS FileLine* const fl = new FileLine{FileLine::commandLineFilename()}; - const AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr}; + AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr}; // Don't actually do it with VL_LEAK_CHECKS, when new/delete calls these. // Otherwise you call addNewed twice on the same address, which is an error. #ifndef VL_LEAK_CHECKS addNewed(newp); deleted(newp); #endif - VL_DO_DANGLING(delete newp, newp); + VL_DO_DANGLING(newp->deleteTree(), newp); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index e5bf9ecf5..05f92799d 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2717,8 +2717,6 @@ class ConstVisitor final : public VNVisitor { if (!cnt2p) return false; // from2p->unlinkFrBack(); - cnt1p->unlinkFrBack(); - cnt2p->unlinkFrBack(); AstReplicate* const newp = new AstReplicate{nodep->fileline(), from2p, cnt1p->toUInt() * cnt2p->toUInt()}; nodep->replaceWithKeepDType(newp); diff --git a/src/V3Control.cpp b/src/V3Control.cpp index 7b4225264..cef5ca180 100644 --- a/src/V3Control.cpp +++ b/src/V3Control.cpp @@ -679,6 +679,7 @@ void V3Control::addVarAttr(FileLine* fl, const string& module, const string& fta // Semantics: sensep only if public_flat_rw if ((attr != VAttrType::VAR_PUBLIC_FLAT_RW) && sensep) { sensep->v3error("sensitivity not expected for attribute"); + VL_DO_DANGLING(sensep->deleteTree(), sensep); return; } // Semantics: Most of the attributes operate on signals diff --git a/src/V3DfgRegularize.cpp b/src/V3DfgRegularize.cpp index 85093ebcf..9853f2bbe 100644 --- a/src/V3DfgRegularize.cpp +++ b/src/V3DfgRegularize.cpp @@ -125,6 +125,7 @@ class DfgRegularize final { // If it's an inlined expression, repalce the VarRef entirely if (AstNodeExpr* const newp = VN_CAST(replacementp, NodeExpr)) { refp->replaceWith(newp->cloneTreePure(false)); + VL_DO_DANGLING(refp->deleteTree(), refp); return; } // Otherwise just re-point the VarRef to the new variable diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2398d9795..2e752ad24 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -971,7 +971,8 @@ class LinkDotFindVisitor final : public VNVisitor { ifacecellp->modp(ifacerefp->ifacep()); m_curSymp = m_modSymp = m_statep->insertTopIface(ifacecellp, m_scope); - { iterate(ifacecellp); } + iterate(ifacecellp); + VL_DO_DANGLING(pushDeletep(ifacecellp), ifacecellp); } } } @@ -3330,12 +3331,12 @@ class LinkDotResolveVisitor final : public VNVisitor { return; } else if (m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is membership. {scope}.{var}.HERE {member} - AstNodeExpr* const varEtcp = VN_AS(m_ds.m_dotp->lhsp()->unlinkFrBack(), NodeExpr); - AstNodeExpr* const newp - = new AstMemberSel{nodep->fileline(), varEtcp, VFlagChildDType{}, nodep->name()}; if (m_ds.m_dotErr) { nodep->unlinkFrBack(); // Avoid circular node loop on errors } else { + AstNodeExpr* const varEtcp = VN_AS(m_ds.m_dotp->lhsp()->unlinkFrBack(), NodeExpr); + AstNodeExpr* const newp = new AstMemberSel{nodep->fileline(), varEtcp, // + VFlagChildDType{}, nodep->name()}; nodep->replaceWith(newp); } VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -3627,7 +3628,7 @@ class LinkDotResolveVisitor final : public VNVisitor { newp = new AstSelBit{cellarrayrefp->fileline(), newp, cellarrayrefp->selp()->unlinkFrBack()}; newp->user3(true); // Don't process again - VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp); + VL_DO_DANGLING(pushDeletep(cellarrayrefp->unlinkFrBack()), cellarrayrefp); m_ds.m_unlinkedScopep = nullptr; } nodep->replaceWith(newp); @@ -4131,6 +4132,7 @@ class LinkDotResolveVisitor final : public VNVisitor { m_ds.m_unlinkedScopep = nullptr; m_ds.m_unresolvedCell = false; nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); 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(), diff --git a/src/V3Param.cpp b/src/V3Param.cpp index b070261f9..3867e92d5 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -759,8 +759,10 @@ class ParamProcessor final { UINFOTREE(1, pinp, "", "errnode"); pinp->v3error("Can't convert defparam value to constant: Param " << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - pinp->exprp()->replaceWith(new AstConst{ - pinp->fileline(), AstConst::WidthedValue{}, modvarp->width(), 0}); + AstNode* const exprp = pinp->exprp(); + exprp->replaceWith(new AstConst{pinp->fileline(), AstConst::WidthedValue{}, + modvarp->width(), 0}); + VL_DO_DANGLING(exprp->deleteTree(), exprp); } else if (origp && exprp->sameTree(origp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index dfdb9edd7..163567a53 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -77,6 +77,7 @@ void V3ParseImp::candidatePli(VSpellCheck* spellerp) { void V3ParseImp::parserClear() { // Clear up any dynamic memory V3Parser required VARDTYPE(nullptr); + GRAMMARP->setNetDelay(nullptr); } //====================================================================== @@ -164,6 +165,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra || VN_IS(rangep->rightp(), Unbounded))) { arrayp = new AstQueueDType{nrangep->fileline(), VFlagChildDType{}, arrayp, rangep->rightp()->cloneTree(true)}; + VL_DO_DANGLING(nrangep->deleteTree(), nrangep); } else if (rangep) { arrayp = new AstUnpackArrayDType{rangep->fileline(), VFlagChildDType{}, arrayp, rangep}; @@ -190,9 +192,8 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, AstNode* attrsp) { - AstNodeDType* dtypep = GRAMMARP->m_varDTypep; - UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl - << " io=" << GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "")); + UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io=" + << GRAMMARP->m_varIO << " dt=" << (GRAMMARP->m_varDTypep ? "set" : "")); if (GRAMMARP->m_varIO == VDirection::NONE // In non-ANSI port list && GRAMMARP->m_varDecl == VVarType::PORT) { // Just a port list with variable name (not v2k format); AstPort already created @@ -203,23 +204,26 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, } return nullptr; } - if (GRAMMARP->m_varDecl == VVarType::WREAL) { - // dtypep might not be null, might be implicit LOGIC before we knew better - dtypep = new AstBasicDType{fileline, VBasicDTypeKwd::DOUBLE}; - } - if (!dtypep) { // Created implicitly + + AstNodeDType* const dtypep = [&]() -> AstNodeDType* { + if (GRAMMARP->m_varDecl == VVarType::WREAL) { + // dtypep might not be null, might be implicit LOGIC before we knew better + return new AstBasicDType{fileline, VBasicDTypeKwd::DOUBLE}; + } + if (GRAMMARP->m_varDTypep) { + // May make new variables with same type, so clone + return GRAMMARP->m_varDTypep->cloneTree(false); + } + // Created implicitly if (m_insideProperty) { if (m_typedPropertyPort) { fileline->v3warn(E_UNSUPPORTED, "Untyped property port following a typed port"); } - dtypep = new AstBasicDType{fileline, VBasicDTypeKwd::UNTYPED}; - } else { - dtypep = new AstBasicDType{fileline, LOGIC_IMPLICIT}; + return new AstBasicDType{fileline, VBasicDTypeKwd::UNTYPED}; } - } else { - // If already consumed by an earlier decl, clone it - if (dtypep->backp()) dtypep = dtypep->cloneTree(false); - } + return new AstBasicDType{fileline, LOGIC_IMPLICIT}; + }(); + // UINFO(0,"CREVAR "<ascii()<<" decl="<m_varDecl.ascii()<<" // io="<m_varIO.ascii()<m_varDecl; @@ -244,7 +248,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, nodep->ansi(m_pinAnsi); nodep->declTyped(m_varDeclTyped); nodep->lifetime(m_varLifetime); - nodep->delayp(getNetDelay()); + if (m_netDelayp) nodep->delayp(m_netDelayp->cloneTree(false)); if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varIO != VDirection::NONE) { nodep->declDirection(GRAMMARP->m_varIO); diff --git a/src/V3ParseGrammar.h b/src/V3ParseGrammar.h index 5cb08aaa7..8934fed02 100644 --- a/src/V3ParseGrammar.h +++ b/src/V3ParseGrammar.h @@ -29,8 +29,7 @@ public: AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration - std::unique_ptr m_netDelayp = nullptr; // Pointer to delay for next signal - // declaration + AstDelay* m_netDelayp = nullptr; // Pointer to delay for next signal declaration AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations AstPin* m_instParamp = nullptr; // Parameters for instantiations @@ -212,13 +211,19 @@ public: } } void setDType(AstNodeDType* dtypep) { - if (m_varDTypep && !m_varDTypep->backp()) { + if (m_varDTypep) { + UASSERT_OBJ(!m_varDTypep->backp(), m_varDTypep, "Should not link directly"); VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr); } m_varDTypep = dtypep; } - void setNetDelay(AstDelay* netDelayp) { m_netDelayp.reset(netDelayp); } - AstDelay* getNetDelay() { return m_netDelayp.release(); } + void setNetDelay(AstDelay* netDelayp) { + if (m_netDelayp) { + UASSERT_OBJ(!m_netDelayp->backp(), m_netDelayp, "Should not link directly"); + VL_DO_CLEAR(m_netDelayp->deleteTree(), m_netDelayp = nullptr); + } + m_netDelayp = netDelayp; + } void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } void pinPush() { m_pinStack.push(m_pinNum); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index d376ba648..2c4c6a824 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -820,6 +820,7 @@ private: } else { outconstp->num().setAllBitsX(); } + m_reclaimValuesp.emplace_back(outconstp); } outconstp->num().opSelInto(fetchConst(valueFromp)->num(), lsb, selp->widthConst()); assignOutValue(nodep, vscp, outconstp); @@ -870,6 +871,7 @@ private: selp->lhsp()->width() + selp->rhsp()->width() + 1, selp->rhsp()->width()); newValue(selp->lhsp(), outconstp); + VL_DO_DANGLING(outconstp->deleteTree(), outconstp); } { AstConst* const outconstp @@ -878,6 +880,7 @@ private: outconstp->num().opSel(fetchConst(valueFromp)->num(), selp->rhsp()->width() - 1, 0); newValue(selp->rhsp(), outconstp); + VL_DO_DANGLING(outconstp->deleteTree(), outconstp); } } handleAssignRecurse(nodep, selp->lhsp(), selp->lhsp()); @@ -1449,8 +1452,13 @@ public: } ~SimulateVisitor() override { m_constps.clear(); - for (AstNode* ip : m_reclaimValuesp) delete ip; + std::vector unusedRootps; + unusedRootps.reserve(m_reclaimValuesp.size()); + for (AstNode* const nodep : m_reclaimValuesp) { + if (!nodep->backp()) unusedRootps.emplace_back(nodep); + } m_reclaimValuesp.clear(); + for (AstNode* const nodep : unusedRootps) VL_DO_DANGLING(nodep->deleteTree(), nodep); } }; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index a3d815973..867d6b422 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1231,10 +1231,10 @@ class TaskVisitor final : public VNVisitor { UASSERT_OBJ(!(nodep->dpiOpenParent() && nodep->dpiOpenChild()), nodep, "DPI task should not be both parent and child"); dpiFuncp = getDpiFunc(nodep, rtnvarp); - if (!dpiFuncp) return nullptr; // There was an error, so bail - if (nodep->dpiImport() && nodep->dpiOpenParent()) { + if (!dpiFuncp || (nodep->dpiImport() && nodep->dpiOpenParent())) { // No need to make more than just the DPI Import prototype, the children will // create the wrapper implementations. + if (rtnvarp) VL_DO_DANGLING(pushDeletep(rtnvarp), rtnvarp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return nullptr; } @@ -1355,7 +1355,7 @@ class TaskVisitor final : public VNVisitor { for (AstNode *nextp, *stmtp = tempp->stmtsp(); stmtp; stmtp = nextp) { nextp = stmtp->nextp(); if (AstVar* const portp = VN_CAST(stmtp, Var)) { - if (portp->isIO()) portp->unlinkFrBack(); + if (portp->isIO()) VL_DO_DANGLING(pushDeletep(portp->unlinkFrBack()), portp); } } if (tempp->stmtsp()) cfuncp->addStmtsp(tempp->stmtsp()->unlinkFrBackWithNext()); diff --git a/src/verilog.y b/src/verilog.y index 4fbbdd836..dd2202b98 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -33,12 +33,6 @@ #define BBCOVERIGN(fl, msg) (fl)->v3warn(COVERIGN, msg) #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) -#define DELETE_ALL(...) \ - { \ - AstNode* nodeps[] = {__VA_ARGS__}; \ - for (AstNode* const nodep : nodeps) \ - if (nodep) nodep->deleteTree(); \ - } #define GATEUNSUP(fl, tok) \ { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } #define RISEFALLDLYUNSUP(nodep) \ @@ -60,6 +54,7 @@ auto* const assignp = VN_AS(nodep, NodeAssign); \ assignp->timingControlp(nodep == assignsp ? delayp : delayp->cloneTree(false)); \ } \ + if (!delayp->backp()) delayp->deleteTree(); \ } #define STRENGTHUNSUP(nodep) \ { \ @@ -131,9 +126,11 @@ const VBasicDTypeKwd LOGIC_IMPLICIT = VBasicDTypeKwd::LOGIC_IMPLICIT; GRAMMARP->m_instParamp = paramsp; \ } -#define DEL(nodep) \ +#define DEL(...) \ { \ - if (nodep) nodep->deleteTree(); \ + AstNode* nodeps[] = {__VA_ARGS__}; \ + for (AstNode* const nodep : nodeps) \ + if (nodep) nodep->deleteTree(); \ } // Apply a strength to a list of nodes under beginp @@ -1527,7 +1524,10 @@ interface_or_generate_item: // ==IEEE: interface_or_generate_item anonymous_program: // ==IEEE: anonymous_program // // See the spec - this doesn't change the scope, items still go up "top" yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM - { $$ = nullptr; BBUNSUP($1, "Unsupported: Anonymous programs"); } + { $$ = nullptr; + BBUNSUP($1, "Unsupported: Anonymous programs"); + VARDTYPE_NDECL(nullptr); + DEL($3); } ; anonymous_program_itemListE: // IEEE: { anonymous_program_item } @@ -1611,11 +1611,11 @@ program_generate_item: // ==IEEE: program_generate_item extern_tf_declaration: // ==IEEE: extern_tf_declaration yEXTERN task_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern task"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern task"); DEL($2); } | yEXTERN function_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern function"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern function"); DEL($2); } | yEXTERN yFORKJOIN task_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern forkjoin"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern forkjoin"); DEL($3); } ; modport_declaration: // ==IEEE: modport_declaration @@ -1661,9 +1661,9 @@ modportPortsDecl: GRAMMARP->m_modportImpExpActive = true; GRAMMARP->m_modportImpExpLastIsExport = true; } | yIMPORT method_prototype - { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport import with prototype"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport import with prototype"); DEL($2); } | yEXPORT method_prototype - { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport export with prototype"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport export with prototype"); DEL($2); } // Continuations of above after a comma. // // IEEE: modport_simple_ports_declaration | modportSimplePortOrTFPort { $$ = GRAMMARP->m_modportImpExpActive ? @@ -1909,7 +1909,7 @@ port_declaration: // ==IEEE: port_declaration dtp->isPortDecl(true); VARDTYPE(dtp); } /*cont*/ mpInstnameList - { $$ = VARDONEP($5, nullptr, nullptr); } + { $$ = VARDONEP($5, nullptr, nullptr); DEL($5); } //UNSUP: strengthSpecE for udp_instantiations ; @@ -2489,7 +2489,7 @@ type_declaration: // ==IEEE: type_declaration $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } // // | yTYPEDEF idAny/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); DEL($6); } // // idAny as also allows redeclaring same typedef again | yTYPEDEF idAny ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2, VFwdType::NONE); } // // IEEE: expanded forward_type to prevent conflict @@ -2594,7 +2594,7 @@ module_common_item: // ==IEEE: module_common_item | continuous_assign { $$ = $1; } // // IEEE: net_alias | yALIAS variable_lvalue aliasEqList ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: alias statements"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: alias statements"); DEL($2); } | initial_construct { $$ = $1; } | final_construct { $$ = $1; } | always_construct { $$ = $1; } @@ -2658,7 +2658,7 @@ bind_directive: // ==IEEE: bind_directive + bind_target_scope // // module_identifier or interface_identifier yBIND bind_target_instance bind_instantiation { $$ = new AstBind{$2, *$2, $3}; } | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation - { $$ = nullptr; BBUNSUP($1, "Unsupported: Bind with instance list"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: Bind with instance list"); DEL($5); } ; bind_target_instance_list: // ==IEEE: bind_target_instance_list @@ -2956,8 +2956,9 @@ netSig: // IEEE: net_decl_assignment - one element from netId sigAttrListE { $$ = VARDONEA($1, *$1, nullptr, $2); } | netId sigAttrListE '=' expr - { AstDelay* const delayp = GRAMMARP->getNetDelay(); + { AstDelay* const delayp = GRAMMARP->m_netDelayp ? GRAMMARP->m_netDelayp->cloneTree(false) : nullptr; AstAssignW* const assignp = new AstAssignW{$3, new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}, $4, delayp}; + GRAMMARP->setNetDelay(nullptr); $$ = VARDONEA($1, *$1, nullptr, $2); if (delayp) GRAMMARP->setNetDelay(delayp->cloneTree(false)); if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); @@ -2965,8 +2966,9 @@ netSig: // IEEE: net_decl_assignment - one element from | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1, *$1, $2, $3); } | netId variable_dimensionList sigAttrListE '=' expr - { AstDelay* const delayp = GRAMMARP->getNetDelay(); + { AstDelay* const delayp = GRAMMARP->m_netDelayp ? GRAMMARP->m_netDelayp->cloneTree(false) : nullptr; AstAssignW* const assignp = new AstAssignW{$4, new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}, $5, delayp}; + GRAMMARP->setNetDelay(nullptr); $$ = VARDONEA($1, *$1, $2, $3); if (delayp) GRAMMARP->setNetDelay(delayp->cloneTree(false)); if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); @@ -3107,7 +3109,7 @@ list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments defparam_assignment: // ==IEEE: defparam_assignment idAny '.' idAny '=' expr { $$ = new AstDefParam{$4, *$1, *$3, $5}; } | idAny '=' expr - { $$ = nullptr; BBUNSUP($2, "Unsupported: defparam with no dot"); } + { $$ = nullptr; BBUNSUP($2, "Unsupported: defparam with no dot"); DEL($3); } | idAny '.' idAny '.' { $$ = nullptr; BBUNSUP($4, "Unsupported: defparam with more than one dot"); } ; @@ -3492,7 +3494,7 @@ statement_item: // IEEE: statement_item | yASSIGN idClassSel '=' delay_or_event_controlE expr ';' { $$ = new AstAssign{$1, $2, $5, $4}; } | yDEASSIGN variable_lvalue ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); DEL($2); } | yFORCE variable_lvalue '=' expr ';' { $$ = new AstAssignForce{$1, $2, $4}; v3Global.setHasForceableSignals(); } | yRELEASE variable_lvalue ';' @@ -3506,7 +3508,7 @@ statement_item: // IEEE: statement_item if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } // &&& is part of expr so case_patternList aliases to case_itemList | unique_priorityE caseStart caseAttrE yMATCHES case_itemList yENDCASE - { $$ = nullptr; BBUNSUP($4, "Unsupported: matches (for tagged union)"); } + { $$ = nullptr; BBUNSUP($4, "Unsupported: matches (for tagged union)"); DEL($2, $5); } | unique_priorityE caseStart caseAttrE yINSIDE case_inside_itemList yENDCASE { $$ = $2; if ($5) $2->addItemsp($5); if (!$2->caseSimple()) $4->v3error("Illegal to have inside on a casex/casez"); @@ -3617,11 +3619,11 @@ statement_item: // IEEE: statement_item | yWAIT yFORK ';' { $$ = new AstWaitFork{$1}; } // // action_block expanded here | yWAIT_ORDER '(' vrdList ')' stmt %prec prLOWER_THAN_ELSE - { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($3, $5); } | yWAIT_ORDER '(' vrdList ')' stmt yELSE stmt - { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($3, $5, $7);} | yWAIT_ORDER '(' vrdList ')' yELSE stmt - { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($3, $6); } // // // IEEE: procedural_assertion_statement | procedural_assertion_statement { $$ = $1; } @@ -3634,11 +3636,11 @@ statement_item: // IEEE: statement_item // // IEEE: expect_property_statement // // action_block expanded here | yEXPECT '(' property_spec ')' stmt %prec prLOWER_THAN_ELSE - { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $5); } | yEXPECT '(' property_spec ')' stmt yELSE stmt - { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $5, $7); } | yEXPECT '(' property_spec ')' yELSE stmt - { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $6); } ; statementFor: // IEEE: part of statement @@ -3817,24 +3819,24 @@ value_range: // ==IEEE: value_range/open_value_range // // Skipped as '$' is part of our expr // // IEEE-2023: '[' expr ':' '$' ']' | '[' expr yP_PLUSSLASHMINUS expr ']' - { $$ = nullptr; BBUNSUP($1, "Unsupported: +/- range"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: +/- range"); DEL($2, $4); } | '[' expr yP_PLUSPCTMINUS expr ']' - { $$ = nullptr; BBUNSUP($1, "Unsupported: +%- range"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: +%- range"); DEL($2, $4); } ; covergroup_value_range: // ==IEEE-2012: covergroup_value_range cgexpr { $$ = $1; } | '[' cgexpr ':' cgexpr ']' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DELETE_ALL($2, $4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); } // // IEEE-2023: added all four: // // Skipped as '$' is part of our expr // // IEEE-2023: '[' '$' ':' cgexpr ']' // // Skipped as '$' is part of our expr // // IEEE-2023: '[' cgexpr ':' '$' ']' | '[' cgexpr yP_PLUSSLASHMINUS cgexpr ']' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DELETE_ALL($2, $4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); } | '[' cgexpr yP_PLUSPCTMINUS cgexpr ']' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DELETE_ALL($2, $4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); } ; caseCondList: // IEEE: part of case_item @@ -3850,7 +3852,7 @@ patternNoExpr: // IEEE: pattern **Excluding Expr* // // IEEE: "expr" excluded; expand in callers // // "yTAGGED idAny [expr]" Already part of expr | yTAGGED idAny/*member_identifier*/ patternNoExpr - { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); DEL($3); } // // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern ; @@ -3873,10 +3875,10 @@ patternMemberList: // IEEE: part of pattern and assignment_pattern patternMemberOne: // IEEE: part of pattern and assignment_pattern patternKey ':' expr { $$ = new AstPatMember{$1->fileline(), $3, $1, nullptr}; } - | patternKey ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } + | patternKey ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); DEL($1, $3); } // // From assignment_pattern_key | yDEFAULT ':' expr { $$ = new AstPatMember{$1, $3, nullptr, nullptr}; $$->isDefault(true); } - | yDEFAULT ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } + | yDEFAULT ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); DEL($3); } ; patternKey: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key @@ -4091,7 +4093,7 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl{$1, VDumpCtlType::ON}; DEL($3); } // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCStmt{$1, $3}); } - | yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); } + | yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); DEL($3); } | yD_STACKTRACE parenE { $$ = new AstStackTraceT{$1}; } | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT{$1, $3}; } // @@ -5737,12 +5739,18 @@ system_timing_check: // ==IEEE: system_timing_check ; setuphold_timing_check: // ==IEEE: $setuphold_timing_check - yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ')' ';' { $$ = nullptr; } - | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ')' ';' { $$ = nullptr; } - | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ')' ';' { $$ = nullptr; } - | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ')' ';' { $$ = nullptr; } - | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' delayed_referenceE ')' ';' { $$ = new AstSetuphold{$1, $3, $5, $17}; } - | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' delayed_referenceE ',' delayed_referenceE ')' ';' { $$ = new AstSetuphold{$1, $3, $5, $17, $19}; } + yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ')' ';' + { $$ = nullptr; DEL($3, $5, $7, $9); } + | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ')' ';' + { $$ = nullptr; DEL($3, $5, $7, $9); } + | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ')' ';' + { $$ = nullptr; DEL($3, $5, $7, $9, $13); } + | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ')' ';' + { $$ = nullptr; DEL($3, $5, $7, $9, $13, $15); } + | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' delayed_referenceE ')' ';' + { $$ = new AstSetuphold{$1, $3, $5, $17}; DEL($7, $9, $13, $15); } + | yD_SETUPHOLD '(' timing_check_event ',' timing_check_event ',' timing_check_limit ',' timing_check_limit ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' delayed_referenceE ',' delayed_referenceE ')' ';' + { $$ = new AstSetuphold{$1, $3, $5, $17, $19}; DEL($7, $9, $13, $15); } ; timing_check_event: // ==IEEE: $timing_check_event @@ -6082,7 +6090,7 @@ clocking_item: // IEEE: clocking_item $$->addNext(GRAMMARP->makeClockingItemList($1, VDirection::OUTPUT, nullptr, $2)); } | assertion_item_declaration { $$ = nullptr; - BBUNSUP($1, "Unsupported: assertion items in clocking blocks"); } + BBUNSUP($1, "Unsupported: assertion items in clocking blocks"); DEL($1); } ; list_of_clocking_decl_assign: // IEEE: list_of_clocking_decl_assign @@ -6107,11 +6115,11 @@ clocking_skew: // IEEE: clocking_skew delay_control { $$ = $1->lhsp()->unlinkFrBack(); $1->deleteTree(); } | '#' y1STEP { $$ = new AstConst{$1, AstConst::OneStep{}}; } | yPOSEDGE delay_controlE { $$ = nullptr; - BBUNSUP($1, "Unsupported: clocking event edge override"); } + BBUNSUP($1, "Unsupported: clocking event edge override"); DEL($2); } | yNEGEDGE delay_controlE { $$ = nullptr; - BBUNSUP($1, "Unsupported: clocking event edge override"); } + BBUNSUP($1, "Unsupported: clocking event edge override"); DEL($2); } | yEDGE delay_controlE { $$ = nullptr; - BBUNSUP($1, "Unsupported: clocking event edge override"); } + BBUNSUP($1, "Unsupported: clocking event edge override"); DEL($2); } ; cycle_delay: // IEEE: cycle_delay @@ -6217,13 +6225,13 @@ concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statemen { $$ = new AstCover{$1, $4, $6, VAssertType::CONCURRENT}; } // // IEEE: cover_sequence_statement | yCOVER ySEQUENCE '(' sexpr ')' stmt - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DELETE_ALL($4, $6); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DEL($4, $6); } // // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt // // sexpr already includes "clocking_event sexpr" | yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DELETE_ALL($4, $8, $10, $12);} + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DEL($4, $8, $10, $12);} | yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DELETE_ALL($7, $9, $11); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); DEL($7, $9, $11); } // // IEEE: restrict_property_statement | yRESTRICT yPROPERTY '(' property_spec ')' ';' { $$ = new AstRestrict{$1, $4}; } @@ -6302,7 +6310,7 @@ property_port_itemDirE: property_declarationBody: // IEEE: part of property_declaration assertion_variable_declarationList - { $$ = nullptr; BBUNSUP($1->fileline(), "Unsupported: property variable declaration"); } + { $$ = nullptr; BBUNSUP($1->fileline(), "Unsupported: property variable declaration"); DEL($1); } // // IEEE-2012: Incorrectly has yCOVER ySEQUENCE then property_spec here. // // Fixed in IEEE 1800-2017 | property_spec { $$ = $1; } @@ -6593,9 +6601,9 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg { $$ = $1; BBUNSUP($2, "Unsupported: intersect (in sequence expression)"); } // | yFIRST_MATCH '(' sexpr ')' - { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); DEL($3); } | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' - { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); DEL($3, $5); } | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { $$ = $1; BBUNSUP($2, "Unsupported: throughout (in sequence expression)"); } // // Below pexpr's are really sequence_expr, but avoid conflict @@ -6741,27 +6749,27 @@ coverage_option: // ==IEEE: coverage_option // // option/type_option aren't really keywords id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr { // TODO: check that 'id' is 'option' or 'type_option' - $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage option"); DELETE_ALL($5); } + $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage option"); DEL($5); } ; cover_point: // ==IEEE: cover_point // // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverpoint"); DELETE_ALL($2, $3, $4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverpoint"); DEL($2, $3, $4); } // // IEEE-2012: class_scope before an ID | id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($3, "Ignoring unsupported: coverpoint"); DELETE_ALL($4, $5, $6);} + { $$ = nullptr; BBCOVERIGN($3, "Ignoring unsupported: coverpoint"); DEL($4, $5, $6);} // // data_type_or_implicit expansion | data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: coverpoint"); DELETE_ALL($1, $5, $6, $7);} + { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: coverpoint"); DEL($1, $5, $6, $7);} | yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DELETE_ALL($2, $6, $7, $8); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); } | yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DELETE_ALL($2, $6, $7, $8); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); } | signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DELETE_ALL($2, $6, $7, $8); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); } | signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty - { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: coverpoint"); DELETE_ALL($5, $6, $7); } + { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: coverpoint"); DEL($5, $6, $7); } // // IEEE-2012: | bins_or_empty { $$ = $1; } ; @@ -6769,7 +6777,7 @@ cover_point: // ==IEEE: cover_point iffE: // IEEE: part of cover_point, others /* empty */ { $$ = nullptr; } | yIFF '(' expr ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover 'iff'"); DELETE_ALL($3); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover 'iff'"); DEL($3); } ; bins_or_empty: // ==IEEE: bins_or_empty @@ -6794,30 +6802,30 @@ bins_or_options: // ==IEEE: bins_or_options coverage_option { $$ = $1; } // // Can't use wildcardE as results in conflicts | bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE - { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: cover bin specification"); DELETE_ALL($3, $6, $8); } + { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: cover bin specification"); DEL($3, $6, $8); } | bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE - { $$ = nullptr; BBCOVERIGN($8, "Ignoring unsupported: cover bin 'with' specification"); DELETE_ALL($3, $6, $10, $12); } + { $$ = nullptr; BBCOVERIGN($8, "Ignoring unsupported: cover bin 'with' specification"); DEL($3, $6, $10, $12); } | yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: cover bin 'wildcard' specification"); DELETE_ALL($4, $7, $9); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: cover bin 'wildcard' specification"); DEL($4, $7, $9); } | yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE - { $$ = nullptr; BBCOVERIGN($9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DELETE_ALL($4, $7, $11, $13); } + { $$ = nullptr; BBCOVERIGN($9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DEL($4, $7, $11, $13); } // // // cgexpr part of trans_list | bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE - { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: cover bin trans list"); DELETE_ALL($3, $5, $6); } + { $$ = nullptr; BBCOVERIGN($4, "Ignoring unsupported: cover bin trans list"); DEL($3, $5, $6); } | yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DELETE_ALL($4, $6, $7);} + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($4, $6, $7);} // | bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: cover bin 'default'"); DELETE_ALL($3, $6); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: cover bin 'default'"); DEL($3, $6); } | bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE - { $$ = nullptr; BBCOVERIGN($6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DELETE_ALL($3, $7); } + { $$ = nullptr; BBCOVERIGN($6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DEL($3, $7); } ; bins_orBraE: // IEEE: part of bins_or_options: /* empty */ { $$ = nullptr; } | '[' ']' { $$ = nullptr; /*UNSUP*/ } - | '[' cgexpr ']' { $$ = nullptr; /*UNSUP*/ } + | '[' cgexpr ']' { $$ = nullptr; /*UNSUP*/ DEL($2); } ; bins_keyword: // ==IEEE: bins_keyword @@ -6835,23 +6843,23 @@ trans_set: // ==IEEE: trans_set trans_range_list { $$ = $1; } // // Note the { => } in the grammar, this is really a list | trans_set yP_EQGT trans_range_list - { $$ = $1; BBCOVERIGN($2, "Ignoring unsupported: cover trans set '=>'"); DELETE_ALL($3); } + { $$ = $1; BBCOVERIGN($2, "Ignoring unsupported: cover trans set '=>'"); DEL($3); } ; trans_range_list: // ==IEEE: trans_range_list trans_item { $$ = $1; } | trans_item yP_BRASTAR cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[*'"); DELETE_ALL($1, $3); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[*'"); DEL($1, $3); } | trans_item yP_BRASTAR cgexpr ':' cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[*'"); DELETE_ALL($1, $3, $5); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[*'"); DEL($1, $3, $5); } | trans_item yP_BRAMINUSGT cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[->'"); DELETE_ALL($1, $3); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[->'"); DEL($1, $3); } | trans_item yP_BRAMINUSGT cgexpr ':' cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[->'"); DELETE_ALL($1, $3, $5); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[->'"); DEL($1, $3, $5); } | trans_item yP_BRAEQ cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[='"); DELETE_ALL($1, $3); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[='"); DEL($1, $3); } | trans_item yP_BRAEQ cgexpr ':' cgexpr ']' - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[='"); DELETE_ALL($1, $3, $5); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover '[='"); DEL($1, $3, $5); } ; trans_item: // ==IEEE: range_list @@ -6866,9 +6874,9 @@ covergroup_range_list: // ==IEEE: covergroup_range_list cover_cross: // ==IEEE: cover_cross id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body - { $$ = nullptr; BBCOVERIGN($3, "Ignoring unsupported: cover cross"); DELETE_ALL($4, $5, $6); } + { $$ = nullptr; BBCOVERIGN($3, "Ignoring unsupported: cover cross"); DEL($4, $5, $6); } | yCROSS list_of_cross_items iffE cross_body - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover cross"); DELETE_ALL($2, $3, $4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: cover cross"); DEL($2, $3, $4); } ; list_of_cross_items: // ==IEEE: list_of_cross_items @@ -6908,24 +6916,24 @@ cross_body_item: // ==IEEE: cross_body_item | coverage_option ';' { $$ = $1; } // // IEEE: bins_selection | bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE ';' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage cross bin"); DELETE_ALL($4, $5); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage cross bin"); DEL($4, $5); } | error ';' { $$ = nullptr; } ; select_expression: // ==IEEE: select_expression // // IEEE: select_condition expanded here yBINSOF '(' bins_expression ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DELETE_ALL($3); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DEL($3); } | '!' yBINSOF '(' bins_expression ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DELETE_ALL($4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DEL($4); } | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DELETE_ALL($3, $7); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($3, $7); } | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } - { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DELETE_ALL($4, $8); } + { $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($4, $8); } | yWITH__PAREN '(' cgexpr ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DELETE_ALL($3); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DEL($3); } | '!' yWITH__PAREN '(' cgexpr ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DELETE_ALL($4); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DEL($4); } // // IEEE-2012: Need clarification as to precedence //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } // // IEEE-2012: Need clarification as to precedence @@ -6933,9 +6941,9 @@ select_expression: // ==IEEE: select_expression // | '(' select_expression ')' { $$ = $2; } | select_expression yP_ANDAND select_expression - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '&&'"); DELETE_ALL($1, $3); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '&&'"); DEL($1, $3); } | select_expression yP_OROR select_expression - { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '||'"); DELETE_ALL($1, $3); } + { $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '||'"); DEL($1, $3); } // // IEEE-2012: cross_identifier // // Part of covergroup_expression - generic identifier // // IEEE-2012: Need clarification as to precedence @@ -6947,7 +6955,7 @@ select_expression: // ==IEEE: select_expression //UNSUP cgexpr yMATCHES cgexpr {..} //UNSUP // Below are all removed | idAny '(' list_of_argumentsE ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select function call"); DELETE_ALL($3); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select function call"); DEL($3); } //UNSUP // Above are all removed, replace with: ; @@ -6962,33 +6970,34 @@ bins_expression: // ==IEEE: bins_expression coverage_eventE: // IEEE: [ coverage_event ] /* empty */ { $$ = nullptr; } | clocking_event - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage clocking event"); DELETE_ALL($1); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage clocking event"); DEL($1); } | yWITH__ETC yFUNCTION idAny/*"sample"*/ '(' tf_port_listE ')' { if (*$3 != "sample") { $3->v3error("Coverage sampling function must be named 'sample'"); $$ = nullptr; + DEL($5); } else { $$ = $5; } } | yP_ATAT '(' block_event_expression ')' - { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage '@@' events"); DELETE_ALL($3); } + { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage '@@' events"); DEL($3); } ; block_event_expression: // ==IEEE: block_event_expression - block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ } - | block_event_expression yOR block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ } + block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ DEL($1); } + | block_event_expression yOR block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ DEL($1, $3); } ; block_event_expressionTerm: // IEEE: part of block_event_expression - yBEGIN hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ } - | yEND hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ } + yBEGIN hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ DEL($2); } + | yEND hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ DEL($2); } ; hierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier // // hierarchical_tf_identifier + hierarchical_block_identifier // // method_identifier - packageClassScopeE idAny { $$ = nullptr; /*UNSUP*/ } + packageClassScopeE idAny { $$ = nullptr; /*UNSUP*/ DEL($1); } ; //********************************************************************** @@ -6996,9 +7005,9 @@ hierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier randsequence_statement: // ==IEEE: randsequence_statement yRANDSEQUENCE '(' ')' rs_productionList yENDSEQUENCE - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); DEL($4); } | yRANDSEQUENCE '(' idAny/*rs_production_identifier*/ ')' rs_productionList yENDSEQUENCE - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); DEL($5); } ; rs_productionList: // IEEE: rs_production+ @@ -7009,7 +7018,7 @@ rs_productionList: // IEEE: rs_production+ rs_production: // ==IEEE: rs_production rs_productionFront ':' rs_ruleList ';' { // TODO makes a function, probably want a new Ast type instead - $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence production"); } + $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence production"); DEL($1, $3); } ; rs_productionFront: // IEEE: part of rs_production @@ -7025,17 +7034,17 @@ rs_ruleList: // IEEE: rs_rule+ part of rs_production rs_rule: // ==IEEE: rs_rule rs_production_list { $$ = $1; } | rs_production_list yP_COLONEQ rs_weight_specification - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); DEL($1, $3); } | rs_production_list yP_COLONEQ rs_weight_specification rs_code_block - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); DEL($1, $3, $4); } ; rs_production_list: // ==IEEE: rs_production_list rs_prodList { $$ = $1; } | yRAND yJOIN rs_production_item rs_production_itemList - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); DEL($3, $4); } | yRAND yJOIN '(' expr ')' rs_production_item rs_production_itemList - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); DEL($4, $6, $7); } ; rs_weight_specification: // ==IEEE: rs_weight_specification @@ -7069,15 +7078,15 @@ rs_prod: // ==IEEE: rs_prod | rs_code_block { $$ = $1; } // // IEEE: rs_if_else | yIF '(' expr ')' rs_production_item %prec prLOWER_THAN_ELSE - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); DEL($3, $5); } | yIF '(' expr ')' rs_production_item yELSE rs_production_item - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); DEL($3, $5, $7); } // // IEEE: rs_repeat | yREPEAT '(' expr ')' rs_production_item - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence repeat"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence repeat"); DEL($3, $5); } // // IEEE: rs_case | yCASE '(' expr ')' rs_case_itemList yENDCASE - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case"); DEL($3, $5); } ; rs_production_itemList: // IEEE: rs_production_item+ @@ -7089,7 +7098,7 @@ rs_production_item: // ==IEEE: rs_production_item idAny/*production_identifier*/ { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); } | idAny/*production_identifier*/ '(' list_of_argumentsE ')' - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); DEL($3); } ; rs_case_itemList: // IEEE: rs_case_item+ @@ -7099,11 +7108,11 @@ rs_case_itemList: // IEEE: rs_case_item+ rs_case_item: // ==IEEE: rs_case_item caseCondList ':' rs_production_item ';' - { $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence case item"); } + { $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence case item"); DEL($1, $3); } | yDEFAULT rs_production_item ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); DEL($2); } | yDEFAULT ':' rs_production_item ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); DEL($3); } ; //********************************************************************** @@ -7203,7 +7212,7 @@ checker_or_generate_item_declaration: // ==IEEE: checker_or_generate_ite { $$ = $2; BBUNSUP($1, "Unsupported: checker rand"); } | function_declaration { $$ = $1; } | checker_declaration - { $$ = nullptr; BBUNSUP($1, "Unsupported: recursive 'checker'"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: recursive 'checker'"); DEL($1); } | assertion_item_declaration { $$ = $1; } | covergroup_declaration { $$ = $1; } // // IEEE deprecated: overload_declaration @@ -7624,7 +7633,7 @@ dist_item: // ==IEEE: dist_item + dist_weight // // IEEE 1800-2023 added: | yDEFAULT yP_COLONDIV expr { BBUNSUP($2, "Unsupported: 'default :/' constraint"); - $$ = nullptr; } + $$ = nullptr; DEL($3); } ; extern_constraint_declaration: // ==IEEE: extern_constraint_declaration @@ -7675,13 +7684,13 @@ configParameterListE: // IEEE: { local_parameter_declaration ';' } ; configParameterList: // IEEE: part of config_declaration - configParameter { $$ = nullptr; } + configParameter { $$ = nullptr; DEL($1); } | configParameterList configParameter { $$ = addNextNull($1, $2); } ; configParameter: // IEEE: part of config_declaration parameter_declaration ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: config localparam declaration"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: config localparam declaration"); DEL($1); } ; design_statement: // == IEEE: design_statement @@ -7780,7 +7789,7 @@ useAssignment: // IEEE: part of use_clause '.' idAny/*parameter_identifier*/ '(' ')' { $$ = nullptr; BBUNSUP($1, "Unsupported: 'config use' parameter assignment"); } | '.' idAny/*parameter_identifier*/ '(' exprOrDataType ')' - { $$ = nullptr; BBUNSUP($1, "Unsupported: 'config use' parameter assignment"); } + { $$ = nullptr; BBUNSUP($1, "Unsupported: 'config use' parameter assignment"); DEL($4); } ; colonConfigE: // IEEE: [ ':' yCONFIG] diff --git a/test_regress/t/t_fuzz_eof_bad.py b/test_regress/t/t_fuzz_eof_bad.py index 31228c9a7..2c7d7a1ce 100755 --- a/test_regress/t/t_fuzz_eof_bad.py +++ b/test_regress/t/t_fuzz_eof_bad.py @@ -11,6 +11,9 @@ import vltest_bootstrap test.scenarios('linter') +# Fails early in lexer, ignore leaks +os.environ["ASAN_OPTIONS"] = "detect_leaks=0" + test.lint(fails=True, expect_filename=test.golden_filename) test.passes()