From 7e8b7b5f38f9a9e3a8750310d0dd018af71231e4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 9 Aug 2021 14:23:05 -0700
Subject: [PROPOSED] Remove some lint found by GCC, Clang

* localtime.c (transtime): Use UNREACHABLE instead of INITIALIZE
to pacify GCC, as this gives more information to the reader.
* localtime.c (tzparse):
* zic.c (rpytime):
Omit unnecessary initialization.
* private.h (UNREACHABLE): New macro.
* zdump.c (main, hunt): Redo to avoid need for INITIALIZE.
The code is arguably cleaner that way anyway.
* zic.c (infile, rulesub): Use UNREACHABLE instead of a panic message.
(inrule): Do not rely on r if rulesub fails.
(inzsub): Avoid unlikely small memory leaks, by not calling
ecpyalloc until checks have succeeded.
---
 localtime.c |  4 +--
 private.h   | 13 +++++++++
 zdump.c     | 25 ++++++++---------
 zic.c       | 77 ++++++++++++++++++++++++-----------------------------
 4 files changed, 63 insertions(+), 56 deletions(-)

diff --git a/localtime.c b/localtime.c
index 9840b89..c986be5 100644
--- a/localtime.c
+++ b/localtime.c
@@ -979,7 +979,6 @@ transtime(const int year, register const struct rule *const rulep,
 	register int	i;
 	int		d, m1, yy0, yy1, yy2, dow;
 
-	INITIALIZE(value);
 	leapyear = isleap(year);
 	switch (rulep->r_type) {
 
@@ -1045,6 +1044,8 @@ transtime(const int year, register const struct rule *const rulep,
 		for (i = 0; i < rulep->r_mon - 1; ++i)
 			value += mon_lengths[leapyear][i] * SECSPERDAY;
 		break;
+
+	default: UNREACHABLE();
 	}
 
 	/*
@@ -1274,7 +1275,6 @@ tzparse(const char *name, struct state *sp, struct state *basep)
 			** Initially we're assumed to be in standard time.
 			*/
 			isdst = false;
-			theiroffset = theirstdoffset;
 			/*
 			** Now juggle transition times and types
 			** tracking offsets as you do.
diff --git a/private.h b/private.h
index 6425298..9dbb071 100644
--- a/private.h
+++ b/private.h
@@ -685,6 +685,19 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
 # define UNINIT_TRAP 0
 #endif
 
+#ifdef DEBUG
+# define UNREACHABLE() abort()
+#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
+# define UNREACHABLE() __builtin_unreachable()
+#elif defined __has_builtin
+# if __has_builtin(__builtin_unreachable)
+#  define UNREACHABLE() __builtin_unreachable()
+# endif
+#endif
+#ifndef UNREACHABLE
+# define UNREACHABLE() ((void) 0)
+#endif
+
 /*
 ** For the benefit of GNU folk...
 ** '_(MSGID)' uses the current locale's message library string for MSGID.
diff --git a/zdump.c b/zdump.c
index bf2da67..b3f3448 100644
--- a/zdump.c
+++ b/zdump.c
@@ -519,9 +519,12 @@ main(int argc, char *argv[])
 		}
 	}
 	gmtzinit();
-	INITIALIZE(now);
-	if (! (iflag | vflag | Vflag))
+	if (iflag | vflag | Vflag)
+	  now = 0;
+	else {
 	  now = time(NULL);
+	  now |= !now;
+	}
 	longest = 0;
 	for (i = optind; i < argc; i++) {
 	  size_t arglen = strlen(argv[i]);
@@ -539,7 +542,7 @@ main(int argc, char *argv[])
 		  perror(argv[i]);
 		  return EXIT_FAILURE;
 		}
-		if (! (iflag | vflag | Vflag)) {
+		if (now) {
 			show(tz, argv[i], now, false);
 			tzfree(tz);
 			continue;
@@ -557,7 +560,6 @@ main(int argc, char *argv[])
 		}
 		if (t + 1 < cutlotime)
 		  t = cutlotime - 1;
-		INITIALIZE (ab);
 		tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
 		if (tm_ok) {
 		  ab = saveabbr(&abbrev, &abbrevsize, &tm);
@@ -565,7 +567,8 @@ main(int argc, char *argv[])
 		    showtrans("\nTZ=%f", &tm, t, ab, argv[i]);
 		    showtrans("-\t-\t%Q", &tm, t, ab, argv[i]);
 		  }
-		}
+		} else
+		  ab = NULL;
 		while (t < cuthitime - 1) {
 		  time_t newt = ((t < absolute_max_time - SECSPERDAY / 2
 				  && t + SECSPERDAY / 2 < cuthitime - 1)
@@ -574,9 +577,9 @@ main(int argc, char *argv[])
 		  struct tm *newtmp = localtime_rz(tz, &newt, &newtm);
 		  bool newtm_ok = newtmp != NULL;
 		  if (tm_ok != newtm_ok
-		      || (tm_ok && (delta(&newtm, &tm) != newt - t
-				    || newtm.tm_isdst != tm.tm_isdst
-				    || strcmp(abbr(&newtm), ab) != 0))) {
+		      || (ab && (delta(&newtm, &tm) != newt - t
+				 || newtm.tm_isdst != tm.tm_isdst
+				 || strcmp(abbr(&newtm), ab) != 0))) {
 		    newt = hunt(tz, argv[i], t, newt, false);
 		    newtmp = localtime_rz(tz, &newt, &newtm);
 		    newtm_ok = newtmp != NULL;
@@ -669,7 +672,6 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok)
 {
 	static char *		loab;
 	static size_t		loabsize;
-	char const *		ab;
 	struct tm		lotm;
 	struct tm		tm;
 
@@ -679,9 +681,8 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok)
 	   LOT, and tzname needs to be changed back.  */
 	bool lotm_ok = my_localtime_rz(tz, &lot, &lotm) != NULL;
 	bool tm_ok;
+	char const *ab = lotm_ok ? saveabbr(&loab, &loabsize, &lotm) : NULL;
 
-	if (lotm_ok)
-	  ab = saveabbr(&loab, &loabsize, &lotm);
 	for ( ; ; ) {
 		/* T = average of LOT and HIT, rounding down.
 		   Avoid overflow, even on oddball C89 platforms
@@ -696,7 +697,7 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok)
 		tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
 		if (lotm_ok == tm_ok
 		    && (only_ok
-			|| (lotm_ok && tm.tm_isdst == lotm.tm_isdst
+			|| (ab && tm.tm_isdst == lotm.tm_isdst
 			    && delta(&tm, &lotm) == t - lot
 			    && strcmp(abbr(&tm), ab) == 0))) {
 		  lot = t;
diff --git a/zic.c b/zic.c
index 8d1ea03..ddcb1e5 100644
--- a/zic.c
+++ b/zic.c
@@ -164,7 +164,7 @@ static void	newabbr(const char * abbr);
 static zic_t	oadd(zic_t t1, zic_t t2);
 static void	outzone(const struct zone * zp, ptrdiff_t ntzones);
 static zic_t	rpytime(const struct rule * rp, zic_t wantedy);
-static void	rulesub(struct rule * rp,
+static bool	rulesub(struct rule * rp,
 			const char * loyearp, const char * hiyearp,
 			const char * typep, const char * monthp,
 			const char * dayp, const char * timep);
@@ -1374,11 +1374,7 @@ infile(const char *name)
 					inexpires(fields, nfields);
 					wantcont = false;
 					break;
-				default:	/* "cannot happen" */
-					fprintf(stderr,
-_("%s: panic: Invalid l_value %d\n"),
-						progname, lp->l_value);
-					exit(EXIT_FAILURE);
+				default: UNREACHABLE();
 			}
 		}
 		free(fields);
@@ -1489,8 +1485,10 @@ inrule(char **fields, int nfields)
 	r.r_filename = filename;
 	r.r_linenum = linenum;
 	r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
-	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
-		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
+	if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
+		     fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
+		     fields[RF_TOD]))
+	  return;
 	r.r_name = ecpyalloc(fields[RF_NAME]);
 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
 	if (max_abbrvar_len < strlen(r.r_abbrvar))
@@ -1549,6 +1547,7 @@ inzsub(char **fields, int nfields, bool iscont)
 	register char *		cp;
 	char *			cp1;
 	struct zone z;
+	size_t format_len;
 	register int		i_stdoff, i_rule, i_format;
 	register int		i_untilyear, i_untilmonth;
 	register int		i_untilday, i_untiltime;
@@ -1562,7 +1561,6 @@ inzsub(char **fields, int nfields, bool iscont)
 		i_untilmonth = ZFC_TILMONTH;
 		i_untilday = ZFC_TILDAY;
 		i_untiltime = ZFC_TILTIME;
-		z.z_name = NULL;
 	} else if (!namecheck(fields[ZF_NAME]))
 		return false;
 	else {
@@ -1573,7 +1571,6 @@ inzsub(char **fields, int nfields, bool iscont)
 		i_untilmonth = ZF_TILMONTH;
 		i_untilday = ZF_TILDAY;
 		i_untiltime = ZF_TILTIME;
-		z.z_name = ecpyalloc(fields[ZF_NAME]);
 	}
 	z.z_filename = filename;
 	z.z_linenum = linenum;
@@ -1585,29 +1582,24 @@ inzsub(char **fields, int nfields, bool iscont)
 			return false;
 		}
 	}
-	z.z_rule = ecpyalloc(fields[i_rule]);
-	z.z_format = cp1 = ecpyalloc(fields[i_format]);
 	z.z_format_specifier = cp ? *cp : '\0';
-	if (z.z_format_specifier == 'z') {
-	  if (noise)
-	    warning(_("format '%s' not handled by pre-2015 versions of zic"),
-		    z.z_format);
-	  cp1[cp - fields[i_format]] = 's';
-	}
-	if (max_format_len < strlen(z.z_format))
-		max_format_len = strlen(z.z_format);
+	format_len = strlen(fields[i_format]);
+	if (max_format_len < format_len)
+	  max_format_len = format_len;
 	hasuntil = nfields > i_untilyear;
 	if (hasuntil) {
 		z.z_untilrule.r_filename = filename;
 		z.z_untilrule.r_linenum = linenum;
-		rulesub(&z.z_untilrule,
+		if (!rulesub(
+			&z.z_untilrule,
 			fields[i_untilyear],
 			"only",
 			"",
 			(nfields > i_untilmonth) ?
 			fields[i_untilmonth] : "Jan",
 			(nfields > i_untilday) ? fields[i_untilday] : "1",
-			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
+			(nfields > i_untiltime) ? fields[i_untiltime] : "0"))
+		  return false;
 		z.z_untiltime = rpytime(&z.z_untilrule,
 			z.z_untilrule.r_loyear);
 		if (iscont && nzones > 0 &&
@@ -1622,6 +1614,15 @@ inzsub(char **fields, int nfields, bool iscont)
 				return false;
 		}
 	}
+	z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]);
+	z.z_rule = ecpyalloc(fields[i_rule]);
+	z.z_format = cp1 = ecpyalloc(fields[i_format]);
+	if (z.z_format_specifier == 'z') {
+	  cp1[cp - fields[i_format]] = 's';
+	  if (noise)
+	    warning(_("format '%s' not handled by pre-2015 versions of zic"),
+		    fields[i_format]);
+	}
 	zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
 	zones[nzones++] = z;
 	/*
@@ -1764,7 +1765,7 @@ inlink(char **fields, int nfields)
 	links[nlinks++] = l;
 }
 
-static void
+static bool
 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 	const char *typep, const char *monthp, const char *dayp,
 	const char *timep)
@@ -1777,7 +1778,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 
 	if ((lp = byword(monthp, mon_names)) == NULL) {
 		error(_("invalid month name"));
-		return;
+		return false;
 	}
 	rp->r_month = lp->l_value;
 	rp->r_todisstd = false;
@@ -1820,14 +1821,10 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 		case YR_MAXIMUM:
 			rp->r_loyear = ZIC_MAX;
 			break;
-		default:	/* "cannot happen" */
-			fprintf(stderr,
-				_("%s: panic: Invalid l_value %d\n"),
-				progname, lp->l_value);
-			exit(EXIT_FAILURE);
+		default: UNREACHABLE();
 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
 		error(_("invalid starting year"));
-		return;
+		return false;
 	}
 	cp = hiyearp;
 	lp = byword(cp, end_years);
@@ -1842,23 +1839,19 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 		case YR_ONLY:
 			rp->r_hiyear = rp->r_loyear;
 			break;
-		default:	/* "cannot happen" */
-			fprintf(stderr,
-				_("%s: panic: Invalid l_value %d\n"),
-				progname, lp->l_value);
-			exit(EXIT_FAILURE);
+		default: UNREACHABLE();
 	} else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
 		error(_("invalid ending year"));
-		return;
+		return false;
 	}
 	if (rp->r_loyear > rp->r_hiyear) {
 		error(_("starting year greater than ending year"));
-		return;
+		return false;
 	}
 	if (*typep != '\0') {
 		error(_("year type \"%s\" is unsupported; use \"-\" instead"),
 			typep);
-		return;
+		return false;
 	}
 	/*
 	** Day work.
@@ -1888,12 +1881,12 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 			if (*ep++ != '=') {
 				error(_("invalid day of month"));
 				free(dp);
-				return;
+				return false;
 			}
 			if ((lp = byword(dp, wday_names)) == NULL) {
 				error(_("invalid weekday name"));
 				free(dp);
-				return;
+				return false;
 			}
 			rp->r_wday = lp->l_value;
 		}
@@ -1902,10 +1895,11 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 			(rp->r_dayofmonth > len_months[1][rp->r_month])) {
 				error(_("invalid day of month"));
 				free(dp);
-				return;
+				return false;
 		}
 	}
 	free(dp);
+	return true;
 }
 
 static void
@@ -3423,7 +3417,6 @@ rpytime(const struct rule *rp, zic_t wantedy)
 		return min_time;
 	if (wantedy == ZIC_MAX)
 		return max_time;
-	dayoff = 0;
 	m = TM_JANUARY;
 	y = EPOCH_YEAR;
 
-- 
2.30.2

