forked from github/verilator
Internals: Add mutex to V3Error (#3680)
This commit is contained in:
parent
4eb280601e
commit
93d50c4499
@ -47,6 +47,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@ -175,6 +176,19 @@ public:
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
|
||||
/// Acquire/lock mutex and check for stop request
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
while (true) {
|
||||
checkStopRequestFunction();
|
||||
if (m_mutex.try_lock()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
@ -192,10 +206,19 @@ public:
|
||||
}
|
||||
/// Destruct and unlock the mutex
|
||||
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
/// Unlock the mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Lock the mutex
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Unlock the mutex
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
|
||||
/// Acquire/lock mutex and check for stop request.
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
m_mutexr.lockCheckStopRequest(checkStopRequestFunction);
|
||||
}
|
||||
};
|
||||
|
||||
// Internals: Remember the calling thread at construction time, and make
|
||||
|
@ -1257,7 +1257,7 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump)
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_MT_SAFE {
|
||||
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
v3errorEnd(str);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
@ -1287,9 +1287,9 @@ string AstNode::instanceStr() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
void AstNode::v3errorEnd(std::ostringstream& str) const {
|
||||
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
if (!m_fileline) {
|
||||
V3Error::v3errorEnd(str, instanceStr());
|
||||
V3Error::s().v3errorEnd(str, instanceStr());
|
||||
} else {
|
||||
std::ostringstream nsstr;
|
||||
nsstr << str.str();
|
||||
@ -1302,8 +1302,8 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
||||
// Don't look for instance name when warning is disabled.
|
||||
// In case of large number of warnings, this can
|
||||
// take significant amount of time
|
||||
m_fileline->v3errorEnd(nsstr,
|
||||
m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr());
|
||||
m_fileline->v3errorEnd(
|
||||
nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr());
|
||||
}
|
||||
}
|
||||
|
||||
|
13
src/V3Ast.h
13
src/V3Ast.h
@ -1853,12 +1853,15 @@ public:
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
// METHODS - dump and error
|
||||
void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE;
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
||||
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex);
|
||||
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
return fileline()->warnContextPrimary();
|
||||
}
|
||||
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||
string warnMore() const { return fileline()->warnMore(); }
|
||||
string warnOther() const { return fileline()->warnOther(); }
|
||||
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||
|
||||
virtual void dump(std::ostream& str = std::cout) const;
|
||||
static void dumpGdb(const AstNode* nodep); // For GDB only
|
||||
|
15
src/V3Dfg.h
15
src/V3Dfg.h
@ -503,14 +503,19 @@ public:
|
||||
inline bool inlined() const;
|
||||
|
||||
// Methods that allow DfgVertex to participate in error reporting/messaging
|
||||
void v3errorEnd(std::ostringstream& str) const { m_filelinep->v3errorEnd(str); }
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN {
|
||||
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
m_filelinep->v3errorEnd(str);
|
||||
}
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
m_filelinep->v3errorEndFatal(str);
|
||||
}
|
||||
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
||||
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
return fileline()->warnContextPrimary();
|
||||
}
|
||||
string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||
string warnMore() const { return fileline()->warnMore(); }
|
||||
string warnOther() const { return fileline()->warnOther(); }
|
||||
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||
|
||||
private:
|
||||
// For internal use only.
|
||||
|
233
src/V3Error.cpp
233
src/V3Error.cpp
@ -25,24 +25,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
// clang-format on
|
||||
|
||||
//======================================================================
|
||||
// Statics
|
||||
|
||||
int V3Error::s_errCount = 0;
|
||||
int V3Error::s_warnCount = 0;
|
||||
int V3Error::s_debugDefault = 0;
|
||||
int V3Error::s_errorLimit = V3Error::MAX_ERRORS;
|
||||
bool V3Error::s_warnFatal = true;
|
||||
int V3Error::s_tellManual = 0;
|
||||
std::ostringstream V3Error::s_errorStr; // Error string being formed
|
||||
V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL;
|
||||
bool V3Error::s_errorContexted = false;
|
||||
bool V3Error::s_errorSuppressed = false;
|
||||
std::array<bool, V3ErrorCode::_ENUM_MAX> V3Error::s_describedEachWarn;
|
||||
std::array<bool, V3ErrorCode::_ENUM_MAX> V3Error::s_pretendError;
|
||||
bool V3Error::s_describedWarnings = false;
|
||||
bool V3Error::s_describedWeb = false;
|
||||
V3Error::MessagesSet V3Error::s_messages;
|
||||
V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr;
|
||||
|
||||
struct v3errorIniter {
|
||||
v3errorIniter() { V3Error::init(); }
|
||||
@ -65,51 +47,10 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3Error class functions
|
||||
// V3ErrorGuarded class functions
|
||||
//
|
||||
|
||||
void V3Error::init() {
|
||||
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
|
||||
s_describedEachWarn[i] = false;
|
||||
s_pretendError[i] = V3ErrorCode{i}.pretendError();
|
||||
}
|
||||
if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
|
||||
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
|
||||
}
|
||||
}
|
||||
|
||||
string V3Error::lineStr(const char* filename, int lineno) {
|
||||
std::ostringstream out;
|
||||
const char* const fnslashp = std::strrchr(filename, '/');
|
||||
if (fnslashp) filename = fnslashp + 1;
|
||||
out << filename << ":" << std::dec << lineno << ":";
|
||||
const char* const spaces = " ";
|
||||
size_t numsp = out.str().length();
|
||||
if (numsp > 20) numsp = 20;
|
||||
out << (spaces + numsp);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void V3Error::incErrors() {
|
||||
s_errCount++;
|
||||
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
|
||||
v3fatalExit("Exiting due to too many errors encountered; --error-limit=" //
|
||||
<< errorCount() << endl);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Error::abortIfWarnings() {
|
||||
const bool exwarn = warnFatal() && warnCount();
|
||||
if (errorCount() && exwarn) {
|
||||
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " //
|
||||
<< warnCount() << " warning(s)\n");
|
||||
} else if (errorCount()) {
|
||||
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n");
|
||||
} else if (exwarn) {
|
||||
v3fatalExit("Exiting due to " << std::dec << warnCount() << " warning(s)\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool V3Error::isError(V3ErrorCode code, bool supp) {
|
||||
bool V3ErrorGuarded::isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex) {
|
||||
if (supp) {
|
||||
return false;
|
||||
} else if (code == V3ErrorCode::USERINFO) {
|
||||
@ -124,16 +65,16 @@ bool V3Error::isError(V3ErrorCode code, bool supp) {
|
||||
return true;
|
||||
} else if (code == V3ErrorCode::EC_ERROR) {
|
||||
return true;
|
||||
} else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) {
|
||||
} else if (code < V3ErrorCode::EC_FIRST_WARN || pretendError(code)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string V3Error::msgPrefix() {
|
||||
const V3ErrorCode code = s_errorCode;
|
||||
const bool supp = s_errorSuppressed;
|
||||
string V3ErrorGuarded::msgPrefix() VL_REQUIRES(m_mutex) {
|
||||
const V3ErrorCode code = m_errorCode;
|
||||
const bool supp = m_errorSuppressed;
|
||||
if (supp) {
|
||||
return "-arning-suppressed: ";
|
||||
} else if (code == V3ErrorCode::USERINFO) {
|
||||
@ -155,10 +96,7 @@ string V3Error::msgPrefix() {
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Abort/exit
|
||||
|
||||
void V3Error::vlAbortOrExit() {
|
||||
void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) {
|
||||
if (V3Error::debugDefault()) {
|
||||
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
|
||||
V3Error::vlAbort();
|
||||
@ -167,50 +105,53 @@ void V3Error::vlAbortOrExit() {
|
||||
}
|
||||
}
|
||||
|
||||
void V3Error::vlAbort() {
|
||||
VL_GCOV_DUMP();
|
||||
std::abort();
|
||||
}
|
||||
string V3ErrorGuarded::warnMore() VL_REQUIRES(m_mutex) { return string(msgPrefix().size(), ' '); }
|
||||
|
||||
//======================================================================
|
||||
// Global Functions
|
||||
|
||||
void V3Error::suppressThisWarning() {
|
||||
void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) {
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + s_errorCode.ascii(), 1);
|
||||
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + errorCode().ascii(), 1);
|
||||
#endif
|
||||
s_errorSuppressed = true;
|
||||
errorSuppressed(true);
|
||||
}
|
||||
|
||||
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
|
||||
|
||||
// cppcheck-has-bug-suppress constParameter
|
||||
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra)
|
||||
VL_REQUIRES(m_mutex) {
|
||||
#if defined(__COVERITY__) || defined(__cppcheck__)
|
||||
if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||
if (m_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||
#endif
|
||||
// Skip suppressed messages
|
||||
if (s_errorSuppressed
|
||||
if (m_errorSuppressed
|
||||
// On debug, show only non default-off warning to prevent pages of warnings
|
||||
&& (!debug() || s_errorCode.defaultsOff()))
|
||||
&& (!debug() || m_errorCode.defaultsOff()))
|
||||
return;
|
||||
string msg = msgPrefix() + sstr.str();
|
||||
if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity
|
||||
// If suppressed print only first line to reduce verbosity
|
||||
if (m_errorSuppressed) {
|
||||
string::size_type pos;
|
||||
if ((pos = msg.find('\n')) != string::npos) {
|
||||
msg.erase(pos, msg.length() - pos);
|
||||
msg += "...";
|
||||
}
|
||||
}
|
||||
string msg_additional;
|
||||
{
|
||||
string::size_type pos;
|
||||
if ((pos = msg.find(V3Error::warnAdditionalInfo())) != string::npos) {
|
||||
msg_additional = msg.substr(pos + V3Error::warnAdditionalInfo().size());
|
||||
msg.erase(pos);
|
||||
}
|
||||
}
|
||||
// Trailing newline (generally not on messages) & remove dup newlines
|
||||
{
|
||||
msg += '\n'; // Trailing newlines generally not put on messages so add
|
||||
string::size_type pos;
|
||||
while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1);
|
||||
while ((pos = msg_additional.find("\n\n")) != string::npos)
|
||||
msg_additional.erase(pos + 1, 1);
|
||||
}
|
||||
// Suppress duplicate messages
|
||||
if (s_messages.find(msg) != s_messages.end()) return;
|
||||
s_messages.insert(msg);
|
||||
if (!m_messages.insert(msg).second) return;
|
||||
if (!extra.empty()) {
|
||||
const string extraMsg = warnMore() + extra + "\n";
|
||||
const size_t pos = msg.find('\n');
|
||||
@ -219,44 +160,45 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
// Output
|
||||
if (
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
!(v3Global.opt.quietExit() && s_errorCode == V3ErrorCode::EC_FATALEXIT)
|
||||
!(v3Global.opt.quietExit() && m_errorCode == V3ErrorCode::EC_FATALEXIT)
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
) {
|
||||
std::cerr << msg;
|
||||
}
|
||||
if (!s_errorSuppressed
|
||||
&& !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) {
|
||||
const bool anError = isError(s_errorCode, s_errorSuppressed);
|
||||
if (s_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !s_describedWeb) {
|
||||
s_describedWeb = true;
|
||||
if (!m_errorSuppressed
|
||||
&& !(m_errorCode == V3ErrorCode::EC_INFO || m_errorCode == V3ErrorCode::USERINFO)) {
|
||||
const bool anError = isError(m_errorCode, m_errorSuppressed);
|
||||
if (m_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !m_describedWeb) {
|
||||
m_describedWeb = true;
|
||||
std::cerr << warnMore() << "... For " << (anError ? "error" : "warning")
|
||||
<< " description see https://verilator.org/warn/" << s_errorCode.ascii()
|
||||
<< " description see https://verilator.org/warn/" << m_errorCode.ascii()
|
||||
<< "?v=" << PACKAGE_VERSION_NUMBER_STRING << endl;
|
||||
}
|
||||
if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) {
|
||||
s_describedEachWarn[s_errorCode] = true;
|
||||
if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
|
||||
s_describedWarnings = true;
|
||||
if (!m_describedEachWarn[m_errorCode] && !m_pretendError[m_errorCode]) {
|
||||
m_describedEachWarn[m_errorCode] = true;
|
||||
if (m_errorCode >= V3ErrorCode::EC_FIRST_WARN && !m_describedWarnings) {
|
||||
m_describedWarnings = true;
|
||||
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
|
||||
<< s_errorCode.ascii()
|
||||
<< m_errorCode.ascii()
|
||||
<< " */\" and lint_on around source to disable this message." << endl;
|
||||
}
|
||||
if (s_errorCode.dangerous()) {
|
||||
if (m_errorCode.dangerous()) {
|
||||
std::cerr << warnMore() << "*** See https://verilator.org/warn/"
|
||||
<< s_errorCode.ascii() << " before disabling this,\n";
|
||||
<< m_errorCode.ascii() << " before disabling this,\n";
|
||||
std::cerr << warnMore() << "else you may end up with different sim results."
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
if (!msg_additional.empty()) { std::cerr << msg_additional; }
|
||||
// If first warning is not the user's fault (internal/unsupported) then give the website
|
||||
// Not later warnings, as a internal may be caused by an earlier problem
|
||||
if (s_tellManual == 0) {
|
||||
if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
|
||||
s_tellManual = 1;
|
||||
if (tellManual() == 0) {
|
||||
if (m_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
|
||||
tellManual(1);
|
||||
} else {
|
||||
s_tellManual = 2;
|
||||
tellManual(2);
|
||||
}
|
||||
}
|
||||
if (anError) {
|
||||
@ -264,26 +206,34 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
} else {
|
||||
incWarnings();
|
||||
}
|
||||
if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT
|
||||
|| s_errorCode == V3ErrorCode::EC_FATALSRC) {
|
||||
if (m_errorCode == V3ErrorCode::EC_FATAL || m_errorCode == V3ErrorCode::EC_FATALEXIT
|
||||
|| m_errorCode == V3ErrorCode::EC_FATALSRC) {
|
||||
static bool inFatal = false;
|
||||
if (!inFatal) {
|
||||
inFatal = true;
|
||||
if (s_tellManual == 1) {
|
||||
if (tellManual() == 1) {
|
||||
std::cerr << warnMore()
|
||||
<< "... See the manual at https://verilator.org/verilator_doc.html "
|
||||
"for more assistance."
|
||||
<< endl;
|
||||
s_tellManual = 2;
|
||||
tellManual(2);
|
||||
}
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
if (dumpTree()) {
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990));
|
||||
}
|
||||
if (debug()) {
|
||||
if (s_errorExitCb) s_errorExitCb();
|
||||
V3Stats::statsFinalAll(v3Global.rootp());
|
||||
V3Stats::statsReport();
|
||||
if (dumpTree() || debug()) {
|
||||
V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) {
|
||||
if (dumpTree()) {
|
||||
v3Global.rootp()->dumpTreeFile(
|
||||
v3Global.debugFilename("final.tree", 990));
|
||||
}
|
||||
if (debug()) {
|
||||
execErrorExitCb();
|
||||
V3Stats::statsFinalAll(v3Global.rootp());
|
||||
V3Stats::statsReport();
|
||||
}
|
||||
// Abort in exclusive access to make sure other threads
|
||||
// don't change error code
|
||||
vlAbortOrExit();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -292,7 +242,52 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
} else if (anError) {
|
||||
// We don't dump tree on any error because a Visitor may be in middle of
|
||||
// a tree cleanup and cause a false broken problem.
|
||||
if (s_errorExitCb) s_errorExitCb();
|
||||
execErrorExitCb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3Error class functions
|
||||
|
||||
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());
|
||||
}
|
||||
if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
|
||||
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
|
||||
}
|
||||
}
|
||||
|
||||
string V3Error::lineStr(const char* filename, int lineno) VL_PURE {
|
||||
std::ostringstream out;
|
||||
const char* const fnslashp = std::strrchr(filename, '/');
|
||||
if (fnslashp) filename = fnslashp + 1;
|
||||
out << filename << ":" << std::dec << lineno << ":";
|
||||
const char* const spaces = " ";
|
||||
size_t numsp = out.str().length();
|
||||
if (numsp > 20) numsp = 20;
|
||||
out << (spaces + numsp);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void V3Error::abortIfWarnings() {
|
||||
const bool exwarn = warnFatal() && warnCount();
|
||||
if (errorCount() && exwarn) {
|
||||
v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s), " //
|
||||
<< V3Error::s().warnCount() << " warning(s)\n");
|
||||
} else if (errorCount()) {
|
||||
v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s)\n");
|
||||
} else if (exwarn) {
|
||||
v3fatalExit("Exiting due to " << std::dec << V3Error::s().warnCount() << " warning(s)\n");
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Abort/exit
|
||||
|
||||
void V3Error::vlAbort() {
|
||||
VL_GCOV_DUMP();
|
||||
std::abort();
|
||||
}
|
||||
|
316
src/V3Error.h
316
src/V3Error.h
@ -20,8 +20,13 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated_threads.h"
|
||||
|
||||
// Limited V3 headers here - this is a base class for Vlc etc
|
||||
#include "V3String.h"
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
#include "V3ThreadPool.h"
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
@ -268,78 +273,224 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class V3Error final {
|
||||
// Base class for any object that wants debugging and error reporting
|
||||
|
||||
class V3ErrorGuarded final {
|
||||
// Should only be used by V3ErrorGuarded::m_mutex is already locked
|
||||
// contains guarded members
|
||||
public:
|
||||
using MessagesSet = std::set<std::string>;
|
||||
using ErrorExitCb = void (*)(void);
|
||||
|
||||
private:
|
||||
static bool s_describedWarnings; // Told user how to disable warns
|
||||
static bool s_describedWeb; // Told user to see web
|
||||
static std::array<bool, V3ErrorCode::_ENUM_MAX>
|
||||
s_describedEachWarn; // Told user specifics about this warning
|
||||
static std::array<bool, V3ErrorCode::_ENUM_MAX>
|
||||
s_pretendError; // Pretend this warning is an error
|
||||
static int s_debugDefault; // Option: --debugi Default debugging level
|
||||
static int s_errorLimit; // Option: --error-limit Number of errors before exit
|
||||
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
|
||||
static int s_errCount; // Error count
|
||||
static int s_warnCount; // Warning count
|
||||
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
|
||||
static std::ostringstream s_errorStr; // Error string being formed
|
||||
static V3ErrorCode s_errorCode; // Error string being formed will abort
|
||||
static bool s_errorContexted; // Error being formed got context
|
||||
static bool s_errorSuppressed; // Error being formed should be suppressed
|
||||
static MessagesSet s_messages; // What errors we've outputted
|
||||
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
|
||||
|
||||
static constexpr unsigned MAX_ERRORS = 50; // Fatal after this may errors
|
||||
|
||||
bool m_describedWarnings VL_GUARDED_BY(m_mutex) = false; // Told user how to disable warns
|
||||
// Tell user to see manual, 0=not yet, 1=doit, 2=disable
|
||||
int m_tellManual VL_GUARDED_BY(m_mutex) = 0;
|
||||
V3ErrorCode m_errorCode VL_GUARDED_BY(m_mutex)
|
||||
= V3ErrorCode::EC_FATAL; // Error string being formed will abort
|
||||
bool m_errorSuppressed VL_GUARDED_BY(m_mutex)
|
||||
= false; // Error being formed should be suppressed
|
||||
MessagesSet m_messages VL_GUARDED_BY(m_mutex); // What errors we've outputted
|
||||
ErrorExitCb m_errorExitCb VL_GUARDED_BY(m_mutex)
|
||||
= nullptr; // Callback when error occurs for dumping
|
||||
bool m_errorContexted VL_GUARDED_BY(m_mutex) = false; // Error being formed got context
|
||||
int m_warnCount VL_GUARDED_BY(m_mutex) = 0; // Warning count
|
||||
int m_errCount VL_GUARDED_BY(m_mutex) = 0; // Error count
|
||||
// Pretend this warning is an error
|
||||
std::array<bool, V3ErrorCode::_ENUM_MAX> m_pretendError VL_GUARDED_BY(m_mutex);
|
||||
bool m_describedWeb VL_GUARDED_BY(m_mutex) = false; // Told user to see web
|
||||
// Told user specifics about this warning
|
||||
std::array<bool, V3ErrorCode::_ENUM_MAX> m_describedEachWarn VL_GUARDED_BY(m_mutex);
|
||||
int m_debugDefault = 0; // Option: --debugi Default debugging level
|
||||
int m_errorLimit VL_GUARDED_BY(m_mutex)
|
||||
= MAX_ERRORS; // Option: --error-limit Number of errors before exit
|
||||
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal
|
||||
std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
|
||||
public:
|
||||
VerilatedMutex m_mutex; // Make sure only single thread is in class
|
||||
|
||||
string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn
|
||||
string warnMore() VL_REQUIRES(m_mutex);
|
||||
void execErrorExitCb() VL_REQUIRES(m_mutex) {
|
||||
if (m_errorExitCb) m_errorExitCb();
|
||||
}
|
||||
void errorExitCb(ErrorExitCb cb) VL_REQUIRES(m_mutex) { m_errorExitCb = cb; }
|
||||
ErrorExitCb errorExitCb() VL_REQUIRES(m_mutex) { return m_errorExitCb; }
|
||||
bool isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex);
|
||||
void vlAbortOrExit() VL_REQUIRES(m_mutex);
|
||||
void errorContexted(bool flag) VL_REQUIRES(m_mutex) { m_errorContexted = flag; }
|
||||
void incWarnings() VL_REQUIRES(m_mutex) { m_warnCount++; }
|
||||
void incErrors() VL_REQUIRES(m_mutex) {
|
||||
m_errCount++;
|
||||
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
|
||||
v3errorEnd(
|
||||
(v3errorPrep(V3ErrorCode::EC_FATALEXIT),
|
||||
(v3errorStr() << "Exiting due to too many errors encountered; --error-limit="
|
||||
<< errorCount() << endl),
|
||||
v3errorStr()));
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
int errorCount() VL_REQUIRES(m_mutex) { return m_errCount; }
|
||||
bool pretendError(int errorCode) VL_REQUIRES(m_mutex) { return m_pretendError[errorCode]; }
|
||||
void pretendError(V3ErrorCode code, bool flag) VL_REQUIRES(m_mutex) {
|
||||
if (code == V3ErrorCode::WIDTH) {
|
||||
m_pretendError[V3ErrorCode::WIDTHTRUNC] = flag;
|
||||
m_pretendError[V3ErrorCode::WIDTHEXPAND] = flag;
|
||||
m_pretendError[V3ErrorCode::WIDTHXZEXPAND] = flag;
|
||||
}
|
||||
m_pretendError[code] = flag;
|
||||
}
|
||||
void debugDefault(int level) VL_MT_UNSAFE { m_debugDefault = level; }
|
||||
int debugDefault() VL_MT_SAFE { return m_debugDefault; }
|
||||
void errorLimit(int level) VL_REQUIRES(m_mutex) { m_errorLimit = level; }
|
||||
int errorLimit() VL_REQUIRES(m_mutex) { return m_errorLimit; }
|
||||
void warnFatal(bool flag) VL_REQUIRES(m_mutex) { m_warnFatal = flag; }
|
||||
bool warnFatal() VL_REQUIRES(m_mutex) { return m_warnFatal; }
|
||||
void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) {
|
||||
m_errorStr.str("");
|
||||
m_errorCode = code;
|
||||
m_errorContexted = false;
|
||||
m_errorSuppressed = false;
|
||||
}
|
||||
std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; }
|
||||
V3ErrorCode errorCode() VL_REQUIRES(m_mutex) { return m_errorCode; }
|
||||
bool errorContexted() VL_REQUIRES(m_mutex) { return m_errorContexted; }
|
||||
int warnCount() VL_REQUIRES(m_mutex) { return m_warnCount; }
|
||||
bool errorSuppressed() VL_REQUIRES(m_mutex) { return m_errorSuppressed; }
|
||||
void errorSuppressed(bool flag) VL_REQUIRES(m_mutex) { m_errorSuppressed = flag; }
|
||||
bool describedWeb() VL_REQUIRES(m_mutex) { return m_describedWeb; }
|
||||
void describedWeb(bool flag) VL_REQUIRES(m_mutex) { m_describedWeb = flag; }
|
||||
bool describedEachWarn(V3ErrorCode code) VL_REQUIRES(m_mutex) {
|
||||
return m_describedEachWarn[code];
|
||||
}
|
||||
void describedEachWarn(V3ErrorCode code, bool flag) VL_REQUIRES(m_mutex) {
|
||||
m_describedEachWarn[code] = flag;
|
||||
}
|
||||
bool describedWarnings() VL_REQUIRES(m_mutex) { return m_describedWarnings; }
|
||||
void describedWarnings(bool flag) VL_REQUIRES(m_mutex) { m_describedWarnings = flag; }
|
||||
int tellManual() VL_REQUIRES(m_mutex) { return m_tellManual; }
|
||||
void tellManual(int level) VL_REQUIRES(m_mutex) { m_tellManual = level; }
|
||||
void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex);
|
||||
void suppressThisWarning() VL_REQUIRES(m_mutex);
|
||||
string warnContextNone() VL_REQUIRES(m_mutex) {
|
||||
errorContexted(true);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
class V3Error final {
|
||||
// Base class for any object that wants debugging and error reporting
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
V3Error() {
|
||||
std::cerr << ("Static class");
|
||||
V3Error::vlAbort();
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static V3ErrorGuarded& s() VL_MT_SAFE { // Singleton
|
||||
static V3ErrorGuarded s_s;
|
||||
return s_s;
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
static void debugDefault(int level) { s_debugDefault = level; }
|
||||
static int debugDefault() VL_MT_SAFE { return s_debugDefault; }
|
||||
static void errorLimit(int level) { s_errorLimit = level; }
|
||||
static int errorLimit() VL_MT_SAFE { return s_errorLimit; }
|
||||
static void warnFatal(bool flag) { s_warnFatal = flag; }
|
||||
static bool warnFatal() { return s_warnFatal; }
|
||||
static string msgPrefix(); // returns %Error/%Warn
|
||||
static int errorCount() VL_MT_SAFE { return s_errCount; }
|
||||
static int warnCount() { return s_warnCount; }
|
||||
static bool errorContexted() VL_MT_SAFE { return s_errorContexted; }
|
||||
static void errorContexted(bool flag) { s_errorContexted = flag; }
|
||||
static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); }
|
||||
static int debugDefault() VL_MT_SAFE { return s().debugDefault(); }
|
||||
static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().errorLimit(level);
|
||||
}
|
||||
static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().errorLimit();
|
||||
}
|
||||
static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().warnFatal(flag);
|
||||
}
|
||||
static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().warnFatal();
|
||||
}
|
||||
// returns %Error/%Warn
|
||||
static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().msgPrefix();
|
||||
}
|
||||
static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().errorCount();
|
||||
}
|
||||
static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().pretendError(errorCode);
|
||||
}
|
||||
static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().warnCount();
|
||||
}
|
||||
static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().errorContexted();
|
||||
}
|
||||
static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().errorContexted(flag);
|
||||
}
|
||||
static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().describedEachWarn(code, flag);
|
||||
}
|
||||
// METHODS
|
||||
static void incErrors();
|
||||
static void incWarnings() { s_warnCount++; }
|
||||
static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().incErrors();
|
||||
}
|
||||
static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().incWarnings();
|
||||
}
|
||||
static void init();
|
||||
static void abortIfErrors() {
|
||||
if (errorCount()) abortIfWarnings();
|
||||
}
|
||||
static void abortIfWarnings();
|
||||
static void suppressThisWarning(); // Suppress next %Warn if user has it off
|
||||
static void pretendError(V3ErrorCode code, bool flag) {
|
||||
if (code == V3ErrorCode::WIDTH) {
|
||||
s_pretendError[V3ErrorCode::WIDTHTRUNC] = flag;
|
||||
s_pretendError[V3ErrorCode::WIDTHEXPAND] = flag;
|
||||
s_pretendError[V3ErrorCode::WIDTHXZEXPAND] = flag;
|
||||
}
|
||||
s_pretendError[code] = flag;
|
||||
// Suppress next %Warn if user has it off
|
||||
static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().suppressThisWarning();
|
||||
}
|
||||
static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().pretendError(code, flag);
|
||||
}
|
||||
static string lineStr(const char* filename, int lineno) VL_PURE;
|
||||
static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().errorCode();
|
||||
}
|
||||
static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().errorExitCb(cb);
|
||||
}
|
||||
static bool isError(V3ErrorCode code, bool supp);
|
||||
static string lineStr(const char* filename, int lineno);
|
||||
static V3ErrorCode errorCode() VL_MT_SAFE { return s_errorCode; }
|
||||
static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; }
|
||||
|
||||
// When printing an error/warning, print prefix for multiline message
|
||||
static string warnMore();
|
||||
static string warnMore() VL_REQUIRES(s().m_mutex) { return s().warnMore(); }
|
||||
// This function should only be used when it is impossible to
|
||||
// generate whole error message inside v3warn macros and it needs to be
|
||||
// streamed directly to cerr.
|
||||
// Use with caution as this function isn't MT_SAFE.
|
||||
static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().warnMore();
|
||||
}
|
||||
// This function marks place in error message from which point message
|
||||
// should be printed after information on the error code.
|
||||
// The post-processing is done in v3errorEnd function.
|
||||
static string warnAdditionalInfo() VL_MT_SAFE { return "__WARNADDITIONALINFO__"; }
|
||||
/// When building an error, don't show context info
|
||||
static string warnContextNone() {
|
||||
V3Error::errorContexted(true);
|
||||
@ -348,37 +499,66 @@ public:
|
||||
|
||||
// Internals for v3error()/v3fatal() macros only
|
||||
// Error end takes the string stream to output, be careful to seek() as needed
|
||||
static void v3errorPrep(V3ErrorCode code) {
|
||||
s_errorStr.str("");
|
||||
s_errorCode = code;
|
||||
s_errorContexted = false;
|
||||
s_errorSuppressed = false;
|
||||
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().v3errorPrep(code);
|
||||
}
|
||||
static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
return s().v3errorStr();
|
||||
}
|
||||
static std::ostringstream& v3errorStr() { return s_errorStr; }
|
||||
static void vlAbortOrExit();
|
||||
static void vlAbort();
|
||||
// static, but often overridden in classes.
|
||||
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "");
|
||||
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "")
|
||||
VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE {
|
||||
const VerilatedLockGuard guard{s().m_mutex};
|
||||
s().v3errorEnd(sstr, extra);
|
||||
}
|
||||
// We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal',
|
||||
// due to bug in GCC (tested on 11.3.0 version with --enable-m32)
|
||||
// causing internal error when backtrace is printed.
|
||||
// Instead use this wrapper.
|
||||
static void v3errorEndGuardedCall(std::ostringstream& sstr, const string& extra = "")
|
||||
VL_REQUIRES(s().m_mutex) VL_MT_SAFE {
|
||||
s().v3errorEnd(sstr, extra);
|
||||
}
|
||||
};
|
||||
|
||||
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
|
||||
inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
|
||||
inline void v3errorEndFatal(std::ostringstream& sstr) {
|
||||
V3Error::v3errorEnd(sstr);
|
||||
inline void v3errorEnd(std::ostringstream& sstr) VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
|
||||
V3Error::v3errorEndGuardedCall(sstr);
|
||||
}
|
||||
inline void v3errorEndFatal(std::ostringstream& sstr)
|
||||
VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
|
||||
V3Error::v3errorEndGuardedCall(sstr);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
}
|
||||
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
#define V3ErrorLockAndCheckStopRequested \
|
||||
V3Error::s().m_mutex.lockCheckStopRequest( \
|
||||
[]() -> void { V3ThreadPool::s().waitIfStopRequested(); })
|
||||
#else
|
||||
#define V3ErrorLockAndCheckStopRequested V3Error::s().m_mutex.lock()
|
||||
#endif
|
||||
|
||||
// Theses allow errors using << operators: v3error("foo"<<"bar");
|
||||
// Careful, you can't put () around msg, as you would in most macro definitions
|
||||
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
|
||||
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
|
||||
// Note: due to limitations of clang thread-safety analysis, we can't use
|
||||
// lock guard here, instead we are locking the mutex as first operation in temporary,
|
||||
// but we are unlocking the mutex after function using comma operator.
|
||||
// This way macros should also work when they are in 'if' stmt without '{}'.
|
||||
#define v3warnCode(code, msg) \
|
||||
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
|
||||
|
||||
v3errorEnd((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \
|
||||
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
|
||||
V3Error::s().m_mutex.unlock()
|
||||
#define v3warnCodeFatal(code, msg) \
|
||||
v3errorEndFatal( \
|
||||
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
|
||||
v3errorEndFatal((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \
|
||||
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
|
||||
V3Error::s().m_mutex.unlock()
|
||||
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
|
||||
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
||||
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
|
||||
@ -391,8 +571,10 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
|
||||
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
|
||||
// Use this when normal v3fatal is called in static method that overrides fileline.
|
||||
#define v3fatalStatic(msg) \
|
||||
(::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
|
||||
(V3Error::v3errorStr() << msg), V3Error::v3errorStr())))
|
||||
(::v3errorEndFatal((V3ErrorLockAndCheckStopRequested, \
|
||||
V3Error::s().v3errorPrep(V3ErrorCode::EC_FATAL), \
|
||||
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr()))), \
|
||||
V3Error::s().m_mutex.unlock()
|
||||
|
||||
#define UINFO(level, stmsg) \
|
||||
do { \
|
||||
|
@ -322,7 +322,7 @@ string FileLine::asciiLineCol() const {
|
||||
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
|
||||
+ cvtToStr(m_contentLineno) + "]");
|
||||
}
|
||||
string FileLine::ascii() const VL_MT_SAFE {
|
||||
string FileLine::ascii() const {
|
||||
// For most errors especially in the parser the lastLineno is more accurate than firstLineno
|
||||
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
|
||||
}
|
||||
@ -369,7 +369,7 @@ void FileLine::warnUnusedOff(bool flag) {
|
||||
warnOff(V3ErrorCode::UNUSEDSIGNAL, flag);
|
||||
}
|
||||
|
||||
bool FileLine::warnIsOff(V3ErrorCode code) const VL_MT_SAFE {
|
||||
bool FileLine::warnIsOff(V3ErrorCode code) const {
|
||||
if (!msgEn().test(code)) return true;
|
||||
if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local
|
||||
if ((code.lintError() || code.styleError()) && !msgEn().test(V3ErrorCode::I_LINT)) {
|
||||
@ -380,7 +380,8 @@ bool FileLine::warnIsOff(V3ErrorCode code) const VL_MT_SAFE {
|
||||
}
|
||||
|
||||
// cppverilator-suppress constParameter
|
||||
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra)
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
std::ostringstream nsstr;
|
||||
if (lastLineno()) nsstr << this;
|
||||
nsstr << sstr.str();
|
||||
@ -390,29 +391,33 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
||||
lstr << std::setw(ascii().length()) << " "
|
||||
<< ": " << extra;
|
||||
}
|
||||
m_waive = V3Config::waive(this, V3Error::errorCode(), sstr.str());
|
||||
if (warnIsOff(V3Error::errorCode()) || m_waive) {
|
||||
V3Error::suppressThisWarning();
|
||||
} else if (!V3Error::errorContexted()) {
|
||||
m_waive = V3Config::waive(this, V3Error::s().errorCode(), sstr.str());
|
||||
if (warnIsOff(V3Error::s().errorCode()) || m_waive) {
|
||||
V3Error::s().suppressThisWarning();
|
||||
} else if (!V3Error::s().errorContexted()) {
|
||||
nsstr << warnContextPrimary();
|
||||
}
|
||||
if (!m_waive) V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str());
|
||||
V3Error::v3errorEnd(nsstr, lstr.str());
|
||||
if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str());
|
||||
V3Error::s().v3errorEnd(nsstr, lstr.str());
|
||||
}
|
||||
|
||||
string FileLine::warnMore() const {
|
||||
string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
if (lastLineno()) {
|
||||
return V3Error::warnMore() + string(ascii().size(), ' ') + ": ";
|
||||
return V3Error::s().warnMore() + string(ascii().size(), ' ') + ": ";
|
||||
} else {
|
||||
return V3Error::warnMore();
|
||||
return V3Error::s().warnMore();
|
||||
}
|
||||
}
|
||||
string FileLine::warnOther() const VL_MT_SAFE {
|
||||
string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
if (lastLineno()) {
|
||||
return V3Error::warnMore() + ascii() + ": ";
|
||||
return V3Error::s().warnMore() + ascii() + ": ";
|
||||
} else {
|
||||
return V3Error::warnMore();
|
||||
return V3Error::s().warnMore();
|
||||
}
|
||||
};
|
||||
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
|
||||
const VerilatedLockGuard guard{V3Error::s().m_mutex};
|
||||
return warnOther();
|
||||
}
|
||||
|
||||
string FileLine::source() const VL_MT_SAFE {
|
||||
@ -435,8 +440,7 @@ string FileLine::prettySource() const VL_MT_SAFE {
|
||||
return VString::spaceUnprintable(out);
|
||||
}
|
||||
|
||||
string FileLine::warnContext(bool secondary) const VL_MT_SAFE {
|
||||
V3Error::errorContexted(true);
|
||||
string FileLine::warnContext() const {
|
||||
if (!v3Global.opt.context()) return "";
|
||||
string out;
|
||||
if (firstLineno() == lastLineno() && firstColumn()) {
|
||||
@ -457,16 +461,18 @@ string FileLine::warnContext(bool secondary) const VL_MT_SAFE {
|
||||
out += "\n";
|
||||
}
|
||||
}
|
||||
if (!secondary) { // Avoid printing long paths on informational part of error
|
||||
for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) {
|
||||
if (parentFl->filenameIsGlobal()) break;
|
||||
out += parentFl->warnOther() + "... note: In file included from "
|
||||
+ parentFl->filebasename() + "\n";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
string FileLine::warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
string out;
|
||||
for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) {
|
||||
if (parentFl->filenameIsGlobal()) break;
|
||||
out += parentFl->warnOther() + "... note: In file included from "
|
||||
+ parentFl->filebasename() + "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
std::unordered_set<FileLine*> fileLineLeakChecks;
|
||||
|
||||
|
@ -314,24 +314,30 @@ public:
|
||||
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); }
|
||||
|
||||
// OPERATORS
|
||||
void v3errorEnd(std::ostringstream& str, const string& extra = "");
|
||||
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN {
|
||||
void v3errorEnd(std::ostringstream& str, const string& extra = "")
|
||||
VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
v3errorEnd(str);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
}
|
||||
/// When building an error, prefix for printing continuation lines
|
||||
/// e.g. information referring to the same FileLine as before
|
||||
string warnMore() const;
|
||||
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
/// When building an error, prefix for printing secondary information
|
||||
/// from a different FileLine than the original error
|
||||
string warnOther() const VL_MT_SAFE;
|
||||
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
string warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE;
|
||||
/// When building an error, current location in include etc
|
||||
/// If not used in a given error, automatically pasted at end of error
|
||||
string warnContextPrimary() const VL_MT_SAFE { return warnContext(false); }
|
||||
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
V3Error::s().errorContexted(true);
|
||||
return warnContext() + warnContextParent();
|
||||
}
|
||||
/// When building an error, additional location for additional references
|
||||
/// Simplified information vs warnContextPrimary() to make dump clearer
|
||||
string warnContextSecondary() const VL_MT_SAFE { return warnContext(true); }
|
||||
string warnContextSecondary() const { return warnContext(); }
|
||||
bool operator==(const FileLine& rhs) const {
|
||||
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
||||
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
||||
@ -354,7 +360,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
string warnContext(bool secondary) const VL_MT_SAFE;
|
||||
string warnContext() const;
|
||||
string warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); }
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
|
||||
|
@ -129,7 +129,7 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVerte
|
||||
}
|
||||
|
||||
// cppcheck-has-bug-suppress constParameter
|
||||
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
|
||||
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
std::ostringstream nsstr;
|
||||
nsstr << str.str();
|
||||
if (debug()) {
|
||||
@ -139,10 +139,11 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
|
||||
if (FileLine* const flp = fileline()) {
|
||||
flp->v3errorEnd(nsstr);
|
||||
} else {
|
||||
V3Error::v3errorEnd(nsstr);
|
||||
V3Error::s().v3errorEnd(nsstr);
|
||||
}
|
||||
}
|
||||
void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const {
|
||||
void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
v3errorEnd(str);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
|
@ -248,8 +248,8 @@ public:
|
||||
V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); }
|
||||
// METHODS
|
||||
/// Error reporting
|
||||
void v3errorEnd(std::ostringstream& str) const;
|
||||
void v3errorEndFatal(std::ostringstream& str) const;
|
||||
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
/// Edges are routed around this vertex to point from "from" directly to "to"
|
||||
void rerouteEdges(V3Graph* graphp);
|
||||
/// Find the edge connecting ap and bp, where bp is wayward from ap.
|
||||
|
@ -59,15 +59,23 @@ void V3LinkLevel::modSortByLevel() {
|
||||
if (tops.size() >= 2) {
|
||||
const AstNode* const secp = tops[1]; // Complain about second one, as first often intended
|
||||
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
||||
auto warnTopModules = [](std::string warnMore, ModVec tops)
|
||||
VL_REQUIRES(V3Error::s().m_mutex) -> std::string {
|
||||
std::stringstream ss;
|
||||
for (AstNode* alsop : tops) {
|
||||
ss << warnMore << "... Top module " << alsop->prettyNameQ() << endl
|
||||
<< alsop->warnContextSecondary();
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
secp->v3warn(MULTITOP, "Multiple top level modules\n"
|
||||
<< secp->warnMore()
|
||||
<< "... Suggest see manual; fix the duplicates, or use "
|
||||
"--top-module to select top."
|
||||
<< V3Error::warnContextNone());
|
||||
for (AstNode* alsop : tops) {
|
||||
std::cerr << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
|
||||
<< alsop->warnContextSecondary();
|
||||
}
|
||||
<< V3Error::s().warnContextNone()
|
||||
<< V3Error::warnAdditionalInfo()
|
||||
<< warnTopModules(secp->warnMore(), tops));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE
|
||||
//======================================================================
|
||||
// Errors
|
||||
|
||||
void V3Number::v3errorEnd(const std::ostringstream& str) const VL_MT_SAFE {
|
||||
void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
std::ostringstream nsstr;
|
||||
nsstr << str.str();
|
||||
if (m_nodep) {
|
||||
@ -84,11 +84,12 @@ void V3Number::v3errorEnd(const std::ostringstream& str) const VL_MT_SAFE {
|
||||
} else if (m_fileline) {
|
||||
m_fileline->v3errorEnd(nsstr);
|
||||
} else {
|
||||
V3Error::v3errorEnd(nsstr);
|
||||
V3Error::s().v3errorEnd(nsstr);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Number::v3errorEndFatal(const std::ostringstream& str) const VL_MT_SAFE {
|
||||
void V3Number::v3errorEndFatal(const std::ostringstream& str) const
|
||||
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
v3errorEnd(str);
|
||||
assert(0); // LCOV_EXCL_LINE
|
||||
VL_UNREACHABLE;
|
||||
|
@ -566,8 +566,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
void v3errorEnd(const std::ostringstream& sstr) const;
|
||||
void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN;
|
||||
void v3errorEnd(const std::ostringstream& sstr) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN
|
||||
VL_REQUIRES(V3Error::s().m_mutex);
|
||||
void width(int width, bool sized = true) {
|
||||
m_data.m_sized = sized;
|
||||
m_data.resize(width);
|
||||
|
@ -572,26 +572,28 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la
|
||||
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
||||
static bool shown_notfound_msg = false;
|
||||
if (modname.find("__Vhsh") != string::npos) {
|
||||
std::cerr << V3Error::warnMore() << "... Unsupported: Name is longer than 127 characters;"
|
||||
std::cerr << V3Error::warnMoreStandalone()
|
||||
<< "... Unsupported: Name is longer than 127 characters;"
|
||||
<< " automatic file lookup not supported.\n";
|
||||
std::cerr << V3Error::warnMore() << "... Suggest putting filename with this module/package"
|
||||
std::cerr << V3Error::warnMoreStandalone()
|
||||
<< "... Suggest putting filename with this module/package"
|
||||
<< " onto command line instead.\n";
|
||||
} else if (!shown_notfound_msg) {
|
||||
shown_notfound_msg = true;
|
||||
if (m_impp->m_incDirUsers.empty()) {
|
||||
fl->v3error("This may be because there's no search path specified with -I<dir>.");
|
||||
}
|
||||
std::cerr << V3Error::warnMore() << "... Looked in:" << endl;
|
||||
std::cerr << V3Error::warnMoreStandalone() << "... Looked in:" << endl;
|
||||
for (const string& dir : m_impp->m_incDirUsers) {
|
||||
for (const string& ext : m_impp->m_libExtVs) {
|
||||
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
||||
std::cerr << V3Error::warnMore() << " " << fn << endl;
|
||||
std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl;
|
||||
}
|
||||
}
|
||||
for (const string& dir : m_impp->m_incDirFallbacks) {
|
||||
for (const string& ext : m_impp->m_libExtVs) {
|
||||
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
||||
std::cerr << V3Error::warnMore() << " " << fn << endl;
|
||||
std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,9 @@ public:
|
||||
// For getline()
|
||||
string m_lineChars; ///< Characters left for next line
|
||||
|
||||
void v3errorEnd(std::ostringstream& str) { fileline()->v3errorEnd(str); }
|
||||
void v3errorEnd(std::ostringstream& str) VL_REQUIRES(V3Error::s().m_mutex) {
|
||||
fileline()->v3errorEnd(str);
|
||||
}
|
||||
|
||||
static const char* tokenName(int tok);
|
||||
void debugToken(int tok, const char* cmtp);
|
||||
|
@ -99,13 +99,13 @@ class Graph final : public V3Graph {
|
||||
// TODO: 'typeName' is an internal thing. This should be more human readable.
|
||||
if (LogicVertex* const lvtxp = dynamic_cast<LogicVertex*>(vtxp)) {
|
||||
AstNode* const logicp = lvtxp->logicp();
|
||||
std::cerr << logicp->fileline()->warnOther()
|
||||
std::cerr << logicp->fileline()->warnOtherStandalone()
|
||||
<< " Example path: " << logicp->typeName() << endl;
|
||||
} else {
|
||||
VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp);
|
||||
UASSERT(vvtxp, "Cannot be anything else");
|
||||
AstVarScope* const vscp = vvtxp->vscp();
|
||||
std::cerr << vscp->fileline()->warnOther()
|
||||
std::cerr << vscp->fileline()->warnOtherStandalone()
|
||||
<< " Example path: " << vscp->prettyName() << endl;
|
||||
}
|
||||
}
|
||||
@ -289,7 +289,7 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
||||
if (i == candidates.size()) break;
|
||||
const Candidate& candidate = candidates[i];
|
||||
AstVar* const varp = candidate.first->varp();
|
||||
std::cerr << V3Error::warnMore() << " " << varp->fileline() << " "
|
||||
std::cerr << V3Error::warnMoreStandalone() << " " << varp->fileline() << " "
|
||||
<< varp->prettyName() << ", width " << std::dec << varp->width()
|
||||
<< ", circular fanout " << candidate.second;
|
||||
if (V3SplitVar::canSplitVar(varp)) {
|
||||
@ -301,19 +301,19 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
||||
};
|
||||
|
||||
// Widest variables
|
||||
std::cerr << V3Error::warnMore() << "... Widest variables candidate to splitting:\n";
|
||||
std::cerr << V3Error::warnMoreStandalone() << "... Widest variables candidate to splitting:\n";
|
||||
reportFirst10([](const Candidate& a, const Candidate& b) {
|
||||
return a.first->varp()->width() > b.first->varp()->width();
|
||||
});
|
||||
|
||||
// Highest fanout
|
||||
std::cerr << V3Error::warnMore() << "... Candidates with the highest fanout:\n";
|
||||
std::cerr << V3Error::warnMoreStandalone() << "... Candidates with the highest fanout:\n";
|
||||
reportFirst10([](const Candidate& a, const Candidate& b) { //
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
if (splittable) {
|
||||
std::cerr << V3Error::warnMore()
|
||||
std::cerr << V3Error::warnMoreStandalone()
|
||||
<< "... Suggest add /*verilator split_var*/ to appropriate variables above."
|
||||
<< std::endl;
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ public:
|
||||
}
|
||||
}
|
||||
if (scopes == "") scopes = "<no instances found>";
|
||||
std::cerr << V3Error::warnMore() << "... Known scopes under '" << prettyName
|
||||
std::cerr << V3Error::warnMoreStandalone() << "... Known scopes under '" << prettyName
|
||||
<< "': " << scopes << endl;
|
||||
if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1);
|
||||
}
|
||||
|
@ -119,10 +119,12 @@ std::ostream& operator<<(std::ostream& str, const Castable& rhs) {
|
||||
}
|
||||
|
||||
#define v3widthWarn(lhs, rhs, msg) \
|
||||
v3errorEnd((V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
|
||||
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
|
||||
: V3ErrorCode::WIDTH), \
|
||||
(V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
|
||||
v3errorEnd((V3Error::s().m_mutex.lock(), \
|
||||
V3Error::s().v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
|
||||
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
|
||||
: V3ErrorCode::WIDTH), \
|
||||
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
|
||||
V3Error::s().m_mutex.unlock()
|
||||
|
||||
//######################################################################
|
||||
// Width state, as a visitor of each AstNode
|
||||
|
@ -36,7 +36,7 @@ sub check {
|
||||
tee => 1,
|
||||
cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]);
|
||||
|
||||
file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 24");
|
||||
file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 14");
|
||||
}
|
||||
|
||||
run_clang_check();
|
||||
|
Loading…
Reference in New Issue
Block a user