Internals: Add new VL_RESTORER flavours

Restrict VL_RESTORER to be usable only with trivially copyable types.
Introduce VL_RESTORER_COPY and VL_RESTORER_CLEAR, which are more
efficient versions usable for non trivially copyable types.

VL_RESTORER_COPY semantically behaves the same as VL_RESTORER, but only
does one copy at initialization, and on scope exit restores via a move.

VL_RESTORER_CLEAR swaps the variable with an new one constructed via
the no-args constructor (e.g. empty collection), which does not require
any copying at any point.

Static assertions enforce picking one of the new flavours when copying
might be expensive.
This commit is contained in:
Geza Lore 2026-07-04 13:24:53 +01:00
parent f82f59a024
commit bbee65ed4b
24 changed files with 180 additions and 148 deletions

View File

@ -1153,12 +1153,11 @@ class AssertVisitor final : public VNVisitor {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_modPastNum); VL_RESTORER(m_modPastNum);
VL_RESTORER(m_modStrobeNum); VL_RESTORER(m_modStrobeNum);
VL_RESTORER(m_modExpr2Sen2DelayedAlwaysp);
VL_RESTORER(m_finalp); VL_RESTORER(m_finalp);
VL_RESTORER_CLEAR(m_modExpr2Sen2DelayedAlwaysp);
m_modp = nodep; m_modp = nodep;
m_modPastNum = 0; m_modPastNum = 0;
m_modStrobeNum = 0; m_modStrobeNum = 0;
m_modExpr2Sen2DelayedAlwaysp.clear();
m_finalp = nullptr; m_finalp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
} }

View File

@ -137,12 +137,9 @@ class BeginVisitor final : public VNVisitor {
UINFO(8, " rename to " << nodep->name()); UINFO(8, " rename to " << nodep->name());
m_statep->userMarkChanged(nodep); m_statep->userMarkChanged(nodep);
} }
VL_RESTORER(m_displayScope); VL_RESTORER_CLEAR(m_displayScope);
VL_RESTORER(m_namedScope); VL_RESTORER_CLEAR(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER_CLEAR(m_unnamedScope);
m_displayScope = "";
m_namedScope = "";
m_unnamedScope = "";
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstNodeProcedure* nodep) override { void visit(AstNodeProcedure* nodep) override {
@ -163,14 +160,13 @@ class BeginVisitor final : public VNVisitor {
// naming; so that any begin's inside the function will rename // naming; so that any begin's inside the function will rename
// inside the function. // inside the function.
// Process children // Process children
VL_RESTORER(m_displayScope); VL_RESTORER_COPY(m_displayScope);
VL_RESTORER(m_ftaskp); VL_RESTORER(m_ftaskp);
VL_RESTORER(m_liftedp); VL_RESTORER(m_liftedp);
VL_RESTORER(m_namedScope); VL_RESTORER_CLEAR(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER_CLEAR(m_unnamedScope);
m_displayScope = dot(m_displayScope, nodep->name()); m_displayScope = dot(m_displayScope, nodep->name());
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep; m_ftaskp = nodep;
m_liftedp = nullptr; m_liftedp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
@ -191,9 +187,9 @@ class BeginVisitor final : public VNVisitor {
void visit(AstGenBlock* nodep) override { void visit(AstGenBlock* nodep) override {
// GenBlocks were only useful in variable creation, change names and delete // GenBlocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep); UINFO(8, " " << nodep);
VL_RESTORER(m_displayScope); VL_RESTORER_COPY(m_displayScope);
VL_RESTORER(m_namedScope); VL_RESTORER_COPY(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER_COPY(m_unnamedScope);
UASSERT_OBJ(!m_keepBegins, nodep, "Should be able to eliminate all AstGenBlock"); UASSERT_OBJ(!m_keepBegins, nodep, "Should be able to eliminate all AstGenBlock");
dotNames(nodep->name(), nodep->fileline(), "__BEGIN__"); dotNames(nodep->name(), nodep->fileline(), "__BEGIN__");
iterateAndNextNull(nodep->itemsp()); iterateAndNextNull(nodep->itemsp());
@ -227,9 +223,9 @@ class BeginVisitor final : public VNVisitor {
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete // Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep); UINFO(8, " " << nodep);
VL_RESTORER(m_displayScope); VL_RESTORER_COPY(m_displayScope);
VL_RESTORER(m_namedScope); VL_RESTORER_COPY(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER_COPY(m_unnamedScope);
{ {
VL_RESTORER(m_keepBegins); VL_RESTORER(m_keepBegins);
m_keepBegins = false; m_keepBegins = false;
@ -261,9 +257,9 @@ class BeginVisitor final : public VNVisitor {
void visit(AstNodeBlock* nodep) override { void visit(AstNodeBlock* nodep) override {
// Begin/Fork blocks were only useful in variable creation, change names and delete // Begin/Fork blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep); UINFO(8, " " << nodep);
VL_RESTORER(m_displayScope); VL_RESTORER_COPY(m_displayScope);
VL_RESTORER(m_namedScope); VL_RESTORER_COPY(m_namedScope);
VL_RESTORER(m_unnamedScope); VL_RESTORER_COPY(m_unnamedScope);
{ {
VL_RESTORER(m_keepBegins); VL_RESTORER(m_keepBegins);
m_keepBegins = VN_IS(nodep, Fork); m_keepBegins = VN_IS(nodep, Fork);

View File

@ -252,18 +252,15 @@ private:
void visit(AstScope* nodep) override { void visit(AstScope* nodep) override {
VL_RESTORER(m_inScope); VL_RESTORER(m_inScope);
m_inScope = true; m_inScope = true;
VL_RESTORER(m_cFuncNames); VL_RESTORER_CLEAR(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep); processAndIterate(nodep);
} }
void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_cFuncNames); VL_RESTORER_CLEAR(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep); processAndIterate(nodep);
} }
void visit(AstNodeUOrStructDType* nodep) override { void visit(AstNodeUOrStructDType* nodep) override {
VL_RESTORER(m_cFuncNames); VL_RESTORER_CLEAR(m_cFuncNames);
m_cFuncNames.clear();
processAndIterate(nodep); processAndIterate(nodep);
} }
void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {

View File

@ -114,7 +114,7 @@ class ClassVisitor final : public VNVisitor {
classScopep->aboveScopep(), classScopep->aboveCellp()}; classScopep->aboveScopep(), classScopep->aboveCellp()};
packagep->addStmtsp(scopep); packagep->addStmtsp(scopep);
// Iterate // Iterate
VL_RESTORER(m_prefix); VL_RESTORER_CLEAR(m_prefix);
VL_RESTORER(m_classPackagep); VL_RESTORER(m_classPackagep);
VL_RESTORER(m_classScopep); VL_RESTORER(m_classScopep);
VL_RESTORER(m_packageScopep); VL_RESTORER(m_packageScopep);
@ -129,7 +129,7 @@ class ClassVisitor final : public VNVisitor {
void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
// Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule)
// Classes are always under a Package (perhaps $unit) or a module // Classes are always under a Package (perhaps $unit) or a module
VL_RESTORER(m_prefix); VL_RESTORER_CLEAR(m_prefix);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
m_modp = nodep; m_modp = nodep;
m_prefix = nodep->name() + "__03a__03a"; // :: m_prefix = nodep->name() + "__03a__03a"; // ::

View File

@ -279,8 +279,8 @@ class CoverageVisitor final : public VNVisitor {
const AstNodeModule* const origModp = m_modp; const AstNodeModule* const origModp = m_modp;
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_state); VL_RESTORER(m_state);
VL_RESTORER(m_exprTempNames); VL_RESTORER_COPY(m_exprTempNames);
VL_RESTORER(m_funcTemps); VL_RESTORER_COPY(m_funcTemps);
createHandle(nodep); createHandle(nodep);
m_modp = nodep; m_modp = nodep;
m_state.m_inModOff = false; // Haven't made top shell, so tops are real tops m_state.m_inModOff = false; // Haven't made top shell, so tops are real tops
@ -294,8 +294,8 @@ class CoverageVisitor final : public VNVisitor {
void visit(AstClass* nodep) override { void visit(AstClass* nodep) override {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_state); VL_RESTORER(m_state);
VL_RESTORER(m_exprTempNames); VL_RESTORER_COPY(m_exprTempNames);
VL_RESTORER(m_funcTemps); VL_RESTORER_COPY(m_funcTemps);
createHandle(nodep); createHandle(nodep);
m_modp = nodep; m_modp = nodep;
// Covergroup declarations are not executable statements; suppress line/expr/toggle // Covergroup declarations are not executable statements; suppress line/expr/toggle
@ -356,8 +356,8 @@ class CoverageVisitor final : public VNVisitor {
void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_ftaskp); VL_RESTORER(m_ftaskp);
VL_RESTORER(m_exprTempNames); VL_RESTORER_COPY(m_exprTempNames);
VL_RESTORER(m_funcTemps); VL_RESTORER_COPY(m_funcTemps);
m_ftaskp = nodep; m_ftaskp = nodep;
if (!nodep->dpiImport()) iterateProcedure(nodep); if (!nodep->dpiImport()) iterateProcedure(nodep);
} }
@ -762,7 +762,7 @@ class CoverageVisitor final : public VNVisitor {
} }
void visit(AstGenBlock* nodep) override { void visit(AstGenBlock* nodep) override {
// Similar to AstBegin // Similar to AstBegin
VL_RESTORER(m_beginHier); VL_RESTORER_COPY(m_beginHier);
if (nodep->name() != "") { if (nodep->name() != "") {
m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name(); m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name();
} }
@ -776,7 +776,7 @@ class CoverageVisitor final : public VNVisitor {
// generate blocks; each point should get separate consideration. // generate blocks; each point should get separate consideration.
// (Currently ignored for line coverage, since any generate iteration // (Currently ignored for line coverage, since any generate iteration
// covers the code in that line.) // covers the code in that line.)
VL_RESTORER(m_beginHier); VL_RESTORER_COPY(m_beginHier);
VL_RESTORER(m_inToggleOff); VL_RESTORER(m_inToggleOff);
VL_RESTORER(m_exprStmtsp); VL_RESTORER(m_exprStmtsp);
m_exprStmtsp = nodep; m_exprStmtsp = nodep;
@ -874,7 +874,7 @@ class CoverageVisitor final : public VNVisitor {
UASSERT_OBJ(m_exprs.empty(), nodep, "unexpected expression coverage garbage"); UASSERT_OBJ(m_exprs.empty(), nodep, "unexpected expression coverage garbage");
VL_RESTORER(m_seeking); VL_RESTORER(m_seeking);
VL_RESTORER(m_objective); VL_RESTORER(m_objective);
VL_RESTORER(m_exprs); VL_RESTORER_CLEAR(m_exprs); // Already asserted above it's empty.
m_seeking = SEEKING; m_seeking = SEEKING;
m_objective = false; m_objective = false;

View File

@ -1727,15 +1727,12 @@ class FunctionalCoverageVisitor final : public VNVisitor {
VL_RESTORER(m_covergroupp); VL_RESTORER(m_covergroupp);
VL_RESTORER(m_sampleFuncp); VL_RESTORER(m_sampleFuncp);
VL_RESTORER(m_constructorp); VL_RESTORER(m_constructorp);
VL_RESTORER(m_coverpoints); VL_RESTORER_CLEAR(m_coverpoints);
VL_RESTORER(m_coverpointMap); VL_RESTORER_CLEAR(m_coverpointMap);
VL_RESTORER(m_coverCrosses); VL_RESTORER_CLEAR(m_coverCrosses);
m_covergroupp = nodep; m_covergroupp = nodep;
m_sampleFuncp = nullptr; m_sampleFuncp = nullptr;
m_constructorp = nullptr; m_constructorp = nullptr;
m_coverpoints.clear();
m_coverpointMap.clear();
m_coverCrosses.clear();
// Extract and store the clocking event from AstCovergroup node // Extract and store the clocking event from AstCovergroup node
// The parser creates this node to preserve the event information // The parser creates this node to preserve the event information

View File

@ -1050,8 +1050,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
if (nodep->packed()) puts("packed "); if (nodep->packed()) puts("packed ");
{ {
puts("{\n"); puts("{\n");
VL_RESTORER(m_packedps); VL_RESTORER_CLEAR(m_packedps);
m_packedps.clear();
for (AstMemberDType* itemp = nodep->membersp(); itemp; for (AstMemberDType* itemp = nodep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) { itemp = VN_AS(itemp->nextp(), MemberDType)) {
iterateConst(itemp); iterateConst(itemp);

View File

@ -561,10 +561,9 @@ class ForkVisitor final : public VNVisitor {
// replace body with a call to that task. Returns true iff wrapped. // replace body with a call to that task. Returns true iff wrapped.
bool taskify(AstBegin* beginp) { bool taskify(AstBegin* beginp) {
// Visit statement to gather variables (And recursively process) // Visit statement to gather variables (And recursively process)
VL_RESTORER(m_forkLocalsp); VL_RESTORER_CLEAR(m_forkLocalsp);
VL_RESTORER(m_capturedVarsp); VL_RESTORER(m_capturedVarsp);
VL_RESTORER(m_capturedArgsp); VL_RESTORER(m_capturedArgsp);
m_forkLocalsp.clear();
m_capturedVarsp = nullptr; m_capturedVarsp = nullptr;
m_capturedArgsp = nullptr; m_capturedArgsp = nullptr;
iterate(beginp); iterate(beginp);

View File

@ -33,6 +33,7 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
@ -44,27 +45,90 @@ class V3ThreadPool;
//====================================================================== //======================================================================
// Restorer // Restorer
/// Save a given variable's value on the stack, restoring it at end-of-scope. // For all flavours, 'var' must be a named scalar variable (simple identifier).
// Object must be named, or it will not persist until end-of-scope.
// Constructor needs () or GCC 4.8 false warning. // Copy given variable's value on the stack, copy saved value back at end-of-scope.
#define VL_RESTORER(var) const VRestorer<typename std::decay_t<decltype(var)>> restorer_##var(var); // Only usable for trivially copyable types; use VL_RESTORER_COPY/VL_RESTORER_CLEAR for
/// Get the copy of the variable previously saved by VL_RESTORER() // non-trivially copyable types, which are more efficient.
#define VL_RESTORER(var) \
const VRestorerTrivial<typename std::decay_t<decltype(var)>> restorer_##var(var);
// This is the equivalent of VL_RESTORER for non-trivially copyable types. Still more efficient
// than VL_RESTORER as uses move to restore.
#define VL_RESTORER_COPY(var) \
const VRestorerCopy<typename std::decay_t<decltype(var)>> restorer_##var(var);
// Swap 'var' with a no-args constructed object of the same type, effectively clearing it, then
// swap back at end-of-scope. No copying involved. Use this e.g. for std containers where they
// would be .clear()'d right after the VL_RESTORER instance.
#define VL_RESTORER_CLEAR(var) \
const VRestorerClear<typename std::decay_t<decltype(var)>> restorer_##var(var);
// Get const reference to the saved copy
#define VL_RESTORER_PREV(var) restorer_##var.saved() #define VL_RESTORER_PREV(var) restorer_##var.saved()
// Object used by VL_RESTORER. This object must be an auto variable, not // Implementation of VL_RESTORER
// allocated on the heap or otherwise.
template <typename T> template <typename T>
class VRestorer final { class VRestorerTrivial final {
static_assert(std::is_trivially_copyable<T>::value,
"Use VL_RESTORER_{COPY,CLEAR} for non trivially copyable types");
T& m_ref; // Reference to object we're saving and restoring T& m_ref; // Reference to object we're saving and restoring
const T m_saved; // Value saved, for later restore const T m_saved; // Value saved, for later restore
public: public:
explicit VRestorer(T& permr) explicit VRestorerTrivial(T& val)
: m_ref{permr} : m_ref{val}
, m_saved{permr} {} , m_saved{val} {}
~VRestorer() { m_ref = m_saved; } ~VRestorerTrivial() { m_ref = m_saved; }
VL_UNCOPYABLE(VRestorerTrivial);
// Must be stack allocated
void* operator new(size_t) = delete;
void operator delete(void*) = delete;
const T& saved() const { return m_saved; }
};
// Implementation of VL_RESTORER_COPY
template <typename T>
class VRestorerCopy final {
static_assert(!std::is_trivially_copyable<T>::value,
"Use VL_RESTORER for trivially copyable types");
T& m_ref; // Reference to object we're saving and restoring
T m_saved; // Value saved, for later restore
public:
explicit VRestorerCopy(T& val)
: m_ref{val}
, m_saved{val} {}
~VRestorerCopy() { m_ref = std::move(m_saved); }
VL_UNCOPYABLE(VRestorerCopy);
// Must be stack allocated
void* operator new(size_t) = delete;
void operator delete(void*) = delete;
const T& saved() const { return m_saved; }
};
// Implementation of VL_RESTORER_CLEAR.
template <typename T>
class VRestorerClear final {
static_assert(!std::is_trivially_copyable<T>::value,
"Use VL_RESTORER for trivially copyable types");
T& m_ref; // Reference to object we're saving and restoring
T m_saved{}; // Owns the swapped-out value; starts empty
public:
explicit VRestorerClear(T& val)
: m_ref{val} {
std::swap(m_ref, m_saved);
}
~VRestorerClear() { std::swap(m_ref, m_saved); }
VL_UNCOPYABLE(VRestorerClear);
// Must be stack allocated
void* operator new(size_t) = delete;
void operator delete(void*) = delete;
const T& saved() const { return m_saved; } const T& saved() const { return m_saved; }
VL_UNCOPYABLE(VRestorer);
}; };
//###################################################################### //######################################################################

View File

@ -331,12 +331,9 @@ class HierBlockUsageCollectVisitor final : public VNVisitorConst {
} }
// This is a hierarchical block, gather parts // This is a hierarchical block, gather parts
VL_RESTORER(m_params); VL_RESTORER_CLEAR(m_params);
VL_RESTORER(m_typeParams); VL_RESTORER_CLEAR(m_typeParams);
VL_RESTORER(m_childrenp); VL_RESTORER_CLEAR(m_childrenp);
m_params.clear();
m_typeParams.clear();
m_childrenp.clear();
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
// Create the graph vertex for this hier block // Create the graph vertex for this hier block
V3HierBlock* const blockp = new V3HierBlock{m_graphp, nodep, m_params, m_typeParams}; V3HierBlock* const blockp = new V3HierBlock{m_graphp, nodep, m_params, m_typeParams};

View File

@ -43,7 +43,7 @@ class InlineIntfRefVisitor final : public VNVisitor {
// VISITORS // VISITORS
void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); } void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); }
void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
VL_RESTORER(m_scope); VL_RESTORER_COPY(m_scope);
if (m_scope.empty()) { if (m_scope.empty()) {
m_scope = nodep->name(); m_scope = nodep->name();
} else { } else {

View File

@ -47,8 +47,8 @@ class LibMapVisitor final : public VNVisitor {
} }
void visit(AstLibrary* nodep) override { void visit(AstLibrary* nodep) override {
VL_RESTORER(m_lib); VL_RESTORER_CLEAR(m_lib);
VL_RESTORER(m_rel); VL_RESTORER_CLEAR(m_rel);
m_lib = nodep->name(); m_lib = nodep->name();
m_rel = V3Os::filenameDir(nodep->fileline()->filename()); m_rel = V3Os::filenameDir(nodep->fileline()->filename());
iterateChildren(nodep); iterateChildren(nodep);

View File

@ -157,11 +157,11 @@ class LinkConfigsVisitor final : public VNVisitor {
m_isDefault = true; m_isDefault = true;
iterateAndNextNull(nodep->usep()); iterateAndNextNull(nodep->usep());
} else if (nodep->isCell()) { } else if (nodep->isCell()) {
VL_RESTORER(m_cell); VL_RESTORER_CLEAR(m_cell);
m_cell = nodep->cellp()->name(); m_cell = nodep->cellp()->name();
iterateAndNextNull(nodep->usep()); iterateAndNextNull(nodep->usep());
} else { } else {
VL_RESTORER(m_hierInst); VL_RESTORER_COPY(m_hierInst);
{ {
VL_RESTORER(m_dotp); VL_RESTORER(m_dotp);
m_dotp = VN_AS(nodep->cellp(), Dot); m_dotp = VN_AS(nodep->cellp(), Dot);

View File

@ -1259,7 +1259,7 @@ class LinkDotFindVisitor final : public VNVisitor {
const bool standalonePkg const bool standalonePkg
= !m_modSymp && (m_statep->forPrearray() && VN_IS(nodep, Package)); = !m_modSymp && (m_statep->forPrearray() && VN_IS(nodep, Package));
const bool doit = (m_modSymp || standalonePkg); const bool doit = (m_modSymp || standalonePkg);
VL_RESTORER(m_scope); VL_RESTORER_COPY(m_scope);
VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_classOrPackagep);
VL_RESTORER(m_modSymp); VL_RESTORER(m_modSymp);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
@ -1335,7 +1335,7 @@ class LinkDotFindVisitor final : public VNVisitor {
void visit(AstClass* nodep) override { // FindVisitor:: void visit(AstClass* nodep) override { // FindVisitor::
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit"); UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
UINFO(8, " " << nodep); UINFO(8, " " << nodep);
VL_RESTORER(m_scope); VL_RESTORER_COPY(m_scope);
VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_classOrPackagep);
VL_RESTORER(m_modSymp); VL_RESTORER(m_modSymp);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
@ -1384,7 +1384,7 @@ class LinkDotFindVisitor final : public VNVisitor {
if (nodep->recursive() && m_inRecursion) return; if (nodep->recursive() && m_inRecursion) return;
iterateChildren(nodep); iterateChildren(nodep);
// Recurse in, preserving state // Recurse in, preserving state
VL_RESTORER(m_scope); VL_RESTORER_COPY(m_scope);
VL_RESTORER(m_modSymp); VL_RESTORER(m_modSymp);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_paramNum); VL_RESTORER(m_paramNum);
@ -3584,7 +3584,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
void symIterateChildren(AstNode* nodep, VSymEnt* symp) { void symIterateChildren(AstNode* nodep, VSymEnt* symp) {
// Iterate children, changing to given context, with restore to old context // Iterate children, changing to given context, with restore to old context
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
m_curSymp = symp; m_curSymp = symp;
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
@ -3592,7 +3592,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
} }
void symIterateNull(AstNode* nodep, VSymEnt* symp) { void symIterateNull(AstNode* nodep, VSymEnt* symp) {
// Iterate node, changing to given context, with restore to old context // Iterate node, changing to given context, with restore to old context
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
m_curSymp = symp; m_curSymp = symp;
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
@ -3805,10 +3805,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep); UINFO(5, indent() << "visit " << nodep);
checkNoDot(nodep); checkNoDot(nodep);
VL_RESTORER(m_usedPins); VL_RESTORER_CLEAR(m_usedPins);
VL_RESTORER(m_usedDefParamPins); VL_RESTORER_CLEAR(m_usedDefParamPins);
m_usedPins.clear();
m_usedDefParamPins.clear();
UASSERT_OBJ(nodep->modp(), nodep, UASSERT_OBJ(nodep->modp(), nodep,
"Instance has unlinked module"); // V3LinkCell should have errored out "Instance has unlinked module"); // V3LinkCell should have errored out
VL_RESTORER(m_cellp); VL_RESTORER(m_cellp);
@ -3845,10 +3843,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep); UINFO(5, indent() << "visit " << nodep);
// Can be under dot if called as package::class and that class resolves, so no checkNoDot // Can be under dot if called as package::class and that class resolves, so no checkNoDot
VL_RESTORER(m_usedPins); VL_RESTORER_CLEAR(m_usedPins);
VL_RESTORER(m_usedDefParamPins); VL_RESTORER_CLEAR(m_usedDefParamPins);
m_usedPins.clear();
m_usedDefParamPins.clear();
UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class"); UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class");
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp() || V3Error::errorCount(), nodep, UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp() || V3Error::errorCount(), nodep,
"class reference parameter not removed by V3Param"); "class reference parameter not removed by V3Param");
@ -4753,14 +4749,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
UINFO(8, indent() << "visit " << nodep); UINFO(8, indent() << "visit " << nodep);
UINFO(9, indent() << m_ds.ascii()); UINFO(9, indent() << m_ds.ascii());
VL_RESTORER(m_usedPins); VL_RESTORER_CLEAR(m_usedPins);
VL_RESTORER(m_usedDefParamPins); VL_RESTORER_CLEAR(m_usedDefParamPins);
m_usedPins.clear();
m_usedDefParamPins.clear();
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep, UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
"class reference parameter not removed by V3Param"); "class reference parameter not removed by V3Param");
{ {
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
VL_RESTORER(m_pinSymp); VL_RESTORER(m_pinSymp);
if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") { if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") {
@ -4834,7 +4828,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
} }
} }
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }
@ -5054,7 +5048,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
// Created here so should already be resolved. // Created here so should already be resolved.
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep); UINFO(5, indent() << "visit " << nodep);
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
VL_RESTORER(m_randSymp); VL_RESTORER(m_randSymp);
VL_RESTORER(m_randMethodCallp); VL_RESTORER(m_randMethodCallp);
{ {
@ -5509,7 +5503,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
checkNoDot(nodep); checkNoDot(nodep);
{ {
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
if (nodep->name() != "") { if (nodep->name() != "") {
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp)); UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
@ -5524,7 +5518,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
checkNoDot(nodep); checkNoDot(nodep);
{ {
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
if (nodep->name() != "") { if (nodep->name() != "") {
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp)); UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
@ -5643,7 +5637,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
checkNoDot(nodep); checkNoDot(nodep);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_currentWithp); VL_RESTORER(m_currentWithp);
VL_RESTORER(m_restrictedNamesUsed); VL_RESTORER_COPY(m_restrictedNamesUsed);
{ {
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
m_currentWithp = nodep; m_currentWithp = nodep;
@ -5813,7 +5807,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_modSymp); VL_RESTORER(m_modSymp);
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_ifClassImpNames); VL_RESTORER_COPY(m_ifClassImpNames);
VL_RESTORER(m_insideClassExtParam); VL_RESTORER(m_insideClassExtParam);
{ {
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
@ -6169,7 +6163,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
void visit(AstDisable* nodep) override { void visit(AstDisable* nodep) override {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
checkNoDot(nodep); checkNoDot(nodep);
VL_RESTORER(m_ds); VL_RESTORER_COPY(m_ds);
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
m_ds.m_dotPos = DP_FIRST; m_ds.m_dotPos = DP_FIRST;
m_ds.m_disablep = nodep; m_ds.m_disablep = nodep;
@ -6249,10 +6243,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
UASSERT_OBJ(ifacep, nodep, "Port parameters of AstIfaceRefDType without ifacep()"); UASSERT_OBJ(ifacep, nodep, "Port parameters of AstIfaceRefDType without ifacep()");
if (ifacep->dead()) return; if (ifacep->dead()) return;
checkNoDot(nodep); checkNoDot(nodep);
VL_RESTORER(m_usedPins); VL_RESTORER_CLEAR(m_usedPins);
VL_RESTORER(m_usedDefParamPins); VL_RESTORER_CLEAR(m_usedDefParamPins);
m_usedPins.clear();
m_usedDefParamPins.clear();
VL_RESTORER(m_pinSymp); VL_RESTORER(m_pinSymp);
m_pinSymp = m_statep->getNodeSym(ifacep); m_pinSymp = m_statep->getNodeSym(ifacep);
iterateAndNextNull(nodep->paramsp()); iterateAndNextNull(nodep->paramsp());

View File

@ -273,7 +273,7 @@ class LinkParseVisitor final : public VNVisitor {
<< nodep->verilogKwd() << "'"); << nodep->verilogKwd() << "'");
} }
VL_RESTORER(m_portDups); VL_RESTORER_COPY(m_portDups);
collectPorts(nodep->stmtsp()); collectPorts(nodep->stmtsp());
iterateChildren(nodep); iterateChildren(nodep);
@ -763,12 +763,12 @@ class LinkParseVisitor final : public VNVisitor {
VL_RESTORER(m_genblkAbove); VL_RESTORER(m_genblkAbove);
VL_RESTORER(m_genblkNum); VL_RESTORER(m_genblkNum);
VL_RESTORER(m_beginDepth); VL_RESTORER(m_beginDepth);
VL_RESTORER(m_implTypedef);
VL_RESTORER(m_lifetime); VL_RESTORER(m_lifetime);
VL_RESTORER(m_lifetimeAllowed); VL_RESTORER(m_lifetimeAllowed);
VL_RESTORER(m_moduleWithGenericIface); VL_RESTORER(m_moduleWithGenericIface);
VL_RESTORER(m_randSequenceNum); VL_RESTORER(m_randSequenceNum);
VL_RESTORER(m_valueModp); VL_RESTORER(m_valueModp);
VL_RESTORER_CLEAR(m_implTypedef);
// Module: Create sim table for entire module and iterate // Module: Create sim table for entire module and iterate
cleanFileline(nodep); cleanFileline(nodep);
@ -780,7 +780,6 @@ class LinkParseVisitor final : public VNVisitor {
m_genblkAbove = 0; m_genblkAbove = 0;
m_genblkNum = 0; m_genblkNum = 0;
m_beginDepth = 0; m_beginDepth = 0;
m_implTypedef.clear();
m_valueModp = nodep; m_valueModp = nodep;
m_lifetime = nodep->lifetime().makeImplicit(); m_lifetime = nodep->lifetime().makeImplicit();
m_lifetimeAllowed = VN_IS(nodep, Class); m_lifetimeAllowed = VN_IS(nodep, Class);
@ -797,7 +796,7 @@ class LinkParseVisitor final : public VNVisitor {
"Verilator top-level internals"); "Verilator top-level internals");
} }
VL_RESTORER(m_portDups); VL_RESTORER_COPY(m_portDups);
collectPorts(nodep->stmtsp()); collectPorts(nodep->stmtsp());
iterateChildren(nodep); iterateChildren(nodep);

View File

@ -32,7 +32,7 @@ class LinkWithVisitor final : public VNVisitor {
// STATE // STATE
// Below state needs to be preserved between each module call. // Below state needs to be preserved between each module call.
string m_randcIllegalWhy; // Why randc illegal const char* m_randcIllegalWhyp = nullptr; // Why randc illegal
AstNode* m_randcIllegalp = nullptr; // Node causing randc illegal AstNode* m_randcIllegalp = nullptr; // Node causing randc illegal
AstNodeExpr* m_currentRandomizeSelectp = nullptr; // fromp() of current `randomize()` call AstNodeExpr* m_currentRandomizeSelectp = nullptr; // fromp() of current `randomize()` call
bool m_inRandomizeWith = false; // If in randomize() with (and no other with afterwards) bool m_inRandomizeWith = false; // If in randomize() with (and no other with afterwards)
@ -49,24 +49,24 @@ class LinkWithVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstConstraintBefore* nodep) override { void visit(AstConstraintBefore* nodep) override {
VL_RESTORER(m_randcIllegalWhy); VL_RESTORER(m_randcIllegalWhyp);
VL_RESTORER(m_randcIllegalp); VL_RESTORER(m_randcIllegalp);
m_randcIllegalWhy = "'solve before' (IEEE 1800-2023 18.5.9)"; m_randcIllegalWhyp = "'solve before' (IEEE 1800-2023 18.5.9)";
m_randcIllegalp = nodep; m_randcIllegalp = nodep;
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
void visit(AstDist* nodep) override { void visit(AstDist* nodep) override {
VL_RESTORER(m_randcIllegalWhy); VL_RESTORER(m_randcIllegalWhyp);
VL_RESTORER(m_randcIllegalp); VL_RESTORER(m_randcIllegalp);
m_randcIllegalWhy = "'constraint dist' (IEEE 1800-2023 18.5.3)"; m_randcIllegalWhyp = "'constraint dist' (IEEE 1800-2023 18.5.3)";
m_randcIllegalp = nodep; m_randcIllegalp = nodep;
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
void visit(AstConstraintExpr* nodep) override { void visit(AstConstraintExpr* nodep) override {
VL_RESTORER(m_randcIllegalWhy); VL_RESTORER(m_randcIllegalWhyp);
VL_RESTORER(m_randcIllegalp); VL_RESTORER(m_randcIllegalp);
if (nodep->isSoft()) { if (nodep->isSoft()) {
m_randcIllegalWhy = "'constraint soft' (IEEE 1800-2023 18.5.13.1)"; m_randcIllegalWhyp = "'constraint soft' (IEEE 1800-2023 18.5.13.1)";
m_randcIllegalp = nodep; m_randcIllegalp = nodep;
} }
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
@ -76,7 +76,7 @@ class LinkWithVisitor final : public VNVisitor {
if (nodep->varp()) { // Else due to dead code, might not have var pointer if (nodep->varp()) { // Else due to dead code, might not have var pointer
if (nodep->varp()->isRandC() && m_randcIllegalp) { if (nodep->varp()->isRandC() && m_randcIllegalp) {
nodep->v3error("Randc variables not allowed in " nodep->v3error("Randc variables not allowed in "
<< m_randcIllegalWhy << '\n' << m_randcIllegalWhyp << '\n'
<< nodep->warnContextPrimary() << '\n' << nodep->warnContextPrimary() << '\n'
<< m_randcIllegalp->warnOther() << m_randcIllegalp->warnOther()
<< "... Location of restricting expression\n" << "... Location of restricting expression\n"

View File

@ -2571,11 +2571,9 @@ class ParamVisitor final : public VNVisitor {
// Iterate the body // Iterate the body
{ {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_ifacePortNames); VL_RESTORER_CLEAR(m_ifacePortNames);
VL_RESTORER(m_ifaceInstCells); VL_RESTORER_CLEAR(m_ifaceInstCells);
m_modp = modp; m_modp = modp;
m_ifacePortNames.clear();
m_ifaceInstCells.clear();
iterateChildren(modp); iterateChildren(modp);
} }
} }
@ -3241,7 +3239,7 @@ class ParamVisitor final : public VNVisitor {
// Note this clears nodep->genforp(), so begin is no longer special // Note this clears nodep->genforp(), so begin is no longer special
} }
} else { } else {
VL_RESTORER(m_generateHierName); VL_RESTORER_COPY(m_generateHierName);
m_generateHierName += "." + nodep->prettyName(); m_generateHierName += "." + nodep->prettyName();
iterateChildren(nodep); iterateChildren(nodep);
} }

View File

@ -136,7 +136,7 @@ class RandSequenceVisitor final : public VNVisitor {
m_modp->addStmtsp(taskp); m_modp->addStmtsp(taskp);
// Create local (not output) break variable // Create local (not output) break variable
VL_RESTORER(m_localizeRemaps); VL_RESTORER_COPY(m_localizeRemaps);
AstVar* breakVarp = newBreakVar(nodep->fileline(), false); AstVar* breakVarp = newBreakVar(nodep->fileline(), false);
taskp->addStmtsp(breakVarp); taskp->addStmtsp(breakVarp);
@ -417,9 +417,9 @@ class RandSequenceVisitor final : public VNVisitor {
m_rsp = nodep; m_rsp = nodep;
VL_RESTORER(m_startProdp); VL_RESTORER(m_startProdp);
VL_RESTORER(m_localizes); VL_RESTORER_COPY(m_localizes);
VL_RESTORER(m_localizeNames); VL_RESTORER_COPY(m_localizeNames);
VL_RESTORER(m_localizeRemaps); VL_RESTORER_COPY(m_localizeRemaps);
findLocalizes(nodep); findLocalizes(nodep);
// Find first production // Find first production
@ -482,7 +482,7 @@ class RandSequenceVisitor final : public VNVisitor {
// TODO we could do this only if break exists in the downstream production, // TODO we could do this only if break exists in the downstream production,
// but as-is we'll optimize it away in most cases anyways // but as-is we'll optimize it away in most cases anyways
VL_RESTORER(m_breakVarp); VL_RESTORER(m_breakVarp);
VL_RESTORER(m_localizeRemaps); VL_RESTORER_COPY(m_localizeRemaps);
m_breakVarp = newBreakVar(nodep->fileline(), true); m_breakVarp = newBreakVar(nodep->fileline(), true);
m_prodFuncp->addStmtsp(m_breakVarp); m_prodFuncp->addStmtsp(m_breakVarp);

View File

@ -306,10 +306,9 @@ private:
} }
void visit(AstClass* nodep) override { void visit(AstClass* nodep) override {
// Move initial statements into the constructor // Move initial statements into the constructor
VL_RESTORER(m_initialps); VL_RESTORER_CLEAR(m_initialps);
VL_RESTORER(m_ctorp); VL_RESTORER(m_ctorp);
VL_RESTORER(m_classp); VL_RESTORER(m_classp);
m_initialps.clear();
m_ctorp = nullptr; m_ctorp = nullptr;
m_classp = nodep; m_classp = nodep;
{ // Find m_initialps, m_ctor { // Find m_initialps, m_ctor

View File

@ -485,7 +485,7 @@ class TraceDeclVisitor final : public VNVisitor {
AstNodeDType* const skipTypep = nodep->skipRefp(); AstNodeDType* const skipTypep = nodep->skipRefp();
// offset and direction args added in EmitCImp // offset and direction args added in EmitCImp
std::string callArgs{"tracep, \"" + VIdProtect::protect(m_traName) + "\""}; std::string callArgs{"tracep, \"" + VIdProtect::protect(m_traName) + "\""};
VL_RESTORER(m_traName); VL_RESTORER_COPY(m_traName);
FileLine* const flp = skipTypep->fileline(); FileLine* const flp = skipTypep->fileline();
const DtypeFuncKey dtypeKey{skipTypep, m_traVscp->varp()->varType()}; const DtypeFuncKey dtypeKey{skipTypep, m_traVscp->varp()->varType()};
@ -530,7 +530,7 @@ class TraceDeclVisitor final : public VNVisitor {
void declUnpackedArray(AstUnpackArrayDType* const nodep, bool newFunc) { void declUnpackedArray(AstUnpackArrayDType* const nodep, bool newFunc) {
string prefixName(newFunc ? "name" : m_traName); string prefixName(newFunc ? "name" : m_traName);
VL_RESTORER(m_traName); VL_RESTORER_COPY(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_UNPACKED, addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_UNPACKED,
@ -568,7 +568,7 @@ class TraceDeclVisitor final : public VNVisitor {
string prefixName(newFunc ? "name" : m_traName); string prefixName(newFunc ? "name" : m_traName);
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
VL_RESTORER(m_traName); VL_RESTORER_COPY(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_PACKED, addToSubFunc(new AstTracePushPrefix{flp, prefixName, VTracePrefixType::ARRAY_PACKED,
@ -918,7 +918,7 @@ class TraceDeclVisitor final : public VNVisitor {
return; return;
} }
VL_RESTORER(m_traName); VL_RESTORER_COPY(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
int nMembers = 0; int nMembers = 0;

View File

@ -2191,8 +2191,8 @@ class TristateVisitor final : public TristateBaseVisitor {
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
VL_RESTORER(m_graphing); VL_RESTORER(m_graphing);
VL_RESTORER(m_unique); VL_RESTORER(m_unique);
VL_RESTORER(m_lhsmap); VL_RESTORER_CLEAR(m_lhsmap);
VL_RESTORER(m_assigns); VL_RESTORER_CLEAR(m_assigns);
// Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph; // Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph;
UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule"); UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule");
@ -2201,8 +2201,6 @@ class TristateVisitor final : public TristateBaseVisitor {
m_tgraph.clearAndCheck(); m_tgraph.clearAndCheck();
m_unique = 0; m_unique = 0;
m_logicp = nullptr; m_logicp = nullptr;
m_lhsmap.clear();
m_assigns.clear();
m_modp = nodep; m_modp = nodep;
// Walk the graph, finding all variables and tristate constructs // Walk the graph, finding all variables and tristate constructs
m_graphing = true; m_graphing = true;

View File

@ -56,14 +56,12 @@ class UdpVisitor final : public VNVisitor {
VL_RESTORER(m_primp); VL_RESTORER(m_primp);
VL_RESTORER(m_outputInitVerfp); VL_RESTORER(m_outputInitVerfp);
VL_RESTORER(m_isFirstOutput); VL_RESTORER(m_isFirstOutput);
VL_RESTORER(m_inputVars); VL_RESTORER_CLEAR(m_inputVars);
VL_RESTORER(m_outputVars); VL_RESTORER_CLEAR(m_outputVars);
m_outputInitVerfp = nullptr; m_outputInitVerfp = nullptr;
m_primp = nodep; m_primp = nodep;
m_isFirstOutput = false; m_isFirstOutput = false;
iterateChildren(nodep); iterateChildren(nodep);
m_inputVars.clear();
m_outputVars.clear();
} }
void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
// Push the input and output vars for primitive. // Push the input and output vars for primitive.

View File

@ -7852,7 +7852,7 @@ class WidthVisitor final : public VNVisitor {
} }
void visit(AstNodeModule* nodep) override { void visit(AstNodeModule* nodep) override {
assertAtStatement(nodep); assertAtStatement(nodep);
VL_RESTORER(m_insideTempNames); VL_RESTORER_COPY(m_insideTempNames);
if (AstClass* const classp = VN_CAST(nodep, Class)) { if (AstClass* const classp = VN_CAST(nodep, Class)) {
visitClass(classp); visitClass(classp);
} else { } else {

View File

@ -47,7 +47,7 @@ class WidthCommitVisitor final : public VNVisitor {
// STATE // STATE
AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeModule* m_modp = nullptr; // Current module AstNodeModule* m_modp = nullptr; // Current module
std::string m_contNba; // In continuous- or non-blocking assignment const char* m_contNbap = nullptr; // In continuous- or non-blocking assignment
bool m_contReads = false; // Check read continuous automatic variables bool m_contReads = false; // Check read continuous automatic variables
bool m_dynsizedelem = false; // Writing dynamically-sized array element, not the array itself bool m_dynsizedelem = false; // Writing dynamically-sized array element, not the array itself
VMemberMap m_memberMap; // Member names cached for fast lookup VMemberMap m_memberMap; // Member names cached for fast lookup
@ -148,7 +148,7 @@ private:
void varLifetimeCheck(AstNode* nodep, AstVar* varp) { void varLifetimeCheck(AstNode* nodep, AstVar* varp) {
// Skip if we are under a member select (lhs of a dot) // Skip if we are under a member select (lhs of a dot)
// We don't care about lifetime of anything else than rhs of a dot // We don't care about lifetime of anything else than rhs of a dot
if (!m_underSel && !m_contNba.empty()) { if (!m_underSel && m_contNbap) {
std::string varType; std::string varType;
const AstNodeDType* const varDtp = varp->dtypep()->skipRefp(); const AstNodeDType* const varDtp = varp->dtypep()->skipRefp();
if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType) if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType)
@ -162,7 +162,7 @@ private:
if (!varType.empty()) { if (!varType.empty()) {
UINFO(1, " Related var dtype: " << varDtp); UINFO(1, " Related var dtype: " << varDtp);
nodep->v3error(varType nodep->v3error(varType
<< " variable not allowed in " << m_contNba << " variable not allowed in " << m_contNbap
<< " assignment (IEEE 1800-2023 6.21): " << varp->prettyNameQ()); << " assignment (IEEE 1800-2023 6.21): " << varp->prettyNameQ());
} }
} }
@ -419,9 +419,9 @@ private:
void visit(AstAssignCont* nodep) override { void visit(AstAssignCont* nodep) override {
iterateAndNextNull(nodep->timingControlp()); iterateAndNextNull(nodep->timingControlp());
{ {
VL_RESTORER(m_contNba); VL_RESTORER(m_contNbap);
VL_RESTORER(m_contReads); VL_RESTORER(m_contReads);
m_contNba = "continuous"; m_contNbap = "continuous";
m_contReads = true; m_contReads = true;
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->rhsp());
@ -432,9 +432,9 @@ private:
iterateAndNextNull(nodep->timingControlp()); iterateAndNextNull(nodep->timingControlp());
iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->rhsp());
{ {
VL_RESTORER(m_contNba); VL_RESTORER(m_contNbap);
VL_RESTORER(m_contReads); VL_RESTORER(m_contReads);
m_contNba = "nonblocking"; m_contNbap = "nonblocking";
m_contReads = false; m_contReads = false;
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
} }
@ -444,9 +444,9 @@ private:
iterateAndNextNull(nodep->timingControlp()); iterateAndNextNull(nodep->timingControlp());
iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->rhsp());
{ {
VL_RESTORER(m_contNba); VL_RESTORER(m_contNbap);
VL_RESTORER(m_contReads); VL_RESTORER(m_contReads);
m_contNba = "continuous"; m_contNbap = "continuous";
m_contReads = false; m_contReads = false;
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
} }