Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839)

This commit is contained in:
Ryszard Rozak 2023-01-05 23:42:05 +01:00 committed by GitHub
parent 78fe77db0f
commit 4784daa7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 160 additions and 40 deletions

View File

@ -1502,7 +1502,7 @@ Summary:
Disable all lint-related warning messages, and all style warnings. This is Disable all lint-related warning messages, and all style warnings. This is
equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE
-Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS
-Wno-IMPLICIT -Wno-LITENDIAN -Wno-PINCONNECTEMPTY -Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-LITENDIAN -Wno-PINCONNECTEMPTY
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED
-Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL
-Wno-WIDTH`` plus the list shown for Wno-style. -Wno-WIDTH`` plus the list shown for Wno-style.

View File

@ -727,6 +727,27 @@ List Of Warnings
implicit definition of wire '...'". implicit definition of wire '...'".
.. option:: IMPLICITSTATIC
Warns that the lifetime of a task or a function was not provided and so
was implicitly set to static. The warning is suppressed when no
variables inside the task or a function are assigned to.
This is a warning because the static default differs from C++, differs
from class member function/tasks. Static is a more dangerous default
then automatic as static prevents the function from being reinterant,
which may be a source of bugs, and/or performance issues.
If the function does not require static behavior, change it to "function
automatic".
If the function requires static behavior, change it to "function
static".
Ignoring this warning will only suppress the lint check; it will
simulate correctly.
.. option:: IMPORTSTAR .. option:: IMPORTSTAR
.. TODO better example .. TODO better example

View File

@ -96,6 +96,7 @@ public:
IGNOREDRETURN, // Ignoring return value (function as task) IGNOREDRETURN, // Ignoring return value (function as task)
IMPERFECTSCH, // Imperfect schedule (disabled by default). Historical, never issued. IMPERFECTSCH, // Imperfect schedule (disabled by default). Historical, never issued.
IMPLICIT, // Implicit wire IMPLICIT, // Implicit wire
IMPLICITSTATIC, // Implicit static function
IMPORTSTAR, // Import::* in $unit IMPORTSTAR, // Import::* in $unit
IMPURE, // Impure function not being inlined IMPURE, // Impure function not being inlined
INCABSPATH, // Include has absolute path INCABSPATH, // Include has absolute path
@ -180,7 +181,7 @@ public:
"DECLFILENAME", "DEFPARAM", "DEPRECATED", "DECLFILENAME", "DEFPARAM", "DEPRECATED",
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "HIERBLOCK", "ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "HIERBLOCK",
"IFDEPTH", "IGNOREDRETURN", "IFDEPTH", "IGNOREDRETURN",
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MODDUP", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MODDUP",
"MULTIDRIVEN", "MULTITOP","NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "MULTIDRIVEN", "MULTITOP","NOLATCH", "NULLPORT", "PINCONNECTEMPTY",
@ -220,9 +221,9 @@ public:
bool lintError() const VL_MT_SAFE { bool lintError() const VL_MT_SAFE {
return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE
|| m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST
|| m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == LATCH || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC
|| m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT || m_e == UNSIGNED || m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT
|| m_e == WIDTH); || m_e == UNSIGNED || m_e == WIDTH);
} }
// Warnings that are style only // Warnings that are style only
bool styleError() const VL_MT_SAFE { bool styleError() const VL_MT_SAFE {

View File

@ -123,6 +123,13 @@ private:
&& (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath && (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath
&& !nodep->stmtsp()->nextp()); // Has only one item && !nodep->stmtsp()->nextp()); // Has only one item
} }
bool hasStaticDeclAssignments(AstNodeFTask* nodep) {
for (const AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
const AstVar* const varp = VN_CAST(itemp, Var);
if (varp && varp->valuep() && !varp->lifetime().isAutomatic()) return true;
}
return false;
}
// VISITs // VISITs
void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
@ -133,10 +140,26 @@ private:
VL_RESTORER(m_lifetime); VL_RESTORER(m_lifetime);
{ {
m_ftaskp = nodep; m_ftaskp = nodep;
m_lifetime = nodep->lifetime(); if (!nodep->lifetime().isNone()) {
if (m_lifetime.isNone()) { m_lifetime = nodep->lifetime();
// Automatic always until we support static } else {
m_lifetime = VLifetime::AUTOMATIC; const AstClassOrPackageRef* const classPkgRefp
= VN_AS(nodep->classOrPackagep(), ClassOrPackageRef);
if (classPkgRefp && VN_IS(classPkgRefp->classOrPackageNodep(), Class)) {
// Class methods are automatic by default
m_lifetime = VLifetime::AUTOMATIC;
} else if (nodep->dpiImport()) {
// DPI-imported function don't have lifetime specifiers
m_lifetime = VLifetime::NONE;
}
if (m_lifetime.isStatic() && hasStaticDeclAssignments(nodep)) {
nodep->v3warn(
IMPLICITSTATIC,
"Function/task's lifetime implicitly set to static\n"
<< nodep->warnMore()
<< "... Suggest use 'function automatic' or 'function static'");
}
nodep->lifetime(m_lifetime);
} }
iterateChildren(nodep); iterateChildren(nodep);
} }

View File

@ -19,19 +19,19 @@ module t (/*AUTOARG*/
return found.size() == 1; return found.size() == 1;
endfunction endfunction
function bit test_find_index; function static bit test_find_index;
int q[$] = {1, 2, 3, 4}; int q[$] = {1, 2, 3, 4};
int found[$] = q.find_index(x) with (x <= 2); int found[$] = q.find_index(x) with (x <= 2);
return found.size() == 2; return found.size() == 2;
endfunction endfunction
function bit test_find_first_index; function static bit test_find_first_index;
int q[] = {1, 2, 3, 4, 5, 6}; int q[] = {1, 2, 3, 4, 5, 6};
int first_even_idx[$] = q.find_first_index(x) with (x % 2 == 0); int first_even_idx[$] = q.find_first_index(x) with (x % 2 == 0);
return first_even_idx[0] == 1; return first_even_idx[0] == 1;
endfunction endfunction
function bit test_sort; function automatic bit test_sort;
int q[] = {-5, 2, -3, 0, 4}; int q[] = {-5, 2, -3, 0, 4};
q.sort(x) with (x >= 0 ? x : -x); q.sort(x) with (x >= 0 ? x : -x);
return q[1] == 2; return q[1] == 2;

View File

@ -21,7 +21,7 @@ module t (/*AUTOARG*/
// associative array of an associative array // associative array of an associative array
logic [31:0] a [logic [31:0]][logic [63:0]]; logic [31:0] a [logic [31:0]][logic [63:0]];
task disp(); task static disp();
int i = 60; int i = 60;
imap[i++] = 600; imap[i++] = 600;
imap[i++] = 601; imap[i++] = 601;

View File

@ -12,7 +12,7 @@ module t(/*AUTOARG*/);
typedef int calc_sums_t [3:0]; typedef int calc_sums_t [3:0];
localparam int SUMS_ARRAY [3:0] = calc_sums_array(SIZES, 4); localparam int SUMS_ARRAY [3:0] = calc_sums_array(SIZES, 4);
function calc_sums_t calc_sums_array(int s[3:0], int n); function automatic calc_sums_t calc_sums_array(int s[3:0], int n);
int sum = 0; int sum = 0;
for (int ii = 0; ii < n; ++ii) begin for (int ii = 0; ii < n; ++ii) begin
sum = sum + s[ii]; sum = sum + s[ii];
@ -23,7 +23,7 @@ module t(/*AUTOARG*/);
`ifndef VERILATOR `ifndef VERILATOR
localparam int SUMS_DYN [3:0] = calc_sums_dyn(SIZES, 4); localparam int SUMS_DYN [3:0] = calc_sums_dyn(SIZES, 4);
`endif `endif
function calc_sums_t calc_sums_dyn(int s[], int n); function automatic calc_sums_t calc_sums_dyn(int s[], int n);
int sum = 0; int sum = 0;
for (int ii = 0; ii < n; ++ii) begin for (int ii = 0; ii < n; ++ii) begin
sum = sum + s[ii]; sum = sum + s[ii];

View File

@ -34,7 +34,7 @@ module t;
hasout = 0; hasout = 0;
endfunction endfunction
function int f( int j = 1, int dup = 0 ); function automatic int f( int j = 1, int dup = 0 );
return (j<<16) | dup; return (j<<16) | dup;
endfunction endfunction

View File

@ -102,7 +102,7 @@ module t;
endcase endcase
endfunction endfunction
function integer f_return(input [31:0] a); function automatic integer f_return(input [31:0] a);
integer out = 2; integer out = 2;
while (1) begin while (1) begin
out = out+1; out = out+1;

View File

@ -5,7 +5,7 @@
// without warranty, 2015 by Todd Strader. // without warranty, 2015 by Todd Strader.
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
function logic foo function automatic logic foo
( (
// Intentionally provide a non-width'ed default value // Intentionally provide a non-width'ed default value
// This should warn, not error out // This should warn, not error out

View File

@ -6,7 +6,7 @@
module t (/*AUTOARG*/); module t (/*AUTOARG*/);
function int f( int j = 1, int s = 0 ); function automatic int f( int j = 1, int s = 0 );
return (j<<16) | s; return (j<<16) | s;
endfunction endfunction

View File

@ -0,0 +1,11 @@
%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:7:14: Function/task's lifetime implicitly set to static
: ... Suggest use 'function automatic' or 'function static'
7 | function int f_implicit_static();
| ^~~~~~~~~~~~~~~~~
... For warning description see https://verilator.org/warn/IMPLICITSTATIC?v=latest
... Use "/* verilator lint_off IMPLICITSTATIC */" and lint_on around source to disable this message.
%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:12:6: Function/task's lifetime implicitly set to static
: ... Suggest use 'function automatic' or 'function static'
12 | task t_implicit_static();
| ^~~~~~~~~~~~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,23 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2023 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(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
execute(
check_finished => 1,
) if !$Self->{vlt_all};
ok(1);
1;

View File

@ -0,0 +1,39 @@
// 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
function int f_implicit_static();
int cnt = 0;
return ++cnt;
endfunction
task t_implicit_static();
int cnt = 0;
$display("%d", ++cnt);
endtask
module t (/*AUTOARG*/
// Inputs
clk
);
// verilator lint_off IMPLICITSTATIC
function int f_implicit_but_lint_off();
int cnt = 0;
return ++cnt;
endfunction
input clk;
int a, b;
initial begin
a = f_implicit_static();
t_implicit_static();
b = f_implicit_but_lint_off();
$stop;
end
endmodule

View File

@ -12,7 +12,7 @@ module t (/*AUTOARG*/
reg [3:0] counter = 0; reg [3:0] counter = 0;
integer l2; integer l2;
function log2 (input [3:0] x); function automatic log2 (input [3:0] x);
integer log2 = (x < 2) ? 1 : (x < 4) ? 2 : (x < 8) ? 3 : 4; integer log2 = (x < 2) ? 1 : (x < 4) ? 2 : (x < 8) ? 3 : 4;
endfunction endfunction
always @(posedge clk) begin always @(posedge clk) begin

View File

@ -10,7 +10,7 @@ module t (/*AUTOARG*/
input clk; input clk;
function bit test_1; function automatic bit test_1;
int iterations = 0; int iterations = 0;
do begin do begin
iterations++; iterations++;
@ -20,7 +20,7 @@ module t (/*AUTOARG*/
return iterations == 1; return iterations == 1;
endfunction endfunction
function bit test_2; function automatic bit test_2;
int iterations = 0; int iterations = 0;
do begin do begin
break; break;
@ -37,7 +37,7 @@ module t (/*AUTOARG*/
return 1'b1; return 1'b1;
endfunction endfunction
function bit test_4; function automatic bit test_4;
int incr = 0; int incr = 0;
do begin do begin
incr++; incr++;
@ -48,7 +48,7 @@ module t (/*AUTOARG*/
return incr == 1; return incr == 1;
endfunction endfunction
function bit test_5; function automatic bit test_5;
int incr = 0; int incr = 0;
do begin do begin
do do
@ -62,7 +62,7 @@ module t (/*AUTOARG*/
return incr == 10; return incr == 10;
endfunction endfunction
function bit test_6; function automatic bit test_6;
int incr = 0; int incr = 0;
do begin do begin
do begin do begin
@ -78,7 +78,7 @@ module t (/*AUTOARG*/
return incr == 10; return incr == 10;
endfunction endfunction
function bit test_7; function automatic bit test_7;
int incr = 0; int incr = 0;
do begin do begin
do begin do begin
@ -95,7 +95,7 @@ module t (/*AUTOARG*/
return incr == 2; return incr == 2;
endfunction endfunction
function bit test_8; function automatic bit test_8;
int incr = 0; int incr = 0;
do begin do begin
incr++; incr++;
@ -106,7 +106,7 @@ module t (/*AUTOARG*/
return incr == 1; return incr == 1;
endfunction endfunction
function bit test_9; function automatic bit test_9;
int incr = 0; int incr = 0;
do begin do begin
incr++; incr++;
@ -117,7 +117,7 @@ module t (/*AUTOARG*/
return incr == 5; return incr == 5;
endfunction endfunction
function bit test_10; function automatic bit test_10;
do begin do begin
continue; continue;
end end
@ -125,7 +125,7 @@ module t (/*AUTOARG*/
return 1'b1; return 1'b1;
endfunction endfunction
function bit test_11; function automatic bit test_11;
int incr = 0; int incr = 0;
do begin do begin
do do
@ -139,7 +139,7 @@ module t (/*AUTOARG*/
return incr == 12; return incr == 12;
endfunction endfunction
function bit test_12; function automatic bit test_12;
int incr = 0; int incr = 0;
do begin do begin
do begin do begin

View File

@ -8,7 +8,7 @@ module t;
parameter int SIZES [3:0] = '{1,2,3,4}; parameter int SIZES [3:0] = '{1,2,3,4};
typedef int calc_sums_t [3:0]; typedef int calc_sums_t [3:0];
function calc_sums_t calc_sums; function static calc_sums_t calc_sums;
int sum = 0; int sum = 0;
for (int i=0; i<4; i++) begin for (int i=0; i<4; i++) begin
sum = sum + SIZES[i]; sum = sum + SIZES[i];

View File

@ -29,7 +29,7 @@ endmodule
module sub; module sub;
parameter WIDTH = 1; parameter WIDTH = 1;
function [WIDTH-1:0] orer; function automatic [WIDTH-1:0] orer;
input [WIDTH-1:0] in; input [WIDTH-1:0] in;
// IEEE provices no way to override this parameter, basically it's a localparam // IEEE provices no way to override this parameter, basically it's a localparam
parameter MASK_W = WIDTH - 2; parameter MASK_W = WIDTH - 2;
@ -39,7 +39,7 @@ module sub;
// verilator lint_on WIDTH // verilator lint_on WIDTH
endfunction endfunction
function [WIDTH-1:0] orer2; function automatic [WIDTH-1:0] orer2;
input [WIDTH-1:0] in; input [WIDTH-1:0] in;
// Same param names as other function to check we disambiguate // Same param names as other function to check we disambiguate
// IEEE provices no way to override this parameter, basically it's a localparam // IEEE provices no way to override this parameter, basically it's a localparam

View File

@ -236,7 +236,7 @@ module t (/*AUTOARG*/
end end
endfunction : print_data_error endfunction : print_data_error
function void print_all_data (string name = ""); function static void print_all_data (string name = "");
foreach (byte_in[i]) $display(" %s byte_in[%0d]=%0h, byte_out=%0h ", name, i, byte_in[i], byte_out[i]); foreach (byte_in[i]) $display(" %s byte_in[%0d]=%0h, byte_out=%0h ", name, i, byte_in[i], byte_out[i]);
$display(" %s packed_data_32=%0h, packed_data_32_ref=%0h", name, packed_data_32, packed_data_32_ref); $display(" %s packed_data_32=%0h, packed_data_32_ref=%0h", name, packed_data_32, packed_data_32_ref);

View File

@ -22,7 +22,7 @@ module t (/*AUTOARG*/
localparam string REGX [0:31] = '{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0/fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5", localparam string REGX [0:31] = '{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0/fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
function string regx (logic [5-1:0] r, bit abi=1'b0); function automatic string regx (logic [5-1:0] r, bit abi=1'b0);
regx = abi ? REGX[r] : $sformatf("x%0d", r); regx = abi ? REGX[r] : $sformatf("x%0d", r);
endfunction: regx endfunction: regx

View File

@ -14,12 +14,12 @@ module t (/*AUTOARG*/);
"s3", "s4", "s5", "s6", "s7", "s8", "s9", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
"s10", "s11", "t3", "t4", "t5", "t6"}; "s10", "s11", "t3", "t4", "t5", "t6"};
function string reg_x (logic [4:0] r, bit abi=1'b0); function automatic string reg_x (logic [4:0] r, bit abi=1'b0);
reg_x = abi ? REG_X[r] : $sformatf("x%0d", r); reg_x = abi ? REG_X[r] : $sformatf("x%0d", r);
endfunction endfunction
// the issue is triggered by a second function containing a case statement // the issue is triggered by a second function containing a case statement
function string f2 (logic [4:0] r, bit abi=0); function automatic string f2 (logic [4:0] r, bit abi=0);
case (r) case (r)
5'd0: f2 = $sformatf("nop"); 5'd0: f2 = $sformatf("nop");
5'd1: f2 = $sformatf("reg %s", reg_x(r[4:0], abi)); 5'd1: f2 = $sformatf("reg %s", reg_x(r[4:0], abi));

View File

@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
compile( compile(
verilator_flags2 => ['-Wno-IMPLICITSTATIC'],
fails => $Self->{vlt_all}, # Verilator unsupported, bug546 fails => $Self->{vlt_all}, # Verilator unsupported, bug546
expect_filename => $Self->{golden_filename}, expect_filename => $Self->{golden_filename},
); );

View File

@ -1,6 +1,6 @@
%Error-UNSUPPORTED: t/t_var_static_param.v:32:18: Unsupported: 'static' function/task variables %Error-UNSUPPORTED: t/t_var_static_param.v:33:18: Unsupported: 'static' function/task variables
: ... In instance t.subb : ... In instance t.subb
32 | static int st = 2; st += P; return st; 33 | static int st = 2; st += P; return st;
| ^~ | ^~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to %Error: Exiting due to

View File

@ -27,6 +27,7 @@ endmodule
module sub; module sub;
parameter P = 1; parameter P = 1;
// verilator lint_off IMPLICITSTATIC
function int f_no_st (); function int f_no_st ();
// This static is unique within each parameterized module // This static is unique within each parameterized module
static int st = 2; st += P; return st; static int st = 2; st += P; return st;