feat(cvlr-spec): add #![no_std] for no_std / wasm32v1-none consumers - #47
Conversation
cvlr-spec uses only core (no std:: references), but lacks the #![no_std] attribute, so it pulls in std and fails to compile for downstream crates targeting wasm32v1-none (e.g. Soroban contracts on recent soroban-sdk). Adding the crate-level attribute makes it usable from no_std contexts; the crate already compiles unchanged otherwise.
|
@1arie1 ping 🙏 |
|
@mihaieremia some tests are failing after the change |
The macrotest snapshot recorded std's internal `vec!` desugaring (`<[_]>::into_vec(box_new([1, 2, 3]))`), which current stable expands to `box_assume_init_into_vec_unsafe(write_box_via_move(...))`. CI pins unpinned `stable`, so the byte-comparison drifts and fails on `main`. The fixture only needs a collection exposing `.len()` / `.iter().sum()`; swap `vec![1, 2, 3]` for the array `[1, 2, 3]`, which expands to itself and is immune to std-internal desugaring changes. Claude-Session: https://claude.ai/code/session_01VArXWJTqakNurd51jzwpHm
CI fix: the failing
|
expansion of vec![1, 2, 3] |
|
|---|---|
| recorded snapshot | <[_]>::into_vec(::alloc::boxed::box_new([1, 2, 3])) |
| current stable (1.95.0) | ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(), [1, 2, 3])) |
CI pins unpinned toolchain: stable, so it floats to the newest stable and no longer matches the snapshot recorded on an older one. Every line our macros generate (_rule_name / _spec / _base blocks) matches byte-for-byte — only std's vec! internals drifted.
Evidence it's pre-existing
git diff main...HEAD(before the fix) touched onlycvlr-spec/src/lib.rs.- The
cvlr-macrossnapshot is byte-identical onmainand this branch. - Running the same test on a clean
mainworktree fails with the identicalbox_assume_init_into_vec_unsafediff. - macrotest reports
1 of 12fixtures differ — only the one usingvec!.
Fix
The fixture (test_spec_with_method_calls) only needs a collection exposing .len() / .iter().sum::<i32>(). Swapping vec![1, 2, 3] → [1, 2, 3] keeps the test's intent (method calls in a spec expression) and expands to itself, so the snapshot is immune to std-internal desugaring changes. Regenerating with MACROTEST=overwrite changed only that one snapshot line; the other 11 are untouched.
Full cargo test is green locally (Rust 1.95.0), including the trybuild compile test that compiles this fixture.
Happy to split this into its own PR if you'd prefer to keep the #![no_std] change isolated — it's just bundled here to get this PR's CI green, since main is currently red for the same reason.
|
@1arie1 Fixed and all checks passed |
|
@mihaieremia thank you! merged. |
Summary
cvlr-spec/src/lib.rshas no crate-level#![no_std]attribute, so the crate linksstd. Consumers that build under#![no_std]— e.g. Soroban smart contracts targetingwasm32v1-none, where the entire contract crate tree must beno_std— cannot depend oncvlr-specas published without patching it.This adds a single
#![no_std]line tocvlr-spec. The crate compiles cleanly asno_std(nostd-only items in use), so this is a non-breaking, additive change for existingstdconsumers (they continue to work viacore/alloc).+#![no_std] //! Specification language for CVL (Certora Verification Language) in Rust.Motivation
We maintain the XOXNO rs-lending-xlm Stellar lending protocol and use CVLR for formal verification. To build the spec crates into our
no_stdSoroban contracts we currently vendorcvlrwith exactly this one-line patch. Upstreaming it lets us (and other Soroban users) drop the vendor and consumecvlrdirectly.Test plan
no_stdin our Certora pipeline (soroban-sdk26.1,wasm32v1-none).stdconsumers / CI.Opening as draft for maintainer feedback on the approach.