Howard brought https://stackoverflow.com/a/79015753/981959 to my
attention, where chrono::parse fails with %c as the format, because we
don't populate all fields of the __timepunct facet for the C locale.

It looks like I noticed that when testing std::format and implemented a
workaround:

          const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
          const _CharT* __formats[2];
          __tp._M_date_time_formats(__formats);
          const _CharT* __rep = __formats[__mod];
          if (!*__rep)
            __rep = _GLIBCXX_WIDEN("%a %b %e %H:%M:%S %Y");

But I didn't notice it affects chrono::parse too. The workaround might
be unnecessary now, but it does no harm to keep it.

Tested x86_64-linux.

-- >8 --

We were using the empty string "" for D_T_FMT and ERA_D_T_FMT in the C
locale, instead of "%a %b %e %T %Y" as the C standard requires. Set it
correctly for each locale implementation that defines time_members.cc.

We can also explicitly set the _M_era_xxx pointers to the same values as
the corresponding _M_xxx ones, rather than setting them to point to
identical string literals. This doesn't rely on the compiler merging
string literals, and makes it more explicit that they're the same in the
C locale.

libstdc++-v3/ChangeLog:

        * config/locale/dragonfly/time_members.cc
        (__timepunct<char>::_M_initialize_timepunc)
        (__timepunct<wchar_t>::_M_initialize_timepunc): Set
        _M_date_time_format for C locale. Set %Ex formats to the same
        values as the %x formats.
        * config/locale/generic/time_members.cc: Likewise.
        * config/locale/gnu/time_members.cc: Likewise.
        * config/locale/ieee_1003.1-2008/time_members.cc: Likewise.
        * testsuite/22_locale/time_get/get/char/5.cc: New test.
        * testsuite/22_locale/time_get/get/wchar_t/5.cc: New test.
---
 .../config/locale/dragonfly/time_members.cc   | 16 ++++----
 .../config/locale/generic/time_members.cc     |  8 ++--
 .../config/locale/gnu/time_members.cc         | 16 ++++----
 .../locale/ieee_1003.1-2008/time_members.cc   | 16 ++++----
 .../22_locale/time_get/get/char/5.cc          | 37 +++++++++++++++++++
 .../22_locale/time_get/get/wchar_t/5.cc       | 37 +++++++++++++++++++
 6 files changed, 102 insertions(+), 28 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/char/5.cc
 create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/5.cc

diff --git a/libstdc++-v3/config/locale/dragonfly/time_members.cc 
b/libstdc++-v3/config/locale/dragonfly/time_members.cc
index 0c96928135e..069b2ddd26b 100644
--- a/libstdc++-v3/config/locale/dragonfly/time_members.cc
+++ b/libstdc++-v3/config/locale/dragonfly/time_members.cc
@@ -67,11 +67,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = "%m/%d/%y";
-         _M_data->_M_date_era_format = "%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = "%H:%M:%S";
-         _M_data->_M_time_era_format = "%H:%M:%S";
-         _M_data->_M_date_time_format = "";
-         _M_data->_M_date_time_era_format = "";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = "%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = "AM";
          _M_data->_M_pm = "PM";
          _M_data->_M_am_pm_format = "%I:%M:%S %p";
@@ -224,11 +224,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = L"%m/%d/%y";
-         _M_data->_M_date_era_format = L"%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = L"%H:%M:%S";
-         _M_data->_M_time_era_format = L"%H:%M:%S";
-         _M_data->_M_date_time_format = L"";
-         _M_data->_M_date_time_era_format = L"";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = L"%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = L"AM";
          _M_data->_M_pm = L"PM";
          _M_data->_M_am_pm_format = L"%I:%M:%S %p";
diff --git a/libstdc++-v3/config/locale/generic/time_members.cc 
b/libstdc++-v3/config/locale/generic/time_members.cc
index 68395820fef..6619f0ca881 100644
--- a/libstdc++-v3/config/locale/generic/time_members.cc
+++ b/libstdc++-v3/config/locale/generic/time_members.cc
@@ -65,11 +65,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _M_data = new __timepunct_cache<char>;
 
       _M_data->_M_date_format = "%m/%d/%y";
-      _M_data->_M_date_era_format = "%m/%d/%y";
+      _M_data->_M_date_era_format = _M_data->_M_date_format;
       _M_data->_M_time_format = "%H:%M:%S";
-      _M_data->_M_time_era_format = "%H:%M:%S";
-      _M_data->_M_date_time_format = "";
-      _M_data->_M_date_time_era_format = "";
+      _M_data->_M_time_era_format = _M_data->_M_time_format;
+      _M_data->_M_date_time_format = "%a %b %e %T %Y";
+      _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
       _M_data->_M_am = "AM";
       _M_data->_M_pm = "PM";
       _M_data->_M_am_pm_format = "%I:%M:%S %p";
diff --git a/libstdc++-v3/config/locale/gnu/time_members.cc 
b/libstdc++-v3/config/locale/gnu/time_members.cc
index 1e3b87488fa..88c8ab70080 100644
--- a/libstdc++-v3/config/locale/gnu/time_members.cc
+++ b/libstdc++-v3/config/locale/gnu/time_members.cc
@@ -73,11 +73,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = "%m/%d/%y";
-         _M_data->_M_date_era_format = "%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = "%H:%M:%S";
-         _M_data->_M_time_era_format = "%H:%M:%S";
-         _M_data->_M_date_time_format = "";
-         _M_data->_M_date_time_era_format = "";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = "%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = "AM";
          _M_data->_M_pm = "PM";
          _M_data->_M_am_pm_format = "%I:%M:%S %p";
@@ -229,11 +229,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = L"%m/%d/%y";
-         _M_data->_M_date_era_format = L"%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = L"%H:%M:%S";
-         _M_data->_M_time_era_format = L"%H:%M:%S";
-         _M_data->_M_date_time_format = L"";
-         _M_data->_M_date_time_era_format = L"";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = L"%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = L"AM";
          _M_data->_M_pm = L"PM";
          _M_data->_M_am_pm_format = L"%I:%M:%S %p";
diff --git a/libstdc++-v3/config/locale/ieee_1003.1-2008/time_members.cc 
b/libstdc++-v3/config/locale/ieee_1003.1-2008/time_members.cc
index eb6e39c40ff..2945362bd55 100644
--- a/libstdc++-v3/config/locale/ieee_1003.1-2008/time_members.cc
+++ b/libstdc++-v3/config/locale/ieee_1003.1-2008/time_members.cc
@@ -64,11 +64,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = "%m/%d/%y";
-         _M_data->_M_date_era_format = "%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = "%H:%M:%S";
-         _M_data->_M_time_era_format = "%H:%M:%S";
-         _M_data->_M_date_time_format = "";
-         _M_data->_M_date_time_era_format = "";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = "%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = "AM";
          _M_data->_M_pm = "PM";
          _M_data->_M_am_pm_format = "%I:%M:%S %p";
@@ -210,11 +210,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_c_locale_timepunct = _S_get_c_locale();
 
          _M_data->_M_date_format = L"%m/%d/%y";
-         _M_data->_M_date_era_format = L"%m/%d/%y";
+         _M_data->_M_date_era_format = _M_data->_M_date_format;
          _M_data->_M_time_format = L"%H:%M:%S";
-         _M_data->_M_time_era_format = L"%H:%M:%S";
-         _M_data->_M_date_time_format = L"";
-         _M_data->_M_date_time_era_format = L"";
+         _M_data->_M_time_era_format = _M_data->_M_time_format;
+         _M_data->_M_date_time_format = L"%a %b %e %T %Y";
+         _M_data->_M_date_time_era_format = _M_data->_M_date_time_format;
          _M_data->_M_am = L"AM";
          _M_data->_M_pm = L"PM";
          _M_data->_M_am_pm_format = L"%I:%M:%S %p";
diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/char/5.cc 
b/libstdc++-v3/testsuite/22_locale/time_get/get/char/5.cc
new file mode 100644
index 00000000000..61fc329cf3c
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/time_get/get/char/5.cc
@@ -0,0 +1,37 @@
+// { dg-do run { target c++11} }
+
+#include <locale>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  using Facet = std::time_get<char>;
+  const Facet& fac = std::use_facet<Facet>(std::locale::classic());
+  std::istringstream ss("Fri Jul 5 14:58:21 2019");
+  std::ios::iostate err = std::ios::goodbit;
+  std::tm tm = {};
+  fac.get(ss, Facet::iter_type(), ss, err, &tm, 'c');
+  VERIFY( err == std::ios::eofbit );
+  VERIFY( tm.tm_year == 119 );
+  VERIFY( tm.tm_mon == 6 );
+  VERIFY( tm.tm_mday == 5 );
+  VERIFY( tm.tm_wday == 5 );
+  VERIFY( tm.tm_hour == 14 );
+  VERIFY( tm.tm_min == 58 );
+  VERIFY( tm.tm_sec == 21 );
+  ss.clear();
+  ss.seekg(0);
+  ss.str(ss.str() + " non-whitespace after the datetime");
+  err = std::ios::goodbit;
+  tm = std::tm();
+  fac.get(ss, Facet::iter_type(), ss, err, &tm, 'c', 'E');
+  VERIFY( err == std::ios::goodbit );
+  VERIFY( tm.tm_year == 119 );
+  VERIFY( tm.tm_mon == 6 );
+  VERIFY( tm.tm_mday == 5 );
+  VERIFY( tm.tm_wday == 5 );
+  VERIFY( tm.tm_hour == 14 );
+  VERIFY( tm.tm_min == 58 );
+  VERIFY( tm.tm_sec == 21 );
+}
diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/5.cc 
b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/5.cc
new file mode 100644
index 00000000000..5f350b043d9
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/5.cc
@@ -0,0 +1,37 @@
+// { dg-do run { target c++11} }
+
+#include <locale>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  using Facet = std::time_get<wchar_t>;
+  const Facet& fac = std::use_facet<Facet>(std::locale::classic());
+  std::wistringstream ss(L"Fri Jul 5 14:58:21 2019");
+  std::ios::iostate err = std::ios::goodbit;
+  std::tm tm = {};
+  fac.get(ss, Facet::iter_type(), ss, err, &tm, 'c');
+  VERIFY( err == std::ios::eofbit );
+  VERIFY( tm.tm_year == 119 );
+  VERIFY( tm.tm_mon == 6 );
+  VERIFY( tm.tm_mday == 5 );
+  VERIFY( tm.tm_wday == 5 );
+  VERIFY( tm.tm_hour == 14 );
+  VERIFY( tm.tm_min == 58 );
+  VERIFY( tm.tm_sec == 21 );
+  ss.clear();
+  ss.seekg(0);
+  ss.str(ss.str() + L" non-whitespace after the datetime");
+  err = std::ios::goodbit;
+  tm = std::tm();
+  fac.get(ss, Facet::iter_type(), ss, err, &tm, 'c', 'E');
+  VERIFY( err == std::ios::goodbit );
+  VERIFY( tm.tm_year == 119 );
+  VERIFY( tm.tm_mon == 6 );
+  VERIFY( tm.tm_mday == 5 );
+  VERIFY( tm.tm_wday == 5 );
+  VERIFY( tm.tm_hour == 14 );
+  VERIFY( tm.tm_min == 58 );
+  VERIFY( tm.tm_sec == 21 );
+}
-- 
2.46.1

Reply via email to