The current implementation of m4_set_foreach leaves its macro variable defined to whatever the final element of the set was. This differs from m4_foreach, which pushes & pops the definition in its expansion.
Since this macro is often used with really short macro names (the manual has an example with m4_set_foreach([a], [i], ...)), this can lead to some incredibly surprising behaviour. For example: % cat >test.m4 <<'EOF' m4_init m4_define([_m4_divert(BODY)], [0]) m4_set_add([a], [not_i]) m4_set_foreach([a], [i]) m4_divert_text([BODY], [i]) EOF % autom4te -l m4sugar test.m4 not_i Turns out the implementation already had a pushdef, and it looks like the popdef was simply forgotten. Add it now. * lib/m4sugar/m4sugar.m4 (m4_set_foreach): pop macro definition. --- lib/m4sugar/m4sugar.m4 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index a93b4392e1c5..5421ed4894b0 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -3126,7 +3126,8 @@ m4_define([m4_set_empty], # guaranteed. This is faster than the corresponding m4_foreach([VAR], # m4_indir([m4_dquote]m4_set_listc([SET])), [ACTION]) m4_define([m4_set_foreach], -[m4_pushdef([$2])m4_set_map_sep([$1], [m4_define([$2],], [)$3])]) +[m4_pushdef([$2])m4_set_map_sep([$1], [m4_define([$2],], [)$3])dnl +m4_popdef([$2])]) # m4_set_intersection(SET1, SET2) # ------------------------------- -- 2.2.2