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

Tomasz Kaminski via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:d581965c0dcd3135e3934484739a814899b92329

commit r16-9373-gd581965c0dcd3135e3934484739a814899b92329
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 79aebf18ca3d..683a9f8f7e81 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -376,13 +376,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&);
     };
@@ -2412,73 +2405,55 @@ constinit tzdb_list::_Node::NumLeapSeconds tzdb_list::_Node::num_leap_seconds;
       }
     };
 
-    // 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;
@@ -2584,11 +2559,7 @@ constinit tzdb_list::_Node::NumLeapSeconds tzdb_list::_Node::num_leap_seconds;
 	  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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.