safe_int, constrained, their error policies, and the safe_iN aliases are
non-framework add-ons, so their public names move out of mp_units into the
mp_units::utility extension tier (next to the representation concepts already
there). The headers move to core/include/mp-units/utility/ accordingly but stay
in the core component: safe_int reuses the core 128-bit integer toolkit
(integral, is_signed_v, int128_t, ...) that also backs the scaling engine, so it
bridges to mp_units::detail with a single using-directive rather than relocating
or duplicating that toolkit. overflow_policies stays framework (it backs bounded
quantity point origins). No deprecation shims: these types are unreleased.
Also fixes utility/representation.h, whose public concepts delegated via the
unqualified detail::X. That resolved to mp_units::detail only as long as
mp_units::utility::detail did not exist; now that constrained/safe_int introduce
it, the references are qualified to ::mp_units::detail:: so they stay
order-independent (this surfaced only in the module build).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI builds the MSVC matrix with `user.mp-units.build:all=False` so neither tests nor examples
are compiled there. Building with `all=True` on MSVC reveals a backlog of warnings that get
promoted to errors by `-WX`:
* `unit_magnitude.h(793)` C4245 — `find_first_factor` takes `uintmax_t`; cast `intmax_t N`
to it explicitly before calling.
* `framework/unit_magnitude.h::mag_ratio` (MSVC ICE workaround) — `prime_factorization` only
accepts positive arguments, but the workaround was passing the original `D` directly, so
`mag_ratio<3, -4>` instantiated `prime_factorization<-4>`. Normalize both halves to be
positive and reconstruct the sign from the parity of `(N < 0) != (D < 0)`.
* `safe_int.h::div_overflows` / `neg_overflows` / `int_in_range` C4702 — MSVC's reachability
analysis does not see the `if constexpr (is_signed_v<T>) return …;` branch as
unconditional for signed instantiations, so the trailing fallback return looks unreachable.
Restructure as `if constexpr (…) … else …;` so both branches share an explicit `else`.
* `safe_int.h::operator-` and `constrained.h::operator-` C4146 — unary minus on an unsigned
operand is well-defined in C++ but MSVC flags it. Suppress locally with the new
`MP_UNITS_DIAGNOSTIC_IGNORE_UNARY_MINUS_UNSIGNED` macro added to `bits/hacks.h`
(no-op on GCC/Clang, `#pragma warning(disable : 4146)` on MSVC).
* `framework/quantity.h` C4459 — the erased-handler trampolines used `void* p`, which shadows
`si::unit_symbols::p` (pico). Renamed to `void* self`, which is also the more accurate
name for a `this`-trampoline.
* `bits/format.h` / `bits/text_tools.h` C4459 — short loop variables in trivial
character-copy loops shadow various single-letter unit-symbol aliases brought into scope
by `using namespace si::unit_symbols`. These are genuinely benign; wrap each loop in
`MP_UNITS_DIAGNOSTIC_IGNORE_SHADOW` rather than chasing the next colliding short name.
* `test/static/bounded_quantity_point_test.cpp` C4459 — local `auto t = time_of_day(...)`
shadows `non_si::unit_symbols::t` (tonne). Renamed to `auto tod = …` — the longer name
reads better in any case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>