Bug 97613 - chrono::year_month_weekday cast to sys_days : return bad value if index() == 0
Summary: chrono::year_month_weekday cast to sys_days : return bad value if index() == 0
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: 11.0
Assignee: Patrick Palka
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-10-28 08:52 UTC by Akira Takahashi
Modified: 2020-10-28 16:44 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-10-28 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Akira Takahashi 2020-10-28 08:52:49 UTC
#include <iostream>
#include <chrono>

namespace chrono = std::chrono;
using namespace std::chrono_literals;

int main()
{
  // 1
  chrono::sys_days date1 = 2020y/3/chrono::Sunday[1];
  assert(chrono::year_month_day{date1} == 2020y/3/1);

  // 2
  chrono::sys_days date2 = 2020y/3/chrono::Sunday[2];
  assert(chrono::year_month_day{date2} == 2020y/3/8);

  // 3
  chrono::sys_days date3 = 2020y/3/chrono::Sunday[0];
  assert(chrono::year_month_day{date3} == 2020y/2/23);
}

Assertion failed the program's No.3 patten.
GCC 11 (trunk) returns `30297y/March/14d`. Clang (libc++) is OK.

See the specification:

> 27.8.16.2 [time.cal.ymwd.members]
> If index() is 0 the returned sys_days represents the date 7 days prior to the first weekday() of year()/month().
Comment 1 Akira Takahashi 2020-10-28 09:05:01 UTC
- #include <iostream>
+ #include <cassert>

#include <cassert>
#include <chrono>

namespace chrono = std::chrono;
using namespace std::chrono_literals;

int main()
{
  chrono::sys_days date1 = 2020y/3/chrono::Sunday[1];
  assert(chrono::year_month_day{date1} == 2020y/3/1);

  chrono::sys_days date2 = 2020y/3/chrono::Sunday[2];
  assert(chrono::year_month_day{date2} == 2020y/3/8);

  chrono::sys_days date3 = 2020y/3/chrono::Sunday[0];
  assert(chrono::year_month_day{date3} == 2020y/2/23);
}
Comment 2 Patrick Palka 2020-10-28 13:45:44 UTC
Confirmed.
Comment 3 Patrick Palka 2020-10-28 16:41:10 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:8572edc828f6d1e7c8243f901fe7c96f62a11a8e

commit r11-4490-g8572edc828f6d1e7c8243f901fe7c96f62a11a8e
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Oct 28 12:28:08 2020 -0400

    libstdc++: Fix arithmetic bug in year_month_weekday conversion [PR96713]
    
    The conversion function year_month_weekday::operator sys_days computes
    the offset in days from the first weekday of the month with:
    
     days{(index()-1)*7}
          ^~~~~~~~~~~~~  type 'unsigned'
    
    We want the above to yield -7d when index() is 0u, but our 'days' alias
    is based on long instead of int, so the conversion from unsigned to the
    underlying type of 'days' instead yields a large positive value.
    
    This patch fixes this by casting the result of index() to int so that
    the initializer is sign-extended in the conversion to long.
    
    The added testcase also verifies we do the right thing when index() == 5.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/96713
            * include/std/chrono (year_month_weekday::operator sys_days):
            Cast the result of index() to int so that the initializer for
            days{} is sign-extended when it's converted to the underlying
            type.
            * testsuite/std/time/year_month_weekday/3.cc: New test.
Comment 4 Patrick Palka 2020-10-28 16:44:07 UTC
This should be fixed now, thanks for the report!