https://gcc.gnu.org/g:2ca5725e104d432317a44ad45183a4f555da3b82
commit r16-293-g2ca5725e104d432317a44ad45183a4f555da3b82 Author: Tomasz KamiĆski <tkami...@redhat.com> Date: Fri Apr 25 20:10:52 2025 +0200 libstdc++: Fix _Padding_sink in case when predicted width is between padwidth and maxwidth [PR109162] The _Padding_sink was behaving incorrectly, when the predicted width (based on code units count) was higher than _M_maxwidth, but lower than _M_padwidth. In this case _M_update() returned without calling _M_force_update() and computing field width for Unicode encoding, because _M_buffering() returned 'true'. As a consequence we switched to _M_ignoring() mode, while storing a sequence with more code units but smaller field width than _M_maxwidth. We now call _M_force_update() if predicted width is greater or equal to either _M_padwidth or _M_maxwidth. This happened for existing test case on 32bit architecture. PR libstdc++/109162 libstdc++-v3/ChangeLog: * include/std/format (_Padding_sink::_M_update): Fixed condition for calling _M_force_update. * testsuite/std/format/debug.cc: Add test that reproduces this issue on 64bit architecture. * testsuite/std/format/ranges/sequence.cc: Another edge value test. Diff: --- libstdc++-v3/include/std/format | 7 ++++--- libstdc++-v3/testsuite/std/format/debug.cc | 9 +++++++++ libstdc++-v3/testsuite/std/format/ranges/sequence.cc | 9 +++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 69d8d189db62..054ce3504408 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -3697,9 +3697,10 @@ namespace __format _M_update(size_t __new) { _M_printwidth += __new; - if (_M_buffering()) - return true; - return _M_force_update(); + // Compute estimated width, to see if is not reduced. + if (_M_printwidth >= _M_padwidth || _M_printwidth >= _M_maxwidth) + return _M_force_update(); + return true; } void diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc index d3402f80f4b6..6165a2954963 100644 --- a/libstdc++-v3/testsuite/std/format/debug.cc +++ b/libstdc++-v3/testsuite/std/format/debug.cc @@ -596,6 +596,10 @@ void test_padding() VERIFY( strip_prefix(resv, 48, '*') ); VERIFY( resv == inv ); + resv = res = std::format("{:*>300.200s}", in); + VERIFY( strip_prefix(resv, 108, '*') ); + VERIFY( resv == inv ); + resv = res = std::format("{:*>240.200s}", in); VERIFY( strip_prefix(resv, 48, '*') ); VERIFY( resv == inv ); @@ -678,6 +682,11 @@ void test_padding() VERIFY( strip_quotes(resv) ); VERIFY( resv == inv ); + resv = res = std::format("{:*>300.200?}", in); + VERIFY( strip_prefix(resv, 106, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + resv = res = std::format("{:*>240.200?}", in); VERIFY( strip_prefix(resv, 46, '*') ); VERIFY( strip_quotes(resv) ); diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc index 75fe4c19a523..32242860f10e 100644 --- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc @@ -295,6 +295,15 @@ void test_padding() resv = res = std::format("{:*>10n:}", vs); VERIFY( check_elems(resv, false) ); + resv = res = std::format("{:*>256}", vs); + VERIFY( strip_prefix(resv, 48, '*') ); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>256n}", vs); + VERIFY( strip_prefix(resv, 50, '*') ); + VERIFY( check_elems(resv, true) ); + resv = res = std::format("{:*>240}", vs); VERIFY( strip_prefix(resv, 32, '*') ); VERIFY( strip_squares(resv) );