Skip to content

Commit

Permalink
Annotate fmt::format and fmt::formatted_size as [[nodiscard]]
Browse files Browse the repository at this point in the history
This prevents accidentally writing fmt::format when fmt::print was
intended. Other than running tests, there's not a good use case for
discarding the formatted output.
  • Loading branch information
0x8000-0000 authored and vitaut committed Nov 25, 2021
1 parent 5abe9e8 commit 491ba2d
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 185 deletions.
21 changes: 16 additions & 5 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 80001

#if defined (__clang__ ) && !defined(__ibmxl__)
#if defined(__clang__) && !defined(__ibmxl__)
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
# define FMT_CLANG_VERSION 0
Expand Down Expand Up @@ -187,6 +187,14 @@
# define FMT_FALLTHROUGH
#endif

#ifndef FMT_NODISCARD
# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
# define FMT_NODISCARD [[nodiscard]]
# else
# define FMT_NODISCARD
# endif
#endif

#ifndef FMT_USE_FLOAT
# define FMT_USE_FLOAT 1
#endif
Expand Down Expand Up @@ -259,8 +267,9 @@
#ifndef FMT_CONSTEVAL
# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
__cplusplus > 201703L && !defined(__apple_build_version__)) || \
(defined(__cpp_consteval) && (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704))
// consteval is broken in MSVC before VS2022 and Apple clang 13.
(defined(__cpp_consteval) && \
(!FMT_MSC_VER || _MSC_FULL_VER >= 193030704))
// consteval is broken in MSVC before VS2022 and Apple clang 13.
# define FMT_CONSTEVAL consteval
# define FMT_HAS_CONSTEVAL
# else
Expand Down Expand Up @@ -3071,7 +3080,8 @@ FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
\endrst
*/
template <typename... T>
FMT_INLINE auto format(format_string<T...> fmt, T&&... args) -> std::string {
FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
-> std::string {
return vformat(fmt, fmt::make_format_args(args...));
}

Expand Down Expand Up @@ -3138,7 +3148,8 @@ FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,

/** Returns the number of chars in the output of ``format(fmt, args...)``. */
template <typename... T>
FMT_INLINE auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t {
FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,
T&&... args) -> size_t {
auto buf = detail::counting_buffer<>();
detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {});
return buf.count();
Expand Down
4 changes: 2 additions & 2 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2863,7 +2863,7 @@ inline auto to_string(const T& value) -> std::string {
}

template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
inline auto to_string(T value) -> std::string {
FMT_NODISCARD inline auto to_string(T value) -> std::string {
// The buffer should be large enough to store the number including the sign
// or "false" for bool.
constexpr int max_size = detail::digits10<T>() + 2;
Expand All @@ -2873,7 +2873,7 @@ inline auto to_string(T value) -> std::string {
}

template <typename Char, size_t SIZE>
auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
FMT_NODISCARD auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
-> std::basic_string<Char> {
auto size = buf.size();
detail::assume(size < std::basic_string<Char>().max_size());
Expand Down
48 changes: 24 additions & 24 deletions test/chrono-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ TEST(chrono_test, grow_buffer) {
for (int i = 0; i < 30; ++i) s += "%c";
s += "}\n";
auto t = std::time(nullptr);
fmt::format(fmt::runtime(s), *std::localtime(&t));
(void)fmt::format(fmt::runtime(s), *std::localtime(&t));
}

TEST(chrono_test, format_to_empty_container) {
Expand Down Expand Up @@ -371,41 +371,41 @@ TEST(chrono_test, format_specs) {

TEST(chrono_test, invalid_specs) {
auto sec = std::chrono::seconds(0);
EXPECT_THROW_MSG(fmt::format(runtime("{:%a}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%a}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%A}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%A}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%c}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%c}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%x}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%x}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%X}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%X}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%D}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%D}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%F}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%F}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%w}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%w}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%u}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%u}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%b}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%b}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%B}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%B}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%z}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%z}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
"no date");
EXPECT_THROW_MSG(fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
"invalid format");
EXPECT_THROW_MSG(fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
"invalid format");
}

Expand Down Expand Up @@ -453,7 +453,7 @@ TEST(chrono_test, format_default_fp) {
}

TEST(chrono_test, format_precision) {
EXPECT_THROW_MSG(fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
fmt::format_error,
"precision not allowed for this argument type");
EXPECT_EQ("1ms", fmt::format("{:.0}", dms(1.234)));
Expand Down Expand Up @@ -493,7 +493,7 @@ TEST(chrono_test, format_simple_q) {
}

TEST(chrono_test, format_precision_q) {
EXPECT_THROW_MSG(fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
fmt::format_error,
"precision not allowed for this argument type");
EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234)));
Expand All @@ -518,12 +518,12 @@ TEST(chrono_test, format_full_specs_q) {
}

TEST(chrono_test, invalid_width_id) {
EXPECT_THROW(fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
EXPECT_THROW((void)fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
fmt::format_error);
}

TEST(chrono_test, invalid_colons) {
EXPECT_THROW(fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
EXPECT_THROW((void)fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
fmt::format_error);
}

Expand All @@ -550,7 +550,7 @@ TEST(chrono_test, special_durations) {
EXPECT_EQ(
"nan nan nan nan nan:nan nan",
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
fmt::format("{:%S}",
(void)fmt::format("{:%S}",
std::chrono::duration<float, std::atto>(1.79400457e+31f));
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
"1Es");
Expand Down
4 changes: 2 additions & 2 deletions test/core-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -902,10 +902,10 @@ TEST(core_test, adl) {
if (fmt::detail::const_check(true)) return;
auto s = adl_test::string();
char buf[10];
fmt::format("{}", s);
(void)fmt::format("{}", s);
fmt::format_to(buf, "{}", s);
fmt::format_to_n(buf, 10, "{}", s);
fmt::formatted_size("{}", s);
(void)fmt::formatted_size("{}", s);
fmt::print("{}", s);
fmt::print(stdout, "{}", s);
}
Expand Down
18 changes: 9 additions & 9 deletions test/enforce-checks-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

// Exercise the API to verify that everything we expect to can compile.
void test_format_api() {
fmt::format(FMT_STRING("{}"), 42);
fmt::format(FMT_STRING(L"{}"), 42);
fmt::format(FMT_STRING("noop"));
(void)fmt::format(FMT_STRING("{}"), 42);
(void)fmt::format(FMT_STRING(L"{}"), 42);
(void)fmt::format(FMT_STRING("noop"));

fmt::to_string(42);
fmt::to_wstring(42);
(void)fmt::to_string(42);
(void)fmt::to_wstring(42);

std::vector<char> out;
fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42);
Expand All @@ -35,13 +35,13 @@ void test_format_api() {
}

void test_chrono() {
fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
(void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
(void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
}

void test_text_style() {
fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
(void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");

fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
std::string out;
Expand All @@ -51,7 +51,7 @@ void test_text_style() {

void test_range() {
std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'};
fmt::format(FMT_STRING("{}"), hello);
(void)fmt::format(FMT_STRING("{}"), hello);
}

int main() {
Expand Down
Loading

0 comments on commit 491ba2d

Please sign in to comment.