libstdc++: Fix operator overload ambiguity with calendar types
authorPatrick Palka <ppalka@redhat.com>
Thu, 27 Aug 2020 18:09:52 +0000 (14:09 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 27 Aug 2020 18:09:52 +0000 (14:09 -0400)
commit7b743c67f04471a0129390ad2808e61e5538e0d3
tree20043ba2843efa697a9372479bec73d877116ebc
parent04df5e7de2f3dd652a9cddc1c9adfbdf45947ae6
libstdc++: Fix operator overload ambiguity with calendar types

We currently don't enforce a constraint on some of the calendar types'
addition/subtraction operator overloads that take a 'months' arguments:

  Constraints: If the argument supplied by the caller for the months
  parameter is convertible to years, its implicit conversion sequence to
  years is worse than its implicit conversion sequence to months.

This constraint is relevant when adding/subtracting a duration to/from,
say, a year_month where the given duration is convertible to both
'months' and to 'years' (as in the new testcases below).  The correct
behavior here in light of this constraint is to perform the operation
through the (more efficient) 'years'-based overload, but we currently
emit an ambiguous overload error.

This patch templatizes the 'months'-based addition/subtraction operator
overloads so that in the event of an implicit-conversion tie, we select
the non-template 'years'-based overload.  This is the same approach
that the date library takes for enforcing this constraint.

libstdc++-v3/ChangeLog:

* include/std/chrono
(__detail::__months_years_conversion_disambiguator): Define.
(year_month::operator+=): Templatize the 'months'-based overload
so that the 'years'-based overload is selected in case of
equally-ranked implicit conversion sequences to both 'months'
and 'years' from the supplied argument.
(year_month::operator-=): Likewise.
(year_month::operator+): Likewise.
(year_month::operator-): Likewise.
(year_month_day::operator+=): Likewise.
(year_month_day::operator-=): Likewise.
(year_month_day::operator+): Likewise.
(year_month_day::operator-): Likewise.
(year_month_day_last::operator+=): Likewise.
(year_month_day_last::operator-=): Likewise.
(year_month_day_last::operator+): Likewise
(year_month_day_last::operator-): Likewise.
(year_month_day_weekday::operator+=): Likewise
(year_month_day_weekday::operator-=): Likewise.
(year_month_day_weekday::operator+): Likewise.
(year_month_day_weekday::operator-): Likewise.
(year_month_day_weekday_last::operator+=): Likewise
(year_month_day_weekday_last::operator-=): Likewise.
(year_month_day_weekday_last::operator+): Likewise.
(year_month_day_weekday_last::operator-): Likewise.
(testsuite/std/time/year_month/2.cc): New test.
(testsuite/std/time/year_month_day/2.cc): New test.
(testsuite/std/time/year_month_day_last/2.cc): New test.
(testsuite/std/time/year_month_weekday/2.cc): New test.
(testsuite/std/time/year_month_weekday_last/2.cc): New test.
libstdc++-v3/include/std/chrono
libstdc++-v3/testsuite/std/time/year_month/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/time/year_month_day/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/time/year_month_day_last/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/time/year_month_weekday/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/time/year_month_weekday_last/2.cc [new file with mode: 0644]