Make disabled EBGEOMETRY_EXPECT truly vanish (unevaluated sizeof) - #141
Conversation
The disabled-assertions branch expanded to ((void)(cond)), which still *evaluates* cond -- relying on the optimiser to dead-code-eliminate it. That elimination is not guaranteed: any assertion condition the compiler cannot prove side-effect-free (e.g. the std::isfinite() precondition checks in the SoA distance kernels, evaluated on the order of 20x per nearest-neighbor query) stayed in the generated code, and at -O0 the whole set survives. Switch the disabled expansion to (static_cast<void>(sizeof((cond)))). sizeof is an unevaluated context, so cond is parsed -- keeping it syntax-checked and keeping assertion-only variables and parameters from tripping unused-entity warnings -- but is never executed, at any optimisation level. Disabled assertions now have exactly zero runtime cost and cannot have side effects. Ported from the EBGeometry checkout used by chombo-discharge, where an interleaved A/B of its NearestNeighbor benchmark measured PointCloudBVH's uniform-cube query ~4-5% faster with the expressions truly gone. That benchmark suite is not part of this repo, so the figure is quoted, not reproduced here. All 826 EBGEOMETRY_EXPECT call sites under Source/ were audited for the two constructs the new expansion would reject: none has a void-typed condition, and none contains a lambda-expression (ill-formed in an unevaluated operand in C++17). No condition has side effects, so ceasing to evaluate them cannot change behaviour. Verified: all four presets' test suites pass (debug, debug-san, release-test, examples); Scripts/run-all-checks.sh passes end to end, including clang-tidy, Doxygen and Sphinx. Every Examples/*/main.cpp also compiles clean with assertions off under the Intel CI warning set (-Wall -Wextra -Wunused-variable -Wunused-but-set-variable -Werror), which is where a regression in unused-entity suppression would surface. Update ConfigurationOptions.rst to match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@claude review |
|
Claude finished @rmrsk's task in 1m 47s —— View job Review complete
SummaryThis is a small, well-scoped, and well-justified change. Switching the disabled A few things I checked and confirmed look right:
Minor, non-blocking observations
I did not find any correctness issues. The stated local verification (all four CMake presets + |
Summary
Background
EBGEOMETRY_EXPECTis opt-in: withEBGEOMETRY_ENABLE_ASSERTIONSundefined (the default, and therelease/release-testpresets) it expanded to((void)(cond)). That still evaluates thecondition — the discard only removes the branch, not the work — so eliminating it was left to the
optimiser, which is not guaranteed. Any condition the compiler cannot prove side-effect-free
survives into the generated code; the
std::isfinite()preconditions in the SoA distance kernelsare the sharp case, since they run on the order of 20× per nearest-neighbor query. At
-O0withassertions off, the whole set survives.
Solution
Expand the disabled branch to
(static_cast<void>(sizeof((cond))))instead.sizeofis anunevaluated operand, so the condition is still parsed — it stays syntax-checked, and variables or
parameters that appear only inside assertions still count as used — but is never executed, at any
optimisation level. Disabled assertions now have exactly zero runtime cost and cannot have
observable side effects.
The change is ported from the EBGeometry checkout used by chombo-discharge, where an interleaved A/B
of its NearestNeighbor benchmark measured
PointCloudBVH's uniform-cube query ~4–5 % faster withthe expressions truly gone. That benchmark suite is not part of this repository, so the figure is
quoted rather than reproduced here.
Docs/Sphinx/source/ConfigurationOptions.rst(Sec:Assertions) and the macro's Doxygen@detailsblock are updated in the same commit; no other page describes the expansion, so no further
.rstwork was needed.
Side-effects
Assertion conditions are no longer evaluated in assertions-OFF builds. Two constructs that were
previously legal in a condition now become compile errors: a void-typed expression (no size), and a
lambda-expression (ill-formed in an unevaluated operand in C++17). All 826
EBGEOMETRY_EXPECTcallsites under
Source/were audited — none uses either, none has side effects in its condition, andnone spans multiple lines.
The regression risk worth watching in CI is unused-entity suppression, since the
-Werrorpathsbuild with assertions off:
Tests/CMakeLists.txt(-Wall -Wextra -Werror, including therelease-testpreset) and the Intelicpxjob (-Wunused-variable -Wunused-but-set-variable -Werrorover the Examples). Locally, GCC 13.3 treats asizeofappearance as a use for bothwarnings, and every
Examples/*/main.cppcompiles clean under that exact flag set with assertionsoff. Clang's
-Wunused-but-set-variableandicpxare only reachable in CI. clang-tidy isunaffected —
Scripts/clang-tidy-check.shconfigures thedebugpreset, where assertions are onand this branch is never compiled.
Local verification:
debug,debug-san,release-testandexamplessuites all pass (290/290 onrelease-test), andScripts/run-all-checks.shcompletes clean end to end, including clang-tidy,Doxygen and Sphinx.
Alternative solutions
((void)(cond))and rely on the optimiser — rejected: not guaranteed for conditions withopaque calls, and untrue at
-O0.assertions-off builds (letting a broken assertion land unnoticed), and assertion-only variables
and parameters would start tripping unused-entity warnings under
-Werror.Reviewer checklist (to be completed by a human)
@claude review.🤖 Generated with Claude Code