diff --git a/stl/inc/chrono b/stl/inc/chrono index a895f59a2c2..e8e701c39c5 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -473,10 +473,12 @@ namespace chrono { private: unsigned char _Weekday; - // courtesy of Howard Hinnant + // courtesy of Howard Hinnant (modified to avoid overflow) // https://howardhinnant.github.io/date_algorithms.html#weekday_from_days _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept { - return static_cast(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6); + _STL_INTERNAL_STATIC_ASSERT(~0u % 7u == 3u); // offset for `_Tp < 0` needs to change + const auto _Before_modulo = static_cast(_Tp) + (_Tp >= 0 ? 4u : 0u); + return _Before_modulo % 7u; // separate expression for MSVC codegen, see GH-5153 } }; 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 6a59c863a07..745eb7b3315 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 @@ -281,6 +281,10 @@ constexpr void weekday_test() { assert(Sunday - Monday == days{6}); assert(Sunday - Tuesday == days{5}); assert(Wednesday - Thursday == days{6}); + + // GH-5153 ": integer overflow in weekday::weekday(sys_days::max())" + assert(weekday{sys_days::max()} == weekday{sys_days::max() - days{7}}); + assert(weekday{local_days::max()} == weekday{local_days::max() - days{7}}); } constexpr void weekday_indexed_test() {