From 680236b03ee23d037834f00a78f9e52e52724f9a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 10 May 2025 16:20:12 -0400 Subject: [PATCH] Internals: Redo post-error additional information to be part of error calls. --- src/V3Error.cpp | 8 +- src/V3Error.h | 23 ++---- src/V3FileLine.cpp | 4 - src/V3FileLine.h | 2 - src/V3Graph.cpp | 13 +-- src/V3Graph.h | 6 +- src/V3GraphAcyc.cpp | 7 +- src/V3GraphAlg.cpp | 17 ++-- src/V3LinkCells.cpp | 4 +- src/V3LinkDot.cpp | 30 ++++--- src/V3Options.cpp | 27 ++++--- src/V3Options.h | 2 +- src/V3SchedAcyclic.cpp | 81 +++++++++++-------- src/V3SymTable.h | 6 +- src/V3Width.cpp | 9 ++- test_regress/t/t_gen_nonconst_bad.out | 4 +- test_regress/t/t_interface_mismodport_bad.out | 2 +- 17 files changed, 128 insertions(+), 117 deletions(-) diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 1acd8e601..dcb00df3d 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -122,6 +122,13 @@ void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) { 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 void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) VL_REQUIRES(m_mutex) { @@ -303,7 +310,6 @@ std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* f v3errorPrep(code) << file << ":" << std::dec << line << ": "; 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) { s().v3errorEnd(sstr, extra); V3Error::s().m_mutex.unlock(); diff --git a/src/V3Error.h b/src/V3Error.h index fdae76e3a..8a5d669c1 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -325,7 +325,7 @@ private: = 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 + MessagesSet m_messages VL_GUARDED_BY(m_mutex); // Errors outputted, to remove dups 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 @@ -341,12 +341,7 @@ private: 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 - void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) { - m_errorStr.str(""); - m_errorCode = code; - m_errorContexted = false; - m_errorSuppressed = false; - } + void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex); std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; } 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); 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 incWarnings() VL_REQUIRES(m_mutex) { ++m_warnCount; } void incErrors() VL_REQUIRES(m_mutex) { - m_errCount++; + ++m_errCount; if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse v3errorEnd( (v3errorPrep(V3ErrorCode::EC_FATALMANY), @@ -509,14 +504,6 @@ public: // When printing an error/warning, print prefix for multiline message 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 // should be printed after information on the error code. // 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& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) 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 void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_RELEASE(s().m_mutex); diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 1ff188e88..2247695c7 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -464,10 +464,6 @@ string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { 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 { if (VL_UNCOVERABLE(!m_contentp)) { // LCOV_EXCL_START diff --git a/src/V3FileLine.h b/src/V3FileLine.h index fe3a6d986..ead89fd63 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -301,7 +301,6 @@ public: void warnUnusedOff(bool flag); void warnStateFrom(const FileLine& from) { m_msgEnIdx = from.m_msgEnIdx; } void warnResetDefault() { warnStateFrom(defaultFileLine()); } - bool lastWarnWaived() const { return m_waive; } // Specific flag ACCESSORS/METHODS bool celldefineOn() const { return msgEn().test(V3ErrorCode::I_CELLDEFINE); } @@ -356,7 +355,6 @@ public: /// When building an error, prefix for printing secondary information /// from a different FileLine than the original error 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_REQUIRES(V3Error::s().m_mutex) { diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index a1af41bb9..de1d19ca9 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -233,13 +233,16 @@ void V3Graph::clearColors() { //====================================================================== // Dumping -void V3Graph::loopsMessageCb(V3GraphVertex* vertexp) { - vertexp->v3fatalSrc("Loops detected in graph: " << vertexp); +void V3Graph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) { + vertexp->v3fatalSrc("Loops detected in graph: " << vertexp << "\n" + << reportLoops(edgeFuncp, vertexp)); } - -void V3Graph::loopsVertexCb(V3GraphVertex* vertexp) { +string V3Graph::loopsVertexCb(V3GraphVertex* vertexp) { // 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 { diff --git a/src/V3Graph.h b/src/V3Graph.h index 9b357ceff..222806bb8 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -430,7 +430,7 @@ public: /// Call loopsVertexCb on any one loop starting where specified /// 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 /// Side-effect: changes user() @@ -484,8 +484,8 @@ public: parallelismReport(std::function vertexCost) VL_MT_DISABLED; // CALLBACKS - virtual void loopsMessageCb(V3GraphVertex* vertexp) VL_MT_DISABLED; - virtual void loopsVertexCb(V3GraphVertex* vertexp) VL_MT_DISABLED; + virtual void loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) VL_MT_DISABLED; + virtual string loopsVertexCb(V3GraphVertex* vertexp) VL_MT_DISABLED; }; //============================================================================ diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index cf3ab8b9c..5e615e1e0 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -343,10 +343,9 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) { V3GraphVertex* inVertexp = inEdgep->fromp(); if (inVertexp == avertexp) { if (debug()) v3error("Non-cutable vertex=" << avertexp); // LCOV_EXCL_LINE - v3error("Circular logic when ordering code (non-cutable edge loop)"); - m_origGraphp->reportLoops( - &V3GraphEdge::followNotCutable, - avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb + v3error("Circular logic when ordering code (non-cutable edge loop)\n" + << m_origGraphp->reportLoops( // calls OrderGraph::loopsVertexCb + &V3GraphEdge::followNotCutable, avertexp->origVertexp())); // Things are unlikely to end well at this point, // but we'll try something to get to further errors... inEdgep->cutable(true); diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index bc0eff17f..56b6e7e1a 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -281,8 +282,7 @@ class GraphAlgRank final : GraphAlg<> { // If larger rank is found, assign it and loop back through // If we hit a back node make a list of all loops if (vertexp->user() == 1) { - m_graphp->reportLoops(m_edgeFuncp, vertexp); - m_graphp->loopsMessageCb(vertexp); + m_graphp->loopsMessageCb(vertexp, m_edgeFuncp); return; // LCOV_EXCL_LINE // gcc gprof bug misses this return } if (vertexp->rank() >= currentRank) return; // Already processed it @@ -313,6 +313,7 @@ void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank{this, edgeFuncp}; } class GraphAlgRLoops final : GraphAlg<> { std::vector m_callTrace; // List of everything we hit processing so far + std::vector m_msgs; // Output messages bool m_done = false; // Exit algorithm void main(V3GraphVertex* vertexp) { @@ -333,9 +334,8 @@ class GraphAlgRLoops final : GraphAlg<> { m_callTrace[currentRank++] = vertexp; if (vertexp->user() == 1) { - for (unsigned i = 0; i < currentRank; i++) { // - m_graphp->loopsVertexCb(m_callTrace[i]); - } + for (unsigned i = 0; i < currentRank; i++) + m_msgs.emplace_back(m_graphp->loopsVertexCb(m_callTrace[i])); m_done = true; return; } @@ -353,10 +353,13 @@ public: main(vertexp); } ~GraphAlgRLoops() = default; + string message() const { + return std::accumulate(m_msgs.begin(), m_msgs.end(), std::string{""}); + } }; -void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { - GraphAlgRLoops{this, edgeFuncp, vertexp}; +string V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { + return GraphAlgRLoops{this, edgeFuncp, vertexp}.message(); } //###################################################################### diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index ed24b42d7..e36611257 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -43,7 +43,7 @@ class LinkCellsGraph final : public V3Graph { public: LinkCellsGraph() = default; ~LinkCellsGraph() override = default; - void loopsMessageCb(V3GraphVertex* vertexp) override; + void loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) override; }; class LinkCellsVertex final : public V3GraphVertex { @@ -73,7 +73,7 @@ public: 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()) { vvertexp->modp()->v3warn(E_UNSUPPORTED, "Unsupported: Recursive multiple modules (module instantiates " diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 5ace4d040..b221d8a09 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3422,11 +3422,11 @@ class LinkDotResolveVisitor final : public VNVisitor { << (!baddot.empty() ? AstNode::prettyNameQ(baddot) : nodep->prettyNameQ()) << " in dotted " << expectWhat << ": '" - << m_ds.m_dotText + "." + nodep->prettyName() << "'"); - if (okSymp) { - okSymp->cellErrorScopes(nodep, - AstNode::prettyName(m_ds.m_dotText)); - } + << m_ds.m_dotText + "." + nodep->prettyName() << "'\n" + << nodep->warnContextPrimary() + << (okSymp ? okSymp->cellErrorScopes( + nodep, AstNode::prettyName(m_ds.m_dotText)) + : "")); } m_ds.m_dotErr = true; } @@ -3611,8 +3611,9 @@ class LinkDotResolveVisitor final : public VNVisitor { if (!nodep->varp()) { nodep->v3error("Can't find definition of " << AstNode::prettyNameQ(baddot) << " in dotted signal: '" - << nodep->dotted() + "." + nodep->prettyName() << "'"); - okSymp->cellErrorScopes(nodep); + << nodep->dotted() + "." + nodep->prettyName() << "'\n" + << nodep->warnContextPrimary() + << okSymp->cellErrorScopes(nodep)); return; } // V3Inst may have expanded arrays of interfaces to @@ -3636,8 +3637,9 @@ class LinkDotResolveVisitor final : public VNVisitor { if (!vscp) { nodep->v3error("Can't find varpin scope of " << AstNode::prettyNameQ(baddot) << " in dotted signal: '" - << nodep->dotted() + "." + nodep->prettyName() << "'"); - okSymp->cellErrorScopes(nodep); + << nodep->dotted() + "." + nodep->prettyName() << "'\n" + << nodep->warnContextPrimary() + << okSymp->cellErrorScopes(nodep)); } else { while (vscp->user2p()) { // If V3Inline aliased it, pick up the new signal 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, true); if (!dotSymp) { - okSymp->cellErrorScopes(nodep); nodep->v3fatalSrc("Couldn't resolve inlined scope " << 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, @@ -3974,8 +3977,9 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->v3error("Can't find definition of " << AstNode::prettyNameQ(baddot) << " in dotted task/function: '" << nodep->dotted() + "." + nodep->prettyName() << "'\n" - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - okSymp->cellErrorScopes(nodep); + << (suggest.empty() ? "" : nodep->warnMore() + suggest) << '\n' + << nodep->warnContextPrimary() + << okSymp->cellErrorScopes(nodep)); } } } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 25f612395..de2d030a9 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -595,40 +595,41 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la // Warn and return not found if (errmsg != "") { - fl->v3error(errmsg + "'"s + filename + "'"s); - filePathLookedMsg(fl, filename); + fl->v3error(errmsg << "'"s << filename << "'\n"s << fl->warnContextPrimary() + << V3Error::warnAdditionalInfo() << filePathLookedMsg(fl, filename)); } return ""; } -void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { +string V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { static bool shown_notfound_msg = false; + std::ostringstream ss; if (modname.find("__Vhsh") != string::npos) { - std::cerr << V3Error::warnMoreStandalone() - << "... Note: Name is longer than 127 characters; automatic" - << " file lookup may have failed due to OS filename length limits.\n"; - std::cerr << V3Error::warnMoreStandalone() - << "... Suggest putting filename with this module/package" - << " onto command line instead.\n"; + ss << V3Error::warnMore() << "... Note: Name is longer than 127 characters; automatic" + << " file lookup may have failed due to OS filename length limits.\n"; + ss << V3Error::warnMore() << "... 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."); + ss << V3Error::warnMore() + << "... This may be because there's no search path specified with -I.\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& ext : m_impp->m_libExtVs) { 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& ext : m_impp->m_libExtVs) { 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 diff --git a/src/V3Options.h b/src/V3Options.h index 75612db10..9ab1b61e3 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -779,7 +779,7 @@ public: string fileExists(const string& filename); string filePath(FileLine* fl, const string& modname, const string& lastpath, const string& errmsg); - void filePathLookedMsg(FileLine* fl, const string& modname); + string filePathLookedMsg(FileLine* fl, const string& modname); V3LangCode fileLanguage(const string& filename); static bool fileStatNormal(const string& filename); diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 54d275b28..46c91aa9e 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -100,17 +100,16 @@ public: }; class Graph final : public V3Graph { - void loopsVertexCb(V3GraphVertex* vtxp) override { - // TODO: 'typeName' is an internal thing. This should be more human readable. + string loopsVertexCb(V3GraphVertex* vtxp) override { if (SchedAcyclicLogicVertex* const lvtxp = vtxp->cast()) { AstNode* const logicp = lvtxp->logicp(); - std::cerr << logicp->fileline()->warnOtherStandalone() - << " Example path: " << logicp->typeName() << endl; + return logicp->fileline()->warnOther() + + " Example path: " + logicp->prettyTypeName() + "\n"; } else { SchedAcyclicVarVertex* const vvtxp = vtxp->as(); AstVarScope* const vscp = vvtxp->vscp(); - std::cerr << vscp->fileline()->warnOtherStandalone() - << " Example path: " << vscp->prettyName() << endl; + return vscp->fileline()->warnOther() + " Example path: " + vscp->prettyName() + + "\n"; } } }; @@ -268,7 +267,8 @@ void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector& candidates } // 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. std::vector 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. - 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 // important" signals. unsigned splittable = 0; - const auto reportFirst10 = [&](std::function less) { + const auto reportFirst10 + = [&](std::function less) -> string { std::stable_sort(candidates.begin(), candidates.end(), less); + std::ostringstream ss2; for (size_t i = 0; i < 10; i++) { if (i == candidates.size()) break; const Candidate& candidate = candidates[i]; AstVar* const varp = candidate.first->varp(); - std::cerr << V3Error::warnMoreStandalone() << " " << varp->fileline() << " " - << varp->prettyName() << ", width " << std::dec << varp->width() - << ", circular fanout " << candidate.second; + + ss2 << V3Error::warnMore() << " " << varp->fileline() << ' ' << varp->prettyName() + << ", width " << std::dec << varp->width() << ", circular fanout " + << candidate.second; if (V3SplitVar::canSplitVar(varp)) { - std::cerr << ", can split_var"; + ss2 << ", can split_var"; ++splittable; } - std::cerr << '\n'; + ss2 << '\n'; } + return ss2.str(); }; // Widest variables - 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(); - }); + ss << V3Error::warnMore() << "... 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::warnMoreStandalone() << "... Candidates with the highest fanout:\n"; - reportFirst10([](const Candidate& a, const Candidate& b) { // - return a.second > b.second; - }); + ss << V3Error::warnMore() << "... Candidates with the highest fanout:\n" + << reportFirst10([](const Candidate& a, const Candidate& b) { // + return a.second > b.second; + }); if (splittable) { - std::cerr << V3Error::warnMoreStandalone() - << "... Suggest add /*verilator split_var*/ or /*verilator " - "isolate_assignments*/ to appropriate variables above." - << std::endl; + ss << V3Error::warnMore() + << "... Suggest add /*verilator split_var*/ or /*verilator " + "isolate_assignments*/ to appropriate variables above.\n"; } V3Stats::addStat("Scheduling, split_var, candidates", splittable); + return ss.str(); } void reportCycles(Graph* graphp, const std::vector& cutVertices) { @@ -330,17 +334,26 @@ void reportCycles(Graph* graphp, const std::vector& cutV FileLine* const flp = vscp->fileline(); // First v3warn not inside warnIsOff so we can see the suppressions with --debug - vscp->v3warn(UNOPTFLAT, "Signal unoptimizable: Circular combinational logic: " - << vscp->prettyNameQ()); - if (!flp->warnIsOff(V3ErrorCode::UNOPTFLAT) && !flp->lastWarnWaived()) { + if (flp->warnIsOff(V3ErrorCode::UNOPTFLAT)) { + // First v3warn not inside warnIsOff so we can see the suppressions with --debug + 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 flp->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); - // Calls Graph::loopsVertexCb - graphp->reportLoops(&V3GraphEdge::followAlwaysTrue, vvtxp); + // Create a subgraph for the UNOPTFLAT loop if (v3Global.opt.reportUnoptflat()) { - // Report candidate variables for splitting - reportLoopVars(graphp, vvtxp); - // Create a subgraph for the UNOPTFLAT loop V3Graph loopGraph; graphp->subtreeLoops(&V3GraphEdge::followAlwaysTrue, vvtxp, &loopGraph); loopGraph.dumpDotFilePrefixedAlways("unoptflat"); diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 84cced2cd..20166c97e 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -256,7 +256,7 @@ public: } } } - void cellErrorScopes(AstNode* lookp, string prettyName = "") { + string cellErrorScopes(AstNode* lookp, string prettyName = "") { if (prettyName == "") prettyName = lookp->prettyName(); string scopes; for (IdNameMap::iterator it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it) { @@ -267,9 +267,9 @@ public: } } if (scopes == "") scopes = ""; - std::cerr << V3Error::warnMoreStandalone() << "... Known scopes under '" << prettyName - << "': " << scopes << endl; if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1); + return V3Error::warnMore() + "... Known scopes under '" + prettyName + "': " + scopes + + '\n'; } }; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 8b9383f61..9f7e85728 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5876,9 +5876,12 @@ class WidthVisitor final : public VNVisitor { // We've resolved parameters and hit a module that we couldn't resolve. It's // finally time to report it. // Note only here in V3Width as this is first visitor after V3Dead. - nodep->modNameFileline()->v3error("Cannot find file containing module: '" - << nodep->modName() << "'"); - v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName()); + nodep->modNameFileline()->v3error( + "Cannot find file containing module: '" + << 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()); userIterateAndNext(nodep->pinsp(), nullptr); diff --git a/test_regress/t/t_gen_nonconst_bad.out b/test_regress/t/t_gen_nonconst_bad.out index 5a50edbcd..9c7aa3c0c 100644 --- a/test_regress/t/t_gen_nonconst_bad.out +++ b/test_regress/t/t_gen_nonconst_bad.out @@ -2,9 +2,7 @@ 8 | nfound nfound(); | ^~~~~~ ... 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. - 8 | nfound nfound(); - | ^~~~~~ + ... This may be because there's no search path specified with -I. ... Looked in: nfound nfound.v diff --git a/test_regress/t/t_interface_mismodport_bad.out b/test_regress/t/t_interface_mismodport_bad.out index 0eaeffb14..a8b307c1f 100644 --- a/test_regress/t/t_interface_mismodport_bad.out +++ b/test_regress/t/t_interface_mismodport_bad.out @@ -1,6 +1,6 @@ %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; | ^~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... Known scopes under 'bad': + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to