Skip to content

fix(plugin, preprocessor): avoid empty variadic macro arguments - #954

Open
mohdTahaRafi wants to merge 2 commits into
metacall:developfrom
mohdTahaRafi:fix/560-clang-zero-variadic
Open

mohdTahaRafi wants to merge 2 commits into
metacall:developfrom
mohdTahaRafi:fix/560-clang-zero-variadic

Conversation

@mohdTahaRafi

@mohdTahaRafi mohdTahaRafi commented Nov 11, 2026 •

Copy link
Copy Markdown

Description

This PR fixes the Clang -Wgnu-zero-variadic-macro-arguments warnings from #560. Before C++20, Clang (with -Wpedantic, which MetaCall uses) gives this warning when a macro with ... gets no argument for it. With Clang 18, cli_core_plugin.cpp had 12 of them, from 2 causes:

  1. Commands with no arguments, like EXTENSION_FUNCTION(METACALL_INT, help) and EXTENSION_FUNCTION_CHECK(HELP_ERROR), left the macro's ... empty.
  2. PREPROCESSOR_FOR called IMPL_1 without the dummy ~ that IMPL_2 already adds, so IMPL_1's ... was empty with one type, and also with zero types (the unused branch of PREPROCESSOR_IF still gets expanded).

Changes:

  • plugin_interface.hpp: EXTENSION_FUNCTION and EXTENSION_FUNCTION_CHECK now take all their arguments through ..., so it is never empty. They use PREPROCESSOR_ARGS_COMMA to check if there are argument types, and pick the IMPL or IMPL_VOID version (the dispatch idea from the issue). The call goes through PREPROCESSOR_TUPLE_EXPAND_MACRO, so MSVC's old preprocessor splits the arguments too (the same NAME (args) pattern its versions of PREPROCESSOR_ARGS_COUNT and PREPROCESSOR_FOR already use; not tested locally). No call sites changed.
  • preprocessor_for_body.h.in and the regenerated preprocessor_for.h: added the missing ~ in PREPROCESSOR_FOR and PREPROCESSOR_FOR_EACH.
  • preprocessor_test.cpp: added for_one and foreach_one tests, because 1 element had no test (0 and many elements did). With the old headers these 2 tests give the warning, with the fix they don't. If you don't want them in this PR, I can remove them.

Testing: Clang warnings went from 12 to 0 in cli_core_plugin.cpp, and from 9 to 0 in the sandbox plugins (cli_sandbox_plugin.cpp 7, sandbox_plugin.cpp 2, built with OPTION_BUILD_PLUGINS_SANDBOX=ON). GCC has no new warnings. The preprocessed (-E -P) output of the 5 files that use these macros is byte-identical to before, so the generated code doesn't change. Full Clang and GCC builds pass, and the full ctest passes 75/75 with both compilers (preprocessor-test now has 23 cases).

Screenshots (Clang 18, same flags as the build, -std=gnu++11 -Wpedantic):

Before (develop): 21 warnings in the 3 plugin files

b1 b2

After (this PR): 0 warnings, the files were compiled, and all tests pass

Screenshot from 2026-11-11 19-26-09

Open questions:

  • I can't test MSVC, so Windows CI needs to confirm it. The existing for and foreach tests already pass string literals through the same PREPROCESSOR_ARGS_COMMA on MSVC, so I expect it to work.
  • preprocessor_test.cpp still has 4 of these warnings (it had 6) because it uses empty arguments on purpose. Should I change those tests?

This is my first commit here, so the PR also has a separate commit adding me to CONTRIBUTORS (the pre-commit hook asks for it).

No new dependencies.

Fixes #560

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation. (nothing to change, no docs cover these macros)
  • My changes generate no new warnings.
  • I have added tests/screenshots (if any) that prove my fix is effective or that my feature works.
  • I have tested the tests implicated (if any) by my own code and they pass (make test or ctest -VV -R <test-name>).
  • If my change is significant or breaking, I have passed all tests with ./docker-compose.sh test &> output and attached the output. (not breaking, and my disk doesn't have space for the Docker images, so I ran the full test suite locally with Clang and GCC: 75/75)
  • I have tested my code with OPTION_BUILD_ADDRESS_SANITIZER or ./docker-compose.sh test-address-sanitizer &> output and OPTION_TEST_MEMORYCHECK. (ASan + UBSan: 74/74 pass, 0 reports; MetaCall skips the sandbox test under sanitizers, so 74 not 75. Memcheck: same 3 failures and same defects as develop without my change, all in Node and simdjson, none in the changed code)
  • I have tested my code with OPTION_BUILD_THREAD_SANITIZER or ./docker-compose.sh test-thread-sanitizer &> output. (74/74 pass, 0 reports)
  • I have tested with Helgrind in case my code works with threading. (no threading in the change; ran the CLI under Helgrind, all reports come from Node, same as on develop)
  • I have run cmake --build build --target clang-format (or cmake -DMODE=fix -P cmake/Format.cmake) in order to format my code and my code follows the style guidelines.
  • I have linked the Issue or Discussion with maintainer scope approval (community-first workflow, else the PR stays ignored).
  • I have disclosed AI assistance in the PR description (AI-ASSISTED: yes/no, model, human reviewer) and I own each line.

AI-ASSISTED: yes, Claude Opus 5.5, Reviewed and tested by me.

Clang warns (-Wgnu-zero-variadic-macro-arguments) when a variadic macro
gets nothing for its "...". cli_core_plugin.cpp had 12 such warnings.
Changes:

- EXTENSION_FUNCTION and EXTENSION_FUNCTION_CHECK now take all their
  arguments through "..." and pick the IMPL or IMPL_VOID variant with
  PREPROCESSOR_ARGS_COMMA, so calls without parameter types no longer
  leave it empty. Call sites are unchanged.
- PREPROCESSOR_FOR and PREPROCESSOR_FOR_EACH now pass the dummy ~ to
  IMPL_1, as IMPL_2 already does, so one-element calls (and the unused
  branch of zero-element calls) no longer leave it empty. Changed in
  preprocessor_for_body.h.in, and preprocessor_for.h is regenerated.
- Add for_one and foreach_one to preprocessor_test, since a single
  element was not tested.

With Clang 18 the warnings go from 12 to 0 in cli_core_plugin.cpp and
from 9 to 0 in the sandbox plugins, and the preprocessed output is the
same as before with both Clang and GCC.

Fixes metacall#560
Copilot AI balanced review requested due to automatic review settings November 11, 2026 13:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@viferga

viferga commented Nov 11, 2026

Copy link
Copy Markdown
Member

I'm gonna run the CI, we can see the build output there.

@viferga

viferga commented Nov 11, 2026

Copy link
Copy Markdown
Member

If it works, next step will be adding -Werror

@mohdTahaRafi

mohdTahaRafi commented Nov 11, 2026 •

Copy link
Copy Markdown
Author

I checked the failed jobs in the CI run and many of them also happen in develop. Most failures appear to be environment related, such as package server connectivity and TSan's unexpected memory mapping error.

The FreeBSD Clang logs also show no warnings from the plugin and preprocessor files modified in this PR.

Regarding -Werror, I noticed four existing warnings in preprocessor_test.cpp and some -Wformat warnings in other files. I think a separate issue and a separate PR for that would be good but if you want it be resolved in this PR only then its fine.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preprocessor warnings with Clang

3 participants