From d8e1c4265a1087ad818aa50aceafa37763250545 Mon Sep 17 00:00:00 2001 From: TheOmegaCarrot <78671864+TheOmegaCarrot@users.noreply.github.com> Date: Sat, 18 Mar 2023 10:07:06 -0400 Subject: [PATCH] fix case of variant which is valueless by exception (#3347) Co-authored-by: theomegacarrot --- include/fmt/std.h | 14 +++++++++----- test/std-test.cc | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/include/fmt/std.h b/include/fmt/std.h index 24bf2c53..1583ca21 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -218,11 +218,15 @@ struct formatter< auto out = ctx.out(); out = detail::write(out, "variant("); - std::visit( - [&](const auto& v) { - out = detail::write_variant_alternative(out, v); - }, - value); + try { + std::visit( + [&](const auto& v) { + out = detail::write_variant_alternative(out, v); + }, + value); + } catch (const std::bad_variant_access&) { + detail::write(out, "valueless by exception"); + } *out++ = ')'; return out; } diff --git a/test/std-test.cc b/test/std-test.cc index d12dbf5d..53c7620d 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -7,6 +7,7 @@ #include "fmt/std.h" +#include #include #include @@ -95,6 +96,26 @@ TEST(std_test, optional) { #endif } +struct throws_on_move { + throws_on_move() = default; + + [[noreturn]] throws_on_move(throws_on_move&&) { + throw std::runtime_error("Thrown by throws_on_move"); + } + + throws_on_move(const throws_on_move&) = default; +}; + +namespace fmt { +template <> struct formatter : formatter { + auto format(const throws_on_move&, format_context& ctx) const + -> decltype(ctx.out()) { + string_view str(""); + return formatter::format(str, ctx); + } +}; +} // namespace fmt + TEST(std_test, variant) { #ifdef __cpp_lib_variant EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate"); @@ -126,6 +147,18 @@ TEST(std_test, variant) { volatile int i = 42; // Test compile error before GCC 11 described in #3068. EXPECT_EQ(fmt::format("{}", i), "42"); + + std::variant v6; + + try { + throws_on_move thrower; + v6.emplace(std::move(thrower)); + } catch (const std::runtime_error&) { + } + // v6 is now valueless by exception + + EXPECT_EQ(fmt::format("{}", v6), "variant(valueless by exception)"); + #endif }