Add check for automatic variable in continuous assignment LHS
This commit is contained in:
parent
8f0e4be643
commit
54b130e43f
|
|
@ -1332,6 +1332,20 @@ public:
|
|||
return new AstAssign{fileline(), lhsp, rhsp, controlp};
|
||||
}
|
||||
};
|
||||
class AstAssignCont final : public AstNodeAssign {
|
||||
// Continuous procedural 'assign'. See AstAssignW for non-procedural version.
|
||||
public:
|
||||
AstAssignCont(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
AstNode* timingControlp = nullptr)
|
||||
: ASTGEN_SUPER_AssignCont(fl, lhsp, rhsp, timingControlp) {
|
||||
dtypeFrom(lhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstAssignCont;
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
||||
return new AstAssignCont{fileline(), lhsp, rhsp, controlp};
|
||||
}
|
||||
};
|
||||
class AstAssignDly final : public AstNodeAssign {
|
||||
public:
|
||||
AstAssignDly(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ class WidthCommitVisitor final : public VNVisitor {
|
|||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
std::string m_contNba; // In continuous- or non-blocking assignment
|
||||
bool m_dynsizedelem
|
||||
= false; // Writing a dynamically-sized array element, not the array itself
|
||||
bool m_contReads = false; // Check read continuous automatic variables
|
||||
bool m_dynsizedelem = false; // Writing dynamically-sized array element, not the array itself
|
||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
bool m_taskRefWarn = true; // Allow task reference warnings
|
||||
bool m_underSel = false; // Under AstMemberSel or AstSel
|
||||
|
|
@ -390,7 +390,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
editDType(nodep);
|
||||
classEncapCheck(nodep, nodep->varp(), VN_CAST(nodep->classOrPackagep(), Class));
|
||||
if (nodep->access().isWriteOrRW()) varLifetimeCheck(nodep, nodep->varp());
|
||||
if (nodep->access().isWriteOrRW() || m_contReads) varLifetimeCheck(nodep, nodep->varp());
|
||||
if (VN_IS(nodep, VarRef))
|
||||
nodep->name(""); // Clear to save memory; nodep->name() will work via nodep->varp()
|
||||
}
|
||||
|
|
@ -416,12 +416,31 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
void visit(AstAssignCont* nodep) override {
|
||||
iterateAndNextNull(nodep->timingControlp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "continuous";
|
||||
m_contReads = true;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
}
|
||||
editDType(nodep);
|
||||
AstNode* const controlp
|
||||
= nodep->timingControlp() ? nodep->timingControlp()->unlinkFrBack() : nullptr;
|
||||
nodep->replaceWith(new AstAssign{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack(), controlp});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void visit(AstAssignDly* nodep) override {
|
||||
iterateAndNextNull(nodep->timingControlp());
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "nonblocking";
|
||||
m_contReads = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
editDType(nodep);
|
||||
|
|
@ -431,7 +450,9 @@ private:
|
|||
iterateAndNextNull(nodep->rhsp());
|
||||
{
|
||||
VL_RESTORER(m_contNba);
|
||||
VL_RESTORER(m_contReads);
|
||||
m_contNba = "continuous";
|
||||
m_contReads = false;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
}
|
||||
editDType(nodep);
|
||||
|
|
@ -470,7 +491,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
editDType(nodep);
|
||||
if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
|
||||
if (AstClassRefDType* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
|
||||
classEncapCheck(nodep, nodep->varp(), classrefp->classp());
|
||||
} // else might be struct, etc
|
||||
varLifetimeCheck(nodep, nodep->varp());
|
||||
|
|
|
|||
|
|
@ -3527,7 +3527,7 @@ statement_item<nodeStmtp>: // IEEE: statement_item
|
|||
{ $$ = new AstAssignDly{$2, $1, $4, $3}; }
|
||||
//UNSUP cycle_delay fexprLvalue yP_LTE ';' { UNSUP }
|
||||
| yASSIGN idClassSel '=' delay_or_event_controlE expr ';'
|
||||
{ $$ = new AstAssign{$1, $2, $5, $4}; }
|
||||
{ $$ = new AstAssignCont{$1, $2, $5, $4}; }
|
||||
| yDEASSIGN variable_lvalue ';'
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); DEL($2); }
|
||||
| yFORCE variable_lvalue '=' expr ';'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
%Error: t/t_assign_cont_automatic_bad.v:14:26: Automatic lifetime variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'l'
|
||||
: ... note: In instance 't'
|
||||
14 | assign g = signed'(l);
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
|
||||
reg g;
|
||||
|
||||
task automatic tsk;
|
||||
reg l;
|
||||
begin: cont_block
|
||||
assign g = signed'(l); // <--- BAD: using automatic in cont assignment
|
||||
end
|
||||
endtask
|
||||
|
||||
initial $stop;
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue