Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][TZDB] Implements time_zone get_info(local_time). #89537

Merged
merged 1 commit into from
Jun 9, 2024

Conversation

mordante
Copy link
Member

@mordante mordante commented Apr 21, 2024

Implements parts of:

  • P0355 Extending chrono to Calendars and Time Zones

@mordante mordante requested a review from a team as a code owner April 21, 2024 11:02
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 21, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Apr 21, 2024

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

Implements parts of:

  • P0355 Extending to Calendars and Time Zones

Patch is 63.94 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89537.diff

5 Files Affected:

  • (modified) libcxx/include/__chrono/time_zone.h (+7)
  • (modified) libcxx/include/chrono (+3)
  • (modified) libcxx/src/time_zone.cpp (+175)
  • (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp (+2)
  • (added) libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp (+1302)
diff --git a/libcxx/include/__chrono/time_zone.h b/libcxx/include/__chrono/time_zone.h
index 799602c1cdbaf0..3ea03683ccc187 100644
--- a/libcxx/include/__chrono/time_zone.h
+++ b/libcxx/include/__chrono/time_zone.h
@@ -17,6 +17,7 @@
 #if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
 
 #  include <__chrono/duration.h>
+#  include <__chrono/local_info.h>
 #  include <__chrono/sys_info.h>
 #  include <__chrono/system_clock.h>
 #  include <__compare/strong_order.h>
@@ -63,12 +64,18 @@ class _LIBCPP_AVAILABILITY_TZDB time_zone {
     return __get_info(chrono::time_point_cast<seconds>(__time));
   }
 
+  template <class _Duration>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_info get_info(const local_time<_Duration>& __time) const {
+    return __get_info(chrono::time_point_cast<seconds>(__time));
+  }
+
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
 
 private:
   [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept;
 
   [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const;
+  [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI local_info __get_info(local_seconds __time) const;
 
   unique_ptr<__impl> __impl_;
 };
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 96a3e92faa81f2..4d8398af1a108f 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -763,6 +763,9 @@ class time_zone {
 
   template<class Duration>
   sys_info get_info(const sys_time<Duration>& st) const;
+
+  template<class Duration>
+  local_info get_info(const local_time<Duration>& tp) const;
 };
 bool operator==(const time_zone& x, const time_zone& y) noexcept;                // C++20
 strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;    // C++20
diff --git a/libcxx/src/time_zone.cpp b/libcxx/src/time_zone.cpp
index 928f3d2855e456..24c22859080e10 100644
--- a/libcxx/src/time_zone.cpp
+++ b/libcxx/src/time_zone.cpp
@@ -34,6 +34,7 @@
 #include <chrono>
 #include <expected>
 #include <map>
+#include <numeric>
 #include <ranges>
 
 #include "include/tzdb/time_zone_private.h"
@@ -903,6 +904,180 @@ time_zone::__get_info(sys_seconds __time) const {
   std::__throw_runtime_error("tzdb: corrupt db");
 }
 
+enum class __position {
+  __beginning,
+  __middle,
+  __end,
+};
+
+// Determines the position of "__time" inside "__info".
+//
+// The code picks an arbitrary value to determine the "middle"
+// - Every time that is more than the threshold from a boundary, or
+// - Every value that is at the boundary sys_seconds::min() or
+//   sys_seconds::max().
+//
+// If not in the middle, it returns __beginning or __end.
+[[nodiscard]] static __position __get_position(sys_seconds __time, const sys_info __info) {
+  _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
+      __time >= __info.begin && __time < __info.end, "A value outside the range's position can't be determined.");
+
+  using _Tp = sys_seconds::rep;
+  // Africa/Freetown has a 4 day "zone"
+  // Africa/Freetown  Fri Sep  1 00:59:59 1939 UT = Thu Aug 31 23:59:59 1939 -01 isdst=0 gmtoff=-3600
+  // Africa/Freetown  Fri Sep  1 01:00:00 1939 UT = Fri Sep  1 00:20:00 1939 -0040 isdst=1 gmtoff=-2400
+  // Africa/Freetown  Tue Sep  5 00:39:59 1939 UT = Mon Sep  4 23:59:59 1939 -0040 isdst=1 gmtoff=-2400
+  // Africa/Freetown  Tue Sep  5 00:40:00 1939 UT = Mon Sep  4 23:40:00 1939 -01 isdst=0 gmtoff=-3600
+  //
+  // Originally used a one week threshold, but due to this switched to 1 day.
+  // This seems to work in practice.
+  //
+  // TODO TZDB Evaluate the proper threshold.
+  constexpr _Tp __threshold = 24 * 3600;
+
+  _Tp __upper = std::__add_sat(__info.begin.time_since_epoch().count(), __threshold);
+  if (__time >= __info.begin && __time.time_since_epoch().count() < __upper)
+    return __info.begin != sys_seconds::min() ? __position::__beginning : __position::__middle;
+
+  _Tp __lower = std::__sub_sat(__info.end.time_since_epoch().count(), __threshold);
+  if (__time < __info.end && __time.time_since_epoch().count() >= __lower)
+    return __info.end != sys_seconds::max() ? __position::__end : __position::__middle;
+
+  return __position::__middle;
+}
+
+[[nodiscard]] static local_info
+__get_info(local_seconds __local_time, const sys_info& __first, const sys_info& __second) {
+  std::chrono::local_seconds __end_first{__first.end.time_since_epoch() + __first.offset};
+  std::chrono::local_seconds __begin_second{__second.begin.time_since_epoch() + __second.offset};
+
+  if (__local_time < __end_first) {
+    if (__local_time >= __begin_second)
+      // |--------|
+      //        |------|
+      //         ^
+      return {local_info::ambiguous, __first, __second};
+
+    // |--------|
+    //          |------|
+    //         ^
+    return {local_info::unique, __first, sys_info{}};
+  }
+
+  if (__local_time < __begin_second)
+    // |--------|
+    //             |------|
+    //           ^
+    return {local_info::nonexistent, __first, __second};
+
+  // |--------|
+  //          |------|
+  //           ^
+  return {local_info::unique, __second, sys_info{}};
+}
+
+[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI local_info
+time_zone::__get_info(local_seconds __local_time) const {
+  seconds __local_seconds = __local_time.time_since_epoch();
+
+  /* An example of a typical year with a DST switch displayed in local time.
+   *
+   * At the first of April the time goes forward one hour. This means the
+   * time marked with ~~ is not a valid local time. This is represented by the
+   * nonexistent value in local_info.result.
+   *
+   * At the first of November the time goes backward one hour. This means the
+   * time marked with ^^ happens twice. This is represented by the ambiguous
+   * value in local_info.result.
+   *
+   * 2020.11.01                  2021.04.01              2021.11.01
+   * offset +05                  offset +05              offset +05
+   * save    0s                  save    1h              save    0s
+   * |-------------W----------|
+   *                             |----------W--------------|
+   *                                                    |-------------
+   *                           ~~                        ^^
+   *
+   * These shifts can happen due to changes in the current time zone for a
+   * location. For example, Indian/Kerguelen switched only once. In 1950 from an
+   * offset of 0 hours to an offset of +05 hours.
+   *
+   * During all these shifts the UTC time will have not gaps.
+   */
+
+  // The code needs to determine the system time for the local time. There is no
+  // information available. Assume the offset between system time and local time
+  // is 0s. This gives an initial estimate.
+  sys_seconds __guess{__local_seconds};
+  sys_info __info = __get_info(__guess);
+
+  // At this point the offset can be used to determine an estimate for the local
+  // time. Before doing the determine the offset validate whether the local time
+  // is the range [chrono::local_seconds::min(), chrono::local_seconds::max()).
+  if (__local_seconds < 0s && __info.offset > 0s)
+    if (__local_seconds - chrono::local_seconds::min().time_since_epoch() < __info.offset)
+      return {-1, __info, {}};
+
+  if (__local_seconds > 0s && __info.offset < 0s)
+    if (chrono::local_seconds::max().time_since_epoch() - __local_seconds < -__info.offset)
+      return {-2, __info, {}};
+
+  // Based on the information in the sys_info found the local time can be
+  // converted to a system time. This resulting time can be in the following
+  // locations of the sys_info found:
+  //
+  //                             |----------W--------------|
+  //                           1   2        3             4  5
+  //
+  // 1. The estimate is before the returned sys_info object.
+  //    The result is either non-existent or unique in the previous sys_info.
+  // 2. The estimate is in the beginning of the returned sys_info object.
+  //    The result is either unique or ambiguous with the previous sys_info.
+  // 3. The estimate is in the "middle" of the returned sys_info.
+  //    The result is unique.
+  // 4. The result is at the end of the returned sys_info object.
+  //    The result is either unique or ambiguous with the next sys_info.
+  // 5. The estimate is after the returned sys_info object.
+  //    The result is either non-existent or unique in the next sys_info.
+  //
+  // There is no specification where the "middle" starts. Similar issues can
+  // happen when sys_info objects are "short", then "unique in the next" could
+  // become "ambiguous in the next and the one following". Theoretically there
+  // is the option of the following time-line
+  //
+  // |------------|
+  //           |----|
+  //       |-----------------|
+  //
+  // However the local_info object only has 2 sys_info objects, so this option
+  // is not tested.
+  //
+  // The positions 2, 3, or 4 are determined by __get_position. This function
+  // also contains the definition of "middle".
+
+  sys_seconds __sys_time{__local_seconds - __info.offset};
+  if (__sys_time < __info.begin)
+    // Case 1 before __info
+    return chrono::__get_info(__local_time, __get_info(__info.begin - 1s), __info);
+
+  if (__sys_time >= __info.end)
+    // Case 5 after __info
+    return chrono::__get_info(__local_time, __info, __get_info(__info.end));
+
+  switch (__get_position(__sys_time, __info)) {
+  case __position::__beginning: // Case 2
+    return chrono::__get_info(__local_time, __get_info(__info.begin - 1s), __info);
+
+  case __position::__middle: // Case 3
+    return {local_info::unique, __info, {}};
+
+  case __position::__end: // Case 4
+    return chrono::__get_info(__local_time, __info, __get_info(__info.end));
+  }
+
+  std::__libcpp_unreachable();
+}
+
 } // namespace chrono
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
index a5ce5d16581306..fea1e4417cc12c 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
@@ -48,8 +48,10 @@ void test() {
 
   {
     std::chrono::sys_seconds s{};
+    std::chrono::local_seconds l{};
     tz.name();           // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     tz.get_info(s);      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    tz.get_info(l);      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     operator==(tz, tz);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     operator<=>(tz, tz); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   }
diff --git a/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp
new file mode 100644
index 00000000000000..6dc15974c44843
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp
@@ -0,0 +1,1302 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class time_zone;
+
+// template <class _Duration>
+//   local_info get_info(const local_time<_Duration>& time) const;
+
+// This test uses the system provided database. This makes the test portable,
+// but may cause failures when the database information changes. Historic data
+// may change if new facts are uncovered, future data may change when regions
+// change their time zone or daylight saving time. Most tests will not look in
+// the future to attempt to avoid issues. All tests list the data on which they
+// are based, this makes debugging easier upon failure; including to see whether
+// the provided data has not been changed.
+//
+// The first part of the test is manually crafted, the second part compares the
+// transitions for all time zones in the database.
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <format>
+
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+// The year range to validate. The dates used in practice are expected to be
+// inside the tested range.
+constexpr std::chrono::year first{1800};
+constexpr std::chrono::year last{2100};
+
+/***** ***** HELPERS ***** *****/
+
+[[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(
+    std::chrono::year year,
+    std::chrono::month month,
+    std::chrono::day day,
+    std::chrono::hours h   = std::chrono::hours(0),
+    std::chrono::minutes m = std::chrono::minutes{0},
+    std::chrono::seconds s = std::chrono::seconds{0}) {
+  std::chrono::year_month_day result{year, month, day};
+
+  return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result)) + h + m + s;
+}
+
+[[nodiscard]] static std::chrono::local_seconds to_local_seconds(
+    std::chrono::year year,
+    std::chrono::month month,
+    std::chrono::day day,
+    std::chrono::hours h   = std::chrono::hours(0),
+    std::chrono::minutes m = std::chrono::minutes{0},
+    std::chrono::seconds s = std::chrono::seconds{0}) {
+  std::chrono::year_month_day result{year, month, day};
+
+  return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::local_days>(result)) + h + m + s;
+}
+
+static void assert_equal(const std::chrono::sys_info& lhs, const std::chrono::sys_info& rhs) {
+  TEST_REQUIRE(lhs.begin == rhs.begin,
+               TEST_WRITE_CONCATENATED("\nBegin:\nExpected output ", lhs.begin, "\nActual output   ", rhs.begin, '\n'));
+  TEST_REQUIRE(lhs.end == rhs.end,
+               TEST_WRITE_CONCATENATED("\nEnd:\nExpected output ", lhs.end, "\nActual output   ", rhs.end, '\n'));
+  TEST_REQUIRE(
+      lhs.offset == rhs.offset,
+      TEST_WRITE_CONCATENATED("\nOffset:\nExpected output ", lhs.offset, "\nActual output   ", rhs.offset, '\n'));
+  TEST_REQUIRE(lhs.save == rhs.save,
+               TEST_WRITE_CONCATENATED("\nSave:\nExpected output ", lhs.save, "\nActual output   ", rhs.save, '\n'));
+  TEST_REQUIRE(
+      lhs.abbrev == rhs.abbrev,
+      TEST_WRITE_CONCATENATED("\nAbbrev:\nExpected output ", lhs.abbrev, "\nActual output   ", rhs.abbrev, '\n'));
+}
+
+static void assert_equal(const std::chrono::local_info& lhs, const std::chrono::local_info& rhs) {
+  TEST_REQUIRE(
+      lhs.result == rhs.result,
+      TEST_WRITE_CONCATENATED("\nResult:\nExpected output ", lhs.result, "\nActual output   ", rhs.result, '\n'));
+
+  assert_equal(lhs.first, rhs.first);
+  assert_equal(lhs.second, rhs.second);
+}
+
+/***** ***** TESTS ***** *****/
+
+static void test_gmt() {
+  // Simple zone always valid, no rule entries, lookup using a link.
+  // L Etc/GMT GMT
+  // Z Etc/GMT 0 - GMT
+
+  using namespace std::literals::chrono_literals;
+  const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");
+
+  assert_equal(
+      std::chrono::local_info(
+          std::chrono::local_info::unique,
+          std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 0s, 0min, "GMT"),
+          std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+      tz->get_info(std::chrono::local_seconds::min()));
+}
+
+static void test_local_time_out_of_range() {
+  // Fixed positive offset
+  // Etc/GMT-1 1 - +01
+
+  using namespace std::literals::chrono_literals;
+  { // lower bound
+    const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT-1");
+
+    assert_equal(
+        std::chrono::local_info(
+            -1,
+            std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
+            std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+        tz->get_info(std::chrono::local_seconds::min()));
+
+    assert_equal(
+        std::chrono::local_info(
+            -1,
+            std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
+            std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+        tz->get_info(std::chrono::local_seconds::min() + 59min + 59s));
+
+    assert_equal(
+        std::chrono::local_info(
+            std::chrono::local_info::unique,
+            std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
+            std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+        tz->get_info(std::chrono::local_seconds::min() + 1h));
+  }
+
+  { // upper bound
+    const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1");
+
+    assert_equal(
+        std::chrono::local_info(
+            -2,
+            std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), -1h, 0min, "-01"),
+            std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+        tz->get_info(std::chrono::local_seconds::max() - 1s));
+
+    assert_equal(
+        std::chrono::local_info(
+            std::chrono::local_info::unique,
+            std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), -1h, 0min, "-01"),
+            std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+        tz->get_info(std::chrono::local_seconds::max() - 1h - 1s));
+  }
+}
+
+static void test_indian_kerguelen() {
+  // One change, no rules, no dst changes.
+
+  // Z Indian/Kerguelen 0 - -00 1950
+  // 5 - +05
+
+  using namespace std::literals::chrono_literals;
+  const std::chrono::time_zone* tz = std::chrono::locate_zone("Indian/Kerguelen");
+
+  assert_equal(
+      std::chrono::local_info(
+          std::chrono::local_info::unique,
+          std::chrono::sys_info(
+              std::chrono::sys_seconds::min(), to_sys_seconds(1950y, std::chrono::January, 1d), 0s, 0min, "-00"),
+          std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+      tz->get_info(std::chrono::local_seconds::min()));
+
+  assert_equal(
+      std::chrono::local_info(
+          std::chrono::local_info::nonexistent,
+          std::chrono::sys_info(
+              std::chrono::sys_seconds::min(), to_sys_seconds(1950y, std::chrono::January, 1d), 0s, 0min, "-00"),
+          std::chrono::sys_info(
+              to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05")),
+      tz->get_info(to_local_seconds(1950y, std::chrono::January, 1d)));
+
+  assert_equal(
+      std::chrono::local_info(
+          std::chrono::local_info::unique,
+          std::chrono::sys_info(
+              to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05"),
+          std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+      tz->get_info(to_local_seconds(1950y, std::chrono::January, 1d, 5h)));
+
+  assert_equal(
+      std::chrono::local_info(
+          std::chrono::local_info::unique,
+          std::chrono::sys_info(
+              to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05"),
+          std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
+      tz->get_info(std::chrono::local_seconds::max() - 1s));
+}
+
+static void test_antarctica_rothera() {
+  // One change, no rules, no dst changes
+
+  // Z Antarctica/Rothera ...
[truncated]

@ldionne ldionne changed the title [libc++][TZDB] Implements time zone get_info(local_time). [libc++][TZDB] Implements time_zone get_info(local_time). Apr 23, 2024
@ldionne ldionne self-assigned this Apr 23, 2024
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
@mordante mordante force-pushed the users/mordante/makes_saturation_functions_available branch from 4838909 to 17f0550 Compare April 23, 2024 20:29
Base automatically changed from users/mordante/makes_saturation_functions_available to main April 24, 2024 15:42
@mordante mordante force-pushed the users/mordante/get_info_local_time branch 2 times, most recently from 827d11e to 6939905 Compare April 24, 2024 17:08
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
Implements parts of:
- P0355 Extending to Calendars and Time Zones
@mordante mordante force-pushed the users/mordante/get_info_local_time branch from 6939905 to a6b280e Compare June 9, 2024 12:26
@mordante mordante merged commit de736d9 into main Jun 9, 2024
54 of 55 checks passed
@mordante mordante deleted the users/mordante/get_info_local_time branch June 9, 2024 16:21
@zeroomega
Copy link
Contributor

We started to see flakiness in test llvm-libc++-static.cfg.in :: std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp in libcxx testing on linux-x64, after this change was landed

Exit Code: 250

Command Output (stdout):
--
# COMPILED WITH
/b/s/w/ir/x/w/llvm_build/./bin/clang++ /b/s/w/ir/x/w/llvm-llvm-project/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp -pthread --target=x86_64-unknown-linux-gnu -nostdinc++ -I /b/s/w/ir/x/w/llvm_build/include/c++/v1 -I /b/s/w/ir/x/w/llvm_build/include/x86_64-unknown-linux-gnu/c++/v1 -I /b/s/w/ir/x/w/llvm-llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings  -lc++experimental -nostdlib++ -L /b/s/w/ir/x/w/llvm_build/./lib/x86_64-unknown-linux-gnu -lc++ -lc++abi -o /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir/t.tmp.exe
# executed command: /b/s/w/ir/x/w/llvm_build/./bin/clang++ /b/s/w/ir/x/w/llvm-llvm-project/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp -pthread --target=x86_64-unknown-linux-gnu -nostdinc++ -I /b/s/w/ir/x/w/llvm_build/include/c++/v1 -I /b/s/w/ir/x/w/llvm_build/include/x86_64-unknown-linux-gnu/c++/v1 -I /b/s/w/ir/x/w/llvm-llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings -lc++experimental -nostdlib++ -L /b/s/w/ir/x/w/llvm_build/./lib/x86_64-unknown-linux-gnu -lc++ -lc++abi -o /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir/t.tmp.exe
# EXECUTED AS
/b/s/w/ir/cipd_bin_packages/cpython3/bin/python3.8 /b/s/w/ir/x/w/llvm-llvm-project/libcxx/utils/run.py --execdir /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir --  /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir/t.tmp.exe
# executed command: /b/s/w/ir/cipd_bin_packages/cpython3/bin/python3.8 /b/s/w/ir/x/w/llvm-llvm-project/libcxx/utils/run.py --execdir /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir -- /b/s/w/ir/x/w/llvm_build/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.local_time.pass.cpp.dir/t.tmp.exe
# .---command stderr------------
# | Assertion failure: lhs.end == rhs.end /b/s/w/ir/x/w/llvm-llvm-project/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp 77
# | 
# | End:
# | Expected output 1880-08-02 00:25:21
# | Actual output   1880-08-02 00:25:00
# `-----------------------------
# error: command failed with exit status: 250

Failed build task: https://ci.chromium.org/ui/p/fuchsia/builders/toolchain.ci/clang-linux-x64/b8745592240286102897/overview

This test fails about 1 in 3 runs, randomly after this PR was landed.
Could you take a look please?

@vvereschaka
Copy link
Contributor

We got the same test failure on Amrv7 Win-to-Linux cross builder
https://lab.llvm.org/buildbot/#/builders/60/builds/17468

llvm-libc++-static.cfg.in :: std/time/time.zone/time.zone.timezone/time.zone.members/get_info.local_time.pass.cpp

"C:/Python310/python.exe" "C:/buildbot/as-builder-1/x-armv7l/llvm-project/libcxx/utils/ssh.py" --host=ubuntu@jetson6.lab.llvm.org --execdir C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\time\time.zone\time.zone.timezone\time.zone.members\Output\get_info.local_time.pass.cpp.dir --  C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\time\time.zone\time.zone.timezone\time.zone.members\Output\get_info.local_time.pass.cpp.dir\t.tmp.exe
# executed command: C:/Python310/python.exe C:/buildbot/as-builder-1/x-armv7l/llvm-project/libcxx/utils/ssh.py --host=ubuntu@jetson6.lab.llvm.org --execdir 'C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\time\time.zone\time.zone.timezone\time.zone.members\Output\get_info.local_time.pass.cpp.dir' -- 'C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\time\time.zone\time.zone.timezone\time.zone.members\Output\get_info.local_time.pass.cpp.dir\t.tmp.exe'
# .---command stderr------------
# | Assertion failure: lhs.result == rhs.result C:\buildbot\as-builder-1\x-armv7l\llvm-project\libcxx\test\std\time\time.zone\time.zone.timezone\time.zone.members\get_info.local_time.pass.cpp 91
# | 
# | Result:
# | Expected output 0
# | Actual output   -1
# `-----------------------------
# error: command failed with exit status: 255

The target system is Ubuntu 18.04.6 LTS (armv7l).

@vitalybuka
Copy link
Collaborator

vitalybuka commented Jun 10, 2024

Also here https://lab.llvm.org/buildbot/#/builders/236/builds/11695

Test was disabled with 503fb1a by @fmayer

@vitalybuka
Copy link
Collaborator

vitalybuka commented Jun 10, 2024

Also here https://lab.llvm.org/buildbot/#/builders/236/builds/11695

Test was disabled with 503fb1a by @fmayer

@fmayer do you know the reason why it hangs?
If not, maybe the correct approach is to revert this patch and investigate. hwasan+libc++ users may hit this issue in their programs.

@fmayer
Copy link
Contributor

fmayer commented Jun 10, 2024

@fmayer do you know the reason why it hangs? If not, maybe correct approach revert this patch and investigate. Downstream hwasan+libc++ users may hit in own programs.

I don't, revert SGTM

@ilovepi
Copy link
Contributor

ilovepi commented Jun 10, 2024

@mordante do you think this could be related to #89629? I'm just catching up on this, so I'm not sure yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants