Disable problematic implicit conversions

This commit is contained in:
Victor Zverovich 2023-04-09 09:08:46 -07:00
parent 02bf4d1c1c
commit fce74caa15
5 changed files with 18 additions and 60 deletions

View File

@ -1441,7 +1441,8 @@ template <typename Context> struct arg_mapper {
template <typename T, typename U = remove_cvref_t<T>> template <typename T, typename U = remove_cvref_t<T>>
struct formattable struct formattable
: bool_constant<has_const_formatter<U, Context>() || : bool_constant<has_const_formatter<U, Context>() ||
!std::is_const<remove_reference_t<T>>::value> {}; (has_formatter<U, Context>::value &&
!std::is_const<remove_reference_t<T>>::value)> {};
template <typename T, FMT_ENABLE_IF(formattable<T>::value)> template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
@ -1453,11 +1454,11 @@ template <typename Context> struct arg_mapper {
} }
template <typename T, typename U = remove_cvref_t<T>, template <typename T, typename U = remove_cvref_t<T>,
FMT_ENABLE_IF(!is_string<U>::value && !is_char<U>::value && FMT_ENABLE_IF((std::is_class<U>::value || std::is_enum<U>::value ||
!std::is_array<U>::value && std::is_union<U>::value) &&
!std::is_pointer<U>::value && !is_string<U>::value && !is_char<U>::value &&
!std::is_arithmetic<format_as_t<U>>::value && !is_named_arg<U>::value &&
has_formatter<U, Context>::value)> !std::is_arithmetic<format_as_t<U>>::value)>
FMT_CONSTEXPR FMT_INLINE auto map(T&& val) FMT_CONSTEXPR FMT_INLINE auto map(T&& val)
-> decltype(this->do_map(std::forward<T>(val))) { -> decltype(this->do_map(std::forward<T>(val))) {
return do_map(std::forward<T>(val)); return do_map(std::forward<T>(val));

View File

@ -672,7 +672,8 @@ TEST(core_test, is_formattable) {
static_assert(fmt::is_formattable<enabled_formatter>::value, ""); static_assert(fmt::is_formattable<enabled_formatter>::value, "");
static_assert(!fmt::is_formattable<enabled_ptr_formatter*>::value, ""); static_assert(!fmt::is_formattable<enabled_ptr_formatter*>::value, "");
static_assert(!fmt::is_formattable<disabled_formatter>::value, ""); static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, ""); static_assert(!fmt::is_formattable<disabled_formatter_convertible>::value,
"");
static_assert(fmt::is_formattable<const_formattable&>::value, ""); static_assert(fmt::is_formattable<const_formattable&>::value, "");
static_assert(fmt::is_formattable<const const_formattable&>::value, ""); static_assert(fmt::is_formattable<const const_formattable&>::value, "");
@ -798,25 +799,6 @@ TEST(core_test, format_explicitly_convertible_to_std_string_view) {
# endif # endif
#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 { namespace adl_test {
template <typename... T> void make_format_args(const T&...) = delete; template <typename... T> void make_format_args(const T&...) = delete;

View File

@ -242,11 +242,11 @@ TEST(fp_test, dragonbox_max_k) {
floor_log10_pow2(std::numeric_limits<float>::min_exponent - floor_log10_pow2(std::numeric_limits<float>::min_exponent -
fmt::detail::num_significand_bits<float>() - 1)); fmt::detail::num_significand_bits<float>() - 1));
using double_info = fmt::detail::dragonbox::float_info<double>; using double_info = fmt::detail::dragonbox::float_info<double>;
EXPECT_EQ( EXPECT_EQ(fmt::detail::const_check(double_info::max_k),
fmt::detail::const_check(double_info::max_k), double_info::kappa -
double_info::kappa - floor_log10_pow2(
floor_log10_pow2(std::numeric_limits<double>::min_exponent - std::numeric_limits<double>::min_exponent -
2 * fmt::detail::num_significand_bits<double>() - 1)); 2 * fmt::detail::num_significand_bits<double>() - 1));
} }
TEST(fp_test, get_round_direction) { TEST(fp_test, get_round_direction) {
@ -382,6 +382,8 @@ struct double_double {
auto operator-() const -> double_double { return double_double(-a, -b); } 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) { bool operator>=(const double_double& lhs, const double_double& rhs) {
return lhs.a + lhs.b >= rhs.a + rhs.b; 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 operator-() const -> slow_float { return slow_float(-value); }
}; };
auto format_as(slow_float f) -> float { return f; }
namespace std { namespace std {
template <> struct is_floating_point<double_double> : std::true_type {}; template <> struct is_floating_point<double_double> : std::true_type {};
template <> struct numeric_limits<double_double> { template <> struct numeric_limits<double_double> {

View File

@ -1967,15 +1967,10 @@ struct formatter<adl_test::fmt::detail::foo> : formatter<std::string> {
}; };
FMT_END_NAMESPACE FMT_END_NAMESPACE
struct convertible_to_int {
operator int() const { return 42; }
};
TEST(format_test, to_string) { TEST(format_test, to_string) {
EXPECT_EQ(fmt::to_string(42), "42"); EXPECT_EQ(fmt::to_string(42), "42");
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234"); EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo"); 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"); EXPECT_EQ(fmt::to_string(foo), "0");
#if FMT_USE_FLOAT128 #if FMT_USE_FLOAT128

View File

@ -226,30 +226,6 @@ TEST(ostream_test, format_to_n) {
EXPECT_EQ("xabx", fmt::string_view(buffer, 4)); EXPECT_EQ("xabx", fmt::string_view(buffer, 4));
} }
template <typename T> 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<unsigned short>(42)));
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("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 {}; struct copyfmt_test {};
std::ostream& operator<<(std::ostream& os, copyfmt_test) { std::ostream& operator<<(std::ostream& os, copyfmt_test) {