diff --git a/stl/inc/chrono b/stl/inc/chrono index 25d3b2ac196..759c2029e1d 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1331,15 +1331,16 @@ namespace chrono { return *this; } - inline constexpr day _Last_day_table[] = { - day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31}, day{30}, day{31}, day{30}, day{31}}; + // To prevent UB by going out of bounds, four extra days with an invalid day are added. + inline constexpr day _Last_day_table[] = {day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31}, + day{30}, day{31}, day{30}, day{31}, day{255}, day{255}, day{255}, day{255}}; _NODISCARD constexpr day _Last_day(const year& _Year, const month& _Month) { if (_Month == month{2} && _Year.is_leap()) { return day{29}; } - return _Last_day_table[static_cast(_Month) - 1]; + return _Last_day_table[(static_cast(_Month) - 1) & 0xF]; } class year_month_day_last; diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp index 4bb31c8a863..6a59c863a07 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp @@ -967,6 +967,7 @@ constexpr void year_month_day_last_test() { if (is_constant_evaluated()) { static_assert((2020y / 1 / last).ok()); static_assert(!(2020y / 13 / last).ok()); + static_assert(!(2020y / 0 / last).day().ok()); // implementation-specific assumption, see GH-1647 } else { for (int iy = y_min; iy <= y_max; ++iy) { for (auto m = 0u; m <= 255u; ++m) { @@ -976,6 +977,7 @@ constexpr void year_month_day_last_test() { assert((y / mdl).ok()); } else { assert(!(y / mdl).ok()); + assert((y / mdl).day().ok() || (y / mdl).day() == day{255}); // implementation-specific assumption } } }