diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 650f709de..cb65085e1 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -300,6 +300,12 @@ class LinkParseVisitor final : public VNVisitor { nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a " "loop converted to automatic"); } + if (!m_lifetimeAllowed && nodep->lifetime().isAutomatic()) { + nodep->v3error( + "Module variables cannot have automatic lifetime (IEEE 1800-2023 6.21): " + << nodep->prettyNameQ()); + nodep->lifetime(VLifetime::STATIC); + } if (!nodep->direction().isAny()) { // Not a port if (nodep->lifetime().isNone()) { if (m_lifetimeAllowed) { diff --git a/test_regress/t/t_assign_automatic_bad.out b/test_regress/t/t_assign_automatic_bad.out index 45e0790c1..393ec33ca 100644 --- a/test_regress/t/t_assign_automatic_bad.out +++ b/test_regress/t/t_assign_automatic_bad.out @@ -1,42 +1,34 @@ -%Error: t/t_assign_automatic_bad.v:37:10: Automatic lifetime variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'bad_auto3' +%Error: t/t_assign_automatic_bad.v:35:10: Dynamically-sized variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'bad_dyn5' : ... note: In instance 't' - 37 | assign bad_auto3 = 2; - | ^~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_assign_automatic_bad.v:38:10: Dynamically-sized variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'bad_dyn5' - : ... note: In instance 't' - 38 | assign bad_dyn5[0] = empty_dyn; + 35 | assign bad_dyn5[0] = empty_dyn; | ^~~~~~~~ -%Error: t/t_assign_automatic_bad.v:40:12: Automatic lifetime variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'm_bad1' + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_assign_automatic_bad.v:37:12: Automatic lifetime variable not allowed in continuous assignment (IEEE 1800-2023 6.21): 'm_bad1' : ... note: In instance 't' - 40 | assign c.m_bad1 = 2; + 37 | assign c.m_bad1 = 2; | ^~~~~~ -%Error: t/t_assign_automatic_bad.v:50:5: Automatic lifetime variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_auto4' +%Error: t/t_assign_automatic_bad.v:47:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_dyn6' : ... note: In instance 't' - 50 | bad_auto4 <= 2; - | ^~~~~~~~~ -%Error: t/t_assign_automatic_bad.v:51:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_dyn6' - : ... note: In instance 't' - 51 | bad_dyn6[0] <= 2; + 47 | bad_dyn6[0] <= 2; | ^~~~~~~~ -%Error: t/t_assign_automatic_bad.v:53:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_queue' +%Error: t/t_assign_automatic_bad.v:49:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_queue' : ... note: In instance 't' - 53 | bad_queue[0] <= 2; + 49 | bad_queue[0] <= 2; | ^~~~~~~~~ -%Error: t/t_assign_automatic_bad.v:55:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_assoc' +%Error: t/t_assign_automatic_bad.v:51:5: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'bad_assoc' : ... note: In instance 't' - 55 | bad_assoc[0] <= 2; + 51 | bad_assoc[0] <= 2; | ^~~~~~~~~ -%Error: t/t_assign_automatic_bad.v:58:7: Automatic lifetime variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'm_bad2' +%Error: t/t_assign_automatic_bad.v:54:7: Automatic lifetime variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 'm_bad2' : ... note: In instance 't' - 58 | c.m_bad2 <= 2; + 54 | c.m_bad2 <= 2; | ^~~~~~ -%Error: t/t_assign_automatic_bad.v:60:10: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 's_dyn' +%Error: t/t_assign_automatic_bad.v:56:10: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 's_dyn' : ... note: In instance 't' - 60 | Cls::s_dyn[0] <= 2; + 56 | Cls::s_dyn[0] <= 2; | ^~~~~ -%Error: t/t_assign_automatic_bad.v:62:26: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 's_dyn' +%Error: t/t_assign_automatic_bad.v:58:26: Dynamically-sized variable not allowed in nonblocking assignment (IEEE 1800-2023 6.21): 's_dyn' : ... note: In instance 't' - 62 | clist[bad_dyn6[0]++].s_dyn[0] <= '1; + 58 | clist[bad_dyn6[0]++].s_dyn[0] <= '1; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assign_automatic_bad.v b/test_regress/t/t_assign_automatic_bad.v index b6e233b5f..90159e5ce 100644 --- a/test_regress/t/t_assign_automatic_bad.v +++ b/test_regress/t/t_assign_automatic_bad.v @@ -23,8 +23,6 @@ module t(clk); Cls c; - automatic int bad_auto3; - automatic int bad_auto4; int bad_dyn5[]; int bad_dyn6[]; int empty_dyn[]; @@ -34,7 +32,6 @@ module t(clk); int bad_assoc[int]; Cls clist[1]; - assign bad_auto3 = 2; // <--- Error: continuous automatic assign bad_dyn5[0] = empty_dyn; // <--- Error: continuous dynarray element assign bad_dyn5 = empty_dyn; // <--- OK: continuous dynarray assignment, not to its element assign c.m_bad1 = 2; // <--- Error: continuous class non-static @@ -47,7 +44,6 @@ module t(clk); endtask always @(posedge clk) begin - bad_auto4 <= 2; // <--- Error: nonblocking automatic bad_dyn6[0] <= 2; // <--- Error: nonblocking dynarray element bad_dyn6 <= empty_dyn; // <--- OK: nonblocking dynarray assignment, not to its element bad_queue[0] <= 2; // Error: nonblocking queue element assignment diff --git a/test_regress/t/t_randstate_func.v b/test_regress/t/t_randstate_func.v index 6f486052c..eea140025 100644 --- a/test_regress/t/t_randstate_func.v +++ b/test_regress/t/t_randstate_func.v @@ -34,9 +34,6 @@ endclass module t; - automatic int rand_result, v1, v2; - automatic string s; - initial begin Cls c; c = new; diff --git a/test_regress/t/t_randstate_obj.v b/test_regress/t/t_randstate_obj.v index aaf07a1b3..fa246aca9 100644 --- a/test_regress/t/t_randstate_obj.v +++ b/test_regress/t/t_randstate_obj.v @@ -5,35 +5,35 @@ // SPDX-License-Identifier: CC0-1.0 class Cls; - rand int length; + rand int length; endclass module t; - automatic int rand_result, v1, v2; - automatic string s; + int rand_result, v1, v2; + string s; - initial begin - Cls c; - c = new; + initial begin + Cls c; + c = new; - s = c.get_randstate(); + s = c.get_randstate(); - rand_result = c.randomize(); - if (rand_result != 1) $stop; - v1 = c.length; + rand_result = c.randomize(); + if (rand_result != 1) $stop; + v1 = c.length; - c.set_randstate(s); + c.set_randstate(s); - rand_result = c.randomize(); - if (rand_result != 1) $stop; - v2 = c.length; + rand_result = c.randomize(); + if (rand_result != 1) $stop; + v2 = c.length; `ifdef VERILATOR // About half of the other simulators fail at this - if (v1 != v2) $stop; + if (v1 != v2) $stop; `endif - $write("*-* All Finished *-*\n"); - $finish; - end + $write("*-* All Finished *-*\n"); + $finish; + end endmodule diff --git a/test_regress/t/t_var_const2.v b/test_regress/t/t_var_const2.v index acc55230a..5e70192bc 100644 --- a/test_regress/t/t_var_const2.v +++ b/test_regress/t/t_var_const2.v @@ -4,21 +4,10 @@ // any use, without warranty, 2025 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// verilog_format: off -`define stop $stop -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); -`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); -`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); -`define checkp(gotv,expv_s) do begin string gotv_s; gotv_s = $sformatf("%p", gotv); if ((gotv_s) != (expv_s)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv_s), (expv_s)); `stop; end end while(0); -// verilog_format: on - module t; const static int a1; const static int a2 = 0; - const automatic int b1; - const automatic int b2 = 0; - initial begin const static int c1; const static int c2 = 0; diff --git a/test_regress/t/t_var_lifetime_module_bad.out b/test_regress/t/t_var_lifetime_module_bad.out new file mode 100644 index 000000000..12d1334f7 --- /dev/null +++ b/test_regress/t/t_var_lifetime_module_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_var_lifetime_module_bad.v:8:17: Module variables cannot have automatic lifetime (IEEE 1800-2023 6.21): 'i' + 8 | automatic int i; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_var_lifetime_module_bad.py b/test_regress/t/t_var_lifetime_module_bad.py new file mode 100755 index 000000000..55203b6c9 --- /dev/null +++ b/test_regress/t/t_var_lifetime_module_bad.py @@ -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() diff --git a/test_regress/t/t_var_lifetime_module_bad.v b/test_regress/t/t_var_lifetime_module_bad.v new file mode 100644 index 000000000..a529822a6 --- /dev/null +++ b/test_regress/t/t_var_lifetime_module_bad.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + automatic int i; +endmodule