From 7521c2c644e7c6a4651efa65c37b9648bf370e4c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 23 Mar 2025 19:51:54 -0400 Subject: [PATCH] Standardize some error messages. --- src/V3AssertPre.cpp | 2 +- src/V3Ast.cpp | 8 ++-- src/V3Dfg.cpp | 6 +-- src/V3DfgDfgToAst.cpp | 2 +- src/V3DfgPasses.cpp | 2 +- src/V3DupFinder.cpp | 2 +- src/V3EmitCConstInit.h | 2 +- src/V3EmitMk.cpp | 2 +- src/V3ExecGraph.cpp | 2 +- src/V3File.cpp | 6 +-- src/V3Graph.cpp | 2 +- src/V3Inline.cpp | 4 +- src/V3LinkDot.cpp | 2 +- src/V3Options.cpp | 18 ++++---- src/V3OrderParallel.cpp | 2 +- src/V3OrderProcessDomains.cpp | 2 +- src/V3ParseImp.cpp | 4 +- src/V3PreProc.cpp | 56 ++++++++++++----------- src/V3PreProc.h | 2 - src/V3Randomize.cpp | 2 +- src/V3SchedReplicate.cpp | 2 +- src/V3StatsReport.cpp | 2 +- src/V3SymTable.h | 2 +- src/V3TSP.cpp | 2 +- src/V3Waiver.cpp | 2 +- src/V3Width.cpp | 2 +- src/VlcTop.cpp | 10 ++-- test_regress/t/t_dist_warn_coverage.py | 39 ++++++++++------ test_regress/t/t_flag_build_jobs_bad.out | 2 + test_regress/t/t_flag_compiler_bad.out | 1 + test_regress/t/t_flag_decorations_bad.out | 1 + test_regress/t/t_flag_make_bad.out | 1 + test_regress/t/t_flag_suggest.out | 1 + test_regress/t/t_flag_threads_dpi_bad.out | 1 + test_regress/t/t_flag_x_assign_bad.out | 1 + test_regress/t/t_flag_x_initial_bad.out | 1 + test_regress/t/t_preproc_ifdefend_bad.out | 4 ++ test_regress/t/t_preproc_ifdefend_bad.py | 16 +++++++ test_regress/t/t_preproc_ifdefend_bad.v | 7 +++ test_regress/t/t_vlcov_nfound_bad.out | 2 +- 40 files changed, 137 insertions(+), 90 deletions(-) create mode 100644 test_regress/t/t_preproc_ifdefend_bad.out create mode 100755 test_regress/t/t_preproc_ifdefend_bad.py create mode 100644 test_regress/t/t_preproc_ifdefend_bad.v diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 3d3aaaab3..2761344df 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -295,7 +295,7 @@ private: popp->makeStmt()}); } } else { - nodep->v3fatal("Invalid direction"); + nodep->v3fatalSrc("Invalid direction"); } VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 3236bd989..46a4b1ca3 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1340,7 +1340,7 @@ void AstNode::dumpTreeFile(const string& filename, bool doDump) { { // Write log & close UINFO(2, "Dumping " << filename << endl); const std::unique_ptr logsp{V3File::new_ofstream(filename)}; - if (logsp->fail()) v3fatal("Can't write " << filename); + if (logsp->fail()) v3fatal("Can't write file: " << filename); *logsp << "Verilator Tree Dump (format 0x3900) from to \n"; if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) { @@ -1385,7 +1385,7 @@ void AstNode::dumpTreeJsonFile(const string& filename, bool doDump) { if (!doDump) return; UINFO(2, "Dumping " << filename << endl); const std::unique_ptr treejsonp{V3File::new_ofstream(filename)}; - if (treejsonp->fail()) v3fatal("Can't write " << filename); + if (treejsonp->fail()) v3fatal("Can't write file: " << filename); dumpTreeJson(*treejsonp); *treejsonp << '\n'; } @@ -1394,7 +1394,7 @@ void AstNode::dumpJsonMetaFileGdb(const char* filename) { dumpJsonMetaFile(filen void AstNode::dumpJsonMetaFile(const string& filename) { UINFO(2, "Dumping " << filename << endl); const std::unique_ptr treejsonp{V3File::new_ofstream(filename)}; - if (treejsonp->fail()) v3fatalStatic("Can't write " << filename); + if (treejsonp->fail()) v3fatalStatic("Can't write file: " << filename); *treejsonp << '{'; FileLine::fileNameNumMapDumpJson(*treejsonp); *treejsonp << ','; @@ -1408,7 +1408,7 @@ void AstNode::dumpTreeDotFile(const string& filename, bool doDump) { if (doDump) { UINFO(2, "Dumping " << filename << endl); const std::unique_ptr treedotp{V3File::new_ofstream(filename)}; - if (treedotp->fail()) v3fatal("Can't write " << filename); + if (treedotp->fail()) v3fatal("Can't write file: " << filename); *treedotp << "digraph vTree{\n"; *treedotp << "\tgraph\t[label=\"" << filename + ".dot" << "\",\n"; diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index 0cbc69966..2dd3c3a7a 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -193,7 +193,7 @@ void DfgGraph::dumpDotFile(const string& filename, const string& label) const { // This generates a file used by graphviz, https://www.graphviz.org // "hardcoded" parameters: const std::unique_ptr os{V3File::new_ofstream(filename)}; - if (os->fail()) v3fatal("Cannot write to file: " << filename); + if (os->fail()) v3fatal("Can't write file: " << filename); dumpDot(*os.get(), label); os->close(); } @@ -244,7 +244,7 @@ void DfgGraph::dumpDotUpstreamCone(const string& fileName, const DfgVertex& vtx, const string& name) const { // Open output file const std::unique_ptr os{V3File::new_ofstream(fileName)}; - if (os->fail()) v3fatal("Cannot write to file: " << fileName); + if (os->fail()) v3fatal("Can't write file: " << fileName); // Header *os << "digraph dfg {\n"; @@ -278,7 +278,7 @@ void DfgGraph::dumpDotAllVarConesPrefixed(const string& label) const { const string coneName{prefix + sinkp->varp()->name()}; const string fileName{v3Global.debugFilename(coneName) + ".dot"}; const std::unique_ptr os{V3File::new_ofstream(fileName)}; - if (os->fail()) v3fatal("Cannot write to file: " << fileName); + if (os->fail()) v3fatal("Can't write file: " << fileName); // Header *os << "digraph dfg {\n"; diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 64a135e33..ce094ccd0 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -199,7 +199,7 @@ class DfgToAstVisitor final : DfgVisitor { // VISITORS void visit(DfgVertex* vtxp) override { // LCOV_EXCL_START - vtxp->v3fatal("Unhandled DfgVertex: " << vtxp->typeName()); + vtxp->v3fatalSrc("Unhandled DfgVertex: " << vtxp->typeName()); } // LCOV_EXCL_STOP void visit(DfgVarPacked* vtxp) override { diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index cf3151720..5c82ba149 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -85,7 +85,7 @@ V3DfgOptimizationContext::~V3DfgOptimizationContext() { + "__stats_dfg_patterns__" + ident + ".txt"; // Open, write, close const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); + if (ofp->fail()) v3fatal("Can't write file: " << filename); m_patternStats.dump(m_label, *ofp); } diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp index c2b44d93d..409caa96c 100644 --- a/src/V3DupFinder.cpp +++ b/src/V3DupFinder.cpp @@ -55,7 +55,7 @@ V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUser void V3DupFinder::dumpFile(const string& filename, bool tree) { UINFO(2, "Dumping " << filename << endl); const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); std::unordered_map dist; diff --git a/src/V3EmitCConstInit.h b/src/V3EmitCConstInit.h index 7fb761828..c80154ddb 100644 --- a/src/V3EmitCConstInit.h +++ b/src/V3EmitCConstInit.h @@ -95,7 +95,7 @@ protected: } void visit(AstInitItem* nodep) override { // LCOV_EXCL_START - nodep->v3fatal("Handled by AstInitArray"); + nodep->v3fatalSrc("Handled by AstInitArray"); } // LCOV_EXCL_STOP void visit(AstConst* nodep) override { diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index e5ae98483..429f07c44 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -408,7 +408,7 @@ private: const string filename = v3Global.debugFilename("outputgroup") + ".txt"; UINFO(5, "Dumping " << filename << endl); m_logp = std::unique_ptr{V3File::new_ofstream(filename)}; - if (m_logp->fail()) v3fatal("Can't write " << filename); + if (m_logp->fail()) v3fatal("Can't write file: " << filename); } if (m_logp) dumpLogScoreHistogram(*m_logp); diff --git a/src/V3ExecGraph.cpp b/src/V3ExecGraph.cpp index edab5679e..4ca91904a 100644 --- a/src/V3ExecGraph.cpp +++ b/src/V3ExecGraph.cpp @@ -98,7 +98,7 @@ private: void dumpDotFile(const V3Graph& graph, const string& filename) const { // This generates a file used by graphviz, https://www.graphviz.org const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); // Header *logp << "digraph v3graph {\n"; diff --git a/src/V3File.cpp b/src/V3File.cpp index 49a4e032b..c10d48976 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -146,7 +146,7 @@ V3FileDependImp dependImp; // Depend implementation class void V3FileDependImp::writeDepend(const string& filename) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); + if (ofp->fail()) v3fatal("Can't write file: " << filename); for (const DependFile& i : m_filenameList) { if (i.target()) *ofp << i.filename() << " "; @@ -179,7 +179,7 @@ std::vector V3FileDependImp::getAllDeps() const { void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); + if (ofp->fail()) v3fatal("Can't write file: " << filename); const string cmdline = stripQuotes(cmdlineIn); *ofp << "# DESCR" @@ -936,7 +936,7 @@ V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang) : V3OutFormatter{filename, lang} , m_bufferp{new std::array{}} { if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) { - v3fatal("Cannot write " << filename); + v3fatal("Can't write file: " << filename); } } diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index c5f57f78d..a1af41bb9 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -284,7 +284,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { // This generates a file used by graphviz, https://www.graphviz.org // "hardcoded" parameters: const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); // Header *logp << "digraph v3graph {\n"; diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index b52be239a..d308eaaf3 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -603,10 +603,10 @@ class InlineVisitor final : public VNVisitor { //-------------------- void visit(AstCell* nodep) override { // LCOV_EXCL_START - nodep->v3fatal("Traversal should have been short circuited"); + nodep->v3fatalSrc("Traversal should have been short circuited"); } void visit(AstNodeStmt* nodep) override { - nodep->v3fatal("Traversal should have been short circuited"); + nodep->v3fatalSrc("Traversal should have been short circuited"); } // LCOV_EXCL_STOP void visit(AstNodeFile*) override {} // Accelerate void visit(AstNodeDType*) override {} // Accelerate diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 088628a4d..dd92ce966 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -171,7 +171,7 @@ public: if (dumpLevel() >= 6 || force) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); std::ostream& os = *logp; // TODO the symbol table has node pointers which may be // dangling, as we call deleteTree in these visitors without diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 3260f5fb4..7f5af8b07 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -474,7 +474,7 @@ void V3Options::decorations(FileLine* fl, const string& arg) { // --decorations m_decoration = true; m_decorationNodes = false; } else { - fl->v3fatal("Unknown setting for --decorations: '" + fl->v3error("Unknown setting for --decorations: '" << arg << "'\n" << fl->warnMore() << "... Suggest 'none', 'medium', or 'node'"); } @@ -1196,7 +1196,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-build-jobs", CbVal, [this, fl](const char* valp) { int val = std::atoi(valp); if (val < 0) { - fl->v3fatal("--build-jobs requires a non-negative integer, but '" << valp + fl->v3error("--build-jobs requires a non-negative integer, but '" << valp << "' was passed"); val = 1; } else if (val == 0) { @@ -1229,7 +1229,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs m_compLimitParens = 80; // 128, but allow some room } else { - fl->v3fatal("Unknown setting for --compiler: '" + fl->v3error("Unknown setting for --compiler: '" << valp << "'\n" << fl->warnMore() << "... Suggest 'clang', 'gcc', or 'msvc'"); } @@ -1417,7 +1417,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, for (int i = V3LangCode::L_ERROR + 1; i < V3LangCode::_ENUM_END; ++i) { spell.pushCandidate(V3LangCode{i}.ascii()); } - fl->v3fatal("Unknown language specified: " << valp << spell.bestCandidateMsg(valp)); + fl->v3error("Unknown language specified: " << valp << spell.bestCandidateMsg(valp)); } }; DECL_OPTION("-default-language", CbVal, setLang); @@ -1446,7 +1446,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, } else if (!std::strcmp(valp, "json")) { m_makeJson = true; } else { - fl->v3fatal("Unknown --make system specified: '" << valp << "'"); + fl->v3error("Unknown --make system specified: '" << valp << "'"); } }); DECL_OPTION("-max-num-width", Set, &m_maxNumWidth); @@ -1487,7 +1487,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-no-pins64", CbCall, [this]() { m_pinsBv = 33; }); DECL_OPTION("-pins-bv", CbVal, [this, fl](const char* valp) { m_pinsBv = std::atoi(valp); - if (m_pinsBv > 65) fl->v3fatal("--pins-bv maximum is 65: " << valp); + if (m_pinsBv > 65) fl->v3error("--pins-bv maximum is 65: " << valp); }); DECL_OPTION("-pins-inout-enables", OnOff, &m_pinsInoutEnables); DECL_OPTION("-pins-sc-uint", CbOnOff, [this](bool flag) { @@ -1608,7 +1608,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, m_threadsDpiPure = true; m_threadsDpiUnpure = false; } else { - fl->v3fatal("Unknown setting for --threads-dpi: '" + fl->v3error("Unknown setting for --threads-dpi: '" << valp << "'\n" << fl->warnMore() << "... Suggest 'all', 'none', or 'pure'"); } @@ -1796,7 +1796,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, } else if (!std::strcmp(valp, "unique")) { m_xAssign = "unique"; } else { - fl->v3fatal("Unknown setting for --x-assign: '" + fl->v3error("Unknown setting for --x-assign: '" << valp << "'\n" << fl->warnMore() << "... Suggest '0', '1', 'fast', or 'unique'"); } @@ -1809,7 +1809,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, } else if (!std::strcmp(valp, "unique")) { m_xInitial = "unique"; } else { - fl->v3fatal("Unknown setting for --x-initial: '" + fl->v3error("Unknown setting for --x-initial: '" << valp << "'\n" << fl->warnMore() << "... Suggest '0', 'fast', or 'unique'"); } diff --git a/src/V3OrderParallel.cpp b/src/V3OrderParallel.cpp index c8a41d254..72473d71e 100644 --- a/src/V3OrderParallel.cpp +++ b/src/V3OrderParallel.cpp @@ -556,7 +556,7 @@ public: UINFO(1, "Writing " << filename << endl); const std::unique_ptr ofp{V3File::new_ofstream(filename)}; std::ostream* const osp = &(*ofp); // &* needed to deref unique_ptr - if (osp->fail()) v3fatalStatic("Can't write " << filename); + if (osp->fail()) v3fatalStatic("Can't write file: " << filename); // Find start vertex with longest CP const LogicMTask* startp = nullptr; diff --git a/src/V3OrderProcessDomains.cpp b/src/V3OrderProcessDomains.cpp index bb028342f..4307bd45e 100644 --- a/src/V3OrderProcessDomains.cpp +++ b/src/V3OrderProcessDomains.cpp @@ -158,7 +158,7 @@ class V3OrderProcessDomains final { // Make report of all signal names and what clock edges they have const string filename = v3Global.debugFilename(m_tag + "_order_edges.txt"); const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); std::deque report; diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index ea82ae952..4bfc49bcb 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -336,7 +336,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i osp = ofp = V3File::new_ofstream(vppfilename); } if (osp->fail()) { - fileline->v3error("Cannot write preprocessor output: " + vppfilename); + fileline->v3error("Can't write file: " + vppfilename); return; } if (v3Global.opt.dumpDefines()) { @@ -371,7 +371,7 @@ void V3ParseImp::dumpInputsFile() { = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__inputs.vpp"; std::ofstream* ofp = V3File::new_ofstream(vppfilename, append); if (ofp->fail()) { - v3error("Cannot write preprocessor output: " + vppfilename); + v3error("Can't write file: " + vppfilename); return; } if (!append) { diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 435fe64c2..f342fd0a8 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -242,7 +242,7 @@ private: void statePop() { m_states.pop(); if (VL_UNCOVERABLE(m_states.empty())) { - error("InternalError: Pop of parser state with nothing on stack"); // LCOV_EXCL_LINE + fileline()->v3fatalSrc("Pop of parser state with nothing on stack"); m_states.push(ps_TOP); // LCOV_EXCL_LINE } } @@ -640,8 +640,8 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { const string arg = trimWhitespace(refp->args()[numArgs], true); if (arg != "") valueDef = arg; } else if (!haveDefault) { - error("Define missing argument '" + argName + "' for: " + refp->name() - + "\n"); + fileline()->v3error("Define missing argument '" + argName + + "' for: " + refp->name()); return " `" + refp->name() + " "; } numArgs++; @@ -679,7 +679,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { // `define X() is ok to call with nothing && !(refp->args().size() == 1 && numArgs == 0 && trimWhitespace(refp->args()[0], false) == "")) { - error("Define passed too many arguments: " + refp->name() + "\n"); + fileline()->v3error("Define passed too many arguments: " + refp->name()); return " `" + refp->name() + " "; } } @@ -800,7 +800,7 @@ void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filenam StrList wholefile; const bool ok = filterp->readWholefile(filename, wholefile /*ref*/); if (!ok) { - error("File not found: " + filename + "\n"); + fileline()->v3error("File not found: " + filename); return; } @@ -808,7 +808,7 @@ void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filenam // We allow the same include file twice, because occasionally it pops // up, with guards preventing a real recursion. if (m_lexp->m_streampStack.size() > V3PreProc::INCLUDE_DEPTH_MAX) { - error("Recursive inclusion of file: " + filename); + fileline()->v3error("Recursive inclusion of file: " + filename); // Include might be a tree of includes that is O(n^2) or worse. // Once hit this error then, ignore all further includes so can unwind. m_incError = true; @@ -964,8 +964,9 @@ int V3PreProcImp::getRawToken() { m_lastLineno = m_lexp->m_tokFilelinep->lineno(); m_tokensOnLine = 0; } else if (++m_tokensOnLine > v3Global.opt.preprocTokenLimit()) { - error("Too many preprocessor tokens on a line (>" - + cvtToStr(v3Global.opt.preprocTokenLimit()) + "); perhaps recursive `define"); + fileline()->v3error("Too many preprocessor tokens on a line (>" + + cvtToStr(v3Global.opt.preprocTokenLimit()) + + "); perhaps recursive `define"); tok = VP_EOF_ERROR; } @@ -1103,7 +1104,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } else if (state() == ps_DEFNAME_ELSIF) { if (m_ifdefStack.empty()) { - error("`elsif with no matching `if\n"); + fileline()->v3error("`elsif with no matching `if"); } else { // Handle `else portion const VPreIfEntry lastIf = m_ifdefStack.top(); @@ -1159,7 +1160,7 @@ int V3PreProcImp::getStateToken() { // IE, `ifdef `MACRO(x): Substitute and come back here when state pops. break; } else { - error("Expecting define name. Found: "s + tokenName(tok) + "\n"); + fileline()->v3error("Expecting define name. Found: "s + tokenName(tok)); goto next_tok; } } @@ -1208,7 +1209,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } else if (state() == ps_EXPR_ELSIF) { if (m_ifdefStack.empty()) { - error("`elsif with no matching `if\n"); + fileline()->v3error("`elsif with no matching `if"); } else { // Handle `else portion const VPreIfEntry lastIf = m_ifdefStack.top(); @@ -1243,8 +1244,8 @@ int V3PreProcImp::getStateToken() { if (VString::removeWhitespace(string{yyourtext(), yyourleng()}).empty()) { return tok; } else { - error("Syntax error in `ifdef () expression; unexpected: '"s + tokenName(tok) - + "'\n"); + fileline()->v3error("Syntax error in `ifdef () expression; unexpected: '"s + + tokenName(tok) + "'"); } goto next_tok; } @@ -1266,7 +1267,8 @@ int V3PreProcImp::getStateToken() { goto next_tok; } } else { - error("Expecting define formal arguments. Found: "s + tokenName(tok) + "\n"); + fileline()->v3error("Expecting define formal arguments. Found: "s + tokenName(tok) + + "\n"); goto next_tok; } } @@ -1318,8 +1320,8 @@ int V3PreProcImp::getStateToken() { } else { UASSERT(!m_defRefs.empty(), "Shouldn't be in DEFPAREN w/o active defref"); const VDefineRef* const refp = &(m_defRefs.top()); - error("Expecting ( to begin argument list for define reference `"s + refp->name() - + "\n"); + fileline()->v3error("Expecting ( to begin argument list for define reference `"s + + refp->name()); statePop(); goto next_tok; } @@ -1392,9 +1394,9 @@ int V3PreProcImp::getStateToken() { statePush(ps_STRIFY); goto next_tok; } else { - error(std::string{ - "Expecting ) or , to end argument list for define reference. Found: "} - + tokenName(tok)); + fileline()->v3error( + "Expecting ) or , to end argument list for define reference. Found: "s + + tokenName(tok)); statePop(); goto next_tok; } @@ -1419,7 +1421,7 @@ int V3PreProcImp::getStateToken() { break; } else { statePop(); - error("Expecting include filename. Found: "s + tokenName(tok) + "\n"); + fileline()->v3error("Expecting include filename. Found: "s + tokenName(tok)); goto next_tok; } } @@ -1427,12 +1429,12 @@ int V3PreProcImp::getStateToken() { if (tok == VP_STRING) { if (!m_off) { m_lastSym.assign(yyourtext(), yyourleng()); - error(m_lastSym); + fileline()->v3error(m_lastSym); } statePop(); goto next_tok; } else { - error("Expecting `error string. Found: "s + tokenName(tok) + "\n"); + fileline()->v3error("Expecting `error string. Found: "s + tokenName(tok)); statePop(); goto next_tok; } @@ -1479,7 +1481,7 @@ int V3PreProcImp::getStateToken() { statePop(); goto next_tok; } else if (tok == VP_EOF) { - error("`\" not terminated at EOF\n"); + fileline()->v3error("`\" not terminated at EOF"); break; } else if (tok == VP_BACKQUOTE) { m_strify += "\\\""; @@ -1513,7 +1515,7 @@ int V3PreProcImp::getStateToken() { case VP_ELSIF: statePush(ps_DEFNAME_ELSIF); goto next_tok; case VP_ELSE: if (m_ifdefStack.empty()) { - error("`else with no matching `if\n"); + fileline()->v3error("`else with no matching `if"); } else { const VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop(); @@ -1527,7 +1529,7 @@ int V3PreProcImp::getStateToken() { case VP_ENDIF: UINFO(4, "Endif " << endl); if (m_ifdefStack.empty()) { - error("`endif with no matching `if\n"); + fileline()->v3error("`endif with no matching `if"); } else { const VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop(); @@ -1547,7 +1549,7 @@ int V3PreProcImp::getStateToken() { unputString("``"); } if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) { - error("Recursive `define substitution: `" + name); + fileline()->v3error("Recursive `define substitution: `" + name); goto next_tok; } // Substitute @@ -1618,7 +1620,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } case VP_EOF: - if (!m_ifdefStack.empty()) error("`ifdef not terminated at EOF\n"); + if (!m_ifdefStack.empty()) fileline()->v3error("`ifdef not terminated at EOF"); return tok; case VP_UNDEFINEALL: if (!m_off) { diff --git a/src/V3PreProc.h b/src/V3PreProc.h index 608447d4b..f6aa9da93 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -84,8 +84,6 @@ public: virtual string removeDefines(const string& text) = 0; // Remove defines in a text string // UTILITIES - void error(const string& msg) { fileline()->v3error(msg); } ///< Report an error - void fatal(const string& msg) { fileline()->v3fatalSrc(msg); } ///< Report a fatal error virtual void dumpDefines(std::ostream& os) = 0; ///< Print list of `defines virtual void candidateDefines(VSpellCheck* spellerp) = 0; ///< Spell check candidate defines diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index d2cd5a300..0ddeaadbd 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -235,7 +235,7 @@ class RandomizeMarkVisitor final : public VNVisitor { "Unsupported: 'rand_mode()' on dynamic array element"); valid = false; } else { - methodHardp->v3fatal("Unknown rand_mode() receiver"); + methodHardp->v3fatalSrc("Unknown rand_mode() receiver"); } } if (!nodep->pinsp() && VN_IS(nodep->backp(), StmtExpr)) { diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index 9dd4fd33d..6f2b519ef 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -108,7 +108,7 @@ public: case REACTIVE | OBSERVED | INPUT | NBA: return "plum"; case REACTIVE | OBSERVED | ACTIVE | NBA: return "lightSeaGreen"; case REACTIVE | OBSERVED | INPUT | ACTIVE | NBA: return "gray50"; - default: v3fatal("There are only 5 region bits"); return ""; + default: v3fatalSrc("There are only 5 region bits"); return ""; } } // LCOV_EXCL_STOP diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index ec62aa3da..5697f5ceb 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -234,7 +234,7 @@ void V3Stats::statsReport() { const string filename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__stats.txt"; std::ofstream* ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); + if (ofp->fail()) v3fatal("Can't write file: " << filename); { StatsReport{ofp}; } // Destruct before cleanup diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 984df3d09..84cced2cd 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -319,7 +319,7 @@ public: const string filename = v3Global.debugFilename(nameComment) + ".txt"; UINFO(2, "Dumping " << filename << endl); const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); dumpSelf(*logp, ""); } } diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 95b71a0ac..ee42d1d17 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -397,7 +397,7 @@ public: if (dumpLevel()) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; - if (logp->fail()) v3fatal("Can't write " << filename); + if (logp->fail()) v3fatal("Can't write file: " << filename); dumpGraph(*logp, nameComment); } } diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index c8d36bd26..8578133ad 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -77,7 +77,7 @@ void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, cons void V3Waiver::write(const std::string& filename) VL_MT_SAFE_EXCLUDES(s_mutex) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); + if (ofp->fail()) v3fatal("Can't write file: " << filename); *ofp << "// DESCR" "IPTION: Verilator output: Waivers generated with --waiver-output\n\n"; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 199f9ac12..43b0715eb 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5881,7 +5881,7 @@ class WidthVisitor final : public VNVisitor { } else if (VN_IS(propStmtp, PropSpec)) { iterateCheckSelf(nodep, "PropSpec", propStmtp, SELF, BOTH); } else { - propStmtp->v3fatal("Invalid statement under AstProperty"); + propStmtp->v3fatalSrc("Invalid statement under AstProperty"); } } nodep->didWidth(true); diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index adedf4425..e16edfab3 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -35,7 +35,7 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) { std::ifstream is{filename.c_str()}; if (!is) { - if (!nonfatal) v3fatal("Can't read " << filename); + if (!nonfatal) v3fatal("Can't read coverage file: " << filename); return; } @@ -70,7 +70,7 @@ void VlcTop::writeCoverage(const string& filename) { std::ofstream os{filename.c_str()}; if (!os) { - v3fatal("Can't write " << filename); + v3fatal("Can't write file: " << filename); return; } @@ -86,7 +86,7 @@ void VlcTop::writeInfo(const string& filename) { std::ofstream os{filename.c_str()}; if (!os) { - v3fatal("Can't write " << filename); + v3fatal("Can't write file: " << filename); return; } @@ -285,13 +285,13 @@ void VlcTop::annotateOutputFiles(const string& dirname) { std::ifstream is{filename.c_str()}; if (!is) { - v3error("Can't read " << filename); + v3error("Can't read annotation file: " << filename); return; } std::ofstream os{outfilename.c_str()}; if (!os) { - v3fatal("Can't write " << outfilename); + v3error("Can't write file: " << outfilename); return; } diff --git a/test_regress/t/t_dist_warn_coverage.py b/test_regress/t/t_dist_warn_coverage.py index cf8133fb1..1c7f19f40 100755 --- a/test_regress/t/t_dist_warn_coverage.py +++ b/test_regress/t/t_dist_warn_coverage.py @@ -29,19 +29,30 @@ for s in [ 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error # Not yet analyzed ' loading non-variable', + '--pins-bv maximum is 65: ', '--pipe-filter protocol error, unexpected: ', + '--pipe-filter returned bad status', + '--pipe-filter: Can\'t pipe: ', + '--pipe-filter: fork failed: ', + '--threads must be >= 0: ', + '--threads-max-mtasks must be >= 1: ', + '--trace-threads must be >= 1: ', '/*verilator sformat*/ can only be applied to last argument of ', 'Argument needed for string.', 'Array initialization has too few elements, need element ', 'Assigned pin is neither input nor output', 'Assignment pattern with no members', 'Can\'t find varpin scope of ', + 'Can\'t read annotation file: ', 'Can\'t resolve module reference: \'', - 'Cannot write preprocessor output: ', + 'Can\'t write file: ', 'Circular logic when ordering code (non-cutable edge loop)', + 'Define missing argument \'', 'Define or directive not defined: `', 'Exceeded limit of ', + 'Expecting define formal arguments. Found: ', 'Extern declaration\'s scope is not a defined class', + 'File not found: ', 'Format to $display-like function must have constant format string', 'Forward typedef used as class/package does not resolve to class/package: ', 'Illegal +: or -: select; type already selected, or bad dimension: ', @@ -62,6 +73,7 @@ for s in [ 'String of ', 'Symbol matching ', 'Unexpected connection to arrayed port', + 'Unmatched brackets in variable substitution in file: ', 'Unsized numbers/parameters not allowed in streams.', 'Unsupported RHS tristate construct: ', 'Unsupported or syntax error: Unsized range in instance or other declaration', @@ -72,9 +84,6 @@ for s in [ 'Unsupported: $bits for queue', 'Unsupported: $c can\'t generate wider than 64 bits', 'Unsupported: &&& expression', - 'Unsupported: \'default :/\' constraint', - 'Unsupported: \'{} .* patterns', - 'Unsupported: \'{} tagged patterns', 'Unsupported: +%- range', 'Unsupported: +/- range', 'Unsupported: 4-state numbers in this context', @@ -96,9 +105,11 @@ for s in [ 'Unsupported: Verilog 1995 deassign', 'Unsupported: Verilog 1995 gate primitive: ', 'Unsupported: [] dimensions', + 'Unsupported: \'default :/\' constraint', + 'Unsupported: \'{} .* patterns', + 'Unsupported: \'{} tagged patterns', 'Unsupported: always[] (in property expression)', 'Unsupported: assertion items in clocking blocks', - 'Unsupported: covergroup within class', 'Unsupported: default clocking identifier', 'Unsupported: don\'t know how to deal with ', 'Unsupported: eventually[] (in property expression)', @@ -106,18 +117,18 @@ for s in [ 'Unsupported: extern interface', 'Unsupported: extern module', 'Unsupported: extern task', + 'Unsupported: modport export', + 'Unsupported: no_inline for tasks', 'Unsupported: property port \'local\'', 'Unsupported: randsequence production list', 'Unsupported: randsequence repeat', 'Unsupported: repeat event control', 'Unsupported: s_always (in property expression)', + 'Unsupported: static cast to ', + 'Unsupported: super', 'Unsupported: this.super', 'Unsupported: trireg', 'Unsupported: with[] stream expression', - 'Unsupported: modport export', - 'Unsupported: no_inline for tasks', - 'Unsupported: static cast to ', - 'Unsupported: super', ]: Suppressed[s] = True @@ -137,11 +148,11 @@ def read_messages(): continue if re.match(r'^\s*/\*', line): continue - if re.search(r'\b(v3error|v3warn|BBUNSUP)\b\($', line): + if re.search(r'\b(v3error|v3warn|v3fatal|BBUNSUP)\b\($', line): if 'LCOV_EXCL_LINE' not in line: read_next = True continue - m = re.search(r'.*\b(v3error|v3warn|BBUNSUP)\b(.*)', line) + m = re.search(r'.*\b(v3error|v3warn|v3fatal|BBUNSUP)\b(.*)', line) if m: line = m.group(2) if 'LCOV_EXCL_LINE' not in line: @@ -185,13 +196,13 @@ def check(): read_outputs() print("Number of suppressions = " + str(len(Suppressed))) - print("Coverage = ", str(100 - int(100 * len(Suppressed) / len(Messages)))) + print("Coverage = %3.1f%%" % (100 - int(100 * len(Suppressed) / len(Messages)))) print() print("Checking for v3error/v3warn messages in sources without") print("coverage in test_regress/t/*.out:") - print("(Developers: If a message is impossible to test, use UASSERT or") - print("v3fatalSrc instead of v3error)") + print("(Developers: If a message is impossible to test, consider using") + print("UASSERT or v3fatalSrc instead of v3error)") print() used_suppressed = {} diff --git a/test_regress/t/t_flag_build_jobs_bad.out b/test_regress/t/t_flag_build_jobs_bad.out index 341b1b979..1c9e263a4 100644 --- a/test_regress/t/t_flag_build_jobs_bad.out +++ b/test_regress/t/t_flag_build_jobs_bad.out @@ -1 +1,3 @@ %Error: --build-jobs requires a non-negative integer, but '-1' was passed +%Error: The following cannot be used together: --build, --lint-only. Suggest see manual +%Error: Exiting due to diff --git a/test_regress/t/t_flag_compiler_bad.out b/test_regress/t/t_flag_compiler_bad.out index db87cd4d0..2a477c239 100644 --- a/test_regress/t/t_flag_compiler_bad.out +++ b/test_regress/t/t_flag_compiler_bad.out @@ -1,2 +1,3 @@ %Error: Unknown setting for --compiler: 'bad_one' ... Suggest 'clang', 'gcc', or 'msvc' +%Error: Exiting due to diff --git a/test_regress/t/t_flag_decorations_bad.out b/test_regress/t/t_flag_decorations_bad.out index be8dbd94e..00ce5476a 100644 --- a/test_regress/t/t_flag_decorations_bad.out +++ b/test_regress/t/t_flag_decorations_bad.out @@ -1,2 +1,3 @@ %Error: Unknown setting for --decorations: 'BAD' ... Suggest 'none', 'medium', or 'node' +%Error: Exiting due to diff --git a/test_regress/t/t_flag_make_bad.out b/test_regress/t/t_flag_make_bad.out index d3a472dd3..ecd9b7d97 100644 --- a/test_regress/t/t_flag_make_bad.out +++ b/test_regress/t/t_flag_make_bad.out @@ -1 +1,2 @@ %Error: Unknown --make system specified: 'bad_one' +%Error: Exiting due to diff --git a/test_regress/t/t_flag_suggest.out b/test_regress/t/t_flag_suggest.out index 01ad7c7b0..0309de666 100644 --- a/test_regress/t/t_flag_suggest.out +++ b/test_regress/t/t_flag_suggest.out @@ -9,3 +9,4 @@ %Error: Invalid option: -Won-SPLITVAR... Suggested alternative: '-Wno-SPLITVAR' %Error: Unknown warning specified: -Wno-SPLITVER... Suggested alternative: '-Wno-SPLITVAR' %Error: Unknown language specified: 1364-1997... Suggested alternative: '1364-1995' +%Error: verilator: No Input Verilog file specified on command line, see verilator --help for more information diff --git a/test_regress/t/t_flag_threads_dpi_bad.out b/test_regress/t/t_flag_threads_dpi_bad.out index ca3423d51..e8c044e6f 100644 --- a/test_regress/t/t_flag_threads_dpi_bad.out +++ b/test_regress/t/t_flag_threads_dpi_bad.out @@ -1,2 +1,3 @@ %Error: Unknown setting for --threads-dpi: 'bad_one' ... Suggest 'all', 'none', or 'pure' +%Error: Exiting due to diff --git a/test_regress/t/t_flag_x_assign_bad.out b/test_regress/t/t_flag_x_assign_bad.out index 43929ec3c..75c4153c3 100644 --- a/test_regress/t/t_flag_x_assign_bad.out +++ b/test_regress/t/t_flag_x_assign_bad.out @@ -1,2 +1,3 @@ %Error: Unknown setting for --x-assign: 'bad_one' ... Suggest '0', '1', 'fast', or 'unique' +%Error: Exiting due to diff --git a/test_regress/t/t_flag_x_initial_bad.out b/test_regress/t/t_flag_x_initial_bad.out index 8f511db51..008b2cf19 100644 --- a/test_regress/t/t_flag_x_initial_bad.out +++ b/test_regress/t/t_flag_x_initial_bad.out @@ -1,2 +1,3 @@ %Error: Unknown setting for --x-initial: 'bad_one' ... Suggest '0', 'fast', or 'unique' +%Error: Exiting due to diff --git a/test_regress/t/t_preproc_ifdefend_bad.out b/test_regress/t/t_preproc_ifdefend_bad.out new file mode 100644 index 000000000..a96bed118 --- /dev/null +++ b/test_regress/t/t_preproc_ifdefend_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_preproc_ifdefend_bad.v:9:1: `ifdef not terminated at EOF + 9 | %Error-internal-contents-bad-ct2-ln9 + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_preproc_ifdefend_bad.py b/test_regress/t/t_preproc_ifdefend_bad.py new file mode 100755 index 000000000..889534217 --- /dev/null +++ b/test_regress/t/t_preproc_ifdefend_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(fails=True, verilator_flags2=['--no-std'], expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_preproc_ifdefend_bad.v b/test_regress/t/t_preproc_ifdefend_bad.v new file mode 100644 index 000000000..3effb41d1 --- /dev/null +++ b/test_regress/t/t_preproc_ifdefend_bad.v @@ -0,0 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef FOO diff --git a/test_regress/t/t_vlcov_nfound_bad.out b/test_regress/t/t_vlcov_nfound_bad.out index 8fd3ed344..6bdeb2873 100644 --- a/test_regress/t/t_vlcov_nfound_bad.out +++ b/test_regress/t/t_vlcov_nfound_bad.out @@ -1 +1 @@ -%Error: Can't read t/t_NOT_FOUND +%Error: Can't read coverage file: t/t_NOT_FOUND