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 <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -175,6 +176,19 @@ public:
|
|||||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
/// 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(); }
|
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
|
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||||
@ -192,10 +206,19 @@ public:
|
|||||||
}
|
}
|
||||||
/// Destruct and unlock the mutex
|
/// Destruct and unlock the mutex
|
||||||
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
||||||
/// Unlock the mutex
|
|
||||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
|
||||||
/// Lock the mutex
|
/// 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(); }
|
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
|
// 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);
|
v3errorEnd(str);
|
||||||
assert(0); // LCOV_EXCL_LINE
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE;
|
||||||
@ -1287,9 +1287,9 @@ string AstNode::instanceStr() const {
|
|||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
void AstNode::v3errorEnd(std::ostringstream& str) const {
|
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
if (!m_fileline) {
|
if (!m_fileline) {
|
||||||
V3Error::v3errorEnd(str, instanceStr());
|
V3Error::s().v3errorEnd(str, instanceStr());
|
||||||
} else {
|
} else {
|
||||||
std::ostringstream nsstr;
|
std::ostringstream nsstr;
|
||||||
nsstr << str.str();
|
nsstr << str.str();
|
||||||
@ -1302,8 +1302,8 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
|||||||
// Don't look for instance name when warning is disabled.
|
// Don't look for instance name when warning is disabled.
|
||||||
// In case of large number of warnings, this can
|
// In case of large number of warnings, this can
|
||||||
// take significant amount of time
|
// take significant amount of time
|
||||||
m_fileline->v3errorEnd(nsstr,
|
m_fileline->v3errorEnd(
|
||||||
m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr());
|
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);
|
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||||
|
|
||||||
// METHODS - dump and error
|
// METHODS - dump and error
|
||||||
void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE;
|
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE;
|
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||||
string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
|
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 warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||||
string warnMore() const { return fileline()->warnMore(); }
|
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||||
string warnOther() const { return fileline()->warnOther(); }
|
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||||
|
|
||||||
virtual void dump(std::ostream& str = std::cout) const;
|
virtual void dump(std::ostream& str = std::cout) const;
|
||||||
static void dumpGdb(const AstNode* nodep); // For GDB only
|
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;
|
inline bool inlined() const;
|
||||||
|
|
||||||
// Methods that allow DfgVertex to participate in error reporting/messaging
|
// Methods that allow DfgVertex to participate in error reporting/messaging
|
||||||
void v3errorEnd(std::ostringstream& str) const { m_filelinep->v3errorEnd(str); }
|
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN {
|
m_filelinep->v3errorEnd(str);
|
||||||
|
}
|
||||||
|
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||||
|
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
m_filelinep->v3errorEndFatal(str);
|
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 warnContextSecondary() const { return fileline()->warnContextSecondary(); }
|
||||||
string warnMore() const { return fileline()->warnMore(); }
|
string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); }
|
||||||
string warnOther() const { return fileline()->warnOther(); }
|
string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// For internal use only.
|
// For internal use only.
|
||||||
|
233
src/V3Error.cpp
233
src/V3Error.cpp
@ -25,24 +25,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||||||
// clang-format on
|
// 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 {
|
struct v3errorIniter {
|
||||||
v3errorIniter() { V3Error::init(); }
|
v3errorIniter() { V3Error::init(); }
|
||||||
@ -65,51 +47,10 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// V3Error class functions
|
// V3ErrorGuarded class functions
|
||||||
|
//
|
||||||
|
|
||||||
void V3Error::init() {
|
bool V3ErrorGuarded::isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex) {
|
||||||
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) {
|
|
||||||
if (supp) {
|
if (supp) {
|
||||||
return false;
|
return false;
|
||||||
} else if (code == V3ErrorCode::USERINFO) {
|
} else if (code == V3ErrorCode::USERINFO) {
|
||||||
@ -124,16 +65,16 @@ bool V3Error::isError(V3ErrorCode code, bool supp) {
|
|||||||
return true;
|
return true;
|
||||||
} else if (code == V3ErrorCode::EC_ERROR) {
|
} else if (code == V3ErrorCode::EC_ERROR) {
|
||||||
return true;
|
return true;
|
||||||
} else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) {
|
} else if (code < V3ErrorCode::EC_FIRST_WARN || pretendError(code)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string V3Error::msgPrefix() {
|
string V3ErrorGuarded::msgPrefix() VL_REQUIRES(m_mutex) {
|
||||||
const V3ErrorCode code = s_errorCode;
|
const V3ErrorCode code = m_errorCode;
|
||||||
const bool supp = s_errorSuppressed;
|
const bool supp = m_errorSuppressed;
|
||||||
if (supp) {
|
if (supp) {
|
||||||
return "-arning-suppressed: ";
|
return "-arning-suppressed: ";
|
||||||
} else if (code == V3ErrorCode::USERINFO) {
|
} else if (code == V3ErrorCode::USERINFO) {
|
||||||
@ -155,10 +96,7 @@ string V3Error::msgPrefix() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) {
|
||||||
// Abort/exit
|
|
||||||
|
|
||||||
void V3Error::vlAbortOrExit() {
|
|
||||||
if (V3Error::debugDefault()) {
|
if (V3Error::debugDefault()) {
|
||||||
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
|
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
|
||||||
V3Error::vlAbort();
|
V3Error::vlAbort();
|
||||||
@ -167,50 +105,53 @@ void V3Error::vlAbortOrExit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3Error::vlAbort() {
|
string V3ErrorGuarded::warnMore() VL_REQUIRES(m_mutex) { return string(msgPrefix().size(), ' '); }
|
||||||
VL_GCOV_DUMP();
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================
|
void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) {
|
||||||
// Global Functions
|
|
||||||
|
|
||||||
void V3Error::suppressThisWarning() {
|
|
||||||
#ifndef V3ERROR_NO_GLOBAL_
|
#ifndef V3ERROR_NO_GLOBAL_
|
||||||
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + s_errorCode.ascii(), 1);
|
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + errorCode().ascii(), 1);
|
||||||
#endif
|
#endif
|
||||||
s_errorSuppressed = true;
|
errorSuppressed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
|
|
||||||
|
|
||||||
// cppcheck-has-bug-suppress constParameter
|
// 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 defined(__COVERITY__) || defined(__cppcheck__)
|
||||||
if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
if (m_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||||
#endif
|
#endif
|
||||||
// Skip suppressed messages
|
// Skip suppressed messages
|
||||||
if (s_errorSuppressed
|
if (m_errorSuppressed
|
||||||
// On debug, show only non default-off warning to prevent pages of warnings
|
// On debug, show only non default-off warning to prevent pages of warnings
|
||||||
&& (!debug() || s_errorCode.defaultsOff()))
|
&& (!debug() || m_errorCode.defaultsOff()))
|
||||||
return;
|
return;
|
||||||
string msg = msgPrefix() + sstr.str();
|
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;
|
string::size_type pos;
|
||||||
if ((pos = msg.find('\n')) != string::npos) {
|
if ((pos = msg.find('\n')) != string::npos) {
|
||||||
msg.erase(pos, msg.length() - pos);
|
msg.erase(pos, msg.length() - pos);
|
||||||
msg += "...";
|
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
|
// Trailing newline (generally not on messages) & remove dup newlines
|
||||||
{
|
{
|
||||||
msg += '\n'; // Trailing newlines generally not put on messages so add
|
msg += '\n'; // Trailing newlines generally not put on messages so add
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1);
|
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
|
// Suppress duplicate messages
|
||||||
if (s_messages.find(msg) != s_messages.end()) return;
|
if (!m_messages.insert(msg).second) return;
|
||||||
s_messages.insert(msg);
|
|
||||||
if (!extra.empty()) {
|
if (!extra.empty()) {
|
||||||
const string extraMsg = warnMore() + extra + "\n";
|
const string extraMsg = warnMore() + extra + "\n";
|
||||||
const size_t pos = msg.find('\n');
|
const size_t pos = msg.find('\n');
|
||||||
@ -219,44 +160,45 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
|||||||
// Output
|
// Output
|
||||||
if (
|
if (
|
||||||
#ifndef V3ERROR_NO_GLOBAL_
|
#ifndef V3ERROR_NO_GLOBAL_
|
||||||
!(v3Global.opt.quietExit() && s_errorCode == V3ErrorCode::EC_FATALEXIT)
|
!(v3Global.opt.quietExit() && m_errorCode == V3ErrorCode::EC_FATALEXIT)
|
||||||
#else
|
#else
|
||||||
true
|
true
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
std::cerr << msg;
|
std::cerr << msg;
|
||||||
}
|
}
|
||||||
if (!s_errorSuppressed
|
if (!m_errorSuppressed
|
||||||
&& !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) {
|
&& !(m_errorCode == V3ErrorCode::EC_INFO || m_errorCode == V3ErrorCode::USERINFO)) {
|
||||||
const bool anError = isError(s_errorCode, s_errorSuppressed);
|
const bool anError = isError(m_errorCode, m_errorSuppressed);
|
||||||
if (s_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !s_describedWeb) {
|
if (m_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !m_describedWeb) {
|
||||||
s_describedWeb = true;
|
m_describedWeb = true;
|
||||||
std::cerr << warnMore() << "... For " << (anError ? "error" : "warning")
|
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;
|
<< "?v=" << PACKAGE_VERSION_NUMBER_STRING << endl;
|
||||||
}
|
}
|
||||||
if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) {
|
if (!m_describedEachWarn[m_errorCode] && !m_pretendError[m_errorCode]) {
|
||||||
s_describedEachWarn[s_errorCode] = true;
|
m_describedEachWarn[m_errorCode] = true;
|
||||||
if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
|
if (m_errorCode >= V3ErrorCode::EC_FIRST_WARN && !m_describedWarnings) {
|
||||||
s_describedWarnings = true;
|
m_describedWarnings = true;
|
||||||
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
|
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
|
||||||
<< s_errorCode.ascii()
|
<< m_errorCode.ascii()
|
||||||
<< " */\" and lint_on around source to disable this message." << endl;
|
<< " */\" 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/"
|
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."
|
std::cerr << warnMore() << "else you may end up with different sim results."
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!msg_additional.empty()) { std::cerr << msg_additional; }
|
||||||
// If first warning is not the user's fault (internal/unsupported) then give the website
|
// 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
|
// Not later warnings, as a internal may be caused by an earlier problem
|
||||||
if (s_tellManual == 0) {
|
if (tellManual() == 0) {
|
||||||
if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
|
if (m_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
|
||||||
s_tellManual = 1;
|
tellManual(1);
|
||||||
} else {
|
} else {
|
||||||
s_tellManual = 2;
|
tellManual(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anError) {
|
if (anError) {
|
||||||
@ -264,26 +206,34 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
|||||||
} else {
|
} else {
|
||||||
incWarnings();
|
incWarnings();
|
||||||
}
|
}
|
||||||
if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT
|
if (m_errorCode == V3ErrorCode::EC_FATAL || m_errorCode == V3ErrorCode::EC_FATALEXIT
|
||||||
|| s_errorCode == V3ErrorCode::EC_FATALSRC) {
|
|| m_errorCode == V3ErrorCode::EC_FATALSRC) {
|
||||||
static bool inFatal = false;
|
static bool inFatal = false;
|
||||||
if (!inFatal) {
|
if (!inFatal) {
|
||||||
inFatal = true;
|
inFatal = true;
|
||||||
if (s_tellManual == 1) {
|
if (tellManual() == 1) {
|
||||||
std::cerr << warnMore()
|
std::cerr << warnMore()
|
||||||
<< "... See the manual at https://verilator.org/verilator_doc.html "
|
<< "... See the manual at https://verilator.org/verilator_doc.html "
|
||||||
"for more assistance."
|
"for more assistance."
|
||||||
<< endl;
|
<< endl;
|
||||||
s_tellManual = 2;
|
tellManual(2);
|
||||||
}
|
}
|
||||||
#ifndef V3ERROR_NO_GLOBAL_
|
#ifndef V3ERROR_NO_GLOBAL_
|
||||||
if (dumpTree()) {
|
if (dumpTree() || debug()) {
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990));
|
V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) {
|
||||||
}
|
if (dumpTree()) {
|
||||||
if (debug()) {
|
v3Global.rootp()->dumpTreeFile(
|
||||||
if (s_errorExitCb) s_errorExitCb();
|
v3Global.debugFilename("final.tree", 990));
|
||||||
V3Stats::statsFinalAll(v3Global.rootp());
|
}
|
||||||
V3Stats::statsReport();
|
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
|
#endif
|
||||||
}
|
}
|
||||||
@ -292,7 +242,52 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
|||||||
} else if (anError) {
|
} else if (anError) {
|
||||||
// We don't dump tree on any error because a Visitor may be in middle of
|
// 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.
|
// 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 "config_build.h"
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include "verilated_threads.h"
|
||||||
|
|
||||||
// Limited V3 headers here - this is a base class for Vlc etc
|
// Limited V3 headers here - this is a base class for Vlc etc
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
#ifndef V3ERROR_NO_GLOBAL_
|
||||||
|
#include "V3ThreadPool.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
@ -268,78 +273,224 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
|
class V3ErrorGuarded final {
|
||||||
class V3Error final {
|
// Should only be used by V3ErrorGuarded::m_mutex is already locked
|
||||||
// Base class for any object that wants debugging and error reporting
|
// contains guarded members
|
||||||
|
public:
|
||||||
using MessagesSet = std::set<std::string>;
|
using MessagesSet = std::set<std::string>;
|
||||||
using ErrorExitCb = void (*)(void);
|
using ErrorExitCb = void (*)(void);
|
||||||
|
|
||||||
private:
|
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
|
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() {
|
V3Error() {
|
||||||
std::cerr << ("Static class");
|
std::cerr << ("Static class");
|
||||||
V3Error::vlAbort();
|
V3Error::vlAbort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
static V3ErrorGuarded& s() VL_MT_SAFE { // Singleton
|
||||||
|
static V3ErrorGuarded s_s;
|
||||||
|
return s_s;
|
||||||
|
}
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
static void debugDefault(int level) { s_debugDefault = level; }
|
static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); }
|
||||||
static int debugDefault() VL_MT_SAFE { return s_debugDefault; }
|
static int debugDefault() VL_MT_SAFE { return s().debugDefault(); }
|
||||||
static void errorLimit(int level) { s_errorLimit = level; }
|
static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
static int errorLimit() VL_MT_SAFE { return s_errorLimit; }
|
const VerilatedLockGuard guard{s().m_mutex};
|
||||||
static void warnFatal(bool flag) { s_warnFatal = flag; }
|
s().errorLimit(level);
|
||||||
static bool warnFatal() { return s_warnFatal; }
|
}
|
||||||
static string msgPrefix(); // returns %Error/%Warn
|
static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
static int errorCount() VL_MT_SAFE { return s_errCount; }
|
const VerilatedLockGuard guard{s().m_mutex};
|
||||||
static int warnCount() { return s_warnCount; }
|
return s().errorLimit();
|
||||||
static bool errorContexted() VL_MT_SAFE { return s_errorContexted; }
|
}
|
||||||
static void errorContexted(bool flag) { s_errorContexted = flag; }
|
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
|
// METHODS
|
||||||
static void incErrors();
|
static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
static void incWarnings() { s_warnCount++; }
|
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 init();
|
||||||
static void abortIfErrors() {
|
static void abortIfErrors() {
|
||||||
if (errorCount()) abortIfWarnings();
|
if (errorCount()) abortIfWarnings();
|
||||||
}
|
}
|
||||||
static void abortIfWarnings();
|
static void abortIfWarnings();
|
||||||
static void suppressThisWarning(); // Suppress next %Warn if user has it off
|
// Suppress next %Warn if user has it off
|
||||||
static void pretendError(V3ErrorCode code, bool flag) {
|
static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
if (code == V3ErrorCode::WIDTH) {
|
const VerilatedLockGuard guard{s().m_mutex};
|
||||||
s_pretendError[V3ErrorCode::WIDTHTRUNC] = flag;
|
s().suppressThisWarning();
|
||||||
s_pretendError[V3ErrorCode::WIDTHEXPAND] = flag;
|
}
|
||||||
s_pretendError[V3ErrorCode::WIDTHXZEXPAND] = flag;
|
static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
}
|
const VerilatedLockGuard guard{s().m_mutex};
|
||||||
s_pretendError[code] = flag;
|
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
|
// 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
|
/// When building an error, don't show context info
|
||||||
static string warnContextNone() {
|
static string warnContextNone() {
|
||||||
V3Error::errorContexted(true);
|
V3Error::errorContexted(true);
|
||||||
@ -348,37 +499,66 @@ public:
|
|||||||
|
|
||||||
// Internals for v3error()/v3fatal() macros only
|
// Internals for v3error()/v3fatal() macros only
|
||||||
// Error end takes the string stream to output, be careful to seek() as needed
|
// Error end takes the string stream to output, be careful to seek() as needed
|
||||||
static void v3errorPrep(V3ErrorCode code) {
|
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
s_errorStr.str("");
|
const VerilatedLockGuard guard{s().m_mutex};
|
||||||
s_errorCode = code;
|
s().v3errorPrep(code);
|
||||||
s_errorContexted = false;
|
}
|
||||||
s_errorSuppressed = false;
|
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 void vlAbort();
|
||||||
// static, but often overridden in classes.
|
// 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.
|
// 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 v3errorEnd(std::ostringstream& sstr) VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
|
||||||
inline void v3errorEndFatal(std::ostringstream& sstr) {
|
V3Error::v3errorEndGuardedCall(sstr);
|
||||||
V3Error::v3errorEnd(sstr);
|
}
|
||||||
|
inline void v3errorEndFatal(std::ostringstream& sstr)
|
||||||
|
VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
|
||||||
|
V3Error::v3errorEndGuardedCall(sstr);
|
||||||
assert(0); // LCOV_EXCL_LINE
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE;
|
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");
|
// Theses allow errors using << operators: v3error("foo"<<"bar");
|
||||||
// Careful, you can't put () around msg, as you would in most macro definitions
|
// 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
|
// 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.
|
// 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) \
|
#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) \
|
#define v3warnCodeFatal(code, msg) \
|
||||||
v3errorEndFatal( \
|
v3errorEndFatal((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \
|
||||||
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
|
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
|
||||||
|
V3Error::s().m_mutex.unlock()
|
||||||
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
|
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
|
||||||
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
||||||
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
|
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
|
||||||
@ -391,8 +571,10 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
|
|||||||
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
|
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
|
||||||
// Use this when normal v3fatal is called in static method that overrides fileline.
|
// Use this when normal v3fatal is called in static method that overrides fileline.
|
||||||
#define v3fatalStatic(msg) \
|
#define v3fatalStatic(msg) \
|
||||||
(::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
|
(::v3errorEndFatal((V3ErrorLockAndCheckStopRequested, \
|
||||||
(V3Error::v3errorStr() << msg), V3Error::v3errorStr())))
|
V3Error::s().v3errorPrep(V3ErrorCode::EC_FATAL), \
|
||||||
|
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr()))), \
|
||||||
|
V3Error::s().m_mutex.unlock()
|
||||||
|
|
||||||
#define UINFO(level, stmsg) \
|
#define UINFO(level, stmsg) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -322,7 +322,7 @@ string FileLine::asciiLineCol() const {
|
|||||||
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
|
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
|
||||||
+ cvtToStr(m_contentLineno) + "]");
|
+ 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
|
// For most errors especially in the parser the lastLineno is more accurate than firstLineno
|
||||||
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
|
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
|
||||||
}
|
}
|
||||||
@ -369,7 +369,7 @@ void FileLine::warnUnusedOff(bool flag) {
|
|||||||
warnOff(V3ErrorCode::UNUSEDSIGNAL, 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 (!msgEn().test(code)) return true;
|
||||||
if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local
|
if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local
|
||||||
if ((code.lintError() || code.styleError()) && !msgEn().test(V3ErrorCode::I_LINT)) {
|
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
|
// 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;
|
std::ostringstream nsstr;
|
||||||
if (lastLineno()) nsstr << this;
|
if (lastLineno()) nsstr << this;
|
||||||
nsstr << sstr.str();
|
nsstr << sstr.str();
|
||||||
@ -390,29 +391,33 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) {
|
|||||||
lstr << std::setw(ascii().length()) << " "
|
lstr << std::setw(ascii().length()) << " "
|
||||||
<< ": " << extra;
|
<< ": " << extra;
|
||||||
}
|
}
|
||||||
m_waive = V3Config::waive(this, V3Error::errorCode(), sstr.str());
|
m_waive = V3Config::waive(this, V3Error::s().errorCode(), sstr.str());
|
||||||
if (warnIsOff(V3Error::errorCode()) || m_waive) {
|
if (warnIsOff(V3Error::s().errorCode()) || m_waive) {
|
||||||
V3Error::suppressThisWarning();
|
V3Error::s().suppressThisWarning();
|
||||||
} else if (!V3Error::errorContexted()) {
|
} else if (!V3Error::s().errorContexted()) {
|
||||||
nsstr << warnContextPrimary();
|
nsstr << warnContextPrimary();
|
||||||
}
|
}
|
||||||
if (!m_waive) V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str());
|
if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str());
|
||||||
V3Error::v3errorEnd(nsstr, lstr.str());
|
V3Error::s().v3errorEnd(nsstr, lstr.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
string FileLine::warnMore() const {
|
string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
if (lastLineno()) {
|
if (lastLineno()) {
|
||||||
return V3Error::warnMore() + string(ascii().size(), ' ') + ": ";
|
return V3Error::s().warnMore() + string(ascii().size(), ' ') + ": ";
|
||||||
} else {
|
} 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()) {
|
if (lastLineno()) {
|
||||||
return V3Error::warnMore() + ascii() + ": ";
|
return V3Error::s().warnMore() + ascii() + ": ";
|
||||||
} else {
|
} 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 {
|
string FileLine::source() const VL_MT_SAFE {
|
||||||
@ -435,8 +440,7 @@ string FileLine::prettySource() const VL_MT_SAFE {
|
|||||||
return VString::spaceUnprintable(out);
|
return VString::spaceUnprintable(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
string FileLine::warnContext(bool secondary) const VL_MT_SAFE {
|
string FileLine::warnContext() const {
|
||||||
V3Error::errorContexted(true);
|
|
||||||
if (!v3Global.opt.context()) return "";
|
if (!v3Global.opt.context()) return "";
|
||||||
string out;
|
string out;
|
||||||
if (firstLineno() == lastLineno() && firstColumn()) {
|
if (firstLineno() == lastLineno() && firstColumn()) {
|
||||||
@ -457,16 +461,18 @@ string FileLine::warnContext(bool secondary) const VL_MT_SAFE {
|
|||||||
out += "\n";
|
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;
|
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
|
#ifdef VL_LEAK_CHECKS
|
||||||
std::unordered_set<FileLine*> fileLineLeakChecks;
|
std::unordered_set<FileLine*> fileLineLeakChecks;
|
||||||
|
|
||||||
|
@ -314,24 +314,30 @@ public:
|
|||||||
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); }
|
void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); }
|
||||||
|
|
||||||
// OPERATORS
|
// OPERATORS
|
||||||
void v3errorEnd(std::ostringstream& str, const string& extra = "");
|
void v3errorEnd(std::ostringstream& str, const string& extra = "")
|
||||||
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN {
|
VL_REQUIRES(V3Error::s().m_mutex);
|
||||||
|
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN
|
||||||
|
VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
v3errorEnd(str);
|
v3errorEnd(str);
|
||||||
assert(0); // LCOV_EXCL_LINE
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE;
|
||||||
}
|
}
|
||||||
/// When building an error, prefix for printing continuation lines
|
/// When building an error, prefix for printing continuation lines
|
||||||
/// e.g. information referring to the same FileLine as before
|
/// 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
|
/// When building an error, prefix for printing secondary information
|
||||||
/// from a different FileLine than the original error
|
/// 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
|
/// When building an error, current location in include etc
|
||||||
/// If not used in a given error, automatically pasted at end of error
|
/// 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
|
/// When building an error, additional location for additional references
|
||||||
/// Simplified information vs warnContextPrimary() to make dump clearer
|
/// 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 {
|
bool operator==(const FileLine& rhs) const {
|
||||||
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
||||||
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
||||||
@ -354,7 +360,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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); }
|
const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); }
|
||||||
};
|
};
|
||||||
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
|
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
|
||||||
|
@ -129,7 +129,7 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVerte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cppcheck-has-bug-suppress constParameter
|
// 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;
|
std::ostringstream nsstr;
|
||||||
nsstr << str.str();
|
nsstr << str.str();
|
||||||
if (debug()) {
|
if (debug()) {
|
||||||
@ -139,10 +139,11 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
|
|||||||
if (FileLine* const flp = fileline()) {
|
if (FileLine* const flp = fileline()) {
|
||||||
flp->v3errorEnd(nsstr);
|
flp->v3errorEnd(nsstr);
|
||||||
} else {
|
} 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);
|
v3errorEnd(str);
|
||||||
assert(0); // LCOV_EXCL_LINE
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE;
|
||||||
|
@ -248,8 +248,8 @@ public:
|
|||||||
V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); }
|
V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); }
|
||||||
// METHODS
|
// METHODS
|
||||||
/// Error reporting
|
/// Error reporting
|
||||||
void v3errorEnd(std::ostringstream& str) const;
|
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||||
void v3errorEndFatal(std::ostringstream& str) const;
|
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"
|
/// Edges are routed around this vertex to point from "from" directly to "to"
|
||||||
void rerouteEdges(V3Graph* graphp);
|
void rerouteEdges(V3Graph* graphp);
|
||||||
/// Find the edge connecting ap and bp, where bp is wayward from ap.
|
/// Find the edge connecting ap and bp, where bp is wayward from ap.
|
||||||
|
@ -59,15 +59,23 @@ void V3LinkLevel::modSortByLevel() {
|
|||||||
if (tops.size() >= 2) {
|
if (tops.size() >= 2) {
|
||||||
const AstNode* const secp = tops[1]; // Complain about second one, as first often intended
|
const AstNode* const secp = tops[1]; // Complain about second one, as first often intended
|
||||||
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
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->v3warn(MULTITOP, "Multiple top level modules\n"
|
||||||
<< secp->warnMore()
|
<< secp->warnMore()
|
||||||
<< "... Suggest see manual; fix the duplicates, or use "
|
<< "... Suggest see manual; fix the duplicates, or use "
|
||||||
"--top-module to select top."
|
"--top-module to select top."
|
||||||
<< V3Error::warnContextNone());
|
<< V3Error::s().warnContextNone()
|
||||||
for (AstNode* alsop : tops) {
|
<< V3Error::warnAdditionalInfo()
|
||||||
std::cerr << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
|
<< warnTopModules(secp->warnMore(), tops));
|
||||||
<< alsop->warnContextSecondary();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Errors
|
// 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;
|
std::ostringstream nsstr;
|
||||||
nsstr << str.str();
|
nsstr << str.str();
|
||||||
if (m_nodep) {
|
if (m_nodep) {
|
||||||
@ -84,11 +84,12 @@ void V3Number::v3errorEnd(const std::ostringstream& str) const VL_MT_SAFE {
|
|||||||
} else if (m_fileline) {
|
} else if (m_fileline) {
|
||||||
m_fileline->v3errorEnd(nsstr);
|
m_fileline->v3errorEnd(nsstr);
|
||||||
} else {
|
} 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);
|
v3errorEnd(str);
|
||||||
assert(0); // LCOV_EXCL_LINE
|
assert(0); // LCOV_EXCL_LINE
|
||||||
VL_UNREACHABLE;
|
VL_UNREACHABLE;
|
||||||
|
@ -566,8 +566,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void v3errorEnd(const std::ostringstream& sstr) const;
|
void v3errorEnd(const std::ostringstream& sstr) const VL_REQUIRES(V3Error::s().m_mutex);
|
||||||
void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN;
|
void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN
|
||||||
|
VL_REQUIRES(V3Error::s().m_mutex);
|
||||||
void width(int width, bool sized = true) {
|
void width(int width, bool sized = true) {
|
||||||
m_data.m_sized = sized;
|
m_data.m_sized = sized;
|
||||||
m_data.resize(width);
|
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) {
|
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
||||||
static bool shown_notfound_msg = false;
|
static bool shown_notfound_msg = false;
|
||||||
if (modname.find("__Vhsh") != string::npos) {
|
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";
|
<< " 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";
|
<< " onto command line instead.\n";
|
||||||
} else if (!shown_notfound_msg) {
|
} else if (!shown_notfound_msg) {
|
||||||
shown_notfound_msg = true;
|
shown_notfound_msg = true;
|
||||||
if (m_impp->m_incDirUsers.empty()) {
|
if (m_impp->m_incDirUsers.empty()) {
|
||||||
fl->v3error("This may be because there's no search path specified with -I<dir>.");
|
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& dir : m_impp->m_incDirUsers) {
|
||||||
for (const string& ext : m_impp->m_libExtVs) {
|
for (const string& ext : m_impp->m_libExtVs) {
|
||||||
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
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& dir : m_impp->m_incDirFallbacks) {
|
||||||
for (const string& ext : m_impp->m_libExtVs) {
|
for (const string& ext : m_impp->m_libExtVs) {
|
||||||
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
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()
|
// For getline()
|
||||||
string m_lineChars; ///< Characters left for next line
|
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);
|
static const char* tokenName(int tok);
|
||||||
void debugToken(int tok, const char* cmtp);
|
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.
|
// TODO: 'typeName' is an internal thing. This should be more human readable.
|
||||||
if (LogicVertex* const lvtxp = dynamic_cast<LogicVertex*>(vtxp)) {
|
if (LogicVertex* const lvtxp = dynamic_cast<LogicVertex*>(vtxp)) {
|
||||||
AstNode* const logicp = lvtxp->logicp();
|
AstNode* const logicp = lvtxp->logicp();
|
||||||
std::cerr << logicp->fileline()->warnOther()
|
std::cerr << logicp->fileline()->warnOtherStandalone()
|
||||||
<< " Example path: " << logicp->typeName() << endl;
|
<< " Example path: " << logicp->typeName() << endl;
|
||||||
} else {
|
} else {
|
||||||
VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp);
|
VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp);
|
||||||
UASSERT(vvtxp, "Cannot be anything else");
|
UASSERT(vvtxp, "Cannot be anything else");
|
||||||
AstVarScope* const vscp = vvtxp->vscp();
|
AstVarScope* const vscp = vvtxp->vscp();
|
||||||
std::cerr << vscp->fileline()->warnOther()
|
std::cerr << vscp->fileline()->warnOtherStandalone()
|
||||||
<< " Example path: " << vscp->prettyName() << endl;
|
<< " Example path: " << vscp->prettyName() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
|||||||
if (i == candidates.size()) break;
|
if (i == candidates.size()) break;
|
||||||
const Candidate& candidate = candidates[i];
|
const Candidate& candidate = candidates[i];
|
||||||
AstVar* const varp = candidate.first->varp();
|
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()
|
<< varp->prettyName() << ", width " << std::dec << varp->width()
|
||||||
<< ", circular fanout " << candidate.second;
|
<< ", circular fanout " << candidate.second;
|
||||||
if (V3SplitVar::canSplitVar(varp)) {
|
if (V3SplitVar::canSplitVar(varp)) {
|
||||||
@ -301,19 +301,19 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Widest variables
|
// 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) {
|
reportFirst10([](const Candidate& a, const Candidate& b) {
|
||||||
return a.first->varp()->width() > b.first->varp()->width();
|
return a.first->varp()->width() > b.first->varp()->width();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Highest fanout
|
// 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) { //
|
reportFirst10([](const Candidate& a, const Candidate& b) { //
|
||||||
return a.second > b.second;
|
return a.second > b.second;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (splittable) {
|
if (splittable) {
|
||||||
std::cerr << V3Error::warnMore()
|
std::cerr << V3Error::warnMoreStandalone()
|
||||||
<< "... Suggest add /*verilator split_var*/ to appropriate variables above."
|
<< "... Suggest add /*verilator split_var*/ to appropriate variables above."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scopes == "") scopes = "<no instances found>";
|
if (scopes == "") scopes = "<no instances found>";
|
||||||
std::cerr << V3Error::warnMore() << "... Known scopes under '" << prettyName
|
std::cerr << V3Error::warnMoreStandalone() << "... Known scopes under '" << prettyName
|
||||||
<< "': " << scopes << endl;
|
<< "': " << scopes << endl;
|
||||||
if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1);
|
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) \
|
#define v3widthWarn(lhs, rhs, msg) \
|
||||||
v3errorEnd((V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
|
v3errorEnd((V3Error::s().m_mutex.lock(), \
|
||||||
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
|
V3Error::s().v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
|
||||||
: V3ErrorCode::WIDTH), \
|
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
|
||||||
(V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
|
: V3ErrorCode::WIDTH), \
|
||||||
|
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
|
||||||
|
V3Error::s().m_mutex.unlock()
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Width state, as a visitor of each AstNode
|
// Width state, as a visitor of each AstNode
|
||||||
|
@ -36,7 +36,7 @@ sub check {
|
|||||||
tee => 1,
|
tee => 1,
|
||||||
cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]);
|
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();
|
run_clang_check();
|
||||||
|
Loading…
Reference in New Issue
Block a user