diff options
| -rw-r--r-- | meta/recipes-devtools/gcc/gcc-14.2.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch | 549 |
2 files changed, 550 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-14.2.inc b/meta/recipes-devtools/gcc/gcc-14.2.inc index f05484cfc0..9cfb246294 100644 --- a/meta/recipes-devtools/gcc/gcc-14.2.inc +++ b/meta/recipes-devtools/gcc/gcc-14.2.inc | |||
| @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ | |||
| 68 | file://0023-Fix-install-path-of-linux64.h.patch \ | 68 | file://0023-Fix-install-path-of-linux64.h.patch \ |
| 69 | file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ | 69 | file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ |
| 70 | file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ | 70 | file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ |
| 71 | file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ | ||
| 71 | " | 72 | " |
| 72 | 73 | ||
| 73 | S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" | 74 | S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" |
diff --git a/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch new file mode 100644 index 0000000000..e5abdcc703 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch | |||
| @@ -0,0 +1,549 @@ | |||
| 1 | From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jonathan Wakely <jwakely@redhat.com> | ||
| 3 | Date: Tue, 30 Apr 2024 09:52:13 +0100 | ||
| 4 | Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard format | ||
| 5 | |||
| 6 | I found some issues in the std::chrono::tzdb parser by testing the | ||
| 7 | tzdata "vanguard" format, which uses new features that aren't enabled in | ||
| 8 | the "main" and "rearguard" data formats. | ||
| 9 | |||
| 10 | Since 2024a the keyword "minimum" is no longer valid for the FROM and TO | ||
| 11 | fields in a Rule line, which means that "m" is now a valid abbreviation | ||
| 12 | for "maximum". Previously we expected either "mi" or "ma". For backwards | ||
| 13 | compatibility, a FROM field beginning with "mi" is still supported and | ||
| 14 | is treated as 1900. The "maximum" keyword is only allowed in TO now, | ||
| 15 | because it makes no sense in FROM. To support these changes the | ||
| 16 | minmax_year and minmax_year2 classes for parsing FROM and TO are | ||
| 17 | replaced with a single years_from_to class that reads both fields. | ||
| 18 | |||
| 19 | The vanguard format makes use of %z in Zone FORMAT fields, which caused | ||
| 20 | an exception to be thrown from ZoneInfo::set_abbrev because no % or / | ||
| 21 | characters were expected when a Zone doesn't use a named Rule. The | ||
| 22 | ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace | ||
| 23 | any %z with the current offset. Although format_abbrev_str also checks | ||
| 24 | for %s and STD/DST formats, those only make sense when a named Rule is | ||
| 25 | in effect, so won't occur when ZoneInfo::to(sys_info&) is used. | ||
| 26 | |||
| 27 | Since making this change on trunk, the tzdata-2024b release started | ||
| 28 | using %z in the main format, not just vanguard. This makes a backport to | ||
| 29 | release branches necessary (see PR 116657). | ||
| 30 | |||
| 31 | This change also implements a feature that has always been missing from | ||
| 32 | time_zone::_M_get_sys_info: finding the Rule that is active before the | ||
| 33 | specified time point, so that we can correctly handle %s in the FORMAT | ||
| 34 | for the first new sys_info that gets created. This requires implementing | ||
| 35 | a poorly documented feature of zic, to get the LETTERS field from a | ||
| 36 | later transition, as described at | ||
| 37 | https://mm.icann.org/pipermail/tz/2024-April/058891.html | ||
| 38 | In order for this to work we need to be able to distinguish an empty | ||
| 39 | letters field (as used by CE%sT where the variable part is either empty | ||
| 40 | or "S") from "the letters field is not known for this transition". The | ||
| 41 | tzdata file uses "-" for an empty letters field, which libstdc++ was | ||
| 42 | previously replacing with "" when the Rule was parsed. Instead, we now | ||
| 43 | preserve the "-" in the Rule object, so that "" can be used for the case | ||
| 44 | where we don't know the letters (and so need to decide it). | ||
| 45 | |||
| 46 | (cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) | ||
| 47 | |||
| 48 | Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9] | ||
| 49 | |||
| 50 | Signed-off-by: Markus Volk <f_l_k@t-online.de> | ||
| 51 | --- | ||
| 52 | libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- | ||
| 53 | .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ | ||
| 54 | libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- | ||
| 55 | 3 files changed, 274 insertions(+), 103 deletions(-) | ||
| 56 | create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc | ||
| 57 | |||
| 58 | diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc | ||
| 59 | index c7c7cc9deee6..7e8cce7ce8cf 100644 | ||
| 60 | --- a/libstdc++-v3/src/c++20/tzdb.cc | ||
| 61 | +++ b/libstdc++-v3/src/c++20/tzdb.cc | ||
| 62 | @@ -342,51 +342,103 @@ namespace std::chrono | ||
| 63 | friend istream& operator>>(istream&, on_day&); | ||
| 64 | }; | ||
| 65 | |||
| 66 | - // Wrapper for chrono::year that reads a year, or one of the keywords | ||
| 67 | - // "minimum" or "maximum", or an unambiguous prefix of a keyword. | ||
| 68 | - struct minmax_year | ||
| 69 | + // Wrapper for two chrono::year values, which reads the FROM and TO | ||
| 70 | + // fields of a Rule line. The FROM field is a year and TO is a year or | ||
| 71 | + // one of the keywords "maximum" or "only" (or an abbreviation of those). | ||
| 72 | + // For backwards compatibility, the keyword "minimum" is recognized | ||
| 73 | + // for FROM and interpreted as 1900. | ||
| 74 | + struct years_from_to | ||
| 75 | { | ||
| 76 | - year& y; | ||
| 77 | + year& from; | ||
| 78 | + year& to; | ||
| 79 | |||
| 80 | - friend istream& operator>>(istream& in, minmax_year&& y) | ||
| 81 | + friend istream& operator>>(istream& in, years_from_to&& yy) | ||
| 82 | { | ||
| 83 | - if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" | ||
| 84 | + string s; | ||
| 85 | + auto c = ws(in).peek(); | ||
| 86 | + if (c == 'm') [[unlikely]] // keyword "minimum" | ||
| 87 | { | ||
| 88 | - string s; | ||
| 89 | - in >> s; // extract the rest of the word, but only look at s[1] | ||
| 90 | - if (s[1] == 'a') | ||
| 91 | - y.y = year::max(); | ||
| 92 | - else if (s[1] == 'i') | ||
| 93 | - y.y = year::min(); | ||
| 94 | - else | ||
| 95 | - in.setstate(ios::failbit); | ||
| 96 | + in >> s; // extract the rest of the word | ||
| 97 | + yy.from = year(1900); | ||
| 98 | + } | ||
| 99 | + else if (int num = 0; in >> num) [[likely]] | ||
| 100 | + yy.from = year{num}; | ||
| 101 | + | ||
| 102 | + c = ws(in).peek(); | ||
| 103 | + if (c == 'm') // keyword "maximum" | ||
| 104 | + { | ||
| 105 | + in >> s; // extract the rest of the word | ||
| 106 | + yy.to = year::max(); | ||
| 107 | + } | ||
| 108 | + else if (c == 'o') // keyword "only" | ||
| 109 | + { | ||
| 110 | + in >> s; // extract the rest of the word | ||
| 111 | + yy.to = yy.from; | ||
| 112 | } | ||
| 113 | else if (int num = 0; in >> num) | ||
| 114 | - y.y = year{num}; | ||
| 115 | + yy.to = year{num}; | ||
| 116 | + | ||
| 117 | return in; | ||
| 118 | } | ||
| 119 | }; | ||
| 120 | |||
| 121 | - // As above for minmax_year, but also supports the keyword "only", | ||
| 122 | - // meaning that the TO year is the same as the FROM year. | ||
| 123 | - struct minmax_year2 | ||
| 124 | + bool | ||
| 125 | + select_std_or_dst_abbrev(string& abbrev, minutes save) | ||
| 126 | { | ||
| 127 | - minmax_year to; | ||
| 128 | - year from; | ||
| 129 | + if (size_t pos = abbrev.find('/'); pos != string::npos) | ||
| 130 | + { | ||
| 131 | + // Select one of "STD/DST" for standard or daylight. | ||
| 132 | + if (save == 0min) | ||
| 133 | + abbrev.erase(pos); | ||
| 134 | + else | ||
| 135 | + abbrev.erase(0, pos + 1); | ||
| 136 | + return true; | ||
| 137 | + } | ||
| 138 | + return false; | ||
| 139 | + } | ||
| 140 | |||
| 141 | - friend istream& operator>>(istream& in, minmax_year2&& y) | ||
| 142 | - { | ||
| 143 | - if (ws(in).peek() == 'o') // keyword "only" | ||
| 144 | - { | ||
| 145 | - string s; | ||
| 146 | - in >> s; // extract the whole keyword | ||
| 147 | - y.to.y = y.from; | ||
| 148 | - } | ||
| 149 | - else | ||
| 150 | - in >> std::move(y.to); | ||
| 151 | - return in; | ||
| 152 | - } | ||
| 153 | - }; | ||
| 154 | + // Set the sys_info::abbrev string by expanding any placeholders. | ||
| 155 | + void | ||
| 156 | + format_abbrev_str(sys_info& info, string_view letters = {}) | ||
| 157 | + { | ||
| 158 | + if (size_t pos = info.abbrev.find('%'); pos != string::npos) | ||
| 159 | + { | ||
| 160 | + if (info.abbrev[pos + 1] == 's') | ||
| 161 | + { | ||
| 162 | + // Expand "%s" to the variable part, given by Rule::letters. | ||
| 163 | + if (letters == "-") | ||
| 164 | + info.abbrev.erase(pos, 2); | ||
| 165 | + else | ||
| 166 | + info.abbrev.replace(pos, 2, letters); | ||
| 167 | + } | ||
| 168 | + else if (info.abbrev[pos + 1] == 'z') | ||
| 169 | + { | ||
| 170 | + // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. | ||
| 171 | + hh_mm_ss<seconds> t(info.offset); | ||
| 172 | + string z(1, "+-"[t.is_negative()]); | ||
| 173 | + long val = t.hours().count(); | ||
| 174 | + int digits = 2; | ||
| 175 | + if (int m = t.minutes().count()) | ||
| 176 | + { | ||
| 177 | + digits = 4; | ||
| 178 | + val *= 100; | ||
| 179 | + val += m; | ||
| 180 | + if (int s = t.seconds().count()) | ||
| 181 | + { | ||
| 182 | + digits = 6; | ||
| 183 | + val *= 100; | ||
| 184 | + val += s; | ||
| 185 | + } | ||
| 186 | + } | ||
| 187 | + auto sval = std::to_string(val); | ||
| 188 | + z += string(digits - sval.size(), '0'); | ||
| 189 | + z += sval; | ||
| 190 | + info.abbrev.replace(pos, 2, z); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + else | ||
| 194 | + select_std_or_dst_abbrev(info.abbrev, info.save); | ||
| 195 | + } | ||
| 196 | |||
| 197 | // A time zone information record. | ||
| 198 | // Zone NAME STDOFF RULES FORMAT [UNTIL] | ||
| 199 | @@ -462,6 +514,7 @@ namespace std::chrono | ||
| 200 | info.offset = offset(); | ||
| 201 | info.save = minutes(m_save); | ||
| 202 | info.abbrev = format(); | ||
| 203 | + format_abbrev_str(info); // expand %z | ||
| 204 | return true; | ||
| 205 | } | ||
| 206 | |||
| 207 | @@ -469,12 +522,9 @@ namespace std::chrono | ||
| 208 | friend class time_zone; | ||
| 209 | |||
| 210 | void | ||
| 211 | - set_abbrev(const string& abbrev) | ||
| 212 | + set_abbrev(string abbrev) | ||
| 213 | { | ||
| 214 | - // In practice, the FORMAT field never needs expanding here. | ||
| 215 | - if (abbrev.find_first_of("/%") != abbrev.npos) | ||
| 216 | - __throw_runtime_error("std::chrono::time_zone: invalid data"); | ||
| 217 | - m_buf = abbrev; | ||
| 218 | + m_buf = std::move(abbrev); | ||
| 219 | m_pos = 0; | ||
| 220 | m_expanded = true; | ||
| 221 | } | ||
| 222 | @@ -544,9 +594,7 @@ namespace std::chrono | ||
| 223 | |||
| 224 | // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S | ||
| 225 | |||
| 226 | - in >> quoted(rule.name) | ||
| 227 | - >> minmax_year{rule.from} | ||
| 228 | - >> minmax_year2{rule.to, rule.from}; | ||
| 229 | + in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; | ||
| 230 | |||
| 231 | if (char type; in >> type && type != '-') | ||
| 232 | in.setstate(ios::failbit); | ||
| 233 | @@ -557,7 +605,7 @@ namespace std::chrono | ||
| 234 | if (save_time.indicator != at_time::Wall) | ||
| 235 | { | ||
| 236 | // We don't actually store the save_time.indicator, because we | ||
| 237 | - // assume that it's always deducable from the actual offset value. | ||
| 238 | + // assume that it's always deducible from the offset value. | ||
| 239 | auto expected = save_time.time == 0s | ||
| 240 | ? at_time::Standard | ||
| 241 | : at_time::Daylight; | ||
| 242 | @@ -567,8 +615,6 @@ namespace std::chrono | ||
| 243 | rule.save = save_time.time; | ||
| 244 | |||
| 245 | in >> rule.letters; | ||
| 246 | - if (rule.letters == "-") | ||
| 247 | - rule.letters.clear(); | ||
| 248 | return in; | ||
| 249 | } | ||
| 250 | |||
| 251 | @@ -719,58 +765,6 @@ namespace std::chrono | ||
| 252 | #endif // TZDB_DISABLED | ||
| 253 | }; | ||
| 254 | |||
| 255 | -#ifndef TZDB_DISABLED | ||
| 256 | - namespace | ||
| 257 | - { | ||
| 258 | - bool | ||
| 259 | - select_std_or_dst_abbrev(string& abbrev, minutes save) | ||
| 260 | - { | ||
| 261 | - if (size_t pos = abbrev.find('/'); pos != string::npos) | ||
| 262 | - { | ||
| 263 | - // Select one of "STD/DST" for standard or daylight. | ||
| 264 | - if (save == 0min) | ||
| 265 | - abbrev.erase(pos); | ||
| 266 | - else | ||
| 267 | - abbrev.erase(0, pos + 1); | ||
| 268 | - return true; | ||
| 269 | - } | ||
| 270 | - return false; | ||
| 271 | - } | ||
| 272 | - | ||
| 273 | - // Set the sys_info::abbrev string by expanding any placeholders. | ||
| 274 | - void | ||
| 275 | - format_abbrev_str(sys_info& info, string_view letters = {}) | ||
| 276 | - { | ||
| 277 | - if (size_t pos = info.abbrev.find("%s"); pos != string::npos) | ||
| 278 | - { | ||
| 279 | - // Expand "%s" to the variable part, given by Rule::letters. | ||
| 280 | - info.abbrev.replace(pos, 2, letters); | ||
| 281 | - } | ||
| 282 | - else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) | ||
| 283 | - { | ||
| 284 | - // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. | ||
| 285 | - hh_mm_ss<seconds> t(info.offset); | ||
| 286 | - string z(1, "+-"[t.is_negative()]); | ||
| 287 | - long val = t.hours().count(); | ||
| 288 | - if (minutes m = t.minutes(); m != m.zero()) | ||
| 289 | - { | ||
| 290 | - val *= 100; | ||
| 291 | - val += m.count(); | ||
| 292 | - if (seconds s = t.seconds(); s != s.zero()) | ||
| 293 | - { | ||
| 294 | - val *= 100; | ||
| 295 | - val += s.count(); | ||
| 296 | - } | ||
| 297 | - } | ||
| 298 | - z += std::to_string(val); | ||
| 299 | - info.abbrev.replace(pos, 2, z); | ||
| 300 | - } | ||
| 301 | - else | ||
| 302 | - select_std_or_dst_abbrev(info.abbrev, info.save); | ||
| 303 | - } | ||
| 304 | - } | ||
| 305 | -#endif // TZDB_DISABLED | ||
| 306 | - | ||
| 307 | // Implementation of std::chrono::time_zone::get_info(const sys_time<D>&) | ||
| 308 | sys_info | ||
| 309 | time_zone::_M_get_sys_info(sys_seconds tp) const | ||
| 310 | @@ -839,12 +833,72 @@ namespace std::chrono | ||
| 311 | info.abbrev = ri.format(); | ||
| 312 | |||
| 313 | string_view letters; | ||
| 314 | - if (i != infos.begin()) | ||
| 315 | + if (i != infos.begin() && i[-1].expanded()) | ||
| 316 | + letters = i[-1].next_letters(); | ||
| 317 | + | ||
| 318 | + if (letters.empty()) | ||
| 319 | { | ||
| 320 | - if (i[-1].expanded()) | ||
| 321 | - letters = i[-1].next_letters(); | ||
| 322 | - // XXX else need to find Rule active before this time and use it | ||
| 323 | - // to know the initial offset, save, and letters. | ||
| 324 | + sys_seconds t = info.begin - seconds(1); | ||
| 325 | + const year_month_day date(chrono::floor<days>(t)); | ||
| 326 | + | ||
| 327 | + // Try to find a Rule active before this time, to get initial | ||
| 328 | + // SAVE and LETTERS values. There may not be a Rule for the period | ||
| 329 | + // before the first DST transition, so find the earliest DST->STD | ||
| 330 | + // transition and use the LETTERS from that. | ||
| 331 | + const Rule* active_rule = nullptr; | ||
| 332 | + sys_seconds active_rule_start = sys_seconds::min(); | ||
| 333 | + const Rule* first_std = nullptr; | ||
| 334 | + for (const auto& rule : rules) | ||
| 335 | + { | ||
| 336 | + if (rule.save == minutes(0)) | ||
| 337 | + { | ||
| 338 | + if (!first_std) | ||
| 339 | + first_std = &rule; | ||
| 340 | + else if (rule.from < first_std->from) | ||
| 341 | + first_std = &rule; | ||
| 342 | + else if (rule.from == first_std->from) | ||
| 343 | + { | ||
| 344 | + if (rule.start_time(rule.from, {}) | ||
| 345 | + < first_std->start_time(first_std->from, {})) | ||
| 346 | + first_std = &rule; | ||
| 347 | + } | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + year y = date.year(); | ||
| 351 | + | ||
| 352 | + if (y > rule.to) // rule no longer applies at time t | ||
| 353 | + continue; | ||
| 354 | + if (y < rule.from) // rule doesn't apply yet at time t | ||
| 355 | + continue; | ||
| 356 | + | ||
| 357 | + sys_seconds rule_start; | ||
| 358 | + | ||
| 359 | + seconds offset{}; // appropriate for at_time::Universal | ||
| 360 | + if (rule.when.indicator == at_time::Wall) | ||
| 361 | + offset = info.offset; | ||
| 362 | + else if (rule.when.indicator == at_time::Standard) | ||
| 363 | + offset = ri.offset(); | ||
| 364 | + | ||
| 365 | + // Time the rule takes effect this year: | ||
| 366 | + rule_start = rule.start_time(y, offset); | ||
| 367 | + | ||
| 368 | + if (rule_start >= t && rule.from < y) | ||
| 369 | + { | ||
| 370 | + // Try this rule in the previous year. | ||
| 371 | + rule_start = rule.start_time(--y, offset); | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + if (active_rule_start < rule_start && rule_start < t) | ||
| 375 | + { | ||
| 376 | + active_rule_start = rule_start; | ||
| 377 | + active_rule = &rule; | ||
| 378 | + } | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + if (active_rule) | ||
| 382 | + letters = active_rule->letters; | ||
| 383 | + else if (first_std) | ||
| 384 | + letters = first_std->letters; | ||
| 385 | } | ||
| 386 | |||
| 387 | const Rule* curr_rule = nullptr; | ||
| 388 | @@ -2069,9 +2123,11 @@ namespace std::chrono | ||
| 389 | istringstream in2(std::move(rules)); | ||
| 390 | in2 >> rules_time; | ||
| 391 | inf.m_save = duration_cast<minutes>(rules_time.time); | ||
| 392 | + // If the FORMAT is "STD/DST" then we can choose the right one | ||
| 393 | + // now, so that we store a shorter string. | ||
| 394 | select_std_or_dst_abbrev(fmt, inf.m_save); | ||
| 395 | } | ||
| 396 | - inf.set_abbrev(fmt); | ||
| 397 | + inf.set_abbrev(std::move(fmt)); | ||
| 398 | } | ||
| 399 | |||
| 400 | // YEAR [MONTH [DAY [TIME]]] | ||
| 401 | @@ -2082,7 +2138,12 @@ namespace std::chrono | ||
| 402 | abbrev_month m{January}; | ||
| 403 | int d = 1; | ||
| 404 | at_time t{}; | ||
| 405 | + // XXX DAY should support ON format, e.g. lastSun or Sun>=8 | ||
| 406 | in >> m >> d >> t; | ||
| 407 | + // XXX UNTIL field should be interpreted | ||
| 408 | + // "using the rules in effect just before the transition" | ||
| 409 | + // so might need to store as year_month_day and hh_mm_ss and only | ||
| 410 | + // convert to a sys_time once we know the offset in effect. | ||
| 411 | inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); | ||
| 412 | } | ||
| 413 | else | ||
| 414 | diff --git a/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc | ||
| 415 | new file mode 100644 | ||
| 416 | index 000000000000..f1a8fff02f58 | ||
| 417 | --- /dev/null | ||
| 418 | +++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc | ||
| 419 | @@ -0,0 +1,106 @@ | ||
| 420 | +// { dg-do run { target c++20 } } | ||
| 421 | +// { dg-require-effective-target tzdb } | ||
| 422 | +// { dg-require-effective-target cxx11_abi } | ||
| 423 | +// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } } | ||
| 424 | + | ||
| 425 | +#include <chrono> | ||
| 426 | +#include <fstream> | ||
| 427 | +#include <testsuite_hooks.h> | ||
| 428 | + | ||
| 429 | +static bool override_used = false; | ||
| 430 | + | ||
| 431 | +namespace __gnu_cxx | ||
| 432 | +{ | ||
| 433 | + const char* zoneinfo_dir_override() { | ||
| 434 | + override_used = true; | ||
| 435 | + return "./"; | ||
| 436 | + } | ||
| 437 | +} | ||
| 438 | + | ||
| 439 | +using namespace std::chrono; | ||
| 440 | + | ||
| 441 | +void | ||
| 442 | +test_format() | ||
| 443 | +{ | ||
| 444 | + std::ofstream("tzdata.zi") << R"(# version test_1 | ||
| 445 | +Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u | ||
| 446 | + -1 - %z 1975 | ||
| 447 | + 0 - GMT | ||
| 448 | +Zon Some/Zone 1:2:3 - %z 1900 | ||
| 449 | + 1:23:45 - %z 1950 | ||
| 450 | +Zo Another/Zone 1:2:3 - AZ0 1901 | ||
| 451 | + 1 Roolz A%sZ 2000 | ||
| 452 | + 1 Roolz SAZ/DAZ 2005 | ||
| 453 | + 1 Roolz %z | ||
| 454 | +Rule Roolz 1950 max - April 1 2 1 D | ||
| 455 | +Rul Roolz 1950 max - Oct 1 1 0 S | ||
| 456 | +Z Strange/Zone 1 - X%sX 1980 | ||
| 457 | + 1 - FOO/BAR 1990 | ||
| 458 | + 2:00 - %zzz 1995 | ||
| 459 | + 0:9 - %zzz 1996 | ||
| 460 | + 0:8:7 - %zzz 1997 | ||
| 461 | + 0:6:5.5 - %zzz 1998 | ||
| 462 | +)"; | ||
| 463 | + | ||
| 464 | + const auto& db = reload_tzdb(); | ||
| 465 | + VERIFY( override_used ); // If this fails then XFAIL for the target. | ||
| 466 | + VERIFY( db.version == "test_1" ); | ||
| 467 | + | ||
| 468 | + // Test formatting %z as | ||
| 469 | + auto tz = locate_zone("Africa/Bissau"); | ||
| 470 | + auto inf = tz->get_info(sys_days(1974y/1/1)); | ||
| 471 | + VERIFY( inf.abbrev == "-01" ); | ||
| 472 | + | ||
| 473 | + tz = locate_zone("Some/Zone"); | ||
| 474 | + inf = tz->get_info(sys_days(1899y/1/1)); | ||
| 475 | + VERIFY( inf.abbrev == "+010203" ); | ||
| 476 | + inf = tz->get_info(sys_days(1955y/1/1)); | ||
| 477 | + VERIFY( inf.abbrev == "+012345" ); | ||
| 478 | + | ||
| 479 | + tz = locate_zone("Another/Zone"); | ||
| 480 | + // Test formatting %s as the LETTER/S field from the active Rule. | ||
| 481 | + inf = tz->get_info(sys_days(1910y/January/1)); | ||
| 482 | + VERIFY( inf.abbrev == "ASZ" ); | ||
| 483 | + inf = tz->get_info(sys_days(1950y/January/1)); | ||
| 484 | + VERIFY( inf.abbrev == "ASZ" ); | ||
| 485 | + inf = tz->get_info(sys_days(1950y/June/1)); | ||
| 486 | + VERIFY( inf.abbrev == "ADZ" ); | ||
| 487 | + inf = tz->get_info(sys_days(1999y/January/1)); | ||
| 488 | + VERIFY( inf.abbrev == "ASZ" ); | ||
| 489 | + inf = tz->get_info(sys_days(1999y/July/1)); | ||
| 490 | + VERIFY( inf.abbrev == "ADZ" ); | ||
| 491 | + // Test formatting STD/DST according to the active Rule. | ||
| 492 | + inf = tz->get_info(sys_days(2000y/January/2)); | ||
| 493 | + VERIFY( inf.abbrev == "SAZ" ); | ||
| 494 | + inf = tz->get_info(sys_days(2001y/January/1)); | ||
| 495 | + VERIFY( inf.abbrev == "SAZ" ); | ||
| 496 | + inf = tz->get_info(sys_days(2001y/July/1)); | ||
| 497 | + VERIFY( inf.abbrev == "DAZ" ); | ||
| 498 | + // Test formatting %z as the offset determined by the active Rule. | ||
| 499 | + inf = tz->get_info(sys_days(2005y/January/2)); | ||
| 500 | + VERIFY( inf.abbrev == "+01" ); | ||
| 501 | + inf = tz->get_info(sys_days(2006y/January/1)); | ||
| 502 | + VERIFY( inf.abbrev == "+01" ); | ||
| 503 | + inf = tz->get_info(sys_days(2006y/July/1)); | ||
| 504 | + VERIFY( inf.abbrev == "+02" ); | ||
| 505 | + | ||
| 506 | + // Test formatting %z, %s and S/D for a Zone with no associated Rules. | ||
| 507 | + tz = locate_zone("Strange/Zone"); | ||
| 508 | + inf = tz->get_info(sys_days(1979y/January/1)); | ||
| 509 | + VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. | ||
| 510 | + inf = tz->get_info(sys_days(1981y/July/1)); | ||
| 511 | + VERIFY( inf.abbrev == "FOO" ); // Always standard time means first string. | ||
| 512 | + inf = tz->get_info(sys_days(1994y/July/1)); | ||
| 513 | + VERIFY( inf.abbrev == "+02zz" ); | ||
| 514 | + inf = tz->get_info(sys_days(1995y/July/1)); | ||
| 515 | + VERIFY( inf.abbrev == "+0009zz" ); | ||
| 516 | + inf = tz->get_info(sys_days(1996y/July/1)); | ||
| 517 | + VERIFY( inf.abbrev == "+000807zz" ); | ||
| 518 | + inf = tz->get_info(sys_days(1997y/July/1)); | ||
| 519 | + VERIFY( inf.abbrev == "+000606zz" ); | ||
| 520 | +} | ||
| 521 | + | ||
| 522 | +int main() | ||
| 523 | +{ | ||
| 524 | + test_format(); | ||
| 525 | +} | ||
| 526 | diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc b/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
| 527 | index 796f3a8b4256..7a31c1c20ba7 100644 | ||
| 528 | --- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
| 529 | +++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
| 530 | @@ -39,11 +39,15 @@ test_locate() | ||
| 531 | const tzdb& db = get_tzdb(); | ||
| 532 | const time_zone* tz = db.locate_zone("GMT"); | ||
| 533 | VERIFY( tz != nullptr ); | ||
| 534 | - VERIFY( tz->name() == "Etc/GMT" ); | ||
| 535 | VERIFY( tz == std::chrono::locate_zone("GMT") ); | ||
| 536 | VERIFY( tz == db.locate_zone("Etc/GMT") ); | ||
| 537 | VERIFY( tz == db.locate_zone("Etc/GMT+0") ); | ||
| 538 | |||
| 539 | + // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice versa, | ||
| 540 | + // but only when using the vanguard format. As of 2024a, the main and | ||
| 541 | + // rearguard formats still have Etc/GMT as a Zone and GMT as a link. | ||
| 542 | + VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); | ||
| 543 | + | ||
| 544 | VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() ); | ||
| 545 | } | ||
| 546 | |||
| 547 | -- | ||
| 548 | 2.43.5 | ||
| 549 | |||
