[libcxx-commits] [libcxx] 0ee73de - [libc++][format] Fixes year formatter on Windows.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 30 09:58:05 PDT 2023


Author: Mark de Wever
Date: 2023-05-30T18:57:55+02:00
New Revision: 0ee73debf7445a9a34dcdf0215a99a2919d00112

URL: https://github.com/llvm/llvm-project/commit/0ee73debf7445a9a34dcdf0215a99a2919d00112
DIFF: https://github.com/llvm/llvm-project/commit/0ee73debf7445a9a34dcdf0215a99a2919d00112.diff

LOG: [libc++][format] Fixes year formatter on Windows.

Windows' libc, like some other libc implementations do not work as
specified for %Y and %y. This uses the fixes used for other libc
implementations.

The work was part of D150593.

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D151612

Added: 
    

Modified: 
    libcxx/include/__chrono/formatter.h
    libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
    libcxx/test/std/time/time.syn/formatter.year.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index c8d5993be1961..679edf39cbb39 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -270,20 +270,19 @@ _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
         //
         // TODO FMT evaluate the comment above.
 
-#  if defined(__GLIBC__) || defined(_AIX)
+#  if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
       case _CharT('y'):
         // Glibc fails for negative values, AIX for positive values too.
         __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100);
         break;
-#  endif // defined(__GLIBC__) || defined(_AIX)
+#  endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
 
-      case _CharT('Y'): {
-        int __year = __t.tm_year + 1900;
-        if (__year < 1000)
-          __formatter::__format_year(__year, __sstr);
-        else
-          __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
-      } break;
+      case _CharT('Y'):
+        // Depending on the platform's libc the range of supported years is
+        // limited. Intead of of testing all conditions use the internal
+        // implementation unconditionally.
+        __formatter::__format_year(__t.tm_year + 1900, __sstr);
+        break;
 
       case _CharT('F'): {
         int __year = __t.tm_year + 1900;

diff  --git a/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp b/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
index 6e95849e9faf4..cd565b82bc2a6 100644
--- a/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
@@ -9,9 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // UNSUPPORTED: no-localization
 
-// TODO FMT Investigate Windows issues.
-// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
-
 // TODO FMT Fix this test using GCC, it currently crashes.
 // UNSUPPORTED: gcc-12
 
@@ -35,9 +32,16 @@
 #include "make_string.h"
 #include "platform_support.h" // locale name macros
 #include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
 
 #define SV(S) MAKE_STRING_VIEW(CharT, S)
 
+#define TEST_EQUAL(OUT, EXPECTED)                                                                                      \
+  TEST_REQUIRE(OUT == EXPECTED,                                                                                        \
+               TEST_WRITE_CONCATENATED(                                                                                \
+                   "\nExpression      ", #OUT, "\nExpected output ", EXPECTED, "\nActual output   ", OUT, '\n'));
+
 template <class CharT>
 static std::basic_string<CharT> stream_c_locale(std::chrono::year year) {
   std::basic_stringstream<CharT> sstr;
@@ -65,23 +69,23 @@ static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::year year) {
 
 template <class CharT>
 static void test() {
-  assert(stream_c_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
-  assert(stream_c_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
-  assert(stream_c_locale<CharT>(std::chrono::year{0}) == SV("0000"));
-  assert(stream_c_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
-  assert(stream_c_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
-
-  assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
-  assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
-  assert(stream_fr_FR_locale<CharT>(std::chrono::year{0}) == SV("0000"));
-  assert(stream_fr_FR_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
-  assert(stream_fr_FR_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
-
-  assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
-  assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
-  assert(stream_ja_JP_locale<CharT>(std::chrono::year{0}) == SV("0000"));
-  assert(stream_ja_JP_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
-  assert(stream_ja_JP_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
+  TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+  TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+  TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{0}), SV("0000"));
+  TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+  TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
+
+  TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+  TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+  TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{0}), SV("0000"));
+  TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+  TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
+
+  TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+  TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+  TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{0}), SV("0000"));
+  TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+  TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
 }
 
 int main(int, char**) {

diff  --git a/libcxx/test/std/time/time.syn/formatter.year.pass.cpp b/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
index c29140c8192c5..33c427932573a 100644
--- a/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
+++ b/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
@@ -10,9 +10,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // UNSUPPORTED: no-localization
 
-// TODO FMT Investigate Windows issues.
-// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
-
 // TODO FMT Fix this test using GCC, it currently crashes.
 // UNSUPPORTED: gcc-12
 
@@ -88,7 +85,7 @@ static void test_valid_values() {
 
   // Non localized output using C-locale
   check(SV("%C='00'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
            "%EC='00'\t"
 #else
            "%EC='0'\t"
@@ -97,7 +94,7 @@ static void test_valid_values() {
            "%Ey='00'\t"
            "%Oy='00'\t"
            "%Y='0000'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
            "%EY='0000'\t"
 #elif defined(_AIX)
            "%EY=''\t"
@@ -132,7 +129,7 @@ static void test_valid_values() {
 
   // Use the global locale (fr_FR)
   check(SV("%C='00'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
            "%EC='00'\t"
 #else
            "%EC='0'\t"
@@ -141,7 +138,7 @@ static void test_valid_values() {
            "%Ey='00'\t"
            "%Oy='00'\t"
            "%Y='0000'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
            "%EY='0000'\t"
 #elif defined(_AIX)
            "%EY=''\t"
@@ -175,10 +172,10 @@ static void test_valid_values() {
         std::chrono::year{2038});
 
   // Use supplied locale (ja_JP). This locale has a 
diff erent alternate.
-#if defined(__APPLE__) || defined(_AIX)
+#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
 
   check(SV("%C='00'\t"
-#  if defined(__APPLE__)
+#  if defined(__APPLE__) || defined(_WIN32)
            "%EC='00'\t"
 #  else
            "%EC='0'\t"
@@ -218,12 +215,12 @@ static void test_valid_values() {
         lfmt,
         std::chrono::year{2038});
 
-#else // defined(__APPLE__) || defined(_AIX)
+#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
   check(loc,
         SV("%C='00'\t"
            "%EC='紀元前'\t"
            "%y='00'\t"
-// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
+  // https://sourceware.org/bugzilla/show_bug.cgi?id=23758
 #  if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
            "%Ey='1'\t"
 #  else
@@ -231,7 +228,7 @@ static void test_valid_values() {
 #  endif
            "%Oy='〇'\t"
            "%Y='0000'\t"
-// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
+  // https://sourceware.org/bugzilla/show_bug.cgi?id=23758
 #  if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
            "%EY='紀元前1年'\t"
 #  else
@@ -265,7 +262,7 @@ static void test_valid_values() {
            "\n"),
         lfmt,
         std::chrono::year{2038});
-#endif // defined(__APPLE__) || defined(_AIX)
+#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
 
   std::locale::global(std::locale::classic());
 }
@@ -273,7 +270,6 @@ static void test_valid_values() {
 template <class CharT>
 static void test_padding() {
   constexpr std::basic_string_view<CharT> fmt = SV("{:%%C='%C'%t%%y='%y'%t%%Y='%Y'%t%n}");
-
   check(SV("%C='-100'\t%y='99'\t%Y='-9999'\t\n"), fmt, std::chrono::year{-9'999});
   check(SV("%C='-10'\t%y='99'\t%Y='-0999'\t\n"), fmt, std::chrono::year{-999});
   check(SV("%C='-1'\t%y='99'\t%Y='-0099'\t\n"), fmt, std::chrono::year{-99});


        


More information about the libcxx-commits mailing list