From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id AD521385842B; Thu, 23 Feb 2023 13:27:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AD521385842B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1677158844; bh=Up2SgDfWn85UaHwBFKNmwDVoexcx6cFDwUGKzjvbY/4=; h=From:To:Subject:Date:From; b=prWi4Un/qMVCmZnrZUcJ6wVuBkqQa6V03VY7ztvWYT5Y1x5MkS9HIiCSbvKxptvPv aPUBMU3p2zqc+unuZH5LNZ9LkY9jYDqUoWQq2wFeePEkgbaVitoCClMVyYeEUSaiDF 6dtjkAxt2m0XkyBmhnAVVb50rsRGSo9O4xNiELxA= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alexandre Oliva To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/testme)] [PR77760] [libstdc++] encode __time_get_state in tm X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/testme X-Git-Oldrev: 43bd3d46e41f17d86d644d319c85c540bde151fc X-Git-Newrev: 86b4c702b17a76cd437cfdec93dbc323099dedff Message-Id: <20230223132724.AD521385842B@sourceware.org> Date: Thu, 23 Feb 2023 13:27:24 +0000 (GMT) List-Id: https://gcc.gnu.org/g:86b4c702b17a76cd437cfdec93dbc323099dedff commit 86b4c702b17a76cd437cfdec93dbc323099dedff Author: Alexandre Oliva Date: Fri Feb 17 01:59:08 2023 -0300 [PR77760] [libstdc++] encode __time_get_state in tm On platforms that fail the ptrtomemfn-cast-to-pfn hack, such as arm-*-vxworks*, time_get fails with %I and %p because the state is not preserved across do_get calls. This patch introduces an alternate hack, that encodes the state in unused bits of struct tm before calling do_get, extracts them in do_get, does the processing, and encodes it back, so that get extracts it. The finalizer is adjusted for idempotence, because both do_get and get may call it. for libstdc++-v3/ChangeLog PR libstdc++/77760 * include/bits/locale_facets_nonio.h (__time_get_state): Add _M_state_tm, _M_save_to and _M_restore_from. * include/bits/locale_facets_nonio.tcc (time_get::get): Drop do_get-overriding hack. Use state unconditionally, and encode it in tm around do_get. (time_get::do_get): Extract state from tm, and encode it back, around parsing and finalizing. * src/c++98/locale_facets.cc (__time_get_state::_M_finalize_state): Make tm_hour and tm_year idempotent. Diff: --- libstdc++-v3/include/bits/locale_facets_nonio.h | 80 +++++++++++++++++++++++ libstdc++-v3/include/bits/locale_facets_nonio.tcc | 43 ++---------- libstdc++-v3/src/c++98/locale_facets.cc | 8 ++- 3 files changed, 93 insertions(+), 38 deletions(-) diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.h b/libstdc++-v3/include/bits/locale_facets_nonio.h index 372cf042950..711bede1584 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.h +++ b/libstdc++-v3/include/bits/locale_facets_nonio.h @@ -361,6 +361,86 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_finalize_state(tm* __tm); + private: + void + _M_state_tm(tm* __tm, bool __totm) + { + // Check we don't invade the in-range tm bits, even if int is + // 16-bits wide. +#define _M_min_shift_tm_sec 6 +#define _M_min_shift_tm_min 6 +#define _M_min_shift_tm_hour 5 +#define _M_min_shift_tm_mday 5 +#define _M_min_shift_tm_mon 4 +#define _M_min_shift_tm_year 16 // 14, but signed, so avoid it. +#define _M_min_shift_tm_wday 3 +#define _M_min_shift_tm_yday 9 +#define _M_min_shift_tm_isdst 1 + // Represent __STF in __WDT bits of __TMF up to the __MSB bit. + // In __MSB, 0 stands for the most significant bit of __TMF, + // 1 the bit next to it, and so on. +#define _M_time_get_state_bitfield_inout(__tmf, __msb, __wdt, __stf) \ + do \ + { \ + const unsigned __shift = (sizeof (__tm->__tmf) * __CHAR_BIT__ \ + - (__msb) - (__wdt)); \ + static char __attribute__ ((__unused__)) \ + __check_parms_##__tmf[(__msb) >= 0 && (__wdt) > 0 \ + && __shift >= (_M_min_shift_##__tmf \ + + (sizeof (__tm->__tmf) \ + * __CHAR_BIT__) - 16) \ + ? 1 : -1]; \ + const unsigned __mask = ((1 << (__wdt)) - 1) << __shift; \ + if (!__totm) \ + this->__stf = (__tm->__tmf & __mask) >> __shift; \ + __tm->__tmf &= ~__mask; \ + if (__totm) \ + __tm->__tmf |= ((unsigned)this->__stf << __shift) & __mask; \ + } \ + while (0) + + _M_time_get_state_bitfield_inout (tm_hour, 0, 1, _M_have_I); + _M_time_get_state_bitfield_inout (tm_wday, 0, 1, _M_have_wday); + _M_time_get_state_bitfield_inout (tm_yday, 0, 1, _M_have_yday); + _M_time_get_state_bitfield_inout (tm_mon, 0, 1, _M_have_mon); + _M_time_get_state_bitfield_inout (tm_mday, 0, 1, _M_have_mday); + _M_time_get_state_bitfield_inout (tm_yday, 1, 1, _M_have_uweek); + _M_time_get_state_bitfield_inout (tm_yday, 2, 1, _M_have_wweek); + _M_time_get_state_bitfield_inout (tm_isdst, 0, 1, _M_have_century); + _M_time_get_state_bitfield_inout (tm_hour, 1, 1, _M_is_pm); + _M_time_get_state_bitfield_inout (tm_isdst, 1, 1, _M_want_century); + _M_time_get_state_bitfield_inout (tm_yday, 3, 1, _M_want_xday); + // _M_pad1 + _M_time_get_state_bitfield_inout (tm_wday, 1, 6, _M_week_no); + // _M_pad2 + _M_time_get_state_bitfield_inout (tm_mon, 1, 8, _M_century); + // _M_pad3 + +#undef _M_min_shift_tm_hour +#undef _M_min_shift_tm_sec +#undef _M_min_shift_tm_min +#undef _M_min_shift_tm_hour +#undef _M_min_shift_tm_mday +#undef _M_min_shift_tm_mon +#undef _M_min_shift_tm_year +#undef _M_min_shift_tm_wday +#undef _M_min_shift_tm_yday +#undef _M_min_shift_tm_isdst +#undef _M_time_get_state_bitfield_inout + } + public: + // Encode *THIS into scratch bits of __TM. + void + _M_save_to(tm* __tm) { + _M_state_tm (__tm, true); + } + + // Decode and zero out scratch bits of __TM back into *THIS. + void + _M_restore_from(tm* __tm) { + _M_state_tm (__tm, false); + } + unsigned int _M_have_I : 1; unsigned int _M_have_wday : 1; unsigned int _M_have_yday : 1; diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc index b19f4425300..47d243ce84d 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc +++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc @@ -1464,21 +1464,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 const locale& __loc = __io._M_getloc(); ctype<_CharT> const& __ctype = use_facet >(__loc); __err = ios_base::goodbit; - bool __use_state = false; -#if __GNUC__ >= 5 && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpmf-conversions" - // Nasty hack. The C++ standard mandates that get invokes the do_get - // virtual method, but unfortunately at least without an ABI change - // for the facets we can't keep state across the different do_get - // calls. So e.g. if __fmt is "%p %I:%M:%S", we can't handle it - // properly, because we first handle the %p am/pm specifier and only - // later the 12-hour format specifier. - if ((void*)(this->*(&time_get::do_get)) == (void*)(&time_get::do_get)) - __use_state = true; -#pragma GCC diagnostic pop -#endif __time_get_state __state = __time_get_state(); + __state._M_save_to (__tm); while (__fmt != __fmtend && __err == ios_base::goodbit) { @@ -1510,26 +1497,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 __err = ios_base::failbit; break; } - if (__use_state) - { - char_type __new_fmt[4]; - __new_fmt[0] = __fmt_start[0]; - __new_fmt[1] = __fmt_start[1]; - if (__mod) - { - __new_fmt[2] = __fmt_start[2]; - __new_fmt[3] = char_type(); - } - else - __new_fmt[2] = char_type(); - __s = _M_extract_via_format(__s, __end, __io, __err, __tm, - __new_fmt, __state); - if (__s == __end) - __err |= ios_base::eofbit; - } - else - __s = this->do_get(__s, __end, __io, __err, __tm, __format, - __mod); + __s = this->do_get(__s, __end, __io, __err, __tm, + __format, __mod); ++__fmt; } else if (__ctype.is(ctype_base::space, *__fmt)) @@ -1556,8 +1525,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 break; } } - if (__use_state) - __state._M_finalize_state(__tm); + __state._M_restore_from (__tm); + __state._M_finalize_state(__tm); return __s; } @@ -1588,9 +1557,11 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 } __time_get_state __state = __time_get_state(); + __state._M_restore_from (__tm); __beg = _M_extract_via_format(__beg, __end, __io, __err, __tm, __fmt, __state); __state._M_finalize_state(__tm); + __state._M_save_to (__tm); if (__beg == __end) __err |= ios_base::eofbit; return __beg; diff --git a/libstdc++-v3/src/c++98/locale_facets.cc b/libstdc++-v3/src/c++98/locale_facets.cc index c0bb7fd181d..28c34b5f379 100644 --- a/libstdc++-v3/src/c++98/locale_facets.cc +++ b/libstdc++-v3/src/c++98/locale_facets.cc @@ -181,12 +181,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __time_get_state:: _M_finalize_state(tm* tm) { - if (_M_have_I && _M_is_pm) + if (_M_have_I && _M_is_pm && (unsigned) tm->tm_hour < 12) tm->tm_hour += 12; if (_M_have_century) { if (_M_want_century) - tm->tm_year = tm->tm_year % 100; + { + tm->tm_year = tm->tm_year % 100; + if (tm->tm_year < 0) + tm->tm_year += 100; + } else tm->tm_year = 0; tm->tm_year += (_M_century - 19) * 100;