Skip to content

Commit 9c053e6

Browse files
committed
[libc++][format] Make public functions nodiscard.
This is an extension and only adds the functions that are a considered a but when called and ignoring the result. Drive-by sort all nodiscard extensions in the documentation. Reviewed By: #libc, philnik Differential Revision: https://reviews.llvm.org/D152097
1 parent 702fe36 commit 9c053e6

File tree

10 files changed

+266
-163
lines changed

10 files changed

+266
-163
lines changed

libcxx/docs/UsingLibcxx.rst

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -380,41 +380,63 @@ which no dialect declares as such (See the second form described above).
380380
* ``adjacent_find``
381381
* ``all_of``
382382
* ``any_of``
383+
* ``as_const``
383384
* ``binary_search``
385+
* ``bit_cast``
386+
* ``cbrt``
387+
* ``ceil``
384388
* ``clamp``
389+
* ``copysign``
385390
* ``count_if``
386391
* ``count``
387392
* ``equal_range``
388393
* ``equal``
394+
* ``fabs``
389395
* ``find_end``
390396
* ``find_first_of``
391397
* ``find_if_not``
392398
* ``find_if``
393399
* ``find``
400+
* ``floor``
401+
* ``fmax``
402+
* ``fmin``
403+
* ``forward``
404+
* ``fpclassify``
394405
* ``get_temporary_buffer``
406+
* ``identity::operator()``
395407
* ``includes``
396408
* ``is_heap_until``
397409
* ``is_heap``
398410
* ``is_partitioned``
399411
* ``is_permutation``
400412
* ``is_sorted_until``
401413
* ``is_sorted``
414+
* ``isfinite``
415+
* ``isgreater``
416+
* ``isgreaterequal``
417+
* ``isinf``
418+
* ``isless``
419+
* ``islessequal``
420+
* ``islessgreater``
421+
* ``isnan``
422+
* ``isnormal``
423+
* ``isunordered``
402424
* ``lexicographical_compare``
425+
* ``lock_guard``'s constructors
403426
* ``lower_bound``
427+
* ``make_format_args``
428+
* ``make_wformat_args``
404429
* ``max_element``
405430
* ``max``
406431
* ``min_element``
407432
* ``min``
408433
* ``minmax_element``
409434
* ``minmax``
410435
* ``mismatch``
436+
* ``move_if_noexcept``
437+
* ``move``
438+
* ``nearbyint``
411439
* ``none_of``
412-
* ``remove_if``
413-
* ``remove``
414-
* ``search_n``
415-
* ``search``
416-
* ``unique``
417-
* ``upper_bound``
418440
* ``ranges::adjacent_find``
419441
* ``ranges::all_of``
420442
* ``ranges::any_of``
@@ -453,38 +475,19 @@ which no dialect declares as such (See the second form described above).
453475
* ``ranges::search``
454476
* ``ranges::unique``
455477
* ``ranges::upper_bound``
456-
* ``lock_guard``'s constructors
457-
* ``as_const``
458-
* ``bit_cast``
459-
* ``forward``
460-
* ``move``
461-
* ``move_if_noexcept``
462-
* ``identity::operator()``
463-
* ``to_integer``
464-
* ``to_underlying``
465-
* ``signbit``
466-
* ``fpclassify``
467-
* ``isfinite``
468-
* ``isinf``
469-
* ``isnan``
470-
* ``isnormal``
471-
* ``isgreater``
472-
* ``isgreaterequal``
473-
* ``isless``
474-
* ``islessequal``
475-
* ``islessgreater``
476-
* ``isunordered``
477-
* ``ceil``
478-
* ``fabs``
479-
* ``floor``
480-
* ``cbrt``
481-
* ``copysign``
482-
* ``fmax``
483-
* ``fmin``
484-
* ``nearbyint``
478+
* ``remove_if``
479+
* ``remove``
485480
* ``rint``
486481
* ``round``
482+
* ``search_n``
483+
* ``search``
484+
* ``signbit``
485+
* ``to_integer``
486+
* ``to_underlying``
487487
* ``trunc``
488+
* ``unique``
489+
* ``upper_bound``
490+
* ``vformat``
488491

489492
Extended integral type support
490493
------------------------------

libcxx/include/__format/format_functions.h

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,17 @@ using wformat_args = basic_format_args<wformat_context>;
6565
#endif
6666

6767
template <class _Context = format_context, class... _Args>
68-
_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
68+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
6969
return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
7070
}
7171

72-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
72+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
7373
template <class... _Args>
74-
_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) {
74+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
75+
make_wformat_args(_Args&&... __args) {
7576
return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
7677
}
77-
#endif
78+
# endif
7879

7980
namespace __format {
8081

@@ -442,38 +443,38 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
442443
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
443444
// fires too eagerly, see http://llvm.org/PR61563.
444445
template <class = void>
445-
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
446+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
446447
vformat(string_view __fmt, format_args __args) {
447448
string __res;
448449
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
449450
return __res;
450451
}
451452

452-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
453+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
453454
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
454455
// fires too eagerly, see http://llvm.org/PR61563.
455456
template <class = void>
456-
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
457+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
457458
vformat(wstring_view __fmt, wformat_args __args) {
458459
wstring __res;
459460
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
460461
return __res;
461462
}
462-
#endif
463+
# endif
463464

464465
template <class... _Args>
465-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(format_string<_Args...> __fmt,
466-
_Args&&... __args) {
466+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
467+
format(format_string<_Args...> __fmt, _Args&&... __args) {
467468
return _VSTD::vformat(__fmt.get(), _VSTD::make_format_args(__args...));
468469
}
469470

470-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
471+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
471472
template <class... _Args>
472-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
473+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
473474
format(wformat_string<_Args...> __fmt, _Args&&... __args) {
474475
return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...));
475476
}
476-
#endif
477+
# endif
477478

478479
template <class _Context, class _OutIt, class _CharT>
479480
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
@@ -509,20 +510,20 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt,
509510
}
510511

511512
template <class... _Args>
512-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
513+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
513514
formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
514515
return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
515516
}
516517

517-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
518+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
518519
template <class... _Args>
519-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
520+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
520521
formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
521522
return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
522523
}
523-
#endif
524+
# endif
524525

525-
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
526+
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
526527

527528
template <class _OutIt, class _CharT, class _FormatOutIt>
528529
requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
@@ -577,43 +578,42 @@ format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&
577578
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
578579
// fires too eagerly, see http://llvm.org/PR61563.
579580
template <class = void>
580-
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
581+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
581582
vformat(locale __loc, string_view __fmt, format_args __args) {
582583
string __res;
583584
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
584585
__args);
585586
return __res;
586587
}
587588

588-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
589+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
589590
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
590591
// fires too eagerly, see http://llvm.org/PR61563.
591592
template <class = void>
592-
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
593+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
593594
vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
594595
wstring __res;
595596
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
596597
__args);
597598
return __res;
598599
}
599-
#endif
600+
# endif
600601

601602
template <class... _Args>
602-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(locale __loc,
603-
format_string<_Args...> __fmt,
604-
_Args&&... __args) {
603+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
604+
format(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
605605
return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
606606
_VSTD::make_format_args(__args...));
607607
}
608608

609-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
609+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
610610
template <class... _Args>
611-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
611+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
612612
format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
613613
return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
614614
_VSTD::make_wformat_args(__args...));
615615
}
616-
#endif
616+
# endif
617617

618618
template <class _Context, class _OutIt, class _CharT>
619619
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
@@ -654,21 +654,20 @@ _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_
654654
}
655655

656656
template <class... _Args>
657-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
657+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
658658
formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
659659
return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
660660
}
661661

662-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
662+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
663663
template <class... _Args>
664-
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
664+
_LIBCPP_NODISCARD_EXT _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
665665
formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
666666
return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
667667
}
668-
#endif
669-
670-
#endif // _LIBCPP_HAS_NO_LOCALIZATION
668+
# endif
671669

670+
# endif // _LIBCPP_HAS_NO_LOCALIZATION
672671

673672
#endif //_LIBCPP_STD_VER >= 20
674673

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// Check that format functions aren't marked [[nodiscard]] when
10+
// _LIBCPP_DISBALE_NODISCARD_EXT is defined
11+
12+
// TODO FMT This test should not require std::to_chars(floating-point)
13+
// XFAIL: availability-fp_to_chars-missing
14+
15+
// UNSUPPORTED: c++03, c++11, c++14 ,c++17
16+
17+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_NODISCARD_EXT
18+
19+
#include <format>
20+
21+
#include "test_macros.h"
22+
23+
#ifndef TEST_HAS_NO_LOCALIZATION
24+
# include <locale>
25+
#endif
26+
27+
void test() {
28+
std::format("");
29+
std::vformat("", std::make_format_args());
30+
std::formatted_size("");
31+
std::make_format_args();
32+
33+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
34+
std::format(L"");
35+
std::vformat(L"", std::make_wformat_args());
36+
std::formatted_size(L"");
37+
std::make_wformat_args();
38+
#endif // TEST_HAS_NO_WIDE_CHARACTERS
39+
40+
#ifndef TEST_HAS_NO_LOCALIZATION
41+
std::format(std::locale::classic(), "");
42+
std::vformat(std::locale::classic(), "", std::make_format_args());
43+
std::formatted_size(std::locale::classic(), "");
44+
# ifndef TEST_HAS_NO_WIDE_CHARACTERS
45+
std::format(std::locale::classic(), L"");
46+
std::vformat(std::locale::classic(), L"", std::make_wformat_args());
47+
std::formatted_size(std::locale::classic(), L"");
48+
# endif // TEST_HAS_NO_WIDE_CHARACTERS
49+
#endif // TEST_HAS_NO_LOCALIZATION
50+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// Check that format functions are marked [[nodiscard]] as a conforming extension
10+
11+
// TODO FMT This test should not require std::to_chars(floating-point)
12+
// XFAIL: availability-fp_to_chars-missing
13+
14+
// UNSUPPORTED: c++03, c++11, c++14 ,c++17
15+
16+
#include <format>
17+
18+
#include "test_macros.h"
19+
20+
#ifndef TEST_HAS_NO_LOCALIZATION
21+
# include <locale>
22+
#endif
23+
24+
void test() {
25+
// clang-format off
26+
std::format(""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
27+
std::vformat("", std::make_format_args()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
28+
std::formatted_size(""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
29+
std::make_format_args(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
30+
31+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
32+
std::format(L""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
33+
std::vformat(L"", std::make_wformat_args()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
34+
std::formatted_size(L""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
35+
std::make_wformat_args(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
36+
#endif // TEST_HAS_NO_WIDE_CHARACTERS
37+
38+
#ifndef TEST_HAS_NO_LOCALIZATION
39+
std::format(std::locale::classic(), ""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
40+
std::vformat(std::locale::classic(), "", std::make_format_args()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
41+
std::formatted_size(std::locale::classic(), ""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
42+
# ifndef TEST_HAS_NO_WIDE_CHARACTERS
43+
std::format(std::locale::classic(), L""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
44+
std::vformat(std::locale::classic(), L"", std::make_wformat_args()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
45+
std::formatted_size(std::locale::classic(), L""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
46+
# endif // TEST_HAS_NO_WIDE_CHARACTERS
47+
#endif // TEST_HAS_NO_LOCALIZATION
48+
// clang-format on
49+
}

0 commit comments

Comments
 (0)