[gcc r14-12778] libstdc++: Use on_month_day istream operator in ZoneInfo parsing. [PR124852]

Tomasz Kaminski via Gcc-cvs <[email protected]> Fri, 31 Jul 2026 10:56:20 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <20260731105620.1EBAC4BCA415__37171.2331472494$1785495599$gmane$org@sourceware.org>
https://gcc.gnu.org/g:9b2b0e0ccf5f47dc1496616440726fac569a52c9

commit r14-12778-g9b2b0e0ccf5f47dc1496616440726fac569a52c9
Author: Tomasz Kamiński <[email protected]>
Date:   Wed May 13 09:17:47 2026 +0200

    libstdc++: Use on_month_day istream operator in ZoneInfo parsing. [PR124852]
    
    This patch changes ZoneInfo parsing, to use operator>> for on_month_day
    directly, and removes on_day tag. The operator>>(istream&, on_month_day)
    is updated to not override on.month if the MONTH component is not present,
    and set failbit instead. This allows to use in >> on >> time, to parse
    MONTH DAY TIME.
    
    We also handle failure to parse day number N for Www>=N or Www<=N
    productions, by leaving the day part of input unchanged and setting
    failbit.
    
            PR libstdc++/124852
    
    libstdc++-v3/ChangeLog:
    
            * src/c++20/tzdb.cc (on_month_day::on_day_t, on_month_day::on_day):
            Remove.
            (operator>>(istream&, on_month_day::day_t&)): Inlined into...
            (operator>>(istream&, on_month_day)): Inlined on_month_day::on_day.
            Avoid modifying on.month if MONTH is not present. Report failure
            on failure to parse day for LessEq / GreaterEq.
    
    Reviewed-by: Jonathan Wakely <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>
    (cherry picked from commit 2451667193e4e00b49c4ef9d95c0a3a1aa955f82)

Diff:
---
 libstdc++-v3/src/c++20/tzdb.cc | 89 ++++++++++++++----------------------------
 1 file changed, 30 insertions(+), 59 deletions(-)

diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index 42c73426b92f..3c19f5c6467c 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -338,13 +338,6 @@ namespace std::chrono
 	return ymd;
       }
 
-      struct on_day_t // tag type for reading ON and DAY fields only
-      {
-	on_month_day& parent;
-	friend istream& operator>>(istream&, on_day_t&&);
-      };
-
-      on_day_t on_day() { return on_day_t{*this}; }
 
       friend istream& operator>>(istream&, on_month_day&);
     };
@@ -2055,73 +2048,55 @@ namespace std::chrono
       }
     };
 
-    // Read the day-component of an on_month_day expression (everything after
-    // the month).  Three forms are accepted: a plain day-of-month number,
-    // "lastXxx" where Xxx is a weekday name (LastWeekday), or "Xxx<=N" or
-    // "Xxx>=N" (LessEq / GreaterEq).  On failure the function sets failbit
-    // and leaves `to.parent` unchanged.
-    istream& operator>>(istream& in, on_month_day::on_day_t&& to)
+    // Read the MONTH DAY. Three forms are accepted for DAY:
+    // * a plain day-of-month number (DayOfMonth),
+    // * "lastWww" where Www is a weekday name (LastWeekday),
+    // * "Www<=N" or "Www>=N" (LessEq / GreaterEq).
+    // On failure to read either MONTH or DAY this function sets
+    // failbit. If DAY is not parsed, only `on.month` is modified,
+    // otherwise `on` is left unchanged.
+    istream& operator>>(istream& in, on_month_day& on)
     {
       using enum on_month_day::Kind;
-
-      on_month_day& on = to.parent;
-      int c = ws(in).peek();
-      if ('0' <= c && c <= '9')
+      if (abbrev_month m{}; in >> m)
 	{
-	  unsigned d;
-	  in >> d;
-	  if (d <= 31) [[likely]]
+ 	  on.month = static_cast<unsigned>(m.m);
+	  if (int c = ws(in).peek(); '0' <= c && c <= '9')
 	    {
-	      on.kind = DayOfMonth;
-	      on.day_of_month = d;
-	      return in;
+	      if (unsigned d; (in >> d) && (d <= 31)) [[likely]]
+		{
+		  on.kind = DayOfMonth;
+		  on.day_of_month = d;
+		  return in;
+		}
 	    }
-	}
-      else if (c == 'l') // lastSunday, lastWed, ...
-	{
-	  in.ignore(4);
-	  if (abbrev_weekday w{}; in >> w) [[likely]]
+	  else if (c == 'l') // lastSunday, lastWed, ...
 	    {
-	      on.kind = LastWeekday;
-	      on.day_of_week = w.wd.c_encoding();
-	      return in;
+	      in.ignore(4);
+	      if (abbrev_weekday w{}; in >> w) [[likely]]
+		{
+		  on.kind = LastWeekday;
+		  on.day_of_week = w.wd.c_encoding();
+		  return in;
+		}
 	    }
-	}
-      else
-	{
-	  abbrev_weekday w;
-	  in >> w;
-	  if (auto c = in.get(); c == '<' || c == '>')
+	  else if (abbrev_weekday w; in >> w) [[likely]]
 	    {
-	      if (in.get() == '=')
-		{
-		  unsigned d;
-		  in >> d;
-		  if (d <= 31) [[likely]]
+	      if (c = in.get(); c == '<' || c == '>')
+		if (in.get() == '=')
+	          if (unsigned d; (in >> d) && (d <= 31)) [[likely]]
 		    {
 		      on.kind = c == '<' ? LessEq : GreaterEq;
 		      on.day_of_week = w.wd.c_encoding();
 		      on.day_of_month = d;
 		      return in;
 		    }
-		}
 	    }
 	}
       in.setstate(ios::failbit);
       return in;
     }
 
-    istream& operator>>(istream& in, on_month_day& to)
-    {
-      on_month_day md{};
-      abbrev_month m{};
-      in >> m;
-      md.month = static_cast<unsigned>(m.m);
-      if (in >> md.on_day())
-	to = md;
-      return in;
-    }
-
     istream& operator>>(istream& in, at_time& at)
     {
       int sign = 1;
@@ -2227,11 +2202,7 @@ namespace std::chrono
 	  on_month_day on{ .kind = on_month_day::DayOfMonth,
 			   .month = 1, .day_of_month = 1 };
 	  at_time t{};
-	  if (abbrev_month m{January}; in >> m)
-	    {
-	      on.month = static_cast<unsigned>(m.m);
-	      in >> on.on_day() >> t;
-	    }
+	  in >> on >> t;
 	  year_month_day ymd = on.pin(year(y));
 	  inf.m_until = sys_days(ymd) + seconds(t.time);
 	  if (t.indicator != at_time::Universal)