Skip to content

Require the compiler's rejection in reject tests, and run them concurrently - #464

Open
Bronek wants to merge 2 commits into
mainfrom
bronek/concurrent_reject_tests
Open

Bronek wants to merge 2 commits into
mainfrom
bronek/concurrent_reject_tests

Conversation

@Bronek

@Bronek Bronek commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Reject tests used WILL_FAIL, so any build failure counted as a pass, including failures before compilation. A lock ran the tests one at a time to prevent concurrent builds in the same tree from interfering with each other.

Scenario targets now compile through cmake/RejectLauncher.cmake. A reject test passes only when the launcher prints a marker confirming that the compiler reported an error at a source line, in GCC/Clang or MSVC format. A broken build fails the test instead, as does a compiler that is killed, crashes or reports an internal error before it reports such an error.

Before the scenarios run, a setup fixture compiles each reject source without a scenario through the same launcher, if any. This regenerates a stale build tree once and prevents errors outside the scenario guards from making every scenario pass. Removing the lock lets ctest -j run reject tests concurrently. Other targets keep any global launcher, such as ccache. Visual Studio generators ignore compiler launchers, so they retain WILL_FAIL and the lock.

The test setup is in cmake/RejectTests.cmake; the launcher's self-test is in tests/cmake/.

Tests that run a program carry fn_run or pfn_run, and reject scenarios fn_reject or pfn_reject, so CTest's label summary shows the time each group takes. Filter on them with an anchored pattern, such as ctest -L '^fn_reject$', since fn_reject alone also matches pfn_reject.

The full suite passes locally under ctest -j 40 with gcc 16.2 and clang 22.1, using Ninja and Makefiles (142 tests, 92 reject scenarios). Additional checks confirm that:

  • A scenario that compiles fails its reject test.
  • A regeneration failure fails every scenario when the fixture is bypassed.
  • A typo outside the scenario guards or a launcher that drops include paths fails the fixture.
  • Real internal compiler errors from GCC and Clang print no marker. Neither does an MSVC 19.44 internal compiler error replayed from a published build log.

This PR's CI is the first run of the Visual Studio fallback and AppleClang.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5-5

…rently

WILL_FAIL counted any failed build as a rejection, so the reject tests
held a lock serializing them: concurrent builds in one tree race on its
build-system state. A build failing before it compiled still passed.

Scenario targets compile through a CMake-script launcher, which prints
a marker only when the compiler exits with a non-zero status after
reporting an error at a source line, in the GCC and Clang or the MSVC
format, and the tests require that marker. An exit status alone cannot
tell: GCC reports its front end killed, as by the OOM killer, and Clang
its own crash, with the status of a rejection. A line reporting an
internal compiler error never counts, since MSVC reports one at a source
line. The launcher replaces any global launcher, such as ccache, on
scenario targets only.

A setup fixture compiles each reject source without a scenario, through
the same launcher, before any scenario runs. This regenerates a stale
build system once, keeps a source broken outside its guards from
passing every scenario, and catches a launcher that breaks the compile
line. The launcher script is an object dependency of the reject
sources, so editing it recompiles these controls. A self-test of the
launcher's verdicts and argument forwarding also gates the scenarios.
Generators other than Ninja and Makefiles ignore compiler launchers,
and keep WILL_FAIL with the lock.

add_reject_tests moves from tests/CMakeLists.txt into
cmake/RejectTests.cmake, beside the launcher, cmake/RejectLauncher.cmake:
cmake/ holds the build's CMake code, and tests/util/ the C++ test
helpers. The launcher's self-test lives in tests/cmake/, mirroring
cmake/.

Locally, with gcc 16.2 and Ninja, ctest -j 40 runs the 79 scenarios in
3 s against 70 s serially. In a stale tree the fixture regenerates once
and every scenario passes on a compiler error, where the concurrent
regenerations used to race and pass all 79 without compiling. With gcc
16.2 and clang 22.1, under Ninja and Makefiles: a scenario that
compiles fails; a failing regeneration fails all 79 with the fixture
bypassed; a typo outside the guards, or a launcher dropping include
paths, fails the fixture and skips the scenarios. With colour
diagnostics on, every scenario still passes. No marker is printed for
GCC's front end killed while it compiles valid code, for internal
compiler errors from GCC's crash and assertion paths, for Clang's crash
pragmas, including assertion failures in a build with assertions, or for
an MSVC 19.44 internal error replayed from a published build log. Only
CI exercises the Visual Studio fallback.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5-5
@codecov

codecov Bot commented Oct 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

CTest's label summary then shows the time each group takes.

Assisted-by: Claude:claude-opus-5-5
@augmentcode

augmentcode Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: Strengthens reject-test validation and enables concurrent scenario builds.

  • Moves reject-target generation into cmake/RejectTests.cmake.
  • Adds a compiler launcher for Ninja and Makefile generators.
  • Requires a source-located compiler error marker rather than accepting any build failure.
  • Recognizes GCC/Clang and MSVC diagnostics and strips ANSI escapes.
  • Excludes internal-error-only output and failures to start or complete compilation.
  • Adds a setup fixture that builds unguarded positive controls through the scenario launcher.
  • Allows concurrent launcher-backed scenarios while retaining serialized WILL_FAIL fallback tests.
  • Preserves global launchers on ordinary targets and adds diagnostic/argument-forwarding self-tests.
  • Adds fn_run, pfn_run, fn_reject, and pfn_reject labels and documents generator-dependent behavior.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot 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.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread cmake/RejectLauncher.cmake Resolved
@sonarqubecloud

Copy link
Copy Markdown

@Bronek

Bronek commented Oct 31, 2026

Copy link
Copy Markdown
Member Author

augment review

@augmentcode augmentcode Bot 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.

Review completed. No suggestions at this time.

Comment augment review to trigger a new review at any time.

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.

1 participant