Skip to content

include/nuttx/macro.h: Add FOREACH_IDX_ARG() and fix REVERSE_ARG() - #20015

Open
JorgeGzm wants to merge 1 commit into
apache:masterfrom
JorgeGzm:macro_foreach_idx
Open

include/nuttx/macro.h: Add FOREACH_IDX_ARG() and fix REVERSE_ARG()#20015
JorgeGzm wants to merge 1 commit into
apache:masterfrom
JorgeGzm:macro_foreach_idx

Conversation

@JorgeGzm

Copy link
Copy Markdown
Member

Summary

FOREACH_ARG() hands the action the position of the argument as an
expression (count - N), which cannot be pasted into an identifier. This
adds a companion that passes it as a two digit literal (00, 01, ...),
so the position can become part of a symbol name and, through
SORT_BY_NAME(), part of the order the linker gives to the objects a
subsystem registers with the link time iterable sections.

The dispatch uses CONCATENATE() and GET_ARG_COUNT(), each arity emits
its own literal, and the list is reversed first with REVERSE_ARG(), so
no increment tables are needed. An empty list expands to nothing.

Using REVERSE_ARG() required fixing it first:

REVERSE_ARG() expanded to REVERSE_ARG_(##__VA_ARGS__). The token
before the ## is an opening parenthesis, not a comma, so the GNU
extension that swallows an empty variable argument list does not apply:
the preprocessor pastes ( with the first argument and the build fails
with

error: pasting "(" and "x" does not give a valid preprocessing token

The macro therefore only ever worked with an empty argument list, which
is why the problem went unnoticed since the file was added in
3271142. Dropping the ## makes the arguments expand; the empty case
is unaffected.

And fix REVERSE_ARG(), which it needs

Impact

Nothing existing is affected. FOREACH_IDX_ARG() is entirely new, and
REVERSE_ARG() has no user in either repository: with arguments it did
not compile, so no code could depend on it, and with an empty list it
expands exactly as before. No macro already in the header changes
behaviour.

The documentation of the iterable sections already said that an instance
may encode its order in its name but not how; it now points at the new
macro (four lines in
Documentation/components/iterable_sections.rst).

The first user of the new macro is the zbus port
(apache/nuttx-apps#3743), which names one object per channel/observer
pair after the position of the observer in the channel definition.

Testing

Host: Ubuntu 24.04.4 x86_64, arm-none-eabi-gcc 13.2.1.

Expansion checked for 0, 1, 3, 8 and 32 arguments with

#define SHOW(p, x, i) [p:x:i]
FOREACH_IDX_ARG(SHOW, P, a, b, c)   /* [P:c:02] [P:b:01] [P:a:00] */
FOREACH_IDX_ARG(SHOW, P)            /* expands to nothing */

and the 32 argument case yields [a1:00] ... [d8:31]. Without the
REVERSE_ARG() fix the same expansions fail with the pasting error
quoted above.

Built and run on linum-stm32h753bi together with apache/nuttx-apps#3743:
the observations of every channel come out of the linker grouped per
channel and ordered by the position in the definition, and the zbus test
suite passes 17/17 twice in the same boot, including a test that asserts
the notification order.

tools/checkpatch.sh -c -u -m -g on the commit: all checks pass, and
sphinx-build -W builds the documentation clean.

@JorgeGzm JorgeGzm self-assigned this Aug 30, 2026
@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Size: S The size of the change in this PR is small labels Aug 30, 2026
@JorgeGzm JorgeGzm removed their assignment Aug 30, 2026
@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Comment thread include/nuttx/macro.h Outdated
@github-actions github-actions Bot added Size: M The size of the change in this PR is medium and removed Size: S The size of the change in this PR is small labels Aug 31, 2026
@github-actions github-actions Bot added Size: S The size of the change in this PR is small and removed Size: M The size of the change in this PR is medium labels Aug 31, 2026
@github-actions github-actions Bot added Size: M The size of the change in this PR is medium and removed Size: S The size of the change in this PR is small labels Aug 31, 2026
FOREACH_ARG() handed the position of each argument as the expression
"count - N", which can be used as a value but cannot be pasted into an
identifier.  Hand it out as a literal instead, so that an action macro
can build a symbol name out of it, which is what a subsystem needs when
the link order of its objects has to follow the declaration order.

The per arity chain the expression form required is dropped and the one
reached through REVERSE_ARG() is kept, so the file carries a single
foreach engine.  Reversing the list is what makes the position a
literal, and each step emits the recursion before its own action, so
the actions still come out in the order the arguments were given.  This
is how the same problem is solved upstream in Zephyr, whose FOR_EACH()
family also reverses the list before walking a per arity chain.

The index values are unchanged, so the arithmetic use keeps working:
NOTE_PRINTF_TYPES(), the only user in tree, produces the same tags.  It
now supplies the leading zero itself, because FOREACH_ARG() no longer
expands to "0" when the list is empty.

Counting the arguments after they are expanded also fixes the empty
list: a macro that expands to nothing used to produce one action on an
empty argument, and now produces none.

REVERSE_ARG() had a "##" right after the opening parenthesis and failed
to expand whenever it was given arguments.  It is used now.

Assisted-by: Claude Code
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Documentation Improvements or additions to documentation Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants