Improve `lint_off` to allow multiple messages and comments (#2755 partial).

This commit is contained in:
Wilson Snyder 2025-10-07 22:49:42 -04:00
parent 2631af977a
commit 1a8f9f0483
13 changed files with 95 additions and 47 deletions

View File

@ -33,6 +33,7 @@ Verilator 5.041 devel
* Support digits in `$sscanf` field width formats (#6083). [Iztok Jeras]
* Support pure functions in sensitivity lists (#6393). [Krzysztof Bieganski, Antmicro Ltd.]
* Support simple alias statements (#6339) (#6501). [Ryszard Rozak, Antmicro Ltd.]
* Improve `lint_off` to allow multiple messages and comments (#2755).
* Improve automatic selection of logic for DFG synthesis (#6370). [Geza Lore]
* Improve `covergroup with function sample` handling (#6387). [Jakub Wasilewski]
* Improve DFG type system (#6390). [Geza Lore]

View File

@ -362,15 +362,20 @@ or "`ifdef`"'s may break other tools.
Same as :option:`isolate_assignments` control file option.
.. option:: /*verilator&32;lint_off <msg>*/
.. option:: /*verilator&32;lint_off <msgs>*/
Disable the specified warning message for any warnings following the
comment.
Disable the specified warning message(s) for any warnings following the
comment. Multiple messages may be specified, separated with commas.
.. option:: /*verilator&32;lint_on <msg>*/
If a one-line slash-slash-format comment is used, then the metacomment
ends at the newline or at an earlier next slash-slash. This allow
commenting the reason for the disable, e.g. :code:`// verilator lint_off
MSG // Because...`.
Re-enable the specified warning message for any warnings following the
comment.
.. option:: /*verilator&32;lint_on <msgs>*/
Re-enable the specified warning message(s) for any warnings following
the comment. Multiple messages may be specified, separated with commas.
.. option:: /*verilator&32;lint_restore*/

View File

@ -368,23 +368,29 @@ std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
return (os);
}
bool FileLine::warnOff(const string& msg, bool flag) {
const char* cmsg = msg.c_str();
// Backward compatibility with msg="UNUSED"
if (V3ErrorCode::unusedMsg(cmsg)) {
warnOff(V3ErrorCode::UNUSEDGENVAR, flag);
warnOff(V3ErrorCode::UNUSEDLOOP, flag);
warnOff(V3ErrorCode::UNUSEDPARAM, flag);
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
return true;
}
const V3ErrorCode code{cmsg};
if (code.hardError()) {
return false;
} else {
warnOff(code, flag);
return true;
string FileLine::warnOffParse(const string& msgs, bool flag) {
string result;
for (const string& msg : VString::split(msgs, ',')) {
const char* cmsg = msg.c_str();
// Backward compatibility with msg="UNUSED"
if (V3ErrorCode::unusedMsg(cmsg)) {
warnOff(V3ErrorCode::UNUSEDGENVAR, flag);
warnOff(V3ErrorCode::UNUSEDLOOP, flag);
warnOff(V3ErrorCode::UNUSEDPARAM, flag);
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
continue;
}
const V3ErrorCode code{cmsg};
if (!code.hardError()) {
warnOff(code, flag);
continue;
}
// Error if not suppressed
if (!v3Global.opt.isFuture(msg)) result = VString::dot(result, ",", cmsg);
}
return result;
}
void FileLine::warnLintOff(bool flag) {

View File

@ -322,7 +322,7 @@ public:
m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, code, flag);
}
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
bool warnOff(const string& msg, bool flag); // Returns 1 if ok
string warnOffParse(const string& msgs, bool flag); // Returns "" if ok
bool warnIsOff(V3ErrorCode code) const VL_MT_SAFE;
void warnLintOff(bool flag);
void warnStyleOff(bool flag);
@ -350,8 +350,8 @@ public:
static void globalWarnOff(V3ErrorCode code, bool flag) {
defaultFileLine().warnOff(code, flag);
}
static bool globalWarnOff(const string& code, bool flag) {
return defaultFileLine().warnOff(code, flag);
static string globalWarnOffParse(const string& msgs, bool flag) {
return defaultFileLine().warnOffParse(msgs, flag);
}
static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); }
static void fileNameNumMapDumpJson(std::ostream& os) {

View File

@ -1807,7 +1807,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
addFuture(optp);
});
DECL_OPTION("-Wno-", CbPartialMatch, [fl, &parser](const char* optp) VL_MT_DISABLED {
if (!FileLine::globalWarnOff(optp, true)) {
const string err = FileLine::globalWarnOffParse(optp, true);
if (!err.empty()) {
const string fullopt = "-Wno-"s + optp;
fl->v3fatal("Unknown warning specified: " << fullopt
<< parser.getSuggestion(fullopt.c_str()));

View File

@ -171,12 +171,9 @@ void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnO
string::size_type pos;
if ((pos = msg.find('*')) != string::npos) msg.erase(pos);
// Use parsep()->lexFileline() as want to affect later FileLine's warnings
if (!(parsep()->lexFileline()->warnOff(msg, warnOff))) {
if (!v3Global.opt.isFuture(msg)) {
fl->v3error("Unknown verilator lint message code: '" << msg << "', in '" << textp
<< "'");
}
}
const string err = parsep()->lexFileline()->warnOffParse(msg, warnOff);
if (!err.empty())
fl->v3error("Unknown verilator lint message code: '" << err << "', in '" << textp << "'");
}
void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) {

View File

@ -438,10 +438,10 @@ bom [\357\273\277]
<ARGMODE>. { FL_FWDC; appendDefValue(yytext, yyleng); FL_BRK; }
/* Pragma comments. */
<INITIAL>"//"{ws}*"verilator lint_off"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, true); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_on"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, false); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_restore"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLintRestore(); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_save"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLintSave(); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_off"[^\n\r/]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, true); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_on"[^\n\r/]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, false); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_restore"[^\n\r/]* { FL_FWDC; LEXP->verilatorCmtLintRestore(); return VP_COMMENT; }
<INITIAL>"//"{ws}*"verilator lint_save"[^\n\r/]* { FL_FWDC; LEXP->verilatorCmtLintSave(); return VP_COMMENT; }
<INITIAL>"/*"{ws}*"verilator lint_off"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, true); return VP_COMMENT; }
<INITIAL>"/*"{ws}*"verilator lint_on"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, false); return VP_COMMENT; }
<INITIAL>"/*"{ws}*"verilator lint_restore"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLintRestore(); return VP_COMMENT; }
@ -788,7 +788,7 @@ void V3PreLex::verilatorCmtLint(const char* textp, bool warnOff) {
}
}
// No warnings on bad warning codes - the verilog.y parse will report as appropriate
curFilelinep()->warnOff(msg, warnOff);
curFilelinep()->warnOffParse(msg, warnOff);
}
/*###################################################################

View File

@ -327,6 +327,14 @@ string VString::replaceWord(const string& str, const string& from, const string&
return result;
}
std::deque<string> VString::split(const string& str, char delimiter) {
std::deque<std::string> results;
std::istringstream is{str};
std::string token;
while (std::getline(is, token, delimiter)) results.push_back(token);
return results;
}
bool VString::endsWith(const string& str, const string& suffix) {
if (str.length() < suffix.length()) return false;
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;

View File

@ -22,6 +22,7 @@
// No V3 headers here - this is a base class for Vlc etc
#include <deque>
#include <iomanip>
#include <map>
#include <set>
@ -138,6 +139,8 @@ public:
// to be a consecutive sequence of the characters [a-zA-Z0-9_]. Sub-words are not replaced.
// e.g.: replaceWords("one apple bad_apple", "apple", "banana") -> "one banana bad_apple"
static string replaceWord(const string& str, const string& from, const string& to);
// Return deque of strings split by the given delimiter
static std::deque<string> split(const string& str, char delimiter = ',');
// Predicate to check if 'str' starts with 'prefix'
static bool startsWith(const string& str, const char* prefixp) {
return !str.rfind(prefixp, 0); // Faster than .find(_) == 0

View File

@ -46,12 +46,7 @@
//END_MODULE_NAME--------------------------------------------------------------
//See also: https://github.com/twosigma/verilator_support
// verilator lint_off COMBDLY
// verilator lint_off INITIALDLY
// verilator lint_off MULTIDRIVEN
// verilator lint_off UNSIGNED
// verilator lint_off WIDTH
// verilator lint_off LATCH
// verilator lint_off COMBDLY,INITIALDLY,LATCH,MULTIDRIVEN,UNSIGNED,WIDTH
// BEGINNING OF MODULE
`timescale 1 ps / 1 ps

View File

@ -154,11 +154,9 @@ module t #(parameter GATED_CLK = 0) (/*AUTOARG*/
logic possibly_gated_clk;
if (GATED_CLK != 0) begin: yes_gated_clock
logic clk_en_latch;
/* verilator lint_off COMBDLY */
/* verilator lint_off LATCH */
// verilator lint_off COMBDLY,LATCH
always_comb if (clk == '0) clk_en_latch <= clk_en;
/* verilator lint_on LATCH */
/* verilator lint_on COMBDLY */
// verilator lint_on COMBDLY,LATCH
assign possibly_gated_clk = clk & clk_en_latch;
end else begin: no_gated_clock
assign possibly_gated_clk = clk;

View File

@ -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('vlt')
test.lint()
test.passes()

View File

@ -0,0 +1,18 @@
// 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 (
input [3:1] i3,
input [4:1] i4,
output [3:1] o3,
output [4:1] o4
);
// verilator lint_off WIDTHTRUNC,WIDTHEXPAND // after slashes ignored
assign o3 = i4;
assign o4 = i3;
endmodule