aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2017-02-06 17:15:14 -0800
committerPaul Eggert2017-02-06 17:34:41 -0800
commit03a012a79679c730634537f966200878bfd1c0b4 (patch)
tree66647b38bffa3eb904da993d9d583cc770c443df /src
parentd45dbccc5d2360818e70bbb0bc816c62c8cf6cbe (diff)
downloademacs-03a012a79679c730634537f966200878bfd1c0b4.tar.gz
emacs-03a012a79679c730634537f966200878bfd1c0b4.zip
Make FOR_EACH_TAIL more like other FOR_EACH macros
See comments by Stefan Monnier in: http://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00181.html and by Eli Zaretskii in: http://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00207.html * src/fns.c (internal_equal): Do not bypass check for depth overflow when tail-recursing via a dotted list tail or an overlay plist, to avoid a rare infloop. * src/lisp.h (FOR_EACH_TAIL, FOR_EACH_TAIL_SAFE): Take TAIL as an arg, and update it at each iteration, rather than have callers access it.tail. All callers changed. (FOR_EACH_TAIL): Do not check for dotted lists, as this is now the caller’s responsibility. All callers changed. (FOR_EACH_TAIL_CONS): Remove. All callers changed. (struct for_each_tail_internal.tail): Remove; no longer needed. (FOR_EACH_TAIL_INTERNAL): Remove dotted arg, and set the tail arg each time through the loop. All callers changed.
Diffstat (limited to 'src')
-rw-r--r--src/fns.c182
-rw-r--r--src/lisp.h48
-rw-r--r--src/xdisp.c4
3 files changed, 123 insertions, 111 deletions
diff --git a/src/fns.c b/src/fns.c
index b5508fb56ab..ffe3218ca7d 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -111,6 +111,7 @@ To get the number of bytes, use `string-bytes'. */)
111 intptr_t i = 0; 111 intptr_t i = 0;
112 FOR_EACH_TAIL (sequence) 112 FOR_EACH_TAIL (sequence)
113 i++; 113 i++;
114 CHECK_LIST_END (sequence, sequence);
114 if (MOST_POSITIVE_FIXNUM < i) 115 if (MOST_POSITIVE_FIXNUM < i)
115 error ("List too long"); 116 error ("List too long");
116 val = make_number (i); 117 val = make_number (i);
@@ -1343,9 +1344,11 @@ DEFUN ("member", Fmember, Smember, 2, 2, 0,
1343The value is actually the tail of LIST whose car is ELT. */) 1344The value is actually the tail of LIST whose car is ELT. */)
1344 (Lisp_Object elt, Lisp_Object list) 1345 (Lisp_Object elt, Lisp_Object list)
1345{ 1346{
1346 FOR_EACH_TAIL (list) 1347 Lisp_Object tail = list;
1347 if (! NILP (Fequal (elt, XCAR (li.tail)))) 1348 FOR_EACH_TAIL (tail)
1348 return li.tail; 1349 if (! NILP (Fequal (elt, XCAR (tail))))
1350 return tail;
1351 CHECK_LIST_END (tail, list);
1349 return Qnil; 1352 return Qnil;
1350} 1353}
1351 1354
@@ -1354,9 +1357,11 @@ DEFUN ("memq", Fmemq, Smemq, 2, 2, 0,
1354The value is actually the tail of LIST whose car is ELT. */) 1357The value is actually the tail of LIST whose car is ELT. */)
1355 (Lisp_Object elt, Lisp_Object list) 1358 (Lisp_Object elt, Lisp_Object list)
1356{ 1359{
1357 FOR_EACH_TAIL (list) 1360 Lisp_Object tail = list;
1358 if (EQ (XCAR (li.tail), elt)) 1361 FOR_EACH_TAIL (tail)
1359 return li.tail; 1362 if (EQ (XCAR (tail), elt))
1363 return tail;
1364 CHECK_LIST_END (tail, list);
1360 return Qnil; 1365 return Qnil;
1361} 1366}
1362 1367
@@ -1368,12 +1373,14 @@ The value is actually the tail of LIST whose car is ELT. */)
1368 if (!FLOATP (elt)) 1373 if (!FLOATP (elt))
1369 return Fmemq (elt, list); 1374 return Fmemq (elt, list);
1370 1375
1371 FOR_EACH_TAIL (list) 1376 Lisp_Object tail = list;
1377 FOR_EACH_TAIL (tail)
1372 { 1378 {
1373 Lisp_Object tem = XCAR (li.tail); 1379 Lisp_Object tem = XCAR (tail);
1374 if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) 1380 if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil))
1375 return li.tail; 1381 return tail;
1376 } 1382 }
1383 CHECK_LIST_END (tail, list);
1377 return Qnil; 1384 return Qnil;
1378} 1385}
1379 1386
@@ -1383,9 +1390,11 @@ The value is actually the first element of LIST whose car is KEY.
1383Elements of LIST that are not conses are ignored. */) 1390Elements of LIST that are not conses are ignored. */)
1384 (Lisp_Object key, Lisp_Object list) 1391 (Lisp_Object key, Lisp_Object list)
1385{ 1392{
1386 FOR_EACH_TAIL (list) 1393 Lisp_Object tail = list;
1387 if (CONSP (XCAR (li.tail)) && EQ (XCAR (XCAR (li.tail)), key)) 1394 FOR_EACH_TAIL (tail)
1388 return XCAR (li.tail); 1395 if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key))
1396 return XCAR (tail);
1397 CHECK_LIST_END (tail, list);
1389 return Qnil; 1398 return Qnil;
1390} 1399}
1391 1400
@@ -1406,13 +1415,15 @@ DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
1406The value is actually the first element of LIST whose car equals KEY. */) 1415The value is actually the first element of LIST whose car equals KEY. */)
1407 (Lisp_Object key, Lisp_Object list) 1416 (Lisp_Object key, Lisp_Object list)
1408{ 1417{
1409 FOR_EACH_TAIL (list) 1418 Lisp_Object tail = list;
1419 FOR_EACH_TAIL (tail)
1410 { 1420 {
1411 Lisp_Object car = XCAR (li.tail); 1421 Lisp_Object car = XCAR (tail);
1412 if (CONSP (car) 1422 if (CONSP (car)
1413 && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key)))) 1423 && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key))))
1414 return car; 1424 return car;
1415 } 1425 }
1426 CHECK_LIST_END (tail, list);
1416 return Qnil; 1427 return Qnil;
1417} 1428}
1418 1429
@@ -1437,9 +1448,11 @@ DEFUN ("rassq", Frassq, Srassq, 2, 2, 0,
1437The value is actually the first element of LIST whose cdr is KEY. */) 1448The value is actually the first element of LIST whose cdr is KEY. */)
1438 (Lisp_Object key, Lisp_Object list) 1449 (Lisp_Object key, Lisp_Object list)
1439{ 1450{
1440 FOR_EACH_TAIL (list) 1451 Lisp_Object tail = list;
1441 if (CONSP (XCAR (li.tail)) && EQ (XCDR (XCAR (li.tail)), key)) 1452 FOR_EACH_TAIL (tail)
1442 return XCAR (li.tail); 1453 if (CONSP (XCAR (tail)) && EQ (XCDR (XCAR (tail)), key))
1454 return XCAR (tail);
1455 CHECK_LIST_END (tail, list);
1443 return Qnil; 1456 return Qnil;
1444} 1457}
1445 1458
@@ -1448,13 +1461,15 @@ DEFUN ("rassoc", Frassoc, Srassoc, 2, 2, 0,
1448The value is actually the first element of LIST whose cdr equals KEY. */) 1461The value is actually the first element of LIST whose cdr equals KEY. */)
1449 (Lisp_Object key, Lisp_Object list) 1462 (Lisp_Object key, Lisp_Object list)
1450{ 1463{
1451 FOR_EACH_TAIL (list) 1464 Lisp_Object tail = list;
1465 FOR_EACH_TAIL (tail)
1452 { 1466 {
1453 Lisp_Object car = XCAR (li.tail); 1467 Lisp_Object car = XCAR (tail);
1454 if (CONSP (car) 1468 if (CONSP (car)
1455 && (EQ (XCDR (car), key) || !NILP (Fequal (XCDR (car), key)))) 1469 && (EQ (XCDR (car), key) || !NILP (Fequal (XCDR (car), key))))
1456 return car; 1470 return car;
1457 } 1471 }
1472 CHECK_LIST_END (tail, list);
1458 return Qnil; 1473 return Qnil;
1459} 1474}
1460 1475
@@ -1470,21 +1485,22 @@ the value of a list `foo'. See also `remq', which does not modify the
1470argument. */) 1485argument. */)
1471 (Lisp_Object elt, Lisp_Object list) 1486 (Lisp_Object elt, Lisp_Object list)
1472{ 1487{
1473 Lisp_Object prev = Qnil; 1488 Lisp_Object prev = Qnil, tail = list;
1474 1489
1475 FOR_EACH_TAIL (list) 1490 FOR_EACH_TAIL (tail)
1476 { 1491 {
1477 Lisp_Object tem = XCAR (li.tail); 1492 Lisp_Object tem = XCAR (tail);
1478 if (EQ (elt, tem)) 1493 if (EQ (elt, tem))
1479 { 1494 {
1480 if (NILP (prev)) 1495 if (NILP (prev))
1481 list = XCDR (li.tail); 1496 list = XCDR (tail);
1482 else 1497 else
1483 Fsetcdr (prev, XCDR (li.tail)); 1498 Fsetcdr (prev, XCDR (tail));
1484 } 1499 }
1485 else 1500 else
1486 prev = li.tail; 1501 prev = tail;
1487 } 1502 }
1503 CHECK_LIST_END (tail, list);
1488 return list; 1504 return list;
1489} 1505}
1490 1506
@@ -1592,20 +1608,21 @@ changing the value of a sequence `foo'. */)
1592 } 1608 }
1593 else 1609 else
1594 { 1610 {
1595 Lisp_Object prev = Qnil; 1611 Lisp_Object prev = Qnil, tail = seq;
1596 1612
1597 FOR_EACH_TAIL (seq) 1613 FOR_EACH_TAIL (tail)
1598 { 1614 {
1599 if (!NILP (Fequal (elt, (XCAR (li.tail))))) 1615 if (!NILP (Fequal (elt, XCAR (tail))))
1600 { 1616 {
1601 if (NILP (prev)) 1617 if (NILP (prev))
1602 seq = XCDR (li.tail); 1618 seq = XCDR (tail);
1603 else 1619 else
1604 Fsetcdr (prev, XCDR (li.tail)); 1620 Fsetcdr (prev, XCDR (tail));
1605 } 1621 }
1606 else 1622 else
1607 prev = li.tail; 1623 prev = tail;
1608 } 1624 }
1625 CHECK_LIST_END (tail, seq);
1609 } 1626 }
1610 1627
1611 return seq; 1628 return seq;
@@ -1678,7 +1695,8 @@ See also the function `nreverse', which is used more often. */)
1678 { 1695 {
1679 new = Qnil; 1696 new = Qnil;
1680 FOR_EACH_TAIL (seq) 1697 FOR_EACH_TAIL (seq)
1681 new = Fcons (XCAR (li.tail), new); 1698 new = Fcons (XCAR (seq), new);
1699 CHECK_LIST_END (seq, seq);
1682 } 1700 }
1683 else if (VECTORP (seq)) 1701 else if (VECTORP (seq))
1684 { 1702 {
@@ -1930,14 +1948,15 @@ corresponding to the given PROP, or nil if PROP is not one of the
1930properties on the list. This function never signals an error. */) 1948properties on the list. This function never signals an error. */)
1931 (Lisp_Object plist, Lisp_Object prop) 1949 (Lisp_Object plist, Lisp_Object prop)
1932{ 1950{
1933 FOR_EACH_TAIL_SAFE (plist) 1951 Lisp_Object tail = plist;
1952 FOR_EACH_TAIL_SAFE (tail)
1934 { 1953 {
1935 if (! CONSP (XCDR (li.tail))) 1954 if (! CONSP (XCDR (tail)))
1936 break; 1955 break;
1937 if (EQ (prop, XCAR (li.tail))) 1956 if (EQ (prop, XCAR (tail)))
1938 return XCAR (XCDR (li.tail)); 1957 return XCAR (XCDR (tail));
1939 li.tail = XCDR (li.tail); 1958 tail = XCDR (tail);
1940 if (EQ (li.tail, li.tortoise)) 1959 if (EQ (tail, li.tortoise))
1941 break; 1960 break;
1942 } 1961 }
1943 1962
@@ -1963,23 +1982,24 @@ use `(setq x (plist-put x prop val))' to be sure to use the new value.
1963The PLIST is modified by side effects. */) 1982The PLIST is modified by side effects. */)
1964 (Lisp_Object plist, Lisp_Object prop, Lisp_Object val) 1983 (Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
1965{ 1984{
1966 Lisp_Object prev = Qnil; 1985 Lisp_Object prev = Qnil, tail = plist;
1967 FOR_EACH_TAIL_CONS (plist) 1986 FOR_EACH_TAIL (tail)
1968 { 1987 {
1969 if (! CONSP (XCDR (li.tail))) 1988 if (! CONSP (XCDR (tail)))
1970 break; 1989 break;
1971 1990
1972 if (EQ (prop, XCAR (li.tail))) 1991 if (EQ (prop, XCAR (tail)))
1973 { 1992 {
1974 Fsetcar (XCDR (li.tail), val); 1993 Fsetcar (XCDR (tail), val);
1975 return plist; 1994 return plist;
1976 } 1995 }
1977 1996
1978 prev = li.tail; 1997 prev = tail;
1979 li.tail = XCDR (li.tail); 1998 tail = XCDR (tail);
1980 if (EQ (li.tail, li.tortoise)) 1999 if (EQ (tail, li.tortoise))
1981 circular_list (plist); 2000 circular_list (plist);
1982 } 2001 }
2002 CHECK_LIST_END (tail, plist);
1983 Lisp_Object newcell 2003 Lisp_Object newcell
1984 = Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev)))); 2004 = Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev))));
1985 if (NILP (prev)) 2005 if (NILP (prev))
@@ -2007,16 +2027,20 @@ corresponding to the given PROP, or nil if PROP is not
2007one of the properties on the list. */) 2027one of the properties on the list. */)
2008 (Lisp_Object plist, Lisp_Object prop) 2028 (Lisp_Object plist, Lisp_Object prop)
2009{ 2029{
2010 FOR_EACH_TAIL_CONS (plist) 2030 Lisp_Object tail = plist;
2031 FOR_EACH_TAIL (tail)
2011 { 2032 {
2012 if (! CONSP (XCDR (li.tail))) 2033 if (! CONSP (XCDR (tail)))
2013 break; 2034 break;
2014 if (! NILP (Fequal (prop, XCAR (li.tail)))) 2035 if (! NILP (Fequal (prop, XCAR (tail))))
2015 return XCAR (XCDR (li.tail)); 2036 return XCAR (XCDR (tail));
2016 li.tail = XCDR (li.tail); 2037 tail = XCDR (tail);
2017 if (EQ (li.tail, li.tortoise)) 2038 if (EQ (tail, li.tortoise))
2018 circular_list (plist); 2039 circular_list (plist);
2019 } 2040 }
2041
2042 CHECK_LIST_END (tail, plist);
2043
2020 return Qnil; 2044 return Qnil;
2021} 2045}
2022 2046
@@ -2030,23 +2054,24 @@ use `(setq x (lax-plist-put x prop val))' to be sure to use the new value.
2030The PLIST is modified by side effects. */) 2054The PLIST is modified by side effects. */)
2031 (Lisp_Object plist, Lisp_Object prop, Lisp_Object val) 2055 (Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
2032{ 2056{
2033 Lisp_Object prev = Qnil; 2057 Lisp_Object prev = Qnil, tail = plist;
2034 FOR_EACH_TAIL_CONS (plist) 2058 FOR_EACH_TAIL (tail)
2035 { 2059 {
2036 if (! CONSP (XCDR (li.tail))) 2060 if (! CONSP (XCDR (tail)))
2037 break; 2061 break;
2038 2062
2039 if (! NILP (Fequal (prop, XCAR (li.tail)))) 2063 if (! NILP (Fequal (prop, XCAR (tail))))
2040 { 2064 {
2041 Fsetcar (XCDR (li.tail), val); 2065 Fsetcar (XCDR (tail), val);
2042 return plist; 2066 return plist;
2043 } 2067 }
2044 2068
2045 prev = li.tail; 2069 prev = tail;
2046 li.tail = XCDR (li.tail); 2070 tail = XCDR (tail);
2047 if (EQ (li.tail, li.tortoise)) 2071 if (EQ (tail, li.tortoise))
2048 circular_list (plist); 2072 circular_list (plist);
2049 } 2073 }
2074 CHECK_LIST_END (tail, plist);
2050 Lisp_Object newcell = list2 (prop, val); 2075 Lisp_Object newcell = list2 (prop, val);
2051 if (NILP (prev)) 2076 if (NILP (prev))
2052 return newcell; 2077 return newcell;
@@ -2095,6 +2120,7 @@ static bool
2095internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, 2120internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props,
2096 Lisp_Object ht) 2121 Lisp_Object ht)
2097{ 2122{
2123 tail_recurse:
2098 if (depth > 10) 2124 if (depth > 10)
2099 { 2125 {
2100 if (depth > 200) 2126 if (depth > 200)
@@ -2123,7 +2149,6 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props,
2123 } 2149 }
2124 } 2150 }
2125 2151
2126 tail_recurse:
2127 if (EQ (o1, o2)) 2152 if (EQ (o1, o2))
2128 return 1; 2153 return 1;
2129 if (XTYPE (o1) != XTYPE (o2)) 2154 if (XTYPE (o1) != XTYPE (o2))
@@ -2144,20 +2169,16 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props,
2144 2169
2145 case Lisp_Cons: 2170 case Lisp_Cons:
2146 { 2171 {
2147 Lisp_Object tail1 = o1; 2172 FOR_EACH_TAIL (o1)
2148 FOR_EACH_TAIL_CONS (o1)
2149 { 2173 {
2150 if (! CONSP (o2)) 2174 if (! CONSP (o2))
2151 return false; 2175 return false;
2152 if (! internal_equal (XCAR (li.tail), XCAR (o2), depth + 1, 2176 if (! internal_equal (XCAR (o1), XCAR (o2), depth + 1, props, ht))
2153 props, ht))
2154 return false; 2177 return false;
2155 tail1 = XCDR (li.tail);
2156 o2 = XCDR (o2); 2178 o2 = XCDR (o2);
2157 if (EQ (tail1, o2)) 2179 if (EQ (XCDR (o1), o2))
2158 return true; 2180 return true;
2159 } 2181 }
2160 o1 = tail1;
2161 depth++; 2182 depth++;
2162 goto tail_recurse; 2183 goto tail_recurse;
2163 } 2184 }
@@ -2340,8 +2361,8 @@ usage: (nconc &rest LISTS) */)
2340 CHECK_CONS (tem); 2361 CHECK_CONS (tem);
2341 2362
2342 Lisp_Object tail; 2363 Lisp_Object tail;
2343 FOR_EACH_TAIL_CONS (tem) 2364 FOR_EACH_TAIL (tem)
2344 tail = li.tail; 2365 tail = tem;
2345 2366
2346 tem = args[argnum + 1]; 2367 tem = args[argnum + 1];
2347 Fsetcdr (tail, tem); 2368 Fsetcdr (tail, tem);
@@ -2763,19 +2784,18 @@ property and a property with the value nil.
2763The value is actually the tail of PLIST whose car is PROP. */) 2784The value is actually the tail of PLIST whose car is PROP. */)
2764 (Lisp_Object plist, Lisp_Object prop) 2785 (Lisp_Object plist, Lisp_Object prop)
2765{ 2786{
2766 FOR_EACH_TAIL (plist) 2787 Lisp_Object tail = plist;
2788 FOR_EACH_TAIL (tail)
2767 { 2789 {
2768 if (EQ (XCAR (li.tail), prop)) 2790 if (EQ (XCAR (tail), prop))
2769 return li.tail; 2791 return tail;
2770 if (!CONSP (XCDR (li.tail))) 2792 tail = XCDR (tail);
2771 { 2793 if (! CONSP (tail))
2772 CHECK_LIST_END (XCDR (li.tail), plist); 2794 break;
2773 return Qnil; 2795 if (EQ (tail, li.tortoise))
2774 } 2796 circular_list (tail);
2775 li.tail = XCDR (li.tail);
2776 if (EQ (li.tail, li.tortoise))
2777 circular_list (plist);
2778 } 2797 }
2798 CHECK_LIST_END (tail, plist);
2779 return Qnil; 2799 return Qnil;
2780} 2800}
2781 2801
diff --git a/src/lisp.h b/src/lisp.h
index b753971fb9c..f1e2685702d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4580,41 +4580,33 @@ enum
4580 Lisp_String)) \ 4580 Lisp_String)) \
4581 : make_unibyte_string (str, len)) 4581 : make_unibyte_string (str, len))
4582 4582
4583/* Loop over tails of LIST, checking for dotted lists and cycles, 4583/* Loop over conses of the list TAIL, signaling if a cycle is found,
4584 and possibly quitting after each loop iteration. 4584 and possibly quitting after each loop iteration. In the loop body,
4585 In the loop body, ‘li.tail’ is the current cons; the name ‘li’ is 4585 set TAIL to the current cons. If the loop exits normally,
4586 short for “list iterator”. The expression LIST may be evaluated 4586 set TAIL to the terminating non-cons, typically nil. The loop body
4587 more than once, and so should not have side effects. The loop body
4588 should not modify the list’s top level structure other than by 4587 should not modify the list’s top level structure other than by
4589 perhaps deleting the current cons. */ 4588 perhaps deleting the current cons. */
4590 4589
4591#define FOR_EACH_TAIL(list) \ 4590#define FOR_EACH_TAIL(tail) \
4592 FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \ 4591 FOR_EACH_TAIL_INTERNAL (tail, circular_list (tail), true)
4593 circular_list (list), true)
4594 4592
4595/* Like FOR_EACH_TAIL (LIST), except do not check for dotted lists. */ 4593/* Like FOR_EACH_TAIL (LIST), except do not signal or quit.
4594 If the loop exits due to a cycle, TAIL’s value is undefined. */
4596 4595
4597#define FOR_EACH_TAIL_CONS(list) \ 4596#define FOR_EACH_TAIL_SAFE(tail) \
4598 FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list), true) 4597 FOR_EACH_TAIL_INTERNAL (tail, (void) ((tail) = Qnil), false)
4599
4600/* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists
4601 nor cycles, and do not quit. */
4602
4603#define FOR_EACH_TAIL_SAFE(list) \
4604 FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil), false)
4605 4598
4606/* Iterator intended for use only within FOR_EACH_TAIL_INTERNAL. */ 4599/* Iterator intended for use only within FOR_EACH_TAIL_INTERNAL. */
4607struct for_each_tail_internal 4600struct for_each_tail_internal
4608{ 4601{
4609 Lisp_Object tail, tortoise; 4602 Lisp_Object tortoise;
4610 intptr_t max, n; 4603 intptr_t max, n;
4611 unsigned short int q; 4604 unsigned short int q;
4612}; 4605};
4613 4606
4614/* Like FOR_EACH_TAIL (LIST), except evaluate DOTTED or CYCLE, 4607/* Like FOR_EACH_TAIL (LIST), except evaluate CYCLE if a cycle is
4615 respectively, if a dotted list or cycle is found, and check for 4608 found, and check for quit if CHECK_QUIT. This is an internal macro
4616 quit if CHECK_QUIT. This is an internal macro intended for use 4609 intended for use only by the above macros.
4617 only by the above macros.
4618 4610
4619 Use Brent’s teleporting tortoise-hare algorithm. See: 4611 Use Brent’s teleporting tortoise-hare algorithm. See:
4620 Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190 4612 Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190
@@ -4626,15 +4618,15 @@ struct for_each_tail_internal
4626 other noninterruptible areas (e.g., garbage collection) that there 4618 other noninterruptible areas (e.g., garbage collection) that there
4627 is little point to calling maybe_quit here. */ 4619 is little point to calling maybe_quit here. */
4628 4620
4629#define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle, check_quit) \ 4621#define FOR_EACH_TAIL_INTERNAL(tail, cycle, check_quit) \
4630 for (struct for_each_tail_internal li = { list, list, 2, 0, 2 }; \ 4622 for (struct for_each_tail_internal li = { tail, 2, 0, 2 }; \
4631 CONSP (li.tail) || (dotted, false); \ 4623 CONSP (tail); \
4632 (li.tail = XCDR (li.tail), \ 4624 ((tail) = XCDR (tail), \
4633 ((--li.q != 0 \ 4625 ((--li.q != 0 \
4634 || ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \ 4626 || ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \
4635 || (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \ 4627 || (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \
4636 li.tortoise = li.tail, false)) \ 4628 li.tortoise = (tail), false)) \
4637 && EQ (li.tail, li.tortoise)) \ 4629 && EQ (tail, li.tortoise)) \
4638 ? (cycle) : (void) 0)) 4630 ? (cycle) : (void) 0))
4639 4631
4640/* Do a `for' loop over alist values. */ 4632/* Do a `for' loop over alist values. */
diff --git a/src/xdisp.c b/src/xdisp.c
index 5e1207f29e3..387a3709722 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -23040,10 +23040,10 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
23040 n += display_mode_element (it, depth, 23040 n += display_mode_element (it, depth,
23041 /* Pad after only the last 23041 /* Pad after only the last
23042 list element. */ 23042 list element. */
23043 (! CONSP (XCDR (li.tail)) 23043 (! CONSP (XCDR (elt))
23044 ? field_width - n 23044 ? field_width - n
23045 : 0), 23045 : 0),
23046 precision - n, XCAR (li.tail), 23046 precision - n, XCAR (elt),
23047 props, risky); 23047 props, risky);
23048 } 23048 }
23049 } 23049 }