Skip to content

Commit

Permalink
Check range_begin is dereferenceable
Browse files Browse the repository at this point in the history
Fixes issue fmtlib#3839
An Eigen 3.4 2x2 matrix has a begin member function that returns void
Be more strict checking that the result of calling *begin() is valid
See input_or_output_iterator concept notes about void
  • Loading branch information
Arghnews committed May 19, 2024
1 parent 75e8924 commit f8d0c51
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 6 deletions.
12 changes: 6 additions & 6 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};

template <typename T>
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};

Expand Down Expand Up @@ -99,15 +99,15 @@ struct has_mutable_begin_end : std::false_type {};

template <typename T>
struct has_const_begin_end<
T,
void_t<
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
T, void_t<decltype(*detail::range_begin(
std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(
std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};

template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T&>())),
T, void_t<decltype(*detail::range_begin(std::declval<T&>())),
decltype(detail::range_end(std::declval<T&>())),
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
Expand Down
22 changes: 22 additions & 0 deletions test/ranges-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -742,3 +742,25 @@ TEST(ranges_test, movable_only_istream_iter_join) {
EXPECT_EQ("1, 2, 3, 4, 5",
fmt::format("{}", fmt::join(std::move(first), last, ", ")));
}

namespace {
template <class T> struct not_range {
void begin() const {}
void end() const {}
};
} // namespace
FMT_BEGIN_NAMESPACE
template <typename T> struct formatter<not_range<T>> {
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx) -> const char* {
return ctx.begin();
}
auto format(const not_range<T>&, format_context& ctx) const
-> format_context::iterator {
return fmt::format_to(ctx.out(), "Dummy output");
}
};
FMT_END_NAMESPACE
TEST(ranges_test, t0) {
EXPECT_EQ("Dummy output", fmt::format("{}", not_range<int>{}));
}

0 comments on commit f8d0c51

Please sign in to comment.