diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 5e0d78d67..3936eb974 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -65,6 +65,7 @@ private: int m_genblkAbove = 0; // Begin block number of if/case/for above int m_genblkNum = 0; // Begin block number, 0=none seen VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime + bool m_insideLoop = false; // True if the node is inside a loop // METHODS void cleanFileline(AstNode* nodep) { @@ -222,6 +223,9 @@ private: void visit(AstVar* nodep) override { cleanFileline(nodep); + if (nodep->lifetime().isStatic() && m_insideLoop) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Static variable inside a loop"); + } if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); } @@ -459,6 +463,8 @@ private: // 2. ASTSELBIT(first, var0)) // 3. ASTSELLOOPVARS(first, var0..var1)) // 4. DOT(DOT(first, second), ASTSELBIT(third, var0)) + VL_RESTORER(m_insideLoop); + m_insideLoop = true; AstNode* bracketp = nodep->arrayp(); while (AstDot* dotp = VN_CAST(bracketp, Dot)) bracketp = dotp->rhsp(); if (AstSelBit* const selp = VN_CAST(bracketp, SelBit)) { @@ -471,14 +477,34 @@ private: } else if (VN_IS(bracketp, SelLoopVars)) { // Ok } else { - nodep->v3error( - "Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3)"); + nodep->v3error("Syntax error; foreach missing bracketed loop variable (IEEE " + "1800-2017 12.7.3)"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } iterateChildren(nodep); } - + void visit(AstRepeat* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } + void visit(AstDoWhile* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } + void visit(AstWhile* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } void visit(AstNodeModule* nodep) override { V3Config::applyModule(nodep); diff --git a/test_regress/t/t_static_in_loop_unsup.out b/test_regress/t/t_static_in_loop_unsup.out new file mode 100644 index 000000000..65c68f6e1 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_static_in_loop_unsup.v:14:24: Unsupported: Static variable inside a loop + 14 | static int a = 0; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_static_in_loop_unsup.pl b/test_regress/t/t_static_in_loop_unsup.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_static_in_loop_unsup.v b/test_regress/t/t_static_in_loop_unsup.v new file mode 100644 index 000000000..87c674688 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + + +module t; + initial begin + int x = 0; + while (x < 10) begin : outer_loop + int y = 0; + while (y < x) begin : inner_loop + static int a = 0; + a++; + y++; + end + x++; + end + if (outer_loop.inner_loop.a != 45) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule