Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions stl/inc/format
Original file line number Diff line number Diff line change
Expand Up @@ -1410,13 +1410,17 @@ _NODISCARD constexpr basic_format_arg<_Context> _Get_arg(const _Context& _Ctx, c
return _Arg;
}

template <class _Ty>
inline constexpr bool _Is_signed_or_unsigned_large_integer_t =
_Is_any_of_v<remove_cv_t<_Ty>, int, unsigned int, long, unsigned long, long long, unsigned long long>;

// Checks that the type and value of an argument associated with a dynamic
// width specifier are valid.
class _Width_checker {
public:
template <class _Ty>
_NODISCARD constexpr unsigned long long operator()(const _Ty _Value) const {
if constexpr (is_integral_v<_Ty>) {
if constexpr (_Is_signed_or_unsigned_large_integer_t<_Ty>) {
if constexpr (is_signed_v<_Ty>) {
if (_Value < 0) {
_Throw_format_error("Negative width.");
Expand All @@ -1435,7 +1439,7 @@ class _Precision_checker {
public:
template <class _Ty>
_NODISCARD constexpr unsigned long long operator()(const _Ty _Value) const {
if constexpr (is_integral_v<_Ty>) {
if constexpr (_Is_signed_or_unsigned_large_integer_t<_Ty>) {
if constexpr (is_signed_v<_Ty>) {
if (_Value < 0) {
_Throw_format_error("Negative precision.");
Expand Down
12 changes: 10 additions & 2 deletions tests/std/tests/P0645R10_text_formatting_formatting/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1356,10 +1356,13 @@ void libfmt_formatter_test_runtime_width() {
throw_helper(STR("{0:{1}}"), 0, (int_max + 1u));
throw_helper(STR("{0:{1}}"), 0, -1l);
throw_helper(STR("{0:{1}}"), 0, (int_max + 1ul));
assert(format(STR("{0:{1}}"), 0, '0')
== STR(" 0")); // behavior differs from libfmt, but conforms
throw_helper(STR("{0:{1}}"), 0, 0.0);

// LWG-3720: Restrict the valid types of arg-id for width and precision in std-format-spec
throw_helper(STR("{:*^{}}"), 'a', true);
throw_helper(STR("{:*^{}}"), 'a', '0');
assert(format(STR("{:*^{}}"), 'a', static_cast<signed char>(2)) == STR("a*"));

assert(format(STR("{0:{1}}"), 42, 0) == STR("42")); // LWG-3721: zero dynamic width is OK

assert(format(STR("{0:{1}}"), -42, 4) == STR(" -42"));
Expand Down Expand Up @@ -1407,6 +1410,11 @@ void libfmt_formatter_test_runtime_precision() {
throw_helper(STR("{0:.{1}}"), reinterpret_cast<void*>(0xcafe), 2);
throw_helper(STR("{0:.{1}f}"), reinterpret_cast<void*>(0xcafe), 2);
assert(format(STR("{0:.{1}}"), STR("str"), 2) == STR("st"));

// LWG-3720: Restrict the valid types of arg-id for width and precision in std-format-spec
throw_helper(STR("{:.{}f}"), 3.14f, true);
throw_helper(STR("{:.{}f}"), 3.14f, '0');
assert(format(STR("{:.{}f}"), 3.14f, static_cast<signed char>(2)) == STR("3.14"));
}

template <class charT>
Expand Down