diff --git a/include/fmt/std.h b/include/fmt/std.h index 02ca6721..2896e82a 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -214,10 +214,40 @@ struct formatter< std::size_t size = 0; std::unique_ptr demangled_name_ptr( abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); - out = detail::write_bytes( - out, - string_view(demangled_name_ptr ? demangled_name_ptr.get() : ti.name()), - spec); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = demangled_name_ptr.get(); + + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* begin = demangled_name_ptr.get(); + char* to = begin + 5; // std:: + for (char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; + } + } + *to++ = *from++; + } + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + } + } else { + demangled_name_view = string_view(ti.name()); + } + out = detail::write_bytes(out, demangled_name_view, spec); #elif FMT_MSC_VERSION string_view demangled_name_view(ti.name()); if (demangled_name_view.starts_with("class ")) diff --git a/test/std-test.cc b/test/std-test.cc index 0f6bf11a..f700a510 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -11,7 +11,9 @@ #include #include "fmt/ranges.h" -#include "gtest/gtest.h" +#include "gtest-extra.h" // StartsWith + +using testing::StartsWith; TEST(std_test, path) { #ifdef __cpp_lib_filesystem @@ -116,4 +118,19 @@ TEST(std_test, exception) { fmt::format("{:t}", ex)); EXPECT_EQ("My Exception", fmt::format("{:}", ex)); } + + try { + throw std::system_error(std::error_code(), "message"); + } catch (const std::system_error& ex) { + EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: ")); + } + +#ifdef __cpp_lib_filesystem + try { + throw std::filesystem::filesystem_error("message", std::error_code()); + } catch (const std::filesystem::filesystem_error& ex) { + EXPECT_THAT(fmt::format("{:t}", ex), + StartsWith("std::filesystem::filesystem_error: ")); + } +#endif }