diff options
-rw-r--r-- | CMake/AbseilDll.cmake | 2 | ||||
-rw-r--r-- | absl/base/internal/unscaledcycleclock.cc | 5 | ||||
-rw-r--r-- | absl/flags/internal/usage.cc | 11 | ||||
-rw-r--r-- | absl/flags/internal/usage_test.cc | 63 | ||||
-rw-r--r-- | absl/numeric/int128_have_intrinsic.inc | 3 | ||||
-rw-r--r-- | absl/status/CMakeLists.txt | 2 | ||||
-rw-r--r-- | absl/strings/BUILD.bazel | 12 | ||||
-rw-r--r-- | absl/strings/CMakeLists.txt | 14 | ||||
-rw-r--r-- | absl/strings/char_formatting_test.cc | 189 | ||||
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_if.cc | 2 | ||||
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_libc.cc | 61 | ||||
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_lookup.cc | 11 | ||||
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_lookup_test.cc | 21 |
13 files changed, 332 insertions, 64 deletions
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 624a9c99..b64f133c 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -815,6 +815,6 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - + add_library(absl::${_dll} ALIAS ${_dll}) endfunction() diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index b1c396c6..05e0e7ba 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc @@ -71,13 +71,12 @@ int64_t UnscaledCycleClock::Now() { #else int32_t tbu, tbl, tmp; asm volatile( - "0:\n" "mftbu %[hi32]\n" "mftb %[lo32]\n" "mftbu %[tmp]\n" "cmpw %[tmp],%[hi32]\n" - "bne 0b\n" - : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp)); + "bne $-16\n" // Retry on failure. + : [hi32] "=r"(tbu), [lo32] "=r"(tbl), [tmp] "=r"(tmp)); return (static_cast<int64_t>(tbu) << 32) | tbl; #endif #endif diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index 6a56fce9..13852e14 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -92,8 +92,16 @@ class XMLElement { case '>': out << ">"; break; + case '\n': + case '\v': + case '\f': + case '\t': + out << " "; + break; default: - out << c; + if (IsValidXmlCharacter(static_cast<unsigned char>(c))) { + out << c; + } break; } } @@ -102,6 +110,7 @@ class XMLElement { } private: + static bool IsValidXmlCharacter(unsigned char c) { return c >= 0x20; } absl::string_view tag_; absl::string_view txt_; }; diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc index c3ab4a42..6847386f 100644 --- a/absl/flags/internal/usage_test.cc +++ b/absl/flags/internal/usage_test.cc @@ -39,6 +39,8 @@ ABSL_FLAG(double, usage_reporting_test_flag_03, 1.03, "usage_reporting_test_flag_03 help message"); ABSL_FLAG(int64_t, usage_reporting_test_flag_04, 1000000000000004L, "usage_reporting_test_flag_04 help message"); +ABSL_FLAG(std::string, usage_reporting_test_flag_07, "\r\n\f\v\a\b\t ", + "usage_reporting_test_flag_07 help \r\n\f\v\a\b\t "); static const char kTestUsageMessage[] = "Custom usage message"; @@ -203,8 +205,12 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -267,8 +273,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kShort); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -285,8 +292,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -301,8 +312,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kImportant); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -319,8 +331,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -361,8 +377,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kMatch); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -379,8 +396,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -395,8 +416,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kPackage); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -413,8 +435,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -471,8 +497,9 @@ path. std::stringstream test_buf_02; EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), flags::HelpMode::kMatch); - EXPECT_EQ(test_buf_02.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf_02.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -489,8 +516,12 @@ path. Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index 3945fa29..6f1ac644 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc @@ -162,9 +162,6 @@ inline int128::operator long double() const { } #else // Clang on PowerPC -// Forward declaration for conversion operators to floating point types. -constexpr int128 operator-(int128 v); -constexpr bool operator!=(int128 lhs, int128 rhs); inline int128::operator float() const { // We must convert the absolute value and then negate as needed, because diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index 15db36af..4a3c5d68 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -25,6 +25,8 @@ absl_cc_library( "status_payload_printer.cc" COPTS ${ABSL_DEFAULT_COPTS} + DEFINES + "$<$<PLATFORM_ID:AIX>:_LINUX_SOURCE_COMPAT>" DEPS absl::atomic_hook absl::config diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index bd33c533..4a111b5a 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -1319,3 +1319,15 @@ cc_binary( "//absl/types:optional", ], ) + +cc_test( + name = "char_formatting_test", + srcs = [ + "char_formatting_test.cc", + ], + deps = [ + ":str_format", + ":strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 9aaa7932..2ad052a3 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -548,6 +548,20 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_test( + NAME + char_formatting_test + SRCS + "char_formatting_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::str_format + absl::strings + GTest::gmock_main +) + # Internal-only target, do not depend on directly. absl_cc_library( NAME diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc new file mode 100644 index 00000000..60416af3 --- /dev/null +++ b/absl/strings/char_formatting_test.cc @@ -0,0 +1,189 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cstddef> + +#include "gtest/gtest.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/substitute.h" + +namespace { + +TEST(CharFormatting, Char) { + const char v = 'A'; + + // Desired behavior: does not compile: + // EXPECT_EQ(absl::StrCat(v, "B"), "AB"); + // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + + // Legacy behavior: format as char: + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +} + +enum CharEnum : char {}; +TEST(CharFormatting, CharEnum) { + auto v = static_cast<CharEnum>('A'); + + // Desired behavior: format as decimal + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + + // Legacy behavior: format as character: + + // Some older versions of gcc behave differently in this one case. +#if !defined(__GNUC__) || defined(__clang__) + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +#endif +} + +enum class CharEnumClass: char {}; +TEST(CharFormatting, CharEnumClass) { + auto v = static_cast<CharEnumClass>('A'); + + // Desired behavior: format as decimal + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + + // Legacy behavior: format as character: + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +} + +TEST(CharFormatting, UnsignedChar) { + const unsigned char v = 'A'; + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + + // Signedness check + const unsigned char w = 255; + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + // EXPECT_EQ(absl::StrFormat("%vB", v), "255B"); +} + +TEST(CharFormatting, SignedChar) { + const signed char v = 'A'; + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + + // Signedness check + const signed char w = -128; + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +enum UnsignedCharEnum : unsigned char {}; +TEST(CharFormatting, UnsignedCharEnum) { + auto v = static_cast<UnsignedCharEnum>('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast<UnsignedCharEnum>(255); + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); +} + +enum SignedCharEnum : signed char {}; +TEST(CharFormatting, SignedCharEnum) { + auto v = static_cast<SignedCharEnum>('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast<SignedCharEnum>(-128); + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +enum class UnsignedCharEnumClass : unsigned char {}; +TEST(CharFormatting, UnsignedCharEnumClass) { + auto v = static_cast<UnsignedCharEnumClass>('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast<UnsignedCharEnumClass>(255); + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); +} + +enum SignedCharEnumClass : signed char {}; +TEST(CharFormatting, SignedCharEnumClass) { + auto v = static_cast<SignedCharEnumClass>('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast<SignedCharEnumClass>(-128); + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +#ifdef __cpp_lib_byte +TEST(CharFormatting, StdByte) { + auto v = static_cast<std::byte>('A'); + // Desired behavior: format as 0xff + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); +} +#endif // _cpp_lib_byte + +} // namespace diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 0319b2f9..1d44dde7 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc @@ -26,6 +26,8 @@ namespace cctz { std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) { // Support "libc:localtime" and "libc:*" to access the legacy // localtime and UTC support respectively from the C library. + // NOTE: The "libc:*" zones are internal, test-only interfaces, and + // are subject to change/removal without notice. Do not use them. if (name.compare(0, 5, "libc:") == 0) { return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5))); } diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index 887dd097..af9f063e 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) { #endif } -// Converts a civil second and "dst" flag into a time_t and UTC offset. +// Converts a civil second and "dst" flag into a time_t and a struct tm. // Returns false if time_t cannot represent the requested civil second. // Caller must have already checked that cs.year() will fit into a tm_year. -bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) { - std::tm tm; - tm.tm_year = static_cast<int>(cs.year() - year_t{1900}); - tm.tm_mon = cs.month() - 1; - tm.tm_mday = cs.day(); - tm.tm_hour = cs.hour(); - tm.tm_min = cs.minute(); - tm.tm_sec = cs.second(); - tm.tm_isdst = is_dst; - *t = std::mktime(&tm); +bool make_time(const civil_second& cs, int is_dst, std::time_t* t, + std::tm* tm) { + tm->tm_year = static_cast<int>(cs.year() - year_t{1900}); + tm->tm_mon = cs.month() - 1; + tm->tm_mday = cs.day(); + tm->tm_hour = cs.hour(); + tm->tm_min = cs.minute(); + tm->tm_sec = cs.second(); + tm->tm_isdst = is_dst; + *t = std::mktime(tm); if (*t == std::time_t{-1}) { std::tm tm2; const std::tm* tmp = local_time(t, &tm2); - if (tmp == nullptr || tmp->tm_year != tm.tm_year || - tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday || - tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min || - tmp->tm_sec != tm.tm_sec) { + if (tmp == nullptr || tmp->tm_year != tm->tm_year || + tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday || + tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min || + tmp->tm_sec != tm->tm_sec) { // A true error (not just one second before the epoch). return false; } } - *off = static_cast<int>(tm_gmtoff(tm)); return true; } @@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { // We probe with "is_dst" values of 0 and 1 to try to distinguish unique // civil seconds from skipped or repeated ones. This is not always possible // however, as the "dst" flag does not change over some offset transitions. - // We are also subject to the vagaries of mktime() implementations. + // We are also subject to the vagaries of mktime() implementations. For + // example, some implementations treat "tm_isdst" as a demand (useless), + // and some as a disambiguator (useful). std::time_t t0, t1; - int offset0, offset1; - if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) { - if (t0 == t1) { + std::tm tm0, tm1; + if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) { + if (tm0.tm_isdst == tm1.tm_isdst) { // The civil time was singular (pre == trans == post). - const time_point<seconds> tp = FromUnixSeconds(t0); + const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0); return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } - if (t0 > t1) { + int offset = tm_gmtoff(tm0); + if (t0 < t1) { // negative DST std::swap(t0, t1); - std::swap(offset0, offset1); + offset = tm_gmtoff(tm1); } - const std::time_t tt = find_trans(t0, t1, offset1); + + const std::time_t tt = find_trans(t1, t0, offset); const time_point<seconds> trans = FromUnixSeconds(tt); - if (offset0 < offset1) { + if (tm0.tm_isdst) { // The civil time did not exist (pre >= trans > post). - const time_point<seconds> pre = FromUnixSeconds(t1); - const time_point<seconds> post = FromUnixSeconds(t0); + const time_point<seconds> pre = FromUnixSeconds(t0); + const time_point<seconds> post = FromUnixSeconds(t1); return {time_zone::civil_lookup::SKIPPED, pre, trans, post}; } // The civil time was ambiguous (pre < trans <= post). - const time_point<seconds> pre = FromUnixSeconds(t0); - const time_point<seconds> post = FromUnixSeconds(t1); + const time_point<seconds> pre = FromUnixSeconds(t1); + const time_point<seconds> post = FromUnixSeconds(t0); return {time_zone::civil_lookup::REPEATED, pre, trans, post}; } diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index 68084ce2..9a30ba5e 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -148,11 +148,12 @@ std::string win32_local_time_zone(const HMODULE combase) { UINT32 wlen; const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen); if (tz_wstr) { - const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr, - 0, nullptr, nullptr); - result.resize(size); - WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr, - nullptr); + const int size = + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen), + nullptr, 0, nullptr, nullptr); + result.resize(static_cast<size_t>(size)); + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen), + &result[0], size, nullptr, nullptr); } windows_delete_string(tz_hstr); } diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 4b093b37..38f10f48 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -1034,16 +1034,16 @@ TEST(MakeTime, SysSecondsLimits) { const time_zone cut = LoadZone("libc:UTC"); const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900; tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut); -#if defined(__FreeBSD__) || defined(__OpenBSD__) - // The BSD gmtime_r() fails on extreme positive tm_year values. +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) + // Some gmtime_r() impls fail on extreme positive values. #else EXPECT_EQ("2147485547-12-31T23:59:59+00:00", absl::time_internal::cctz::format(RFC3339, tp, cut)); #endif const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900; tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut); -#if defined(__Fuchsia__) - // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527). +#if defined(__Fuchsia__) || defined(__EMSCRIPTEN__) + // Some gmtime_r() impls fail on extreme negative values (fxbug.dev/78527). #else EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", absl::time_internal::cctz::format(RFC3339, tp, cut)); @@ -1072,7 +1072,7 @@ TEST(MakeTime, LocalTimeLibC) { tp = zi.lookup(transition.to).trans) { const auto fcl = zi.lookup(transition.from); const auto tcl = zi.lookup(transition.to); - civil_second cs; // compare cs in zi and lc + civil_second cs, us; // compare cs and us in zi and lc if (fcl.kind == time_zone::civil_lookup::UNIQUE) { if (tcl.kind == time_zone::civil_lookup::UNIQUE) { // Both unique; must be an is_dst or abbr change. @@ -1088,12 +1088,14 @@ TEST(MakeTime, LocalTimeLibC) { } ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind); cs = transition.to; + us = transition.from; } else { ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind); ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind); cs = transition.from; + us = transition.to; } - if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t) + if (us.year() > 2037) break; // limit test time (and to 32-bit time_t) const auto cl_zi = zi.lookup(cs); if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) { // The "libc" implementation cannot correctly classify transitions @@ -1125,6 +1127,13 @@ TEST(MakeTime, LocalTimeLibC) { EXPECT_EQ(cl_zi.pre, cl_lc.pre); EXPECT_EQ(cl_zi.trans, cl_lc.trans); EXPECT_EQ(cl_zi.post, cl_lc.post); + const auto ucl_zi = zi.lookup(us); + const auto ucl_lc = lc.lookup(us); + SCOPED_TRACE(testing::Message() << "For " << us << " in " << *np); + EXPECT_EQ(ucl_zi.kind, ucl_lc.kind); + EXPECT_EQ(ucl_zi.pre, ucl_lc.pre); + EXPECT_EQ(ucl_zi.trans, ucl_lc.trans); + EXPECT_EQ(ucl_zi.post, ucl_lc.post); } } if (ep == nullptr) { |