One possibility is to create an alternative macro that must be used in C89 code. You'd have to extend the scope and encapsulate the action, such as by making a new set of macros as follows:
/* Force a compiler error if non-C99 code uses the C99 macro. */
#if __STDC_VERSION__ >= 199901L
/* C99 code */
#define MAP_FOREACH(key, val, map) \
for (struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup))); \
(key) = iter->pair->key, \
(value) = iter->pair->value; \
iter = iter->get_next_cb())
#endif
/* C89-compatible macro */
#define MAP_FOREACH_DO(key, val, map, statement) \
do{ struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup))); \
for (; \
(key) = iter->pair->key, \
(value) = iter->pair->value; \
iter = iter->get_next_cb()) \
{ \
statement; \
} \
}while(0)
That way for simple statements you can just do something like:
MAP_FOREACH_DO(..., printf(%s=%s\n", key, value));
... and for more complex statements you can call a function.
Ideally, of course, you just switch to C99 (at least for the relevant code) and be done with it.