From fce74caa15b24cbc0fcafe4706692cb06cb0b815 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 9 Apr 2023 09:08:46 -0700 Subject: [PATCH] Disable problematic implicit conversions --- include/fmt/core.h | 13 +++++++------ test/core-test.cc | 22 ++-------------------- test/format-impl-test.cc | 14 +++++++++----- test/format-test.cc | 5 ----- test/ostream-test.cc | 24 ------------------------ 5 files changed, 18 insertions(+), 60 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 50a6fd8d..738b85df 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1441,7 +1441,8 @@ template struct arg_mapper { template > struct formattable : bool_constant() || - !std::is_const>::value> {}; + (has_formatter::value && + !std::is_const>::value)> {}; template ::value)> FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { @@ -1453,11 +1454,11 @@ template struct arg_mapper { } template , - FMT_ENABLE_IF(!is_string::value && !is_char::value && - !std::is_array::value && - !std::is_pointer::value && - !std::is_arithmetic>::value && - has_formatter::value)> + FMT_ENABLE_IF((std::is_class::value || std::is_enum::value || + std::is_union::value) && + !is_string::value && !is_char::value && + !is_named_arg::value && + !std::is_arithmetic>::value)> FMT_CONSTEXPR FMT_INLINE auto map(T&& val) -> decltype(this->do_map(std::forward(val))) { return do_map(std::forward(val)); diff --git a/test/core-test.cc b/test/core-test.cc index 71686105..22a49def 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -672,7 +672,8 @@ TEST(core_test, is_formattable) { static_assert(fmt::is_formattable::value, ""); static_assert(!fmt::is_formattable::value, ""); static_assert(!fmt::is_formattable::value, ""); - static_assert(fmt::is_formattable::value, ""); + static_assert(!fmt::is_formattable::value, + ""); static_assert(fmt::is_formattable::value, ""); static_assert(fmt::is_formattable::value, ""); @@ -798,25 +799,6 @@ TEST(core_test, format_explicitly_convertible_to_std_string_view) { # endif #endif -struct convertible_to_long_long { - operator long long() const { return 1LL << 32; } -}; - -TEST(core_test, format_convertible_to_long_long) { - EXPECT_EQ("100000000", fmt::format("{:x}", convertible_to_long_long())); -} - -struct disabled_rvalue_conversion { - operator const char*() const& { return "foo"; } - operator const char*() & { return "foo"; } - operator const char*() const&& = delete; - operator const char*() && = delete; -}; - -TEST(core_test, disabled_rvalue_conversion) { - EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion())); -} - namespace adl_test { template void make_format_args(const T&...) = delete; diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index e39bde74..02101a21 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -242,11 +242,11 @@ TEST(fp_test, dragonbox_max_k) { floor_log10_pow2(std::numeric_limits::min_exponent - fmt::detail::num_significand_bits() - 1)); using double_info = fmt::detail::dragonbox::float_info; - EXPECT_EQ( - fmt::detail::const_check(double_info::max_k), - double_info::kappa - - floor_log10_pow2(std::numeric_limits::min_exponent - - 2 * fmt::detail::num_significand_bits() - 1)); + EXPECT_EQ(fmt::detail::const_check(double_info::max_k), + double_info::kappa - + floor_log10_pow2( + std::numeric_limits::min_exponent - + 2 * fmt::detail::num_significand_bits() - 1)); } TEST(fp_test, get_round_direction) { @@ -382,6 +382,8 @@ struct double_double { auto operator-() const -> double_double { return double_double(-a, -b); } }; +auto format_as(double_double d) -> double { return d; } + bool operator>=(const double_double& lhs, const double_double& rhs) { return lhs.a + lhs.b >= rhs.a + rhs.b; } @@ -394,6 +396,8 @@ struct slow_float { auto operator-() const -> slow_float { return slow_float(-value); } }; +auto format_as(slow_float f) -> float { return f; } + namespace std { template <> struct is_floating_point : std::true_type {}; template <> struct numeric_limits { diff --git a/test/format-test.cc b/test/format-test.cc index 98395353..e798da1d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1967,15 +1967,10 @@ struct formatter : formatter { }; FMT_END_NAMESPACE -struct convertible_to_int { - operator int() const { return 42; } -}; - TEST(format_test, to_string) { EXPECT_EQ(fmt::to_string(42), "42"); EXPECT_EQ(fmt::to_string(reinterpret_cast(0x1234)), "0x1234"); EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo"); - EXPECT_EQ(fmt::to_string(convertible_to_int()), "42"); EXPECT_EQ(fmt::to_string(foo), "0"); #if FMT_USE_FLOAT128 diff --git a/test/ostream-test.cc b/test/ostream-test.cc index b9a6b352..8db9cda4 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -226,30 +226,6 @@ TEST(ostream_test, format_to_n) { EXPECT_EQ("xabx", fmt::string_view(buffer, 4)); } -template struct convertible { - T value; - explicit convertible(const T& val) : value(val) {} - operator T() const { return value; } -}; - -TEST(ostream_test, disable_builtin_ostream_operators) { - EXPECT_EQ("42", fmt::format("{:d}", convertible(42))); - EXPECT_EQ("foo", fmt::format("{}", convertible("foo"))); -} - -struct streamable_and_convertible_to_bool { - operator bool() const { return true; } -}; - -std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) { - return os << "foo"; -} - -TEST(ostream_test, format_convertible_to_bool) { - // operator<< is intentionally not used because of potential ODR violations. - EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true"); -} - struct copyfmt_test {}; std::ostream& operator<<(std::ostream& os, copyfmt_test) {