[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 682b068ba7: Merge remote-tracking branch 'origin/scratch/noverlay
From: |
Stefan Monnier |
Subject: |
master 682b068ba7: Merge remote-tracking branch 'origin/scratch/noverlay' |
Date: |
Thu, 17 Nov 2022 18:52:54 -0500 (EST) |
branch: master
commit 682b068ba712075cea34d8bc790620ba82169d6c
Merge: 17889dd828 091e0f04ff
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
Merge remote-tracking branch 'origin/scratch/noverlay'
---
src/alloc.c | 5 -
src/buffer.c | 12 +-
src/emacs.c | 3 -
src/eval.c | 1 -
src/itree.c | 432 +++++++++++++++++++++++++++--------------------------------
src/itree.h | 55 ++++----
src/xdisp.c | 10 +-
7 files changed, 230 insertions(+), 288 deletions(-)
diff --git a/src/alloc.c b/src/alloc.c
index 6862cf916f..b9d12dff7e 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6279,11 +6279,6 @@ garbage_collect (void)
image_prune_animation_caches (false);
#endif
- /* ELisp code run by `gc-post-hook' could result in itree iteration,
- which must not happen while the itree is already busy. See
- bug#58639. */
- eassert (!itree_iterator_busy_p ());
-
if (!NILP (Vpost_gc_hook))
{
specpdl_ref gc_count = inhibit_garbage_collection ();
diff --git a/src/buffer.c b/src/buffer.c
index 9be2c4a970..4da5b451d0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2985,17 +2985,13 @@ overlays_in (ptrdiff_t beg, ptrdiff_t end, bool extend,
if (node->begin > end)
{
next = min (next, node->begin);
- ITREE_FOREACH_ABORT ();
break;
}
else if (node->begin == end)
{
next = node->begin;
if ((! empty || end < ZV) && beg < end)
- {
- ITREE_FOREACH_ABORT ();
- break;
- }
+ break;
if (empty && node->begin != node->end)
continue;
}
@@ -3050,7 +3046,6 @@ next_overlay_change (ptrdiff_t pos)
of pos, because the search is limited to [pos,next) . */
eassert (node->begin < next);
next = node->begin;
- ITREE_FOREACH_ABORT ();
break;
}
else if (node->begin < node->end && node->end < next)
@@ -3155,10 +3150,7 @@ overlay_touches_p (ptrdiff_t pos)
pos. */
ITREE_FOREACH (node, current_buffer->overlays, pos - 1, pos + 1, DESCENDING)
if (node->begin == pos || node->end == pos)
- {
- ITREE_FOREACH_ABORT ();
- return true;
- }
+ return true;
return false;
}
diff --git a/src/emacs.c b/src/emacs.c
index c4c8bfc82f..85102acd28 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1932,7 +1932,6 @@ Using an Emacs configured with --with-x-toolkit=lucid
does not have this problem
running_asynch_code = 0;
init_random ();
init_xfaces ();
- init_itree ();
#if defined HAVE_JSON && !defined WINDOWSNT
init_json ();
@@ -3105,8 +3104,6 @@ You must run Emacs in batch mode in order to dump it. */)
gflags.will_dump_with_unexec_ = false;
gflags.dumped_with_unexec_ = true;
- forget_itree ();
-
alloc_unexec_pre ();
unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0);
diff --git a/src/eval.c b/src/eval.c
index ea23829948..78e606267f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1716,7 +1716,6 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object
data, bool keyboard_quit)
Lisp_Object clause = Qnil;
struct handler *h;
- eassert (!itree_iterator_busy_p ());
if (gc_in_progress || waiting_for_input)
emacs_abort ();
diff --git a/src/itree.c b/src/itree.c
index 3b219d958a..7bf3b9507b 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -131,33 +131,10 @@ along with GNU Emacs. If not, see
<http://www.gnu.org/licenses/>. */
* | Stack
* +=======================================================================+ */
-typedef uintptr_t nodeptr_and_flag;
-
-static inline nodeptr_and_flag
-make_nav (struct itree_node *ptr, bool flag)
-{
- uintptr_t v = (uintptr_t) ptr;
- /* We assume alignment imposes the LSB is clear for us to use it. */
- eassert (!(v & 1));
- return v | !!flag;
-}
-
-static inline struct itree_node *
-nav_nodeptr (nodeptr_and_flag nav)
-{
- return (struct itree_node *) (nav & (~(uintptr_t)1));
-}
-
-static inline bool
-nav_flag (nodeptr_and_flag nav)
-{
- return (bool) (nav & 1);
-}
-
/* Simple dynamic array. */
struct itree_stack
{
- nodeptr_and_flag *nodes;
+ struct itree_node **nodes;
size_t size;
size_t length;
};
@@ -184,12 +161,6 @@ itree_stack_destroy (struct itree_stack *stack)
xfree (stack);
}
-static void
-itree_stack_clear (struct itree_stack *stack)
-{
- stack->length = 0;
-}
-
static inline void
itree_stack_ensure_space (struct itree_stack *stack, uintmax_t nelements)
{
@@ -204,104 +175,32 @@ itree_stack_ensure_space (struct itree_stack *stack,
uintmax_t nelements)
/* Push NODE on the STACK, while settings its visited flag to FLAG. */
static inline void
-itree_stack_push_flagged (struct itree_stack *stack,
- struct itree_node *node, bool flag)
+itree_stack_push (struct itree_stack *stack, struct itree_node *node)
{
eassert (node);
-
- /* FIXME: While the stack used in the iterator is bounded by the tree
- depth and could be easily pre-allocated to a large enough size to avoid
- this "ensure" check, `itree_stack_push` is also used elsewhere to
- simply collect some subset of the overlays, where it's only bounded by
- the total number of overlays in the buffer (which can be large and thus
- preferably not pre-allocated needlessly). */
itree_stack_ensure_space (stack, stack->length + 1);
- stack->nodes[stack->length] = make_nav (node, flag);
+ stack->nodes[stack->length] = node;
stack->length++;
}
-static inline void
-itree_stack_push (struct itree_stack *stack, struct itree_node *node)
-{
- itree_stack_push_flagged (stack, node, false);
-}
-
-static inline nodeptr_and_flag
+static inline struct itree_node *
itree_stack_pop (struct itree_stack *stack)
{
if (stack->length == 0)
- return make_nav (NULL, false);
+ return NULL;
return stack->nodes[--stack->length];
}
/* +-----------------------------------------------------------------------+ */
-/* State used when iterating interval. */
-struct itree_iterator
-{
- struct itree_stack *stack;
- ptrdiff_t begin;
- ptrdiff_t end;
-
- /* A copy of the tree's `otick`. */
- uintmax_t otick;
- enum itree_order order;
- bool running;
- const char *file;
- int line;
-};
-
-/* Ideally, every iteration would use its own `iter` object, so we could
- have several iterations active at the same time. In practice, iterations
- are limited by the fact we don't allow modifying the tree at the same
- time, making the use of nested iterations quite rare anyway.
- So we just use a single global iterator instead for now. */
-static struct itree_iterator *iter = NULL;
-
static int
itree_max_height (const struct itree_tree *tree)
{
return 2 * log (tree->size + 1) / log (2) + 0.5;
}
-/* Allocate a new iterator for TREE. */
-
-static struct itree_iterator *
-itree_iterator_create (struct itree_tree *tree)
-{
- struct itree_iterator *g = xmalloc (sizeof *g);
- /* 19 here just avoids starting with a silly-small stack.
- FIXME: Since this stack only needs to be about 2*max_depth
- in the worst case, we could completely pre-allocate it to something
- like word-bit-size * 2 and then never worry about growing it. */
- const int size = (tree ? itree_max_height (tree) : 19) + 1;
-
- g->stack = itree_stack_create (size);
- g->running = false;
- g->begin = 0;
- g->end = 0;
- g->file = NULL;
- g->line = 0;
- return g;
-}
-
-void
-init_itree (void)
-{
- eassert (!iter);
- iter = itree_iterator_create (NULL);
-}
-
-#ifdef HAVE_UNEXEC
-void
-forget_itree (void)
-{
- iter = NULL;
-}
-#endif
-
struct check_subtree_result
{
/* Node count of the tree. */
@@ -869,14 +768,11 @@ itree_node_set_region (struct itree_tree *tree,
static bool
itree_contains (struct itree_tree *tree, struct itree_node *node)
{
- eassert (iter && node);
+ eassert (node);
struct itree_node *other;
ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING)
if (other == node)
- {
- ITREE_FOREACH_ABORT ();
- return true;
- }
+ return true;
return false;
}
@@ -1138,52 +1034,6 @@ itree_remove (struct itree_tree *tree, struct itree_node
*node)
return node;
}
-bool
-itree_iterator_busy_p (void)
-{
- return (iter && iter->running);
-}
-
-/* Start a iterator enumerating all intervals in [BEGIN,END) in the
- given ORDER. Only one iterator per tree can be running at any time. */
-
-struct itree_iterator *
-itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin,
- ptrdiff_t end, enum itree_order order,
- const char *file, int line)
-{
- eassert (iter);
- if (iter->running)
- {
- fprintf (stderr,
- "Detected nested iteration!\nOuter: %s:%d\nInner: %s:%d\n",
- iter->file, iter->line, file, line);
- emacs_abort ();
- }
- iter->begin = begin;
- iter->end = end;
- iter->otick = tree->otick;
- iter->order = order;
- itree_stack_clear (iter->stack);
- if (begin <= end && tree->root != NULL)
- itree_stack_push_flagged (iter->stack, tree->root, false);
- iter->file = file;
- iter->line = line;
- iter->running = true;
- /* itree_stack_ensure_space (iter->stack,
- 2 * itree_max_height (tree)); */
- return iter;
-}
-
-/* Stop using the iterator. */
-
-void
-itree_iterator_finish (struct itree_iterator *iter)
-{
- eassert (iter && iter->running);
- iter->running = false;
-}
-
/* +=======================================================================+
* | Insert/Delete Gaps
@@ -1214,6 +1064,7 @@ itree_insert_gap (struct itree_tree *tree,
struct itree_node *node = NULL;
if (!before_markers)
{
+ /* Actually any order would do. */
ITREE_FOREACH (node, tree, pos, pos + 1, PRE_ORDER)
{
if (node->begin == pos && node->front_advance
@@ -1225,7 +1076,7 @@ itree_insert_gap (struct itree_tree *tree,
}
}
for (size_t i = 0; i < saved->length; ++i)
- itree_remove (tree, nav_nodeptr (saved->nodes[i]));
+ itree_remove (tree, saved->nodes[i]);
/* We can't use an iterator here, because we can't effectively
narrow AND shift some subtree at the same time. */
@@ -1234,9 +1085,7 @@ itree_insert_gap (struct itree_tree *tree,
const int size = itree_max_height (tree) + 1;
struct itree_stack *stack = itree_stack_create (size);
itree_stack_push (stack, tree->root);
- nodeptr_and_flag nav;
- while ((nav = itree_stack_pop (stack),
- node = nav_nodeptr (nav)))
+ while ((node = itree_stack_pop (stack)))
{
/* Process in pre-order. */
itree_inherit_offset (tree->otick, node);
@@ -1273,9 +1122,7 @@ itree_insert_gap (struct itree_tree *tree,
/* Reinsert nodes starting at POS having front-advance. */
uintmax_t notick = tree->otick;
- nodeptr_and_flag nav;
- while ((nav = itree_stack_pop (saved),
- node = nav_nodeptr (nav)))
+ while ((node = itree_stack_pop (saved)))
{
eassert (node->otick == ootick);
eassert (node->begin == pos);
@@ -1308,10 +1155,8 @@ itree_delete_gap (struct itree_tree *tree,
struct itree_node *node;
itree_stack_push (stack, tree->root);
- nodeptr_and_flag nav;
- while ((nav = itree_stack_pop (stack)))
+ while ((node = itree_stack_pop (stack)))
{
- node = nav_nodeptr (nav);
itree_inherit_offset (tree->otick, node);
if (pos > node->limit)
continue;
@@ -1357,80 +1202,205 @@ itree_delete_gap (struct itree_tree *tree,
static inline bool
itree_node_intersects (const struct itree_node *node,
- ptrdiff_t begin, ptrdiff_t end)
+ ptrdiff_t begin, ptrdiff_t end)
{
return (begin < node->end && node->begin < end)
|| (node->begin == node->end && begin == node->begin);
}
-/* Return the next node of the iterator in the order given when it was
- started; or NULL if there are no more nodes. */
+/* Return the "next" node in the current traversal order.
-struct itree_node *
-itree_iterator_next (struct itree_iterator *g)
-{
- eassert (g && g->running);
+ Note that this should return all the nodes that we need to traverse
+ in order to traverse the nodes selected by the current narrowing (i.e.
+ `ITER->begin..ITER->end`) so it will also return some nodes which aren't in
+ that narrowing simply because they may have children which are.
- struct itree_node *const null = NULL;
- struct itree_node *node;
+ The code itself is very unsatifactory because the code of each one
+ of the supported traversals seems completely different from the others.
+ If someone knows how to make it more uniform and "obviously correct",
+ please make yourself heard. */
- /* The `visited` flag stored in each node is used here (and only here):
- We keep a "workstack" of nodes we need to consider. This stack
- consist of nodes of two types: nodes that we have decided
- should be returned by the iterator, and nodes which we may
- need to consider (including checking their children).
- We start an iteration with a stack containing just the root
- node marked as "not visited" which means that it (and its children)
- needs to be considered but we haven't yet decided whether it's included
- in the iterator's output. */
-
- do
+static struct itree_node *
+itree_iter_next_in_subtree (struct itree_node *node,
+ struct itree_iterator *iter)
+{
+ struct itree_node *next;
+ switch (iter->order)
{
- nodeptr_and_flag nav;
- bool visited;
- while ((nav = itree_stack_pop (g->stack),
- node = nav_nodeptr (nav),
- visited = nav_flag (nav),
- node && !visited))
- {
- struct itree_node *const left = node->left;
- struct itree_node *const right = node->right;
+ case ITREE_ASCENDING:
+ next = node->right;
+ if (!next)
+ {
+ while ((next = node->parent)
+ && next->right == node)
+ node = next;
+ if (!next)
+ return NULL; /* No more nodes to visit. */
+ node = next;
+ }
+ else
+ {
+ node = next;
+ itree_inherit_offset (iter->otick, node);
+ while ((next = node->left)
+ && (itree_inherit_offset (iter->otick, next),
+ iter->begin <= next->limit))
+ node = next;
+ }
+ if (node->begin > iter->end)
+ return NULL; /* No more nodes within begin..end. */
+ return node;
+
+ case ITREE_DESCENDING:
+ next = node->left;
+ if (!next
+ || (itree_inherit_offset (iter->otick, next),
+ next->limit < iter->begin))
+ {
+ while ((next = node->parent)
+ && next->left == node)
+ node = next;
+ if (!next)
+ return NULL; /* No more nodes to visit. */
+ node = next;
+ }
+ else
+ {
+ node = next;
+ while (node->begin <= iter->end
+ && (next = node->right))
+ {
+ itree_inherit_offset (iter->otick, next),
+ node = next;
+ }
+ }
+ return node;
+
+ case ITREE_PRE_ORDER:
+ next = node->left;
+ if (next
+ && (itree_inherit_offset (iter->otick, next),
+ !(next->limit < iter->begin)))
+ return next;
+ next = node->right;
+ if (node->begin <= iter->end && next)
+ {
+ itree_inherit_offset (iter->otick, next);
+ return next;
+ }
+ while ((next = node->parent))
+ {
+ if (next->right == node)
+ node = next;
+ else
+ {
+ eassert (next->left == node);
+ node = next;
+ next = node->right;
+ if (node->begin <= iter->end && next)
+ {
+ itree_inherit_offset (iter->otick, next);
+ return next;
+ }
+ }
+ }
+ return NULL;
+
+ case ITREE_POST_ORDER:
+ next = node->parent;
+ if (!next || next->right == node)
+ return next;
+ eassert (next->left == node);
+ node = next;
+ next = node->right;
+ if (!(node->begin <= iter->end && next))
+ return node;
+ node = next;
+ itree_inherit_offset (iter->otick, node);
+ while (((next = node->left)
+ && (itree_inherit_offset (iter->otick, next),
+ iter->begin <= next->limit))
+ || (node->begin <= iter->end
+ && (next = node->right)
+ && (itree_inherit_offset (iter->otick, next), true)))
+ node = next;
+ return node;
+
+ default:
+ emacs_abort ();
+ }
+}
- itree_inherit_offset (g->otick, node);
- eassert (itree_limit_is_stable (node));
- switch (g->order)
- {
- case ITREE_ASCENDING:
- if (right != null && node->begin <= g->end)
- itree_stack_push_flagged (g->stack, right, false);
- if (itree_node_intersects (node, g->begin, g->end))
- itree_stack_push_flagged (g->stack, node, true);
- /* Node's children may still be off-set and we need to add it. */
- if (left != null && g->begin <= left->limit + left->offset)
- itree_stack_push_flagged (g->stack, left, false);
- break;
- case ITREE_DESCENDING:
- if (left != null && g->begin <= left->limit + left->offset)
- itree_stack_push_flagged (g->stack, left, false);
- if (itree_node_intersects (node, g->begin, g->end))
- itree_stack_push_flagged (g->stack, node, true);
- if (right != null && node->begin <= g->end)
- itree_stack_push_flagged (g->stack, right, false);
- break;
- case ITREE_PRE_ORDER:
- if (right != null && node->begin <= g->end)
- itree_stack_push_flagged (g->stack, right, false);
- if (left != null && g->begin <= left->limit + left->offset)
- itree_stack_push_flagged (g->stack, left, false);
- if (itree_node_intersects (node, g->begin, g->end))
- itree_stack_push_flagged (g->stack, node, true);
- break;
- }
- }
- /* Node may have been invalidated by itree_iterator_narrow
- after it was pushed: Check if it still intersects. */
- } while (node && ! itree_node_intersects (node, g->begin, g->end));
+static struct itree_node *
+itree_iterator_first_node (struct itree_tree *tree,
+ struct itree_iterator *iter)
+{
+ struct itree_node *node = tree->root;
+ if (node)
+ {
+ struct itree_node dummy;
+ dummy.left = NULL;
+ dummy.parent = NULL;
+ dummy.right = NULL;
+ itree_inherit_offset (iter->otick, node);
+ switch (iter->order)
+ {
+ case ITREE_ASCENDING:
+ dummy.right = node;
+ dummy.begin = PTRDIFF_MIN;
+ node = itree_iter_next_in_subtree (&dummy, iter);
+ break;
+
+ case ITREE_DESCENDING:
+ dummy.left = node;
+ node = itree_iter_next_in_subtree (&dummy, iter);
+ break;
+
+ case ITREE_PRE_ORDER:
+ break;
+
+ case ITREE_POST_ORDER:
+ dummy.parent = &dummy;
+ dummy.left = &dummy;
+ dummy.right = node;
+ dummy.begin = PTRDIFF_MIN;
+ node = itree_iter_next_in_subtree (&dummy, iter);
+ break;
+ default:
+ emacs_abort ();
+ }
+ }
+ return node;
+}
+
+/* Start a iterator enumerating all intervals in [BEGIN,END) in the
+ given ORDER. */
+struct itree_iterator *
+itree_iterator_start (struct itree_iterator *iter,
+ struct itree_tree *tree,
+ ptrdiff_t begin, ptrdiff_t end, enum itree_order order)
+{
+ eassert (iter);
+ iter->begin = begin;
+ iter->end = end;
+ iter->otick = tree->otick;
+ iter->order = order;
+ iter->node = itree_iterator_first_node (tree, iter);
+ return iter;
+}
+
+struct itree_node *
+itree_iterator_next (struct itree_iterator *iter)
+{
+ struct itree_node *node = iter->node;
+ while (node
+ && !itree_node_intersects (node, iter->begin, iter->end))
+ {
+ node = itree_iter_next_in_subtree (node, iter);
+ eassert (itree_limit_is_stable (node));
+ }
+ iter->node = node ? itree_iter_next_in_subtree (node, iter) : NULL;
return node;
}
@@ -1441,7 +1411,7 @@ void
itree_iterator_narrow (struct itree_iterator *g,
ptrdiff_t begin, ptrdiff_t end)
{
- eassert (g && g->running);
+ eassert (g);
eassert (begin >= g->begin);
eassert (end <= g->end);
g->begin = max (begin, g->begin);
diff --git a/src/itree.h b/src/itree.h
index 10ee0897c3..291fa53fd3 100644
--- a/src/itree.h
+++ b/src/itree.h
@@ -104,12 +104,9 @@ enum itree_order
ITREE_ASCENDING,
ITREE_DESCENDING,
ITREE_PRE_ORDER,
+ ITREE_POST_ORDER,
};
-extern void init_itree (void);
-#ifdef HAVE_UNEXEC
-extern void forget_itree (void);
-#endif
extern void itree_node_init (struct itree_node *, bool, bool, Lisp_Object);
extern ptrdiff_t itree_node_begin (struct itree_tree *, struct itree_node *);
extern ptrdiff_t itree_node_end (struct itree_tree *, struct itree_node *);
@@ -128,20 +125,28 @@ extern void itree_delete_gap (struct itree_tree *,
ptrdiff_t, ptrdiff_t);
/* Iteration functions. Almost all code should use ITREE_FOREACH
instead. */
-extern bool itree_iterator_busy_p (void);
-extern struct itree_iterator *itree_iterator_start (struct itree_tree *,
+extern struct itree_iterator *itree_iterator_start (struct itree_iterator *,
+ struct itree_tree *,
ptrdiff_t,
ptrdiff_t,
- enum itree_order,
- const char *, int);
+ enum itree_order);
extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t,
ptrdiff_t);
-extern void itree_iterator_finish (struct itree_iterator *);
extern struct itree_node *itree_iterator_next (struct itree_iterator *);
+/* State used when iterating interval. */
+struct itree_iterator
+ {
+ struct itree_node *node;
+ ptrdiff_t begin;
+ ptrdiff_t end;
+ uintmax_t otick; /* A copy of the tree's `otick`. */
+ enum itree_order order;
+ };
+
/* Iterate over the intervals between BEG and END in the tree T.
N will hold successive nodes. ORDER can be one of : `ASCENDING`,
- `DESCENDING`, or `PRE_ORDER`.
+ `DESCENDING`, `POST_ORDER`, or `PRE_ORDER`.
It should be used as:
ITREE_FOREACH (n, t, beg, end, order)
@@ -152,33 +157,23 @@ extern struct itree_node *itree_iterator_next (struct
itree_iterator *);
BEWARE:
- The expression T may be evaluated more than once, so make sure
it is cheap and pure.
- - Only a single iteration can happen at a time, so make sure none of the
- code within the loop can start another tree iteration, i.e. it shouldn't
- be able to run ELisp code, nor GC since GC can run ELisp by way
- of `post-gc-hook`.
- - If you need to exit the loop early, you *have* to call `ITREE_ABORT`
- just before exiting (e.g. with `break` or `return`).
- - Non-local exits are not supported within the body of the loop.
- Don't modify the tree during the iteration.
*/
#define ITREE_FOREACH(n, t, beg, end, order) \
- /* FIXME: We'd want to declare `x` right here, but I can't figure out
+ /* FIXME: We'd want to declare `n` right here, but I can't figure out
how to make that work here: the `for` syntax only allows a single
clause for the var declarations where we need 2 different types.
We could use the `struct {foo x; bar y; } p;` trick to declare two
vars `p.x` and `p.y` of unrelated types, but then none of the names
- of the vars matches the `n` we receive :-(. */ \
- if (!t) \
- { } \
- else \
- for (struct itree_iterator *itree_iter_ \
- = itree_iterator_start (t, beg, end, ITREE_##order, \
- __FILE__, __LINE__); \
- ((n = itree_iterator_next (itree_iter_)) \
- || (itree_iterator_finish (itree_iter_), false));)
-
-#define ITREE_FOREACH_ABORT() \
- itree_iterator_finish (itree_iter_)
+ of the vars matches the `n` we receive :-(. */ \
+ if (!t) \
+ { } \
+ else \
+ for (struct itree_iterator itree_local_iter_, \
+ *itree_iter_ \
+ = itree_iterator_start (&itree_local_iter_, \
+ t, beg, end, ITREE_##order); \
+ ((n = itree_iterator_next (itree_iter_)));)
#define ITREE_FOREACH_NARROW(beg, end) \
itree_iterator_narrow (itree_iter_, beg, end)
diff --git a/src/xdisp.c b/src/xdisp.c
index 3b4f0b3956..f8fc0f5787 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -7044,17 +7044,11 @@ strings_with_newlines (ptrdiff_t startpos, ptrdiff_t
endpos, struct window *w)
str = Foverlay_get (overlay, Qbefore_string);
if (STRINGP (str) && SCHARS (str)
&& memchr (SDATA (str), '\n', SBYTES (str)))
- {
- ITREE_FOREACH_ABORT ();
- return true;
- }
+ return true;
str = Foverlay_get (overlay, Qafter_string);
if (STRINGP (str) && SCHARS (str)
&& memchr (SDATA (str), '\n', SBYTES (str)))
- {
- ITREE_FOREACH_ABORT ();
- return true;
- }
+ return true;
}
/* Check for 'display' properties whose values include strings. */