diff options
| author | Paul Eggert | 2017-02-06 17:15:14 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-02-06 17:34:41 -0800 |
| commit | 03a012a79679c730634537f966200878bfd1c0b4 (patch) | |
| tree | 66647b38bffa3eb904da993d9d583cc770c443df /src | |
| parent | d45dbccc5d2360818e70bbb0bc816c62c8cf6cbe (diff) | |
| download | emacs-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.c | 182 | ||||
| -rw-r--r-- | src/lisp.h | 48 | ||||
| -rw-r--r-- | src/xdisp.c | 4 |
3 files changed, 123 insertions, 111 deletions
| @@ -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, | |||
| 1343 | The value is actually the tail of LIST whose car is ELT. */) | 1344 | The 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, | |||
| 1354 | The value is actually the tail of LIST whose car is ELT. */) | 1357 | The 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. | |||
| 1383 | Elements of LIST that are not conses are ignored. */) | 1390 | Elements 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, | |||
| 1406 | The value is actually the first element of LIST whose car equals KEY. */) | 1415 | The 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, | |||
| 1437 | The value is actually the first element of LIST whose cdr is KEY. */) | 1448 | The 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, | |||
| 1448 | The value is actually the first element of LIST whose cdr equals KEY. */) | 1461 | The 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 | |||
| 1470 | argument. */) | 1485 | argument. */) |
| 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 | |||
| 1930 | properties on the list. This function never signals an error. */) | 1948 | properties 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. | |||
| 1963 | The PLIST is modified by side effects. */) | 1982 | The 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 | |||
| 2007 | one of the properties on the list. */) | 2027 | one 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. | |||
| 2030 | The PLIST is modified by side effects. */) | 2054 | The 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 | |||
| 2095 | internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | 2120 | internal_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. | |||
| 2763 | The value is actually the tail of PLIST whose car is PROP. */) | 2784 | The 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. */ |
| 4607 | struct for_each_tail_internal | 4600 | struct 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 | } |