Internals: Redo post-error additional information to be part of error calls.

This commit is contained in:
Wilson Snyder 2025-05-10 16:20:12 -04:00
parent 0f528d136d
commit 680236b03e
17 changed files with 128 additions and 117 deletions

View File

@ -122,6 +122,13 @@ void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) {
errorSuppressed(true); errorSuppressed(true);
} }
void V3ErrorGuarded::v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) {
m_errorStr.str("");
m_errorCode = code;
m_errorContexted = false;
m_errorSuppressed = false;
}
// cppcheck-has-bug-suppress constParameter // cppcheck-has-bug-suppress constParameter
void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra)
VL_REQUIRES(m_mutex) { VL_REQUIRES(m_mutex) {
@ -303,7 +310,6 @@ std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* f
v3errorPrep(code) << file << ":" << std::dec << line << ": "; v3errorPrep(code) << file << ":" << std::dec << line << ": ";
return v3errorStr(); return v3errorStr();
} }
std::ostringstream& V3Error::v3errorStr() VL_REQUIRES(s().m_mutex) { return s().v3errorStr(); }
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) VL_RELEASE(s().m_mutex) { void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) VL_RELEASE(s().m_mutex) {
s().v3errorEnd(sstr, extra); s().v3errorEnd(sstr, extra);
V3Error::s().m_mutex.unlock(); V3Error::s().m_mutex.unlock();

View File

@ -325,7 +325,7 @@ private:
= V3ErrorCode::EC_FATAL; // Error string being formed will abort = V3ErrorCode::EC_FATAL; // Error string being formed will abort
bool m_errorSuppressed VL_GUARDED_BY(m_mutex) bool m_errorSuppressed VL_GUARDED_BY(m_mutex)
= false; // Error being formed should be suppressed = false; // Error being formed should be suppressed
MessagesSet m_messages VL_GUARDED_BY(m_mutex); // What errors we've outputted MessagesSet m_messages VL_GUARDED_BY(m_mutex); // Errors outputted, to remove dups
ErrorExitCb m_errorExitCb VL_GUARDED_BY(m_mutex) ErrorExitCb m_errorExitCb VL_GUARDED_BY(m_mutex)
= nullptr; // Callback when error occurs for dumping = nullptr; // Callback when error occurs for dumping
bool m_errorContexted VL_GUARDED_BY(m_mutex) = false; // Error being formed got context bool m_errorContexted VL_GUARDED_BY(m_mutex) = false; // Error being formed got context
@ -341,12 +341,7 @@ private:
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal 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 std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) { 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; } std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; }
void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex); void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex);
@ -363,9 +358,9 @@ public:
bool isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex); bool isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex);
void vlAbortOrExit() VL_REQUIRES(m_mutex); void vlAbortOrExit() VL_REQUIRES(m_mutex);
void errorContexted(bool flag) VL_REQUIRES(m_mutex) { m_errorContexted = flag; } void errorContexted(bool flag) VL_REQUIRES(m_mutex) { m_errorContexted = flag; }
void incWarnings() VL_REQUIRES(m_mutex) { m_warnCount++; } void incWarnings() VL_REQUIRES(m_mutex) { ++m_warnCount; }
void incErrors() VL_REQUIRES(m_mutex) { void incErrors() VL_REQUIRES(m_mutex) {
m_errCount++; ++m_errCount;
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
v3errorEnd( v3errorEnd(
(v3errorPrep(V3ErrorCode::EC_FATALMANY), (v3errorPrep(V3ErrorCode::EC_FATALMANY),
@ -509,14 +504,6 @@ public:
// When printing an error/warning, print prefix for multiline message // When printing an error/warning, print prefix for multiline message
static string warnMore() VL_REQUIRES(s().m_mutex) { return s().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 V3RecursiveLockGuard guard{s().m_mutex};
return s().warnMore();
}
// This function marks place in error message from which point message // This function marks place in error message from which point message
// should be printed after information on the error code. // should be printed after information on the error code.
// The post-processing is done in v3errorEnd function. // The post-processing is done in v3errorEnd function.
@ -532,7 +519,7 @@ public:
static std::ostringstream& v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex); static std::ostringstream& v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex);
static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line)
VL_ACQUIRE(s().m_mutex); VL_ACQUIRE(s().m_mutex);
static std::ostringstream& v3errorStr() VL_REQUIRES(s().m_mutex); static std::ostringstream& v3errorStr() VL_REQUIRES(s().m_mutex) { return s().v3errorStr(); }
// 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_RELEASE(s().m_mutex); VL_RELEASE(s().m_mutex);

View File

@ -464,10 +464,6 @@ string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) {
return V3Error::s().warnMore(); return V3Error::s().warnMore();
} }
}; };
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
const V3RecursiveLockGuard guard{V3Error::s().m_mutex};
return warnOther();
}
string FileLine::source() const VL_MT_SAFE { string FileLine::source() const VL_MT_SAFE {
if (VL_UNCOVERABLE(!m_contentp)) { // LCOV_EXCL_START if (VL_UNCOVERABLE(!m_contentp)) { // LCOV_EXCL_START

View File

@ -301,7 +301,6 @@ public:
void warnUnusedOff(bool flag); void warnUnusedOff(bool flag);
void warnStateFrom(const FileLine& from) { m_msgEnIdx = from.m_msgEnIdx; } void warnStateFrom(const FileLine& from) { m_msgEnIdx = from.m_msgEnIdx; }
void warnResetDefault() { warnStateFrom(defaultFileLine()); } void warnResetDefault() { warnStateFrom(defaultFileLine()); }
bool lastWarnWaived() const { return m_waive; }
// Specific flag ACCESSORS/METHODS // Specific flag ACCESSORS/METHODS
bool celldefineOn() const { return msgEn().test(V3ErrorCode::I_CELLDEFINE); } bool celldefineOn() const { return msgEn().test(V3ErrorCode::I_CELLDEFINE); }
@ -356,7 +355,6 @@ public:
/// 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_REQUIRES(V3Error::s().m_mutex); 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_REQUIRES(V3Error::s().m_mutex) { string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {

View File

@ -233,13 +233,16 @@ void V3Graph::clearColors() {
//====================================================================== //======================================================================
// Dumping // Dumping
void V3Graph::loopsMessageCb(V3GraphVertex* vertexp) { void V3Graph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) {
vertexp->v3fatalSrc("Loops detected in graph: " << vertexp); vertexp->v3fatalSrc("Loops detected in graph: " << vertexp << "\n"
<< reportLoops(edgeFuncp, vertexp));
} }
string V3Graph::loopsVertexCb(V3GraphVertex* vertexp) {
void V3Graph::loopsVertexCb(V3GraphVertex* vertexp) {
// Needed here as V3GraphVertex<< isn't defined until later in header // Needed here as V3GraphVertex<< isn't defined until later in header
if (debug()) std::cerr << "-Info-Loop: " << cvtToHex(vertexp) << " " << vertexp << endl; if (debug())
return "-Info-Loop: "s + cvtToHex(vertexp) + ' ' + cvtToStr(vertexp) + '\n';
else
return "";
} }
void V3Graph::dump(std::ostream& os) const { void V3Graph::dump(std::ostream& os) const {

View File

@ -430,7 +430,7 @@ public:
/// Call loopsVertexCb on any one loop starting where specified /// Call loopsVertexCb on any one loop starting where specified
/// Side-effect: changes user() /// Side-effect: changes user()
void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) VL_MT_DISABLED; string reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) VL_MT_DISABLED;
/// Build a subgraph of all loops starting where specified /// Build a subgraph of all loops starting where specified
/// Side-effect: changes user() /// Side-effect: changes user()
@ -484,8 +484,8 @@ public:
parallelismReport(std::function<uint64_t(const V3GraphVertex*)> vertexCost) VL_MT_DISABLED; parallelismReport(std::function<uint64_t(const V3GraphVertex*)> vertexCost) VL_MT_DISABLED;
// CALLBACKS // CALLBACKS
virtual void loopsMessageCb(V3GraphVertex* vertexp) VL_MT_DISABLED; virtual void loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) VL_MT_DISABLED;
virtual void loopsVertexCb(V3GraphVertex* vertexp) VL_MT_DISABLED; virtual string loopsVertexCb(V3GraphVertex* vertexp) VL_MT_DISABLED;
}; };
//============================================================================ //============================================================================

View File

@ -343,10 +343,9 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) {
V3GraphVertex* inVertexp = inEdgep->fromp(); V3GraphVertex* inVertexp = inEdgep->fromp();
if (inVertexp == avertexp) { if (inVertexp == avertexp) {
if (debug()) v3error("Non-cutable vertex=" << avertexp); // LCOV_EXCL_LINE if (debug()) v3error("Non-cutable vertex=" << avertexp); // LCOV_EXCL_LINE
v3error("Circular logic when ordering code (non-cutable edge loop)"); v3error("Circular logic when ordering code (non-cutable edge loop)\n"
m_origGraphp->reportLoops( << m_origGraphp->reportLoops( // calls OrderGraph::loopsVertexCb
&V3GraphEdge::followNotCutable, &V3GraphEdge::followNotCutable, avertexp->origVertexp()));
avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb
// Things are unlikely to end well at this point, // Things are unlikely to end well at this point,
// but we'll try something to get to further errors... // but we'll try something to get to further errors...
inEdgep->cutable(true); inEdgep->cutable(true);

View File

@ -29,6 +29,7 @@
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <map> #include <map>
#include <numeric>
#include <vector> #include <vector>
VL_DEFINE_DEBUG_FUNCTIONS; VL_DEFINE_DEBUG_FUNCTIONS;
@ -281,8 +282,7 @@ class GraphAlgRank final : GraphAlg<> {
// If larger rank is found, assign it and loop back through // If larger rank is found, assign it and loop back through
// If we hit a back node make a list of all loops // If we hit a back node make a list of all loops
if (vertexp->user() == 1) { if (vertexp->user() == 1) {
m_graphp->reportLoops(m_edgeFuncp, vertexp); m_graphp->loopsMessageCb(vertexp, m_edgeFuncp);
m_graphp->loopsMessageCb(vertexp);
return; // LCOV_EXCL_LINE // gcc gprof bug misses this return return; // LCOV_EXCL_LINE // gcc gprof bug misses this return
} }
if (vertexp->rank() >= currentRank) return; // Already processed it if (vertexp->rank() >= currentRank) return; // Already processed it
@ -313,6 +313,7 @@ void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank{this, edgeFuncp}; }
class GraphAlgRLoops final : GraphAlg<> { class GraphAlgRLoops final : GraphAlg<> {
std::vector<V3GraphVertex*> m_callTrace; // List of everything we hit processing so far std::vector<V3GraphVertex*> m_callTrace; // List of everything we hit processing so far
std::vector<string> m_msgs; // Output messages
bool m_done = false; // Exit algorithm bool m_done = false; // Exit algorithm
void main(V3GraphVertex* vertexp) { void main(V3GraphVertex* vertexp) {
@ -333,9 +334,8 @@ class GraphAlgRLoops final : GraphAlg<> {
m_callTrace[currentRank++] = vertexp; m_callTrace[currentRank++] = vertexp;
if (vertexp->user() == 1) { if (vertexp->user() == 1) {
for (unsigned i = 0; i < currentRank; i++) { // for (unsigned i = 0; i < currentRank; i++)
m_graphp->loopsVertexCb(m_callTrace[i]); m_msgs.emplace_back(m_graphp->loopsVertexCb(m_callTrace[i]));
}
m_done = true; m_done = true;
return; return;
} }
@ -353,10 +353,13 @@ public:
main(vertexp); main(vertexp);
} }
~GraphAlgRLoops() = default; ~GraphAlgRLoops() = default;
string message() const {
return std::accumulate(m_msgs.begin(), m_msgs.end(), std::string{""});
}
}; };
void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { string V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) {
GraphAlgRLoops{this, edgeFuncp, vertexp}; return GraphAlgRLoops{this, edgeFuncp, vertexp}.message();
} }
//###################################################################### //######################################################################

View File

@ -43,7 +43,7 @@ class LinkCellsGraph final : public V3Graph {
public: public:
LinkCellsGraph() = default; LinkCellsGraph() = default;
~LinkCellsGraph() override = default; ~LinkCellsGraph() override = default;
void loopsMessageCb(V3GraphVertex* vertexp) override; void loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) override;
}; };
class LinkCellsVertex final : public V3GraphVertex { class LinkCellsVertex final : public V3GraphVertex {
@ -73,7 +73,7 @@ public:
string name() const override VL_MT_STABLE { return "*LIBRARY*"; } string name() const override VL_MT_STABLE { return "*LIBRARY*"; }
}; };
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) {
if (const LinkCellsVertex* const vvertexp = vertexp->cast<LinkCellsVertex>()) { if (const LinkCellsVertex* const vvertexp = vertexp->cast<LinkCellsVertex>()) {
vvertexp->modp()->v3warn(E_UNSUPPORTED, vvertexp->modp()->v3warn(E_UNSUPPORTED,
"Unsupported: Recursive multiple modules (module instantiates " "Unsupported: Recursive multiple modules (module instantiates "

View File

@ -3422,11 +3422,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
<< (!baddot.empty() ? AstNode::prettyNameQ(baddot) << (!baddot.empty() ? AstNode::prettyNameQ(baddot)
: nodep->prettyNameQ()) : nodep->prettyNameQ())
<< " in dotted " << expectWhat << ": '" << " in dotted " << expectWhat << ": '"
<< m_ds.m_dotText + "." + nodep->prettyName() << "'"); << m_ds.m_dotText + "." + nodep->prettyName() << "'\n"
if (okSymp) { << nodep->warnContextPrimary()
okSymp->cellErrorScopes(nodep, << (okSymp ? okSymp->cellErrorScopes(
AstNode::prettyName(m_ds.m_dotText)); nodep, AstNode::prettyName(m_ds.m_dotText))
} : ""));
} }
m_ds.m_dotErr = true; m_ds.m_dotErr = true;
} }
@ -3611,8 +3611,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (!nodep->varp()) { if (!nodep->varp()) {
nodep->v3error("Can't find definition of " nodep->v3error("Can't find definition of "
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '" << AstNode::prettyNameQ(baddot) << " in dotted signal: '"
<< nodep->dotted() + "." + nodep->prettyName() << "'"); << nodep->dotted() + "." + nodep->prettyName() << "'\n"
okSymp->cellErrorScopes(nodep); << nodep->warnContextPrimary()
<< okSymp->cellErrorScopes(nodep));
return; return;
} }
// V3Inst may have expanded arrays of interfaces to // V3Inst may have expanded arrays of interfaces to
@ -3636,8 +3637,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (!vscp) { if (!vscp) {
nodep->v3error("Can't find varpin scope of " nodep->v3error("Can't find varpin scope of "
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '" << AstNode::prettyNameQ(baddot) << " in dotted signal: '"
<< nodep->dotted() + "." + nodep->prettyName() << "'"); << nodep->dotted() + "." + nodep->prettyName() << "'\n"
okSymp->cellErrorScopes(nodep); << nodep->warnContextPrimary()
<< okSymp->cellErrorScopes(nodep));
} else { } else {
while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal
UINFO(7, indent() << "Resolved pre-alias " << vscp UINFO(7, indent() << "Resolved pre-alias " << vscp
@ -3844,10 +3846,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp, dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp,
true); true);
if (!dotSymp) { if (!dotSymp) {
okSymp->cellErrorScopes(nodep);
nodep->v3fatalSrc("Couldn't resolve inlined scope " nodep->v3fatalSrc("Couldn't resolve inlined scope "
<< AstNode::prettyNameQ(baddot) << AstNode::prettyNameQ(baddot)
<< " in: " << nodep->inlinedDots()); << " in: " << nodep->inlinedDots() << '\n'
<< nodep->warnContextPrimary()
<< okSymp->cellErrorScopes(nodep));
} }
} }
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot, dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
@ -3974,8 +3977,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
nodep->v3error("Can't find definition of " nodep->v3error("Can't find definition of "
<< AstNode::prettyNameQ(baddot) << " in dotted task/function: '" << AstNode::prettyNameQ(baddot) << " in dotted task/function: '"
<< nodep->dotted() + "." + nodep->prettyName() << "'\n" << nodep->dotted() + "." + nodep->prettyName() << "'\n"
<< (suggest.empty() ? "" : nodep->warnMore() + suggest)); << (suggest.empty() ? "" : nodep->warnMore() + suggest) << '\n'
okSymp->cellErrorScopes(nodep); << nodep->warnContextPrimary()
<< okSymp->cellErrorScopes(nodep));
} }
} }
} }

View File

@ -595,40 +595,41 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la
// Warn and return not found // Warn and return not found
if (errmsg != "") { if (errmsg != "") {
fl->v3error(errmsg + "'"s + filename + "'"s); fl->v3error(errmsg << "'"s << filename << "'\n"s << fl->warnContextPrimary()
filePathLookedMsg(fl, filename); << V3Error::warnAdditionalInfo() << filePathLookedMsg(fl, filename));
} }
return ""; return "";
} }
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { string V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
static bool shown_notfound_msg = false; static bool shown_notfound_msg = false;
std::ostringstream ss;
if (modname.find("__Vhsh") != string::npos) { if (modname.find("__Vhsh") != string::npos) {
std::cerr << V3Error::warnMoreStandalone() ss << V3Error::warnMore() << "... Note: Name is longer than 127 characters; automatic"
<< "... Note: Name is longer than 127 characters; automatic" << " file lookup may have failed due to OS filename length limits.\n";
<< " file lookup may have failed due to OS filename length limits.\n"; ss << V3Error::warnMore() << "... Suggest putting filename with this module/package"
std::cerr << V3Error::warnMoreStandalone() << " onto command line instead.\n";
<< "... Suggest putting filename with this module/package"
<< " 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>."); ss << V3Error::warnMore()
<< "... This may be because there's no search path specified with -I<dir>.\n";
} }
std::cerr << V3Error::warnMoreStandalone() << "... Looked in:" << endl; ss << V3Error::warnMore() << "... Looked in:\n";
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::filenameJoin(dir, modname + ext); const string fn = V3Os::filenameJoin(dir, modname + ext);
std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; ss << V3Error::warnMore() << " " << fn << "\n";
} }
} }
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::filenameJoin(dir, modname + ext); const string fn = V3Os::filenameJoin(dir, modname + ext);
std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; ss << V3Error::warnMore() << " " << fn << "\n";
} }
} }
} }
return ss.str();
} }
//! Determine what language is associated with a filename //! Determine what language is associated with a filename

View File

@ -779,7 +779,7 @@ public:
string fileExists(const string& filename); string fileExists(const string& filename);
string filePath(FileLine* fl, const string& modname, const string& lastpath, string filePath(FileLine* fl, const string& modname, const string& lastpath,
const string& errmsg); const string& errmsg);
void filePathLookedMsg(FileLine* fl, const string& modname); string filePathLookedMsg(FileLine* fl, const string& modname);
V3LangCode fileLanguage(const string& filename); V3LangCode fileLanguage(const string& filename);
static bool fileStatNormal(const string& filename); static bool fileStatNormal(const string& filename);

View File

@ -100,17 +100,16 @@ public:
}; };
class Graph final : public V3Graph { class Graph final : public V3Graph {
void loopsVertexCb(V3GraphVertex* vtxp) override { string loopsVertexCb(V3GraphVertex* vtxp) override {
// TODO: 'typeName' is an internal thing. This should be more human readable.
if (SchedAcyclicLogicVertex* const lvtxp = vtxp->cast<SchedAcyclicLogicVertex>()) { if (SchedAcyclicLogicVertex* const lvtxp = vtxp->cast<SchedAcyclicLogicVertex>()) {
AstNode* const logicp = lvtxp->logicp(); AstNode* const logicp = lvtxp->logicp();
std::cerr << logicp->fileline()->warnOtherStandalone() return logicp->fileline()->warnOther()
<< " Example path: " << logicp->typeName() << endl; + " Example path: " + logicp->prettyTypeName() + "\n";
} else { } else {
SchedAcyclicVarVertex* const vvtxp = vtxp->as<SchedAcyclicVarVertex>(); SchedAcyclicVarVertex* const vvtxp = vtxp->as<SchedAcyclicVarVertex>();
AstVarScope* const vscp = vvtxp->vscp(); AstVarScope* const vscp = vvtxp->vscp();
std::cerr << vscp->fileline()->warnOtherStandalone() return vscp->fileline()->warnOther() + " Example path: " + vscp->prettyName()
<< " Example path: " << vscp->prettyName() << endl; + "\n";
} }
} }
}; };
@ -268,7 +267,8 @@ void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector<Candidate>& candidates
} }
// Find all variables in a loop (SCC) that are candidates for splitting to break loops. // Find all variables in a loop (SCC) that are candidates for splitting to break loops.
void reportLoopVars(Graph* graphp, SchedAcyclicVarVertex* vvtxp) { std::string reportLoopVars(FileLine* warnFl, Graph* graphp, SchedAcyclicVarVertex* vvtxp) {
std::ostringstream ss;
// Vector of variables in UNOPTFLAT loop that are candidates for splitting. // Vector of variables in UNOPTFLAT loop that are candidates for splitting.
std::vector<Candidate> candidates; std::vector<Candidate> candidates;
{ {
@ -281,47 +281,51 @@ void reportLoopVars(Graph* graphp, SchedAcyclicVarVertex* vvtxp) {
} }
// Possible we only have candidates the user cannot do anything about, so don't bother them. // Possible we only have candidates the user cannot do anything about, so don't bother them.
if (candidates.empty()) return; if (candidates.empty()) return "";
// There may be a very large number of candidates, so only report up to 10 of the "most // There may be a very large number of candidates, so only report up to 10 of the "most
// important" signals. // important" signals.
unsigned splittable = 0; unsigned splittable = 0;
const auto reportFirst10 = [&](std::function<bool(const Candidate&, const Candidate&)> less) { const auto reportFirst10
= [&](std::function<bool(const Candidate&, const Candidate&)> less) -> string {
std::stable_sort(candidates.begin(), candidates.end(), less); std::stable_sort(candidates.begin(), candidates.end(), less);
std::ostringstream ss2;
for (size_t i = 0; i < 10; i++) { for (size_t i = 0; i < 10; i++) {
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::warnMoreStandalone() << " " << varp->fileline() << " "
<< varp->prettyName() << ", width " << std::dec << varp->width() ss2 << V3Error::warnMore() << " " << varp->fileline() << ' ' << varp->prettyName()
<< ", circular fanout " << candidate.second; << ", width " << std::dec << varp->width() << ", circular fanout "
<< candidate.second;
if (V3SplitVar::canSplitVar(varp)) { if (V3SplitVar::canSplitVar(varp)) {
std::cerr << ", can split_var"; ss2 << ", can split_var";
++splittable; ++splittable;
} }
std::cerr << '\n'; ss2 << '\n';
} }
return ss2.str();
}; };
// Widest variables // Widest variables
std::cerr << V3Error::warnMoreStandalone() << "... Widest variables candidate to splitting:\n"; ss << V3Error::warnMore() << "... 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::warnMoreStandalone() << "... Candidates with the highest fanout:\n"; ss << V3Error::warnMore() << "... 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::warnMoreStandalone() ss << V3Error::warnMore()
<< "... Suggest add /*verilator split_var*/ or /*verilator " << "... Suggest add /*verilator split_var*/ or /*verilator "
"isolate_assignments*/ to appropriate variables above." "isolate_assignments*/ to appropriate variables above.\n";
<< std::endl;
} }
V3Stats::addStat("Scheduling, split_var, candidates", splittable); V3Stats::addStat("Scheduling, split_var, candidates", splittable);
return ss.str();
} }
void reportCycles(Graph* graphp, const std::vector<SchedAcyclicVarVertex*>& cutVertices) { void reportCycles(Graph* graphp, const std::vector<SchedAcyclicVarVertex*>& cutVertices) {
@ -330,17 +334,26 @@ void reportCycles(Graph* graphp, const std::vector<SchedAcyclicVarVertex*>& cutV
FileLine* const flp = vscp->fileline(); FileLine* const flp = vscp->fileline();
// First v3warn not inside warnIsOff so we can see the suppressions with --debug // First v3warn not inside warnIsOff so we can see the suppressions with --debug
vscp->v3warn(UNOPTFLAT, "Signal unoptimizable: Circular combinational logic: " if (flp->warnIsOff(V3ErrorCode::UNOPTFLAT)) {
<< vscp->prettyNameQ()); // First v3warn not inside warnIsOff so we can see the suppressions with --debug
if (!flp->warnIsOff(V3ErrorCode::UNOPTFLAT) && !flp->lastWarnWaived()) { vscp->v3warn(UNOPTFLAT, "Signal unoptimizable: Circular combinational logic: "
<< vscp->prettyNameQ());
} else {
vscp->v3warn(UNOPTFLAT,
"Signal unoptimizable: Circular combinational logic: "
<< vscp->prettyNameQ() << '\n'
<< vscp->warnContextPrimary()
<< V3Error::warnAdditionalInfo()
// Calls Graph::loopsVertexCb
<< graphp->reportLoops(&V3GraphEdge::followAlwaysTrue, vvtxp)
// Report candidate variables for splitting
<< (v3Global.opt.reportUnoptflat()
? reportLoopVars(vscp->fileline(), graphp, vvtxp)
: ""));
// Complain just once // Complain just once
flp->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); flp->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true);
// Calls Graph::loopsVertexCb // Create a subgraph for the UNOPTFLAT loop
graphp->reportLoops(&V3GraphEdge::followAlwaysTrue, vvtxp);
if (v3Global.opt.reportUnoptflat()) { if (v3Global.opt.reportUnoptflat()) {
// Report candidate variables for splitting
reportLoopVars(graphp, vvtxp);
// Create a subgraph for the UNOPTFLAT loop
V3Graph loopGraph; V3Graph loopGraph;
graphp->subtreeLoops(&V3GraphEdge::followAlwaysTrue, vvtxp, &loopGraph); graphp->subtreeLoops(&V3GraphEdge::followAlwaysTrue, vvtxp, &loopGraph);
loopGraph.dumpDotFilePrefixedAlways("unoptflat"); loopGraph.dumpDotFilePrefixedAlways("unoptflat");

View File

@ -256,7 +256,7 @@ public:
} }
} }
} }
void cellErrorScopes(AstNode* lookp, string prettyName = "") { string cellErrorScopes(AstNode* lookp, string prettyName = "") {
if (prettyName == "") prettyName = lookp->prettyName(); if (prettyName == "") prettyName = lookp->prettyName();
string scopes; string scopes;
for (IdNameMap::iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) { for (IdNameMap::iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) {
@ -267,9 +267,9 @@ public:
} }
} }
if (scopes == "") scopes = "<no instances found>"; if (scopes == "") scopes = "<no instances found>";
std::cerr << V3Error::warnMoreStandalone() << "... Known scopes under '" << prettyName
<< "': " << scopes << endl;
if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1); if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1);
return V3Error::warnMore() + "... Known scopes under '" + prettyName + "': " + scopes
+ '\n';
} }
}; };

View File

@ -5876,9 +5876,12 @@ class WidthVisitor final : public VNVisitor {
// We've resolved parameters and hit a module that we couldn't resolve. It's // We've resolved parameters and hit a module that we couldn't resolve. It's
// finally time to report it. // finally time to report it.
// Note only here in V3Width as this is first visitor after V3Dead. // Note only here in V3Width as this is first visitor after V3Dead.
nodep->modNameFileline()->v3error("Cannot find file containing module: '" nodep->modNameFileline()->v3error(
<< nodep->modName() << "'"); "Cannot find file containing module: '"
v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName()); << nodep->modName() << "'\n"
<< nodep->modNameFileline()->warnContextPrimary()
<< V3Error::warnAdditionalInfo()
<< v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName()));
} }
if (nodep->rangep()) userIterateAndNext(nodep->rangep(), WidthVP{SELF, BOTH}.p()); if (nodep->rangep()) userIterateAndNext(nodep->rangep(), WidthVP{SELF, BOTH}.p());
userIterateAndNext(nodep->pinsp(), nullptr); userIterateAndNext(nodep->pinsp(), nullptr);

View File

@ -2,9 +2,7 @@
8 | nfound nfound(); 8 | nfound nfound();
| ^~~~~~ | ^~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_gen_nonconst_bad.v:8:4: This may be because there's no search path specified with -I<dir>. ... This may be because there's no search path specified with -I<dir>.
8 | nfound nfound();
| ^~~~~~
... Looked in: ... Looked in:
nfound nfound
nfound.v nfound.v

View File

@ -1,6 +1,6 @@
%Error: t/t_interface_mismodport_bad.v:32:12: Can't find definition of 'bad' in dotted signal: 'isub.bad' %Error: t/t_interface_mismodport_bad.v:32:12: Can't find definition of 'bad' in dotted signal: 'isub.bad'
32 | isub.bad = i_value; 32 | isub.bad = i_value;
| ^~~ | ^~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
... Known scopes under 'bad': <no instances found> ... Known scopes under 'bad': <no instances found>
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to %Error: Exiting due to