diff --git a/kernel/io.cc b/kernel/io.cc index ef73a3b3d..62cf6b7f4 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -575,6 +575,17 @@ void format_emit_string_view(std::string &result, std::string_view spec, int *dy format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, std::string(arg).c_str()); } +void format_emit_idstring(std::string &result, std::string_view spec, int *dynamic_ints, + DynamicIntCount num_dynamic_ints, const IdString &arg) +{ + if (spec == "%s") { + // Format checking will have guaranteed num_dynamic_ints == 0. + result += arg.c_str(); + return; + } + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg.c_str()); +} + void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints, DynamicIntCount num_dynamic_ints, const void *arg) { diff --git a/kernel/io.h b/kernel/io.h index dafef8bfa..08c234d6e 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -8,6 +8,10 @@ YOSYS_NAMESPACE_BEGIN +namespace RTLIL { + struct IdString; +} + inline std::string vstringf(const char *fmt, va_list ap) { // For the common case of strings shorter than 128, save a heap @@ -240,7 +244,8 @@ constexpr void check_format(std::string_view fmt, int fmt_start, bool *has_escap case CONVSPEC_CHAR_PTR: if constexpr (!std::is_convertible_v && !std::is_convertible_v && - !std::is_convertible_v) { + !std::is_convertible_v && + !std::is_convertible_v) { YOSYS_ABORT("Expected type convertible to char *"); } *specs = found; @@ -279,6 +284,10 @@ void format_emit_string(std::string &result, std::string_view spec, int *dynamic void format_emit_string_view(std::string &result, std::string_view spec, int *dynamic_ints, DynamicIntCount num_dynamic_ints, std::string_view arg); +// Emit the string representation of `arg` that has been converted to a `RTLIL::IdString'. +void format_emit_idstring(std::string &result, std::string_view spec, int *dynamic_ints, + DynamicIntCount num_dynamic_ints, const RTLIL::IdString &arg); + // Emit the string representation of `arg` that has been converted to a `double'. void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints, DynamicIntCount num_dynamic_ints, const void *arg); @@ -329,6 +338,11 @@ inline void format_emit_one(std::string &result, std::string_view fmt, const Fou format_emit_string_view(result, spec, dynamic_ints, num_dynamic_ints, s); return; } + if constexpr (std::is_convertible_v) { + const RTLIL::IdString &s = arg; + format_emit_idstring(result, spec, dynamic_ints, num_dynamic_ints, s); + return; + } break; case CONVSPEC_VOID_PTR: if constexpr (std::is_convertible_v) { @@ -433,7 +447,7 @@ template struct WrapType { using type = T; }; template using TypeIdentity = typename WrapType::type; template -inline std::string stringf(FmtString...> fmt, Args... args) +inline std::string stringf(FmtString...> fmt, const Args &... args) { return fmt.format(args...); } diff --git a/tests/unit/kernel/ioTest.cc b/tests/unit/kernel/ioTest.cc index 43a71eb79..6186c34cb 100644 --- a/tests/unit/kernel/ioTest.cc +++ b/tests/unit/kernel/ioTest.cc @@ -1,6 +1,7 @@ #include #include "kernel/io.h" +#include "kernel/rtlil.h" YOSYS_NAMESPACE_BEGIN @@ -44,6 +45,12 @@ TEST(KernelStringfTest, stringViewParam) EXPECT_EQ(stringf("%s", std::string_view("hello")), "hello"); } +TEST(KernelStringfTest, idStringParam) +{ + RTLIL::IdString id("$hello"); + EXPECT_EQ(stringf("%s", id), "$hello"); +} + TEST(KernelStringfTest, escapePercent) { EXPECT_EQ(stringf("%%"), "%");