From 18239a6fbb227ce2a3f89593b14ed319164f5bf5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 15 Sep 2026 14:29:36 +0200 Subject: [PATCH] logger: add LogSourceLocation --- frontends/ast/ast.cc | 4 +- frontends/ast/genrtlil.cc | 31 ++++++------ frontends/ast/simplify.cc | 13 +++-- frontends/verilog/const2ast.cc | 8 +-- frontends/verilog/preproc.cc | 2 +- frontends/verilog/verilog_error.cc | 6 +-- frontends/verilog/verilog_lexer.l | 10 ++-- frontends/verilog/verilog_location.h | 4 ++ kernel/driver.cc | 3 ++ kernel/fmt.cc | 14 +++--- kernel/fmt.h | 3 +- kernel/log.cc | 74 +++++++++++----------------- kernel/log.h | 56 ++++++++++++--------- kernel/log_compat.cc | 10 ++-- pyosys/wrappers_tpl.cc | 14 +++--- 15 files changed, 124 insertions(+), 128 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 0257a4be7..a73836e1c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1460,7 +1460,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump if (design->has(child->str)) { RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str); + log_file_error(child->location.to_src(), "Re-definition of module `%s'!\n", child->str); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", child->str.c_str(), child->loc_string().c_str()); @@ -1938,7 +1938,7 @@ void AstModule::loadconfig() const void AstNode::formatted_input_error(std::string_view format, std::string str) const { - logger().formatted_file_error(*location.begin.filename, location.begin.line, format, std::move(str)); + logger().formatted_error(location.to_src(), "ERROR:", format, std::move(str)); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ddbf5575d..7e4757914 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -840,8 +840,7 @@ struct AST_INTERNAL::ProcessGenerator node->detectSignWidth(width, is_signed, nullptr); VerilogFmtArg arg = {}; - arg.filename = *node->location.begin.filename; - arg.first_line = node->location.begin.line; + arg.src = node->location.to_src(); if (node->type == AST_CONSTANT && node->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node->bitsAsConst().decode_string(); @@ -867,7 +866,7 @@ struct AST_INTERNAL::ProcessGenerator fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { - log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str); + log_file_error(ast->location.to_src(), "Found unsupported invocation of system task `%s'!\n", ast->str); } break; @@ -919,7 +918,7 @@ struct AST_INTERNAL::ProcessGenerator cell->set_bool_attribute(ID(keep)); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first); + log_file_error(ast->location.to_src(), "Attribute `%s' with non-constant value!\n", attr.first); cell->attributes[attr.first] = attr.second->asAttrConst(); } cell->setParam(ID::FLAVOR, flavor); @@ -1529,7 +1528,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); + log_file_warning(location.to_src(), "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -1554,7 +1553,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) wire->name = str; if (flag_autowire) - log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str); + log_file_warning(location.to_src(), "Identifier `%s' is implicitly declared.\n", str); else input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str); } @@ -1659,10 +1658,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = source_width - (chunk.offset + chunk.width); if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) - log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + log_file_warning(location.to_src(), "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); else - log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + log_file_warning(location.to_src(), "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { @@ -1676,10 +1675,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + log_file_warning(location.to_src(), "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + log_file_warning(location.to_src(), "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } @@ -2082,7 +2081,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n" + log_file_warning(location.to_src(), "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); @@ -2115,7 +2114,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; const auto* value = child->children[0].get(); if (value->type == AST_REALVALUE) - log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n", + log_file_warning(location.to_src(), "Replacing floating point parameter %s.%s = %f with string.\n", cell, paraname.unescape(), value->realvalue); else if (value->type != AST_CONSTANT) input_error("Parameter %s.%s with non-constant value!\n", @@ -2216,14 +2215,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int sz = children.size(); if (str == "$info") { if (sz > 0) - log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str); + log_file_info(location.to_src(), "%s.\n", children[0]->str); else - log_file_info(*location.begin.filename, location.begin.line, "\n"); + log_file_info(location.to_src(), "\n"); } else if (str == "$warning") { if (sz > 0) - log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str); + log_file_warning(location.to_src(), "%s.\n", children[0]->str); else - log_file_warning(*location.begin.filename, location.begin.line, "\n"); + log_file_warning(location.to_src(), "\n"); } else if (str == "$error") { if (sz > 0) input_error("%s.\n", children[0]->str); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 43a83a66f..4c880c85d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -149,8 +149,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; - arg.filename = *location.begin.filename; - arg.first_line = location.begin.line; + arg.src = location.to_src(); if (node_arg->type == AST_CONSTANT && node_arg->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node_arg->bitsAsConst().decode_string(); @@ -167,10 +166,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ arg.sig = node_arg->bitsAsConst(); arg.signed_ = node_arg->is_signed; } else if (may_fail) { - log_file_info(*location.begin.filename, location.begin.line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str, index + 1); + log_file_info(arg.src, "Skipping system task `%s' with non-constant argument at position %zu.\n", str, index + 1); return Fmt(); } else { - log_file_error(*location.begin.filename, location.begin.line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str, index + 1); + log_file_error(arg.src, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str, index + 1); } args.push_back(arg); } @@ -1178,7 +1177,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(*location.begin.filename, location.begin.line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str); + log_file_warning(location.to_src(), "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str); delete_children(); str = std::string(); } @@ -1188,7 +1187,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { - log_file_warning(*location.begin.filename, location.begin.line, "System task `%s' outside initial or always block is unsupported.\n", str); + log_file_warning(location.to_src(), "System task `%s' outside initial or always block is unsupported.\n", str); delete_children(); str = std::string(); } else { @@ -2362,7 +2361,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", + log_file_warning(location.to_src(), "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); children[0] = mkconst_bits(location, constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 450a3ea1b..4a5b7be9f 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -47,9 +47,9 @@ using namespace VERILOG_FRONTEND; void ConstParser::log_maybe_loc_error(std::string msg) { if (loc.begin.filename) - log_file_error(*loc.begin.filename, loc.begin.line, "%s", msg); + log_file_error(loc.to_src(), "%s", msg); else if (!Frontend::current_script_filename.empty()) - log_file_error(Frontend::current_script_filename, Frontend::current_script_lineno, + log_file_error(LogSourceLocation(Frontend::current_script_filename, Frontend::current_script_lineno), "Failed to parse constant `%s': %s", code_str, msg); else log_error("Failed to parse constant `%s': %s", code_str, msg); @@ -57,9 +57,9 @@ void ConstParser::log_maybe_loc_error(std::string msg) { void ConstParser::log_maybe_loc_warn(std::string msg) { if (loc.begin.filename) - log_file_warning(*loc.begin.filename, loc.begin.line, "%s", msg); + log_file_warning(loc.to_src(), "%s", msg); else if (!Frontend::current_script_filename.empty()) - log_file_warning(Frontend::current_script_filename, Frontend::current_script_lineno, + log_file_warning(LogSourceLocation(Frontend::current_script_filename, Frontend::current_script_lineno), "While parsing constant `%s': %s", code_str, msg); else log_warning("While parsing constant `%s': %s", code_str, msg); diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index fb7f0aaf5..b2cd43791 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -741,7 +741,7 @@ read_define(const std::string &filename, defines_map.add(name, value, (state == 2) ? &args : nullptr); global_defines_cache.add(name, value, (state == 2) ? &args : nullptr); } else { - log_file_error(filename, 0, "Invalid name for macro definition: >>%s<<.\n", name); + log_file_error(LogSourceLocation(filename), "Invalid name for macro definition: >>%s<<.\n", name); } } diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc index b968b3e21..cc14e03dd 100644 --- a/frontends/verilog/verilog_error.cc +++ b/frontends/verilog/verilog_error.cc @@ -34,12 +34,10 @@ USING_YOSYS_NAMESPACE [[noreturn]] void VERILOG_FRONTEND::formatted_err_at_loc(Location loc, std::string str) { - YOSYS_NAMESPACE_PREFIX log_file_error(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, - "%s\n", std::move(str)); + YOSYS_NAMESPACE_PREFIX log_file_error(loc.to_src(), "%s\n", std::move(str)); } void VERILOG_FRONTEND::formatted_warn_at_loc(Location loc, std::string str) { - YOSYS_NAMESPACE_PREFIX log_file_warning(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, - "%s\n", std::move(str)); + YOSYS_NAMESPACE_PREFIX log_file_warning(loc.to_src(), "%s\n", std::move(str)); } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 2b0d9f44d..8923a44da 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -162,7 +162,7 @@ static bool is_hex_dig(char c, int *val, parser::location_type loc) *val = c - 'A' + 0xA; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(*loc.begin.filename, loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c); + log_file_warning(loc.to_src(), "'%c' not a valid digit in hex escape sequence.\n", c); *val = 0; // not semantically valid in hex escape... return true; // ...but still processed as part of hex token } @@ -176,7 +176,7 @@ static bool is_oct_dig(char c, int *val, parser::location_type loc) *val = c - '0'; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(*loc.begin.filename, loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c); + log_file_warning(loc.to_src(), "'%c' not a valid digit in octal escape sequence.\n", c); *val = 0; // not semantically valid in octal escape... return true; // ...but still processed as part of octal token } @@ -196,7 +196,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) in++; if (!triple) - log_file_warning(*loc.begin.filename, loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n"); + log_file_warning(loc.to_src(), "Multi-line string literals should be triple-quoted or escaped.\n"); *out++ = '\n'; break; case '\\': @@ -233,7 +233,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: } out++; } else - log_file_warning(*loc.begin.filename, loc.begin.line, "ignoring invalid hex escape.\n"); + log_file_warning(loc.to_src(), "ignoring invalid hex escape.\n"); break; case '\\': *out++ = '\\'; @@ -256,7 +256,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: in++; if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { if (*out >= 040) - log_file_warning(*loc.begin.filename, loc.begin.line, "octal escape exceeds \\377\n"); + log_file_warning(loc.to_src(), "octal escape exceeds \\377\n"); *out = *out * 010 + val; in++; } diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h index 8ffe0552d..76b2b9170 100644 --- a/frontends/verilog/verilog_location.h +++ b/frontends/verilog/verilog_location.h @@ -88,6 +88,10 @@ struct Location { return oss.str(); } + + YOSYS_NAMESPACE_PREFIX LogSourceLocation to_src() const { + return YOSYS_NAMESPACE_PREFIX LogSourceLocation(begin.filename ? *(begin.filename) : "UNKNOWN", begin.line, begin.column, end.line, end.column); + } }; static inline std::ostream& operator<<(std::ostream& os, const Location& loc) { diff --git a/kernel/driver.cc b/kernel/driver.cc index 537a3976c..ac5006d2d 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -166,6 +166,9 @@ void ColorConsoleLogSink::log(const LogMessage &msg) fmt::print(f, fg(fmt::terminal_color::blue), "{}", time_str); } + if (!msg.src.filename.empty()) + fmt::print(f, fg(fmt::terminal_color::bright_cyan), "{}:{}: ", msg.src.filename, msg.src.start_line); + switch (msg.severity) { case LogSeverity::Warning: fmt::print(f, fg(fmt::terminal_color::bright_yellow), "{}", msg.prefix); diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 15179a75a..13f2f7560 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -401,11 +401,11 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik part = {}; } if (++i == fmt.size()) { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); } if (++arg == args.end()) { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name, fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name, fmtarg - args.begin() + 1); } part.sig = arg->sig; part.signed_ = arg->signed_; @@ -420,7 +420,7 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik } else break; } if (i == fmt.size()) { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); } bool has_leading_zero = false, has_width = false; @@ -465,15 +465,15 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik if (!has_width && !has_leading_zero) part.width = 20; } else { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name, fmt[i], fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name, fmt[i], fmtarg - args.begin() + 1); } } else { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name, fmt[i], fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name, fmt[i], fmtarg - args.begin() + 1); } break; } if (i == fmt.size()) { - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); } if (part.padding == '\0') { @@ -486,7 +486,7 @@ void Fmt::parse_verilog(const std::vector &args, bool sformat_lik } if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS) - log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); + log_file_error(fmtarg->src, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name, fmtarg - args.begin() + 1); if (part.base != 10) part.signed_ = false; diff --git a/kernel/fmt.h b/kernel/fmt.h index 2d4b24979..01050fbfc 100644 --- a/kernel/fmt.h +++ b/kernel/fmt.h @@ -34,8 +34,7 @@ struct VerilogFmtArg { } type; // All types - std::string filename; - unsigned first_line; + LogSourceLocation src; // STRING type std::string str; diff --git a/kernel/log.cc b/kernel/log.cc index 3c9c42cc1..6d4a47f24 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -130,12 +130,13 @@ void ScratchPadLogSink::log(const LogMessage &msg) design->scratchpad[scratchpad].append(msg.cached_msg); } -LogMessage::LogMessage(LogSeverity severity, std::string_view prefix, std::string_view format, std::string_view message) : +LogMessage::LogMessage(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string_view message) : severity(severity), prefix(prefix), format(format), message(message), - timestamp(std::chrono::steady_clock::now()) + timestamp(std::chrono::steady_clock::now()), + src(src) { std::string time_str; if (logger().get_log_time()) @@ -156,7 +157,8 @@ LogMessage::LogMessage(LogSeverity severity, std::string_view prefix, std::strin if (format == "%s" && !message.empty() && message.back() == '\n') next_print_log = true; } - cached_msg = stringf("%s%s%s", time_str, prefix, message); + std::string loc = !src.filename.empty() ? stringf("%s:%d: ", src.filename, src.start_line) : ""; + cached_msg = stringf("%s%s%s%s", loc, time_str, prefix, message); } static void log_id_cache_clear() @@ -166,10 +168,10 @@ static void log_id_cache_clear() log_id_cache.clear(); } -void LogManager::logv_string(LogSeverity severity, std::string_view prefix, std::string_view format, std::string str_in) { +void LogManager::logv_string(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string str_in) { size_t remove_leading = 0; while (format.size() > 1 && format[0] == '\n') { - logv_string(severity, prefix, "\n", "\n"); + logv_string(severity, src, prefix, "\n", "\n"); format = format.substr(1); ++remove_leading; } @@ -177,7 +179,8 @@ void LogManager::logv_string(LogSeverity severity, std::string_view prefix, std: str_in = str_in.substr(remove_leading); } - std::string str = stringf("%s%s",prefix,str_in); + std::string loc = !src.filename.empty() ? stringf("%s:%d: ", src.filename, src.start_line) : ""; + std::string str = stringf("%s%s%s",loc,prefix,str_in); if (str.empty()) return; @@ -191,7 +194,7 @@ void LogManager::logv_string(LogSeverity severity, std::string_view prefix, std: if (hasher) hasher->update(str); - auto msg = LogMessage(severity, prefix, format, str_in); + auto msg = LogMessage(severity, src, prefix, format, str_in); for (auto &sink : sinks) { if (sink->should_log(msg)) sink->log(msg); @@ -232,13 +235,13 @@ void LogManager::logv_string(LogSeverity severity, std::string_view prefix, std: } } -void LogManager::formatted_string(LogSeverity severity, std::string_view prefix, std::string_view format, std::string str) +void LogManager::formatted_string(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string str) { log_assert(!Multithreading::active()); if (make_debug && !is_debug(1)) return; - logv_string(severity, prefix, format, std::move(str)); + logv_string(severity, src, prefix, format, std::move(str)); } void LogManager::formatted_header(RTLIL::Design *design, std::string_view format, std::string str) @@ -258,7 +261,7 @@ void LogManager::formatted_header(RTLIL::Design *design, std::string_view format for (int c : header_count) header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); - formatted_string(LogSeverity::Header, stringf("%s. ", header_id), format, std::move(str)); + formatted_string(LogSeverity::Header, LogSourceLocation{}, stringf("%s. ", header_id), format, std::move(str)); flush(); if (hdump_all) @@ -276,7 +279,7 @@ void LogManager::formatted_header(RTLIL::Design *design, std::string_view format log_stderr_sink_forced = false; } -void LogManager::formatted_warning(std::string_view prefix, std::string_view format, std::string message) +void LogManager::formatted_warning(LogSourceLocation src, std::string_view prefix, std::string_view format, std::string message) { log_assert(!Multithreading::active()); @@ -286,9 +289,10 @@ void LogManager::formatted_warning(std::string_view prefix, std::string_view for if (std::regex_search(message, re)) suppressed = true; + std::string loc = !src.filename.empty() ? stringf("%s:%d: ", src.filename, src.start_line) : ""; if (suppressed) { - log("Suppressed %s%s", prefix, message); + log("Suppressed %s%s%s", loc, prefix, message); } else { @@ -297,7 +301,7 @@ void LogManager::formatted_warning(std::string_view prefix, std::string_view for for (auto &re : werror_regexes) if (std::regex_search(message, re)) - formatted_error(format, message); + formatted_error(src, "ERROR: ", format, message); bool warning_match = false; for (auto &[_, item] : expect_warning) @@ -306,20 +310,21 @@ void LogManager::formatted_warning(std::string_view prefix, std::string_view for warning_match = true; } + std::string pattern = loc + string(prefix) + message; for (auto &[_, item] : expect_prefix_warning) - if (std::regex_search(string(prefix) + message, item.pattern)) { + if (std::regex_search(pattern, item.pattern)) { item.current_count++; warning_match = true; } if (warnings.count(message)) { - formatted_string(LogSeverity::Info, prefix, format, message); + formatted_string(LogSeverity::Info, src, prefix, format, message); flush(); } else { - formatted_string(LogSeverity::Warning, prefix, format, message); + formatted_string(LogSeverity::Warning, src, prefix, format, message); flush(); warnings.insert(message); } @@ -331,34 +336,22 @@ void LogManager::formatted_warning(std::string_view prefix, std::string_view for } } -void LogManager::formatted_file_warning(std::string_view filename, int lineno, std::string_view format, std::string str) -{ - std::string prefix = stringf("%s:%d: Warning: ", filename, lineno); - formatted_warning(prefix, format, std::move(str)); -} - -void LogManager::formatted_file_info(std::string_view filename, int lineno, std::string_view format, std::string str) -{ - std::string prefix = stringf("%s:%d: Info: ", filename, lineno); - formatted_string(LogSeverity::Info, prefix, format, std::move(str)); -} - void LogManager::suppressed() { if (debug_suppressed && !make_debug) { constexpr const char* format = "\n"; - logv_string(LogSeverity::Info, {}, format, stringf(format, debug_suppressed)); + logv_string(LogSeverity::Info, LogSourceLocation{}, {}, format, stringf(format, debug_suppressed)); debug_suppressed = 0; } } [[noreturn]] -void LogManager::error_with_prefix(std::string_view prefix, std::string_view format, std::string message) +void LogManager::formatted_error(LogSourceLocation src, std::string_view prefix, std::string_view format, std::string message) { int bak_make_debug = make_debug; make_debug = 0; suppressed(); - formatted_string(LogSeverity::Error, prefix, format, message); + formatted_string(LogSeverity::Error, src, prefix, format, message); flush(); make_debug = bak_make_debug; @@ -367,8 +360,10 @@ void LogManager::error_with_prefix(std::string_view prefix, std::string_view for if (std::regex_search(message, item.pattern)) item.current_count++; + std::string loc = !src.filename.empty() ? stringf("%s:%d: ", src.filename, src.start_line) : ""; + std::string pattern = loc + string(prefix) + message; for (auto &[_, item] : expect_prefix_error) - if (std::regex_search(string(prefix) + message, item.pattern)) + if (std::regex_search(pattern, item.pattern)) item.current_count++; errors_count++; @@ -390,12 +385,6 @@ void LogManager::error_with_prefix(std::string_view prefix, std::string_view for #endif } -void LogManager::formatted_file_error(std::string_view filename, int lineno, std::string_view format, std::string str) -{ - std::string prefix = stringf("%s:%d: ERROR: ", filename, lineno); - error_with_prefix(prefix, format, str); -} - void LogManager::add_experimental(const std::string &str) { if (experimental_ignored.count(str) == 0 && experimental.count(str) == 0) { @@ -412,11 +401,6 @@ void LogManager::add_deprecated(const std::string &str) } } -void LogManager::formatted_error(std::string_view format, std::string str) -{ - error_with_prefix("ERROR: ", format, std::move(str)); -} - void log_assert_failure(const char *expr, const char *file, int line) { log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); @@ -435,13 +419,13 @@ void log_yosys_abort_message(std::string_view file, int line, std::string_view f void LogManager::formatted_cmd_error(std::string_view format, std::string message) { if (cmd_error_throw) { - formatted_string(LogSeverity::Error, "ERROR: ", format, message); + formatted_string(LogSeverity::Error, LogSourceLocation{}, "ERROR: ", format, message); flush(); throw log_cmd_error_exception(); } - formatted_error(format, message); + formatted_error(LogSourceLocation{}, "ERROR: ", format, message); } void LogManager::spacer() diff --git a/kernel/log.h b/kernel/log.h index f31f37a58..1a021060a 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -95,13 +95,27 @@ enum class LogSeverity { Error }; +struct LogSourceLocation { + LogSourceLocation() : filename({}),start_line(-1),start_col(-1),end_line(-1),end_col(-1) { } + LogSourceLocation(std::string filename) : filename(filename),start_line(-1),start_col(-1),end_line(-1),end_col(-1) { } + LogSourceLocation(std::string filename,int start_line) : filename(filename),start_line(start_line),start_col(-1),end_line(-1),end_col(-1) { } + LogSourceLocation(std::string filename,int start_line,int start_col,int end_line,int end_col) : + filename(filename),start_line(start_line),start_col(start_col),end_line(end_line),end_col(end_col) { } + std::string filename; + int start_line; + int start_col; + int end_line; + int end_col; +}; + struct LogMessage { - LogMessage(LogSeverity severity, std::string_view prefix, std::string_view format, std::string_view message); + LogMessage(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string_view message); LogSeverity severity; std::string prefix; std::string format; std::string message; std::chrono::steady_clock::time_point timestamp; + LogSourceLocation src; std::string cached_msg; }; @@ -399,13 +413,10 @@ public: void add_hdump(std::string name, std::string value) { hdump[name].insert(value); } - void formatted_string(LogSeverity severity, std::string_view prefix, std::string_view format, std::string str); + void formatted_string(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string str); void formatted_header(RTLIL::Design *design, std::string_view format, std::string str); - void formatted_warning(std::string_view prefix, std::string_view format, std::string message); - void formatted_file_warning(std::string_view filename, int lineno, std::string_view format, std::string str); - void formatted_file_info(std::string_view filename, int lineno, std::string_view format, std::string str); - [[noreturn]] void formatted_file_error(std::string_view filename, int lineno, std::string_view format, std::string str); - [[noreturn]] void formatted_error(std::string_view format, std::string str); + void formatted_warning(LogSourceLocation src, std::string_view prefix, std::string_view format, std::string message); + [[noreturn]] void formatted_error(LogSourceLocation src, std::string_view prefix, std::string_view format, std::string message); [[noreturn]] void formatted_cmd_error(std::string_view format, std::string message); void suppressed(); void add_experimental(const std::string &str); @@ -427,8 +438,7 @@ public: std::string finish_hasher(); private: - void logv_string(LogSeverity severity, std::string_view prefix, std::string_view format, std::string str_in); - [[noreturn]] void error_with_prefix(std::string_view prefix, std::string_view format, std::string message); + void logv_string(LogSeverity severity, LogSourceLocation src, std::string_view prefix, std::string_view format, std::string str_in); std::vector> sinks; int verbose_level = 0; @@ -470,23 +480,23 @@ static inline bool ys_debug(int = 0) { return false; } template inline void log(FmtString...> fmt, const Args &... args) { - logger().formatted_string(LogSeverity::Info, {}, fmt.format_string(), fmt.format(args...)); + logger().formatted_string(LogSeverity::Info, LogSourceLocation{}, {}, fmt.format_string(), fmt.format(args...)); } template inline void log_comment(FmtString...> fmt, const Args &... args) { - logger().formatted_string(LogSeverity::Comment, {}, fmt.format_string(), fmt.format(args...)); + logger().formatted_string(LogSeverity::Comment, LogSourceLocation{}, {}, fmt.format_string(), fmt.format(args...)); } template -inline void log_formatted_string(LogSeverity severity, std::string_view prefix, +inline void log_formatted_string(LogSeverity severity, LogSourceLocation src, std::string_view prefix, FmtString...> fmt, const Args &... args) { - logger().formatted_string(severity, prefix, fmt.format_string(), fmt.format(args...)); + logger().formatted_string(severity, src, prefix, fmt.format_string(), fmt.format(args...)); } -#define log_debug(...) do { if (ys_debug(1)) YOSYS_NAMESPACE_PREFIX log_formatted_string(YOSYS_NAMESPACE_PREFIX LogSeverity::Debug, {}, __VA_ARGS__); } while (0) +#define log_debug(...) do { if (ys_debug(1)) YOSYS_NAMESPACE_PREFIX log_formatted_string(YOSYS_NAMESPACE_PREFIX LogSeverity::Debug, {}, {}, __VA_ARGS__); } while (0) template inline void log_header(RTLIL::Design *design, FmtString...> fmt, const Args &... args) @@ -497,13 +507,13 @@ inline void log_header(RTLIL::Design *design, FmtString...> f template inline void log_warning(FmtString...> fmt, const Args &... args) { - logger().formatted_warning("Warning: ", fmt.format_string(), fmt.format(args...)); + logger().formatted_warning(LogSourceLocation{}, "Warning: ", fmt.format_string(), fmt.format(args...)); } template inline void log_warning_noprefix(FmtString...> fmt, const Args &... args) { - logger().formatted_warning({}, fmt.format_string(), fmt.format(args...)); + logger().formatted_warning(LogSourceLocation{}, {}, fmt.format_string(), fmt.format(args...)); } inline void log_experimental(const std::string &str) @@ -518,27 +528,27 @@ inline void log_deprecated(const std::string &str) // Log with filename to report a problem in a source file. template -void log_file_warning(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +void log_file_warning(LogSourceLocation src, FmtString...> fmt, const Args &... args) { - logger().formatted_file_warning(filename, lineno, fmt.format_string(), fmt.format(args...)); + logger().formatted_warning(src, "Warning: ", fmt.format_string(), fmt.format(args...)); } template -void log_file_info(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +void log_file_info(LogSourceLocation src, FmtString...> fmt, const Args &... args) { - logger().formatted_file_info(filename, lineno, fmt.format_string(), fmt.format(args...)); + logger().formatted_string(LogSeverity::Info, src, "Info: ", fmt.format_string(), fmt.format(args...)); } template [[noreturn]] void log_error(FmtString...> fmt, const Args &... args) { - logger().formatted_error(fmt.format_string(), fmt.format(args...)); + logger().formatted_error(LogSourceLocation{}, "ERROR: ", fmt.format_string(), fmt.format(args...)); } template -[[noreturn]] void log_file_error(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +[[noreturn]] void log_file_error(LogSourceLocation src, FmtString...> fmt, const Args &... args) { - logger().formatted_file_error(filename, lineno, fmt.format_string(), fmt.format(args...)); + logger().formatted_error(src, "ERROR: ", fmt.format_string(), fmt.format(args...)); } template diff --git a/kernel/log_compat.cc b/kernel/log_compat.cc index 835185e1a..3553913e0 100644 --- a/kernel/log_compat.cc +++ b/kernel/log_compat.cc @@ -46,7 +46,7 @@ void log_warning(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - logger().formatted_warning("Warning: ", format, formatted); + logger().formatted_warning(LogSourceLocation{}, "Warning: ", format, formatted); } void log_warning_noprefix(const char *format, ...) @@ -55,7 +55,7 @@ void log_warning_noprefix(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - logger().formatted_warning({}, format, formatted); + logger().formatted_warning(LogSourceLocation{}, {}, format, formatted); } void log_error(const char *format, ...) @@ -64,7 +64,7 @@ void log_error(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - logger().formatted_error(format, formatted); + logger().formatted_error(LogSourceLocation{}, "ERROR:", format, formatted); } void log(const char *format, ...) @@ -73,7 +73,7 @@ void log(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - logger().formatted_string(LogSeverity::Info, {}, format, formatted); + logger().formatted_string(LogSeverity::Info, LogSourceLocation{}, {}, format, formatted); } void log_compat(const char *format, ...) @@ -82,7 +82,7 @@ void log_compat(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - logger().formatted_string(LogSeverity::Info, {}, format, formatted); + logger().formatted_string(LogSeverity::Info, LogSourceLocation{}, {}, format, formatted); } YOSYS_NAMESPACE_END diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index 327b21ff7..ce0b39d33 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -179,13 +179,13 @@ namespace pyosys { // Logging Methods m.def("log_header", [](Design *d, std::string s) { logger().formatted_header(d, "%s", s); }); - m.def("log", [](std::string s) { logger().formatted_string(LogSeverity::Info, {}, "%s", s); }); - m.def("log_file_info", [](std::string_view file, int line, std::string s) { logger().formatted_file_info(file, line, "%s", s); }); - m.def("log_warning", [](std::string s) { logger().formatted_warning("Warning: ", "%s", s); }); - m.def("log_warning_noprefix", [](std::string s) { logger().formatted_warning("", "%s", s); }); - m.def("log_file_warning", [](std::string_view file, int line, std::string s) { logger().formatted_file_warning(file, line, "%s", s); }); - m.def("log_error", [](std::string s) { logger().formatted_error("%s", s); }); - m.def("log_file_error", [](std::string_view file, int line, std::string s) { logger().formatted_file_error(file, line, "%s", s); }); + m.def("log", [](std::string s) { logger().formatted_string(LogSeverity::Info, LogSourceLocation{}, {}, "%s", s); }); + m.def("log_file_info", [](std::string file, int line, std::string s) { logger().formatted_string(LogSeverity::Info, LogSourceLocation(file,line), "Info: ", "%s", s); }); + m.def("log_warning", [](std::string s) { logger().formatted_warning(LogSourceLocation{}, "Warning: ", "%s", s); }); + m.def("log_warning_noprefix", [](std::string s) { logger().formatted_warning(LogSourceLocation{}, "", "%s", s); }); + m.def("log_file_warning", [](std::string file, int line, std::string s) { logger().formatted_warning(LogSourceLocation(file,line), "Warning: ", "%s", s); }); + m.def("log_error", [](std::string s) { logger().formatted_error(LogSourceLocation{}, "ERROR: ", "%s", s); }); + m.def("log_file_error", [](std::string file, int line, std::string s) { logger().formatted_error(LogSourceLocation(file,line), "ERROR: ", "%s", s); }); // Namespace to host global objects auto global_variables = py::class_(m, "Globals");