BTAS_ASSERT_POLICY: real THROW / ABORT / IGNORE modes - #188
Merged
Merged
Conversation
BTAS_ASSERT used to have 2 modes, selected by the boolean BTAS_ASSERT_THROWS: throw btas::exception (ON), or plain assert() (OFF). The latter conflates 2 distinct behaviors -- abort, and do nothing -- and lets NDEBUG decide between them, so there was no way to ask for "BTAS_ASSERT does nothing" or for "BTAS_ASSERT aborts" independently of the build type. This matters to projects that forward their own assert policy to their dependencies: TiledArray's TA_ASSERT_POLICY and SeQuant's SEQUANT_ASSERT_BEHAVIOR both have 3 modes, and BTAS_ASSERT_THROWS=OFF cannot express either IGNORE or ABORT. Replace it with the BTAS_ASSERT_POLICY cache variable, mirroring TiledArray's TA_ASSERT_POLICY: - BTAS_ASSERT_THROW -- throw btas::exception (as BTAS_ASSERT_THROWS=ON did) - BTAS_ASSERT_ABORT -- report to stderr and abort() - BTAS_ASSERT_IGNORE -- expand to nothing; the argument is NOT evaluated None of these depends on NDEBUG. The choice is exported by the BTAS target as the BTAS_ASSERT_POLICY macro, so consumers compile against the same policy; btas/error.h defaults to BTAS_ASSERT_ABORT if the macro is absent. The default preserves today's effective behavior: BTAS_ASSERT_THROW if BUILD_TESTING=ON, else BTAS_ASSERT_IGNORE for Release/MinSizeRel builds (where assert() used to be elided) and BTAS_ASSERT_ABORT otherwise. BTAS_ASSERT_THROWS is kept as a deprecated compatibility alias: if it is given and BTAS_ASSERT_POLICY is not, it provides the default (ON -> THROW, OFF -> ABORT) and a deprecation message; it is still defined as a macro when the policy is BTAS_ASSERT_THROW. Also: - unittest/assert_policy_test.cc + 3 ctest tests (btas/unit/run/assert/*) compile btas/error.h against each policy, with NDEBUG defined, and check that it throws / aborts / does not even evaluate its argument. - the Catch-based unit tests, which catch BTAS_ASSERT failures, are now skipped (with a warning) rather than failing to compile when the policy is not BTAS_ASSERT_THROW. - BTAS_ASSERT no longer supplies the trailing semicolon of a statement (it expands to a do-while now), so add the missing semicolons at the call sites that relied on it.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved moderate findings remain in CMake defaults, policy-test configuration, and the SIGABRT handler.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds explicit BTAS_ASSERT THROW, ABORT, and IGNORE policies with CMake propagation, compatibility handling, documentation, and dedicated tests.
Changes:
- Implements and exports the three assertion policies.
- Updates assertion call sites and compatibility behavior.
- Adds policy-specific tests and documentation.
File summaries
| File | Summary | Review notes |
|---|---|---|
unittest/test.h |
Restricts Catch tests to THROW mode. | None |
unittest/CMakeLists.txt |
Adds policy-specific test targets. | Moderate (1 vote): policy tests are skipped when BUILD_TESTING=OFF. |
unittest/assert_policy_test.cc |
Verifies all three assertion modes. | Moderate (2 votes): the SIGABRT handler uses non-async-signal-safe functions. |
README.md |
Documents policy options and defaults. | None |
CMakeLists.txt |
Configures, validates, and exports the assertion policy. | Moderate (2 votes): default handling misses RelWithDebInfo and multi-config Release/MinSizeRel cases. |
btas/generic/tuck_cp_als.h |
Updates assertion statements. | None |
btas/generic/element_wise_contract.h |
Updates assertion statements. | None |
btas/generic/cp_als.h |
Updates assertion statements. | None |
btas/error.h |
Implements assertion policy behavior and diagnostics. | Nit (1 vote): the non-IGNORE branch label is inverted. |
Review details
Suppressed comments (2)
btas/error.h:88
- The
#elsebranch below is the THROW/ABORT implementation, so this condition label is inverted and will mislead anyone maintaining the policy split. Please label it as the non-IGNORE branch.
#else // BTAS_ASSERT_POLICY == BTAS_ASSERT_IGNORE
unittest/CMakeLists.txt:44
- This loop is only configured when the parent
CMakeLists.txtenters itsif (BUILD_TESTING)branch, so withBUILD_TESTING=OFFnone of the three policy executables or tests exists. That contradicts the comment that these checks run regardless of configuration and leaves the no-testing configurations without the policy coverage introduced here; move the policy-test setup outside that guard or update the intended coverage.
# BTAS_ASSERT policy checks: btas/error.h is compiled against each of the 3
# policies (with NDEBUG defined, to confirm that none of them depends on it),
# regardless of how this build was configured
foreach(_policy THROW ABORT IGNORE)
set(_exec btas_assert_policy_${_policy}_test)
add_executable(${_exec} EXCLUDE_FROM_ALL assert_policy_test.cc)
- Files reviewed: 9/9 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- assert_policy_test: the SIGABRT handler only calls _Exit (async-signal-safe); reaching it is the success condition - error.h: fix the inverted #else label of the policy split - unittest/CMakeLists.txt: the policy checks run regardless of the configured BTAS_ASSERT_POLICY (not regardless of BUILD_TESTING); say so - CMakeLists.txt/README: document that RelWithDebInfo keeps BTAS_ASSERT live (like TA_ASSERT) and that multi-config generators default to BTAS_ASSERT_ABORT for every configuration (the policy is a single configure-time choice exported to consumers); emit a STATUS note there
There was a problem hiding this comment.
🔵 Needs a closer look
Resolve the multi-config build-type handling and stale BTAS_ASSERT_THROWS cache default issues.
Review details
Suppressed comments (2)
CMakeLists.txt:87
- On a multi-config generator,
CMAKE_BUILD_TYPEis not guaranteed to be empty; a project that passes-DCMAKE_BUILD_TYPE=Releasestill leaves this variable set even though Xcode/Visual Studio ignore it. This branch then selectsBTAS_ASSERT_IGNOREfor every configuration and skips the multi-config warning, so a Debug build can silently compile with assertions disabled. CheckGENERATOR_IS_MULTI_CONFIGbefore the build-type test (after theBUILD_TESTINGcase) so the documented global multi-config default remainsBTAS_ASSERT_ABORT.
elseif (CMAKE_BUILD_TYPE STREQUAL Release OR CMAKE_BUILD_TYPE STREQUAL MinSizeRel)
set(BTAS_ASSERT_POLICY_DEFAULT BTAS_ASSERT_IGNORE)
CMakeLists.txt:76
- On an in-place upgrade,
BTAS_ASSERT_THROWSremains inCMakeCache.txtfrom the previousredefaultable_option(including its defaultOFF). Because this branch checks onlyDEFINED, a priorBUILD_TESTING=OFFRelease/MinSizeRel build is treated as an explicit deprecated override and selectsBTAS_ASSERT_ABORTinstead of the documentedBTAS_ASSERT_IGNOREdefault. Please handle or document stale cache entries so the new defaults are not changed unintentionally.
if (DEFINED BTAS_ASSERT_THROWS AND NOT DEFINED BTAS_ASSERT_POLICY)
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Lite
evaleev
added a commit
to ValeevGroup/tiledarray
that referenced
this pull request
Sep 14, 2026
BTAS (ValeevGroup/BTAS#188) now has the same three assertion modes as TA; map TA_ASSERT_{THROW,ABORT,IGNORE} onto BTAS_ASSERT_{THROW,ABORT,IGNORE} instead of the deprecated boolean BTAS_ASSERT_THROWS, whose OFF setting was a plain assert() (elided under NDEBUG) rather than an abort.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
Two review comments on the forwarding added in the previous commit:
1. mapping IGNORE (and ABORT) onto BTAS_ASSERT_THROWS=OFF does not
implement IGNORE. At the BTAS tracked so far, BTAS_ASSERT_THROWS=OFF
makes BTAS_ASSERT a plain assert(), so a Debug build configured with
SEQUANT_ASSERT_BEHAVIOR=IGNORE still aborted on a BTAS assertion.
BTAS has since gained a real 3-mode policy, BTAS_ASSERT_POLICY =
BTAS_ASSERT_{THROW,ABORT,IGNORE} (ValeevGroup/BTAS#188), that is not
affected by NDEBUG; forward that as the primary knob, in both modules.
BTAS_ASSERT_THROWS is kept as the compatibility shim for a BTAS older
than that -- notably the one the tracked TiledArray builds, until its
tag moves past ValeevGroup/tiledarray#587 -- where both ABORT and
IGNORE still degrade to assert() semantics. The modules, AGENTS.md and
installing.rst say so; that is a limitation of the older BTAS, not
alignment.
2. in FindOrFetchTiledArray.cmake the BTAS setting was derived from
SEQUANT_ASSERT_BEHAVIOR, so a user who overrode TA_ASSERT_POLICY (e.g.
TA_ASSERT_IGNORE with SEQUANT_ASSERT_BEHAVIOR=THROW) got a BTAS that
disagreed with TiledArray. Derive it from the effective
TA_ASSERT_POLICY instead, i.e. after the override guard, and derive
the BTAS_ASSERT_THROWS shim from the effective BTAS_ASSERT_POLICY, so
that an explicit BTAS_ASSERT_POLICY is not contradicted by the shim.
The independent BTAS_ASSERT_{POLICY,THROWS} override guards remain.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
Brings in BTAS_ASSERT_POLICY (ValeevGroup/BTAS#188), which FindOrFetchBTAS.cmake now forwards SEQUANT_ASSERT_BEHAVIOR to; without it SEQUANT_ASSERT_BEHAVIOR=IGNORE only reaches BTAS as the deprecated BTAS_ASSERT_THROWS=OFF, i.e. as a plain assert() that still aborts unless NDEBUG is defined. N.B. this tag is only used when SeQuant itself builds BTAS, i.e. in a SEQUANT_BTAS build without TiledArray; otherwise TiledArray's own BTAS tag decides.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
Brings in the TiledArray side of the assert-policy forwarding (ValeevGroup/tiledarray#587): TiledArray now pins a BTAS that has BTAS_ASSERT_POLICY (ValeevGroup/BTAS#188) and forwards TA_ASSERT_POLICY to it itself. Without this, the BTAS that TiledArray builds in a SEQUANT_TILEDARRAY build only understands the deprecated BTAS_ASSERT_THROWS, whose OFF is a plain assert() -- neither ABORT nor IGNORE.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
…_THROWS shim Both tracked tags are past BTAS_ASSERT_POLICY (ValeevGroup/BTAS#188) and TiledArray's own forwarding of TA_ASSERT_POLICY to BTAS (ValeevGroup/tiledarray#587), so SeQuant no longer needs to derive BTAS's policy itself when TiledArray builds BTAS, nor to set the deprecated boolean. FindOrFetchTiledArray forwards SEQUANT_ASSERT_BEHAVIOR as TA_ASSERT_POLICY only, and only when TiledArray is built from source (probed the way FetchContent's FIND_PACKAGE_ARGS will); FindOrFetchBTAS (used when SeQuant builds BTAS itself) forwards BTAS_ASSERT_POLICY only. Each keeps its SEQUANT_*_ASSERT_POLICY_FOLLOWS_SEQUANT opt-out and _SEEN marker. This retires the cases where the shim and the duplicate derivation disagreed: an undefined TA_ASSERT_POLICY producing BTAS_ASSERT_ (following off on a fresh configure), a changed BTAS_ASSERT_THROWS ignored next to a cached BTAS_ASSERT_POLICY, the shim losing to TiledArray's own forwarding, and forced cache entries when TiledArray comes installed.
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
evaleev
added a commit
to ValeevGroup/SeQuant
that referenced
this pull request
Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
BTAS_ASSERThas had 2 modes, selected by the booleanBTAS_ASSERT_THROWS: throwbtas::exception(ON), or a plainassert()(OFF). TheOFFmode conflates two distinct behaviors — abort and do-nothing — and letsNDEBUGpick between them, so there is no way to ask BTAS for "assertions are no-ops" or for "assertions abort" independently of the build type.This blocks assert-policy forwarding in the dependents:
TA_ASSERT_POLICY(TA_ASSERT_{THROW,ABORT,IGNORE}) to BTASSEQUANT_ASSERT_BEHAVIOR(THROW/ABORT/IGNORE) to TiledArray and BTASBoth could only map
IGNOREandABORTontoBTAS_ASSERT_THROWS=OFF, i.e. ontoassert()— which, in aDebugbuild, still aborts when the user asked forIGNORE(this is exactly what Copilot flagged on both PRs). A real 3-mode policy in BTAS is the proper fix.What this does
Adds the
BTAS_ASSERT_POLICYcache variable, named and valued after TiledArray'sTA_ASSERT_POLICY:BTAS_ASSERT_POLICYBTAS_ASSERT(x)ifxis falseBTAS_ASSERT_THROWbtas::exception(whatBTAS_ASSERT_THROWS=ONdid)BTAS_ASSERT_ABORTstderrand callsstd::abort()BTAS_ASSERT_IGNOREdo {} while(0), soxis not evaluatedNDEBUG— in particularABORTaborts inReleasetoo, andIGNOREis a no-op inDebug.BTAS_EXCEPTION_MESSAGEis unchanged, except that the stringized assertion expression is now included.BTASINTERFACE target as-DBTAS_ASSERT_POLICY=..., so consumers compile against the same policy.btas/error.hdefaults toBTAS_ASSERT_ABORTif the macro is absent.BTAS_ASSERT_THROWifBUILD_TESTING=ON(the unit tests checkBTAS_ASSERTfailures, hence must be able to catch them), elseBTAS_ASSERT_IGNOREforRelease/MinSizeRelandBTAS_ASSERT_ABORTotherwise. That preserves today's effective behavior in every configuration (assert()used to be elided underNDEBUGand to abort otherwise).Compatibility
BTAS_ASSERT_THROWSis kept as a deprecated alias: if it is given andBTAS_ASSERT_POLICYis not, it sets the default (ON->BTAS_ASSERT_THROW,OFF->BTAS_ASSERT_ABORT) and issues aDEPRECATIONmessage.BTAS_ASSERT_THROWS=1is still defined as a macro when the policy isBTAS_ASSERT_THROW, andbtas/error.hstill honors a user-definedBTAS_ASSERT_THROWSwhenBTAS_ASSERT_POLICYis not defined — so older consumers keep working unchanged.BTAS_ASSERTno longer supplies the trailing semicolon of a statement (it is ado-whilenow, which also fixes the dangling-elsehazard theTHROWform had), so the handful of call sites inbtas/generic/that relied on it got their semicolons.Tests
unittest/assert_policy_test.ccis compiled 3 times, once per policy and always withNDEBUGdefined, and run asbtas/unit/run/assert/{THROW,ABORT,IGNORE}(picked up by thecheck-btastarget). Each run verifies the mode: the exception is thrown and the argument was evaluated exactly once, the process aborts (SIGABRThandler), or nothing happens and the argument was not evaluated.Configure matrix checked (macOS, clang, Ninja): default (
BUILD_TESTING=ON) ->THROW;BUILD_TESTING=OFF->ABORT;BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release->IGNORE;-DBTAS_ASSERT_THROWS=ON/OFF->THROW/ABORT+ deprecation message;-DBTAS_ASSERT_POLICY=BOGUS-> fatal error. The exportedINTERFACE_COMPILE_DEFINITIONScarries the policy in each case. The BTAS headers that useBTAS_ASSERTwere syntax-checked under all 3 policies.The Catch-based unit tests, which catch
BTAS_ASSERTfailures, are now skipped with a warning when the policy is notBTAS_ASSERT_THROW, instead of failing to compile via the#errorinunittest/test.h.🤖 Generated with Claude Code