[gcc(refs/users/wschmidt/heads/builtins3)] libstdc++: Fix operator overload ambiguity with calendar types

William Schmidt wschmidt@gcc.gnu.org
Fri Aug 28 20:04:50 GMT 2020


https://gcc.gnu.org/g:7b743c67f04471a0129390ad2808e61e5538e0d3

commit 7b743c67f04471a0129390ad2808e61e5538e0d3
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Aug 27 14:09:52 2020 -0400

    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.

Diff:
---
 libstdc++-v3/include/std/chrono                    | 286 ++++++++++++---------
 libstdc++-v3/testsuite/std/time/year_month/2.cc    |  40 +++
 .../testsuite/std/time/year_month_day/2.cc         |  40 +++
 .../testsuite/std/time/year_month_day_last/2.cc    |  40 +++
 .../testsuite/std/time/year_month_weekday/2.cc     |  40 +++
 .../std/time/year_month_weekday_last/2.cc          |  40 +++
 6 files changed, 367 insertions(+), 119 deletions(-)

diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 01f1e2d2b71..df2f5d23f52 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -2046,6 +2046,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     // YEAR_MONTH
 
+    namespace __detail
+    {
+      // [time.cal.ym], [time.cal.ymd], etc constrain the 'months'-based
+      // addition/subtraction operator overloads like so:
+      //
+      //   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.
+      //
+      // We realize this constraint by templatizing the 'months'-based
+      // overloads (using a dummy defaulted template parameter), so that
+      // overload resolution doesn't select the 'months'-based overload unless
+      // the implicit conversion sequence to 'months' is better than that to
+      // 'years'.
+      using __months_years_conversion_disambiguator = void;
+    }
+
     class year_month
     {
     private:
@@ -2068,19 +2085,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       month() const noexcept
       { return _M_m; }
 
-      constexpr year_month&
-      operator+=(const months& __dm) noexcept
-      {
-	*this = *this + __dm;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month&
+	operator+=(const months& __dm) noexcept
+	{
+	  *this = *this + __dm;
+	  return *this;
+	}
 
-      constexpr year_month&
-      operator-=(const months& __dm) noexcept
-      {
-	*this = *this - __dm;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month&
+	operator-=(const months& __dm) noexcept
+	{
+	  *this = *this - __dm;
+	  return *this;
+	}
 
       constexpr year_month&
       operator+=(const years& __dy)  noexcept
@@ -2108,25 +2127,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator<=>(const year_month& __x, const year_month& __y) noexcept
 	= default;
 
-      friend constexpr year_month
-      operator+(const year_month& __ym, const months& __dm) noexcept
-      {
-	// TODO: Optimize?
-	auto __m = __ym.month() + __dm;
-	auto __i = unsigned{__ym.month()} - 1 + __dm.count();
-	auto __y = (__i < 0
-		    ? __ym.year() + years{(__i - 11) / 12}
-		    : __ym.year() + years{__i / 12});
-	return __y / __m;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month
+	operator+(const year_month& __ym, const months& __dm) noexcept
+	{
+	  // TODO: Optimize?
+	  auto __m = __ym.month() + __dm;
+	  auto __i = unsigned{__ym.month()} - 1 + __dm.count();
+	  auto __y = (__i < 0
+		      ? __ym.year() + years{(__i - 11) / 12}
+		      : __ym.year() + years{__i / 12});
+	  return __y / __m;
+	}
 
-      friend constexpr year_month
-      operator+(const months& __dm, const year_month& __ym) noexcept
-      { return __ym + __dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month
+	operator+(const months& __dm, const year_month& __ym) noexcept
+	{ return __ym + __dm; }
 
-      friend constexpr year_month
-      operator-(const year_month& __ym, const months& __dm) noexcept
-      { return __ym + -__dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month
+	operator-(const year_month& __ym, const months& __dm) noexcept
+	{ return __ym + -__dm; }
 
       friend constexpr months
       operator-(const year_month& __x, const year_month& __y) noexcept
@@ -2200,19 +2222,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : year_month_day(sys_days{__dp.time_since_epoch()})
       { }
 
-      constexpr year_month_day&
-      operator+=(const months& __m) noexcept
-      {
-	*this = *this + __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_day&
+	operator+=(const months& __m) noexcept
+	{
+	  *this = *this + __m;
+	  return *this;
+	}
 
-      constexpr year_month_day&
-      operator-=(const months& __m) noexcept
-      {
-	*this = *this - __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_day&
+	operator-=(const months& __m) noexcept
+	{
+	  *this = *this - __m;
+	  return *this;
+	}
 
       constexpr year_month_day&
       operator+=(const years& __y) noexcept
@@ -2262,13 +2286,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator<=>(const year_month_day& __x, const year_month_day& __y) noexcept
 	= default;
 
-      friend constexpr year_month_day
-      operator+(const year_month_day& __ymd, const months& __dm) noexcept
-      { return (__ymd.year() / __ymd.month() + __dm) / __ymd.day(); }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day
+	operator+(const year_month_day& __ymd, const months& __dm) noexcept
+	{ return (__ymd.year() / __ymd.month() + __dm) / __ymd.day(); }
 
-      friend constexpr year_month_day
-      operator+(const months& __dm, const year_month_day& __ymd) noexcept
-      { return __ymd + __dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day
+	operator+(const months& __dm, const year_month_day& __ymd) noexcept
+	{ return __ymd + __dm; }
 
       friend constexpr year_month_day
       operator+(const year_month_day& __ymd, const years& __dy) noexcept
@@ -2278,9 +2304,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator+(const years& __dy, const year_month_day& __ymd) noexcept
       { return __ymd + __dy; }
 
-      friend constexpr year_month_day
-      operator-(const year_month_day& __ymd, const months& __dm) noexcept
-      { return __ymd + -__dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day
+	operator-(const year_month_day& __ymd, const months& __dm) noexcept
+	{ return __ymd + -__dm; }
 
       friend constexpr year_month_day
       operator-(const year_month_day& __ymd, const years& __dy) noexcept
@@ -2364,19 +2391,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : _M_y{__y}, _M_mdl{__mdl}
       { }
 
-      constexpr year_month_day_last&
-      operator+=(const months& __m) noexcept
-      {
-	*this = *this + __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_day_last&
+	operator+=(const months& __m) noexcept
+	{
+	  *this = *this + __m;
+	  return *this;
+	}
 
-      constexpr year_month_day_last&
-      operator-=(const months& __m) noexcept
-      {
-	*this = *this - __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_day_last&
+	operator-=(const months& __m) noexcept
+	{
+	  *this = *this - __m;
+	  return *this;
+	}
 
       constexpr year_month_day_last&
       operator+=(const years& __y)  noexcept
@@ -2438,20 +2467,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		  const year_month_day_last& __y) noexcept
 	= default;
 
-      friend constexpr year_month_day_last
-      operator+(const year_month_day_last& __ymdl,
-		const months& __dm) noexcept
-      { return (__ymdl.year() / __ymdl.month() + __dm) / last; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day_last
+	operator+(const year_month_day_last& __ymdl,
+		  const months& __dm) noexcept
+	{ return (__ymdl.year() / __ymdl.month() + __dm) / last; }
 
-      friend constexpr year_month_day_last
-      operator+(const months& __dm,
-		const year_month_day_last& __ymdl) noexcept
-      { return __ymdl + __dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day_last
+	operator+(const months& __dm,
+		  const year_month_day_last& __ymdl) noexcept
+	{ return __ymdl + __dm; }
 
-      friend constexpr year_month_day_last
-      operator-(const year_month_day_last& __ymdl,
-		const months& __dm) noexcept
-      { return __ymdl + -__dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_day_last
+	operator-(const year_month_day_last& __ymdl,
+		  const months& __dm) noexcept
+	{ return __ymdl + -__dm; }
 
       friend constexpr year_month_day_last
       operator+(const year_month_day_last& __ymdl,
@@ -2544,19 +2576,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : year_month_weekday{sys_days{__dp.time_since_epoch()}}
       { }
 
-      constexpr year_month_weekday&
-      operator+=(const months& __m) noexcept
-      {
-	*this = *this + __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_weekday&
+	operator+=(const months& __m) noexcept
+	{
+	  *this = *this + __m;
+	  return *this;
+	}
 
-      constexpr year_month_weekday&
-      operator-=(const months& __m) noexcept
-      {
-	*this = *this - __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_weekday&
+	operator-=(const months& __m) noexcept
+	{
+	  *this = *this - __m;
+	  return *this;
+	}
 
       constexpr year_month_weekday&
       operator+=(const years& __y) noexcept
@@ -2626,13 +2660,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  && __x.weekday_indexed() == __y.weekday_indexed();
       }
 
-      friend constexpr year_month_weekday
-      operator+(const year_month_weekday& __ymwd, const months& __dm) noexcept
-      { return (__ymwd.year() / __ymwd.month() + __dm) / __ymwd.weekday_indexed(); }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday
+	operator+(const year_month_weekday& __ymwd, const months& __dm) noexcept
+	{
+	  return ((__ymwd.year() / __ymwd.month() + __dm)
+		  / __ymwd.weekday_indexed());
+	}
 
-      friend constexpr year_month_weekday
-      operator+(const months& __dm, const year_month_weekday& __ymwd) noexcept
-      { return __ymwd + __dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday
+	operator+(const months& __dm, const year_month_weekday& __ymwd) noexcept
+	{ return __ymwd + __dm; }
 
       friend constexpr year_month_weekday
       operator+(const year_month_weekday& __ymwd, const years& __dy) noexcept
@@ -2642,9 +2681,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator+(const years& __dy, const year_month_weekday& __ymwd) noexcept
       { return __ymwd + __dy; }
 
-      friend constexpr year_month_weekday
-      operator-(const year_month_weekday& __ymwd, const months& __dm) noexcept
-      { return __ymwd + -__dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday
+	operator-(const year_month_weekday& __ymwd, const months& __dm) noexcept
+	{ return __ymwd + -__dm; }
 
       friend constexpr year_month_weekday
       operator-(const year_month_weekday& __ymwd, const years& __dy) noexcept
@@ -2690,19 +2730,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : _M_y{__y}, _M_m{__m}, _M_wdl{__wdl}
       { }
 
-      constexpr year_month_weekday_last&
-      operator+=(const months& __m) noexcept
-      {
-	*this = *this + __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_weekday_last&
+	operator+=(const months& __m) noexcept
+	{
+	  *this = *this + __m;
+	  return *this;
+	}
 
-      constexpr year_month_weekday_last&
-      operator-=(const months& __m) noexcept
-      {
-	*this = *this - __m;
-	return *this;
-      }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	constexpr year_month_weekday_last&
+	operator-=(const months& __m) noexcept
+	{
+	  *this = *this - __m;
+	  return *this;
+	}
 
       constexpr year_month_weekday_last&
       operator+=(const years& __y)  noexcept
@@ -2759,15 +2801,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  && __x.weekday_last() == __y.weekday_last();
       }
 
-      friend constexpr year_month_weekday_last
-      operator+(const year_month_weekday_last& __ymwdl,
-		const months& __dm) noexcept
-      { return (__ymwdl.year() / __ymwdl.month() + __dm) / __ymwdl.weekday_last(); }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday_last
+	operator+(const year_month_weekday_last& __ymwdl,
+		  const months& __dm) noexcept
+	{
+	  return ((__ymwdl.year() / __ymwdl.month() + __dm)
+		  / __ymwdl.weekday_last());
+	}
 
-      friend constexpr year_month_weekday_last
-      operator+(const months& __dm,
-		const year_month_weekday_last& __ymwdl) noexcept
-      { return __ymwdl + __dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday_last
+	operator+(const months& __dm,
+		  const year_month_weekday_last& __ymwdl) noexcept
+	{ return __ymwdl + __dm; }
 
       friend constexpr year_month_weekday_last
       operator+(const year_month_weekday_last& __ymwdl,
@@ -2779,10 +2826,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		const year_month_weekday_last& __ymwdl) noexcept
       { return __ymwdl + __dy; }
 
-      friend constexpr year_month_weekday_last
-      operator-(const year_month_weekday_last& __ymwdl,
-		const months& __dm) noexcept
-      { return __ymwdl + -__dm; }
+      template<typename = __detail::__months_years_conversion_disambiguator>
+	friend constexpr year_month_weekday_last
+	operator-(const year_month_weekday_last& __ymwdl,
+		  const months& __dm) noexcept
+	{ return __ymwdl + -__dm; }
 
       friend constexpr year_month_weekday_last
       operator-(const year_month_weekday_last& __ymwdl,
diff --git a/libstdc++-v3/testsuite/std/time/year_month/2.cc b/libstdc++-v3/testsuite/std/time/year_month/2.cc
new file mode 100644
index 00000000000..36e14667547
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/year_month/2.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Class template year_month [time.cal.year_month]
+
+#include <chrono>
+
+constexpr void
+constexpr_year_month_op_overload_disambiguation()
+{
+  using namespace std::chrono;
+  using decades = duration<long long, std::ratio<31556952 * 10>>;
+  static_assert(std::convertible_to<decades, months>
+		&& std::convertible_to<decades, years>);
+  using ym = year_month;
+
+  constexpr ym ym1 = 2015y/June;
+  static_assert(ym1 + decades{1} == 2025y/June);
+  static_assert(ym1 - decades{1} == 2005y/June);
+  static_assert(decades{1} + ym1 == 2025y/June);
+  static_assert((ym{ym1} += decades{1}) == 2025y/June);
+  static_assert((ym{ym1} -= decades{1}) == 2005y/June);
+}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day/2.cc b/libstdc++-v3/testsuite/std/time/year_month_day/2.cc
new file mode 100644
index 00000000000..80d1f033c1d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/year_month_day/2.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Class template year_month_day [time.cal.year_month_day]
+
+#include <chrono>
+
+constexpr void
+constexpr_year_month_day_op_overload_disambiguation()
+{
+  using namespace std::chrono;
+  using decades = duration<long long, std::ratio<31556952 * 10>>;
+  static_assert(std::convertible_to<decades, months>
+		&& std::convertible_to<decades, years>);
+  using ymd = year_month_day;
+
+  constexpr ymd ymd1 = 2015y/June/15d;
+  static_assert(ymd1 + decades{1} == 2025y/June/15d);
+  static_assert(ymd1 - decades{1} == 2005y/June/15d);
+  static_assert(decades{1} + ymd1 == 2025y/June/15d);
+  static_assert((ymd{ymd1} += decades{1}) == 2025y/June/15d);
+  static_assert((ymd{ymd1} -= decades{1}) == 2005y/June/15d);
+}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day_last/2.cc b/libstdc++-v3/testsuite/std/time/year_month_day_last/2.cc
new file mode 100644
index 00000000000..dadbd3c38b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/year_month_day_last/2.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Class template year_month_day_last [time.cal.year_month_day_last]
+
+#include <chrono>
+
+constexpr void
+constexpr_year_month_day_last_op_overload_disambiguation()
+{
+  using namespace std::chrono;
+  using decades = duration<long long, std::ratio<31556952 * 10>>;
+  static_assert(std::convertible_to<decades, months>
+		&& std::convertible_to<decades, years>);
+  using ymdl = year_month_day_last;
+
+  constexpr ymdl ymdl1 = 2015y/June/last;
+  static_assert(ymdl1 + decades{1} == 2025y/June/last);
+  static_assert(ymdl1 - decades{1} == 2005y/June/last);
+  static_assert(decades{1} + ymdl1 == 2025y/June/last);
+  static_assert((ymdl{ymdl1} += decades{1}) == 2025y/June/last);
+  static_assert((ymdl{ymdl1} -= decades{1}) == 2005y/June/last);
+}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday/2.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday/2.cc
new file mode 100644
index 00000000000..6ddfb15b283
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday/2.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Class template year_month_weekday [time.cal.year_month_weekday]
+
+#include <chrono>
+
+constexpr void
+constexpr_year_month_weekday_op_overload_disambiguation()
+{
+  using namespace std::chrono;
+  using decades = duration<long long, std::ratio<31556952 * 10>>;
+  static_assert(std::convertible_to<decades, months>
+		&& std::convertible_to<decades, years>);
+  using ymwd = year_month_weekday;
+
+  constexpr ymwd ymwd1 = 2015y/June/Monday[3];
+  static_assert(ymwd1 + decades{1} == 2025y/June/Monday[3]);
+  static_assert(ymwd1 - decades{1} == 2005y/June/Monday[3]);
+  static_assert(decades{1} + ymwd1 == 2025y/June/Monday[3]);
+  static_assert((ymwd{ymwd1} += decades{1}) == 2025y/June/Monday[3]);
+  static_assert((ymwd{ymwd1} -= decades{1}) == 2005y/June/Monday[3]);
+}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/2.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/2.cc
new file mode 100644
index 00000000000..170b5a45ad6
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/2.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Class template year_month_weekday_last [time.cal.year_month_weekday_last]
+
+#include <chrono>
+
+constexpr void
+constexpr_year_month_weekday_last_op_overload_disambiguation()
+{
+  using namespace std::chrono;
+  using decades = duration<long long, std::ratio<31556952 * 10>>;
+  static_assert(std::convertible_to<decades, months>
+		&& std::convertible_to<decades, years>);
+  using ymwdl = year_month_weekday_last;
+
+  constexpr ymwdl ymwdl1 = 2015y/June/Monday[last];
+  static_assert(ymwdl1 + decades{1} == 2025y/June/Monday[last]);
+  static_assert(ymwdl1 - decades{1} == 2005y/June/Monday[last]);
+  static_assert(decades{1} + ymwdl1 == 2025y/June/Monday[last]);
+  static_assert((ymwdl{ymwdl1} += decades{1}) == 2025y/June/Monday[last]);
+  static_assert((ymwdl{ymwdl1} -= decades{1}) == 2005y/June/Monday[last]);
+}


More information about the Libstdc++-cvs mailing list