◐ Shell
clean mode source ↗

Fix: simplecpp ## fails to expand function-like macro when '(' is not adjacent by paulafy6 · Pull Request #655 · cppcheck-opensource/simplecpp

… adjacent

When the ## operator concatenates two tokens to form a function-like macro
name (e.g. PREFIX_ ## kind → PREFIX_SCALAR), simplecpp looked for the
argument list '(...)' only at B->next. In PAR-style indirection patterns
the '(' is separated from B by a comma or a variadic parameter token:

  #define PAR(a, ...) a __VA_ARGS__
  #define PREFIX_SCALAR(T, N) T N
  #define DISPATCH(kind, ...) PAR(PREFIX_ ## kind, (__VA_ARGS__))
  DISPATCH(SCALAR, int, x)   // was: [unknownMacro] — now: int x

Because '(' was not found, expansion was aborted and the macro was
reported as unknownMacro, causing cppcheck to skip the entire translation
unit.

Fix: when B->next is not '(' and we are in the appendTokens context
(expandResult==false), walk forward on the same line skipping ',' separators
and resolving named parameter tokens via expandArg(). The first '(' found
(literally or as the head of an expanded argument) is used as lpar and
passed to appendTokens() as before. The forwardScan flag ensures
expandToken() is called on the result even when expandResult is false.

The forward scan is restricted to expandResult==false to avoid unintended
side-effects in the main expansion loop.

@paulafy6 mentioned this pull request

May 28, 2026
…like_par_indirection)

Covers the fix in expandHashHash(): when ## concatenation produces a
function-like macro name but '(' is not immediately adjacent in the
replacement text (hidden behind a comma/parameter), the forward scan
must locate '(' and complete the expansion.

  #define PAR(a, ...) a __VA_ARGS__
  #define PREFIX_SCALAR(T, N) T N
  #define DISPATCH(kind, ...) PAR(PREFIX_ ## kind, (__VA_ARGS__))
  DISPATCH(SCALAR, int, x)   // expected: int x

@danmar danmar linked an issue

Jun 2, 2026

that may be closed by this pull request

danmar