Internals: Refactor some V3Error code handling and add tests. No functional change intended.

This commit is contained in:
Wilson Snyder 2025-12-29 18:17:24 -05:00
parent 4775399716
commit 2e394c3c04
15 changed files with 121 additions and 49 deletions

View File

@ -445,12 +445,11 @@ public:
bool waive(V3ErrorCode code, const string& message) {
if (code.hardError()) return false;
for (const auto& itr : m_waivers) {
if ((code.isUnder(itr.m_code) || (itr.m_code == V3ErrorCode::I_LINT)))
if ((code.isUnder(itr.m_code) || (itr.m_code == V3ErrorCode::I_LINT))
&& VString::wildmatch(message, itr.m_match)
&& WildcardContents::resolve(itr.m_contents)) {
return true;
}
if ((code.isUnder(itr.m_code) || (itr.m_code == V3ErrorCode::I_LINT))
&& VString::wildmatch(message, itr.m_match)
&& WildcardContents::resolve(itr.m_contents)) {
return true;
}
}
return false;
}

View File

@ -301,8 +301,9 @@ void V3ErrorGuarded::v3errorEndGuts(const std::ostringstream& sstr, const string
void V3Error::init() {
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
describedEachWarn(static_cast<V3ErrorCode>(i), false);
pretendError(static_cast<V3ErrorCode>(i), V3ErrorCode{i}.pretendError());
const V3ErrorCode code{i};
describedEachWarn(code, false);
pretendError(code, code.pretendError());
}
// Not an UASSERT as failure would call V3Error and it's broken due to this
assert(std::string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} == " MAX");

View File

@ -197,6 +197,8 @@ public:
constexpr V3ErrorCode(en _e)
: m_e{_e} {}
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
explicit V3ErrorCode(const std::string& msg)
: V3ErrorCode{msg.c_str()} {}
explicit V3ErrorCode(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const VL_MT_SAFE { return m_e; }
@ -427,7 +429,7 @@ public:
bool isErrorOrWarn() VL_REQUIRES(m_mutex) {
return errorCount() || (warnFatal() && warnCount());
}
bool pretendError(int errorCode) VL_REQUIRES(m_mutex) { return m_pretendError[errorCode]; }
bool pretendError(V3ErrorCode code) VL_REQUIRES(m_mutex) { return m_pretendError[code]; }
void pretendError(V3ErrorCode code, bool flag) VL_REQUIRES(m_mutex) {
if (code == V3ErrorCode::WIDTH) {
m_pretendError[V3ErrorCode::WIDTHTRUNC] = flag;
@ -504,9 +506,9 @@ public:
const V3RecursiveLockGuard guard{s().m_mutex};
return s().errorCount();
}
static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
static bool pretendError(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
const V3RecursiveLockGuard guard{s().m_mutex};
return s().pretendError(errorCode);
return s().pretendError(code);
}
static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
const V3RecursiveLockGuard guard{s().m_mutex};

View File

@ -126,7 +126,7 @@ FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBi
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() VL_MT_SAFE {
MsgEnBitSet msgEnBitSet;
for (int i = V3ErrorCode::EC_MIN; i < V3ErrorCode::_ENUM_MAX; ++i) {
// "-Wall" and the like only adjsut the code subset, so use default enablement there
// "-Wall" and the like only adjust the code subset, so use default enablement there
msgEnBitSet.set(MsgEnBitSet::Subset::CODE, i, !V3ErrorCode{i}.defaultsOff());
// The control file subset is only adjusted by the control files, everything enabled by
// default
@ -374,22 +374,22 @@ std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
return (os);
}
string FileLine::warnOffParse(const string& msgs, bool flag) {
string FileLine::warnOffParse(const string& msgs, bool turnOff) {
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);
warnOff(V3ErrorCode::UNUSEDGENVAR, turnOff);
warnOff(V3ErrorCode::UNUSEDLOOP, turnOff);
warnOff(V3ErrorCode::UNUSEDPARAM, turnOff);
warnOff(V3ErrorCode::UNUSEDSIGNAL, turnOff);
continue;
}
const V3ErrorCode code{cmsg};
const V3ErrorCode code{msg};
if (!code.hardError()) {
warnOff(code, flag);
warnOff(code, turnOff);
continue;
}
@ -399,25 +399,25 @@ string FileLine::warnOffParse(const string& msgs, bool flag) {
return result;
}
void FileLine::warnLintOff(bool flag) {
void FileLine::warnLintOff(bool turnOff) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
const V3ErrorCode code{codei};
if (code.lintError()) warnOff(code, flag);
if (code.lintError()) warnOff(code, turnOff);
}
}
void FileLine::warnStyleOff(bool flag) {
void FileLine::warnStyleOff(bool turnOff) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
const V3ErrorCode code{codei};
if (code.styleError()) warnOff(code, flag);
if (code.styleError()) warnOff(code, turnOff);
}
}
void FileLine::warnUnusedOff(bool flag) {
warnOff(V3ErrorCode::UNUSEDGENVAR, flag);
warnOff(V3ErrorCode::UNUSEDLOOP, flag);
warnOff(V3ErrorCode::UNUSEDPARAM, flag);
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
void FileLine::warnUnusedOff(bool turnOff) {
warnOff(V3ErrorCode::UNUSEDGENVAR, turnOff);
warnOff(V3ErrorCode::UNUSEDLOOP, turnOff);
warnOff(V3ErrorCode::UNUSEDPARAM, turnOff);
warnOff(V3ErrorCode::UNUSEDSIGNAL, turnOff);
}
bool FileLine::warnIsOff(V3ErrorCode code) const {

View File

@ -373,7 +373,7 @@ private:
warnSet(subset, V3ErrorCode::WIDTHEXPAND, flag);
warnSet(subset, V3ErrorCode::WIDTHXZEXPAND, flag);
}
if (code == V3ErrorCode::E_UNSUPPORTED) { warnSet(subset, V3ErrorCode::COVERIGN, flag); }
if (code == V3ErrorCode::E_UNSUPPORTED) warnSet(subset, V3ErrorCode::COVERIGN, flag);
m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, subset, code, flag);
}
@ -382,12 +382,12 @@ public:
void warnOnCtrl(V3ErrorCode code, bool flag) {
warnSet(MsgEnBitSet::Subset::CTRL, code, flag);
}
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
string warnOffParse(const string& msgs, bool flag); // Returns "" if ok
void warnOff(V3ErrorCode code, bool turnOff) { warnOn(code, !turnOff); }
string warnOffParse(const string& msgs, bool turnOff); // Returns "" if ok
bool warnIsOff(V3ErrorCode code) const VL_MT_SAFE;
void warnLintOff(bool flag);
void warnStyleOff(bool flag);
void warnUnusedOff(bool flag);
void warnLintOff(bool turnOff);
void warnStyleOff(bool turnOff);
void warnUnusedOff(bool turnOff);
void warnStateFrom(const FileLine& from) { m_msgEnIdx = from.m_msgEnIdx; }
void warnResetDefault() { warnStateFrom(defaultFileLine()); }
@ -405,14 +405,14 @@ public:
// <command-line> and <built-in> match what GCC outputs
static string commandLineFilename() VL_MT_SAFE { return "<command-line>"; }
static string builtInFilename() VL_MT_SAFE { return "<built-in>"; }
static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); }
static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); }
static void globalWarnUnusedOff(bool flag) { defaultFileLine().warnUnusedOff(flag); }
static void globalWarnOff(V3ErrorCode code, bool flag) {
defaultFileLine().warnOff(code, flag);
static void globalWarnLintOff(bool turnOff) { defaultFileLine().warnLintOff(turnOff); }
static void globalWarnStyleOff(bool turnOff) { defaultFileLine().warnStyleOff(turnOff); }
static void globalWarnUnusedOff(bool turnOff) { defaultFileLine().warnUnusedOff(turnOff); }
static void globalWarnOff(V3ErrorCode code, bool turnOff) {
defaultFileLine().warnOff(code, turnOff);
}
static string globalWarnOffParse(const string& msgs, bool flag) {
return defaultFileLine().warnOffParse(msgs, flag);
static string globalWarnOffParse(const string& msgs, bool turnOff) {
return defaultFileLine().warnOffParse(msgs, turnOff);
}
static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); }
static void fileNameNumMapDumpJson(std::ostream& os) {
@ -427,7 +427,7 @@ public:
// Change the current fileline due to actions discovered after parsing
// and may have side effects on other nodes sharing this FileLine.
// Use only when this is intended
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); }
void modifyWarnOff(V3ErrorCode code, bool turnOff) { warnOff(code, turnOff); }
// OPERATORS
void v3errorEnd(std::ostringstream& str, const string& extra = "")

View File

@ -161,7 +161,7 @@ void V3ParseImp::lexVerilatorCmtLintRestore(FileLine* fl) {
m_lexLintState.pop_back();
}
void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) {
void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool turnOff) {
const char* sp = textp;
while (*sp && !std::isspace(*sp)) ++sp;
while (*sp && std::isspace(*sp)) ++sp;
@ -171,7 +171,7 @@ 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
const string err = parsep()->lexFileline()->warnOffParse(msg, warnOff);
const string err = parsep()->lexFileline()->warnOffParse(msg, turnOff);
if (!err.empty())
fl->v3error("Unknown verilator lint message code: '" << err << "', in '" << textp << "'");
}

View File

@ -196,7 +196,7 @@ public:
static string lexParseTag(const char* textp) VL_MT_DISABLED;
static double lexParseTimenum(const char* text) VL_MT_DISABLED;
void lexPpline(const char* textp) VL_MT_DISABLED;
void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) VL_MT_DISABLED;
void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool turnOff) VL_MT_DISABLED;
void lexVerilatorCmtLintSave(const FileLine* fl) VL_MT_DISABLED;
void lexVerilatorCmtLintRestore(FileLine* fl) VL_MT_DISABLED;
static void lexVerilatorCmtBad(FileLine* fl, const char* textp) VL_MT_DISABLED;

View File

@ -211,7 +211,7 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp
}
}
void warnBackslashSpace();
void verilatorCmtLint(const char* textp, bool warnOff);
void verilatorCmtLint(const char* textp, bool turnOff);
void verilatorCmtLintRestore();
void verilatorCmtLintSave();
// Called by V3PreProc.cpp to inform lexer

View File

@ -799,7 +799,7 @@ void V3PreLex::verilatorCmtLintRestore() {
curFilelinep()->warnStateFrom(m_lexLintState.back());
m_lexLintState.pop_back();
}
void V3PreLex::verilatorCmtLint(const char* textp, bool warnOff) {
void V3PreLex::verilatorCmtLint(const char* textp, bool turnOff) {
const char* sp = textp;
while (*sp && std::isspace(*sp)) ++sp;
while (*sp && !std::isspace(*sp)) ++sp; // "verilator"
@ -814,7 +814,7 @@ void V3PreLex::verilatorCmtLint(const char* textp, bool warnOff) {
}
}
// No warnings on bad warning codes - the verilog.y parse will report as appropriate
curFilelinep()->warnOffParse(msg, warnOff);
curFilelinep()->warnOffParse(msg, turnOff);
}
/*###################################################################

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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.top_filename = "t/t_covergroup_unsup.v"
test.lint(verilator_flags2=[
'--assert --coverage --Wwarn-UNSUPPORTED -Wno-fatal +define+T_COVERGROUP_UNSUP_IGN'
])
test.passes()

View File

@ -12,6 +12,8 @@ import vltest_bootstrap
test.scenarios('vlt')
test.top_filename = "t/t_flag_werror.v"
test.lint(fails=True, verilator_flags=["-cc -Werror-WIDTH"], expect_filename=test.golden_filename)
test.lint(fails=True,
verilator_flags=["-cc -Wno-fatal -Werror-WIDTH"],
expect_filename=test.golden_filename)
test.passes()

View File

@ -93,6 +93,7 @@ module t;
// verilator lint_off SPLITVAR
// verilator lint_off STATICVAR
// verilator lint_off STMTDLY
// verilator lint_off SUPERNFIRST
// verilator lint_off SYMRSVDWORD
// verilator lint_off SYNCASYNCNET
// verilator lint_off TICKCOUNT
@ -103,6 +104,7 @@ module t;
// verilator lint_off UNOPTTHREADS
// verilator lint_off UNPACKED
// verilator lint_off UNSIGNED
// verilator lint_off UNUSED
// verilator lint_off UNUSEDGENVAR
// verilator lint_off UNUSEDLOOP
// verilator lint_off UNUSEDPARAM

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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.top_filename = 't/t_lint_unused_bad.v'
test.lint(verilator_flags2=[
"--lint-only --bbox-sys --bbox-unsup -Wall -Wno-DECLFILENAME", "t/t_lint_unused_vlt.vlt"
])
test.passes()

View File

@ -0,0 +1,10 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`verilator_config
lint_off --rule UNDRIVEN
// Checks UNUSED delegation to UNUSEDSIGNAL etc
lint_off --rule UNUSED

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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.top_filename = 't/t_lint_unused_bad.v'
test.lint(verilator_flags2=["--lint-only --bbox-sys --bbox-unsup -Wall -Wno-fatal -Werror-UNUSED"],
fails=True)
test.passes()