Internals: Add mutex to V3Error (#3680)

This commit is contained in:
Kamil Rakoczy 2023-02-10 04:15:37 +01:00 committed by GitHub
parent 4eb280601e
commit 93d50c4499
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 505 additions and 267 deletions

View File

@ -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

View File

@ -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());
}
}

View File

@ -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

View File

@ -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.

View File

@ -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();
}

View File

@ -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 { \

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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();