Edition Restrictions
Problem
Rust's borrow checker is designed for complex ownership graphs: multiple references with different lifetimes, interior mutability, self-referential structs. This complexity exists to support general-purpose programming. An OS kernel for a blockchain node doesn't need most of it.
Solution
In edition = "rs", the compiler enforces a simpler ownership model through lints. This is not a language change — it's a restriction.
Restrictions
// edition = "rs" (set in Cargo.toml or via rsc --edition rs)
// FORBIDDEN (unless opted-in):
let x = Boxnew;
//~^ error[RS501]: heap allocation forbidden in rs edition
//~| help: use a stack value or Arena<T, N>
let v = Vecnew;
//~^ error[RS502]: growable collections forbidden in rs edition
//~| help: use BoundedVec<T, N> with compile-time capacity
let s = Stringfrom;
//~^ error[RS503]: heap-allocated strings forbidden in rs edition
//~| help: use &str or ArrayString<N>
let d: = ...;
//~^ error[RS504]: dynamic dispatch forbidden in rs edition
//~| help: use generics or enum dispatch
let r = new;
let r2 = new;
//~^ error[RS505]: reference counting forbidden in rs edition
//~| help: use cell-owned state or bounded channels
let s: = new;
//~^ error[RS507]: non-deterministic collections forbidden in rs edition
//~| help: use BTreeSet for deterministic iteration order
// ALLOWED:
let a: = ; // stack allocation
let arena: = new; // typed arena, compile-time sized
let bv: = new; // bounded, no heap
let s: = from; // fixed-capacity string
Arena Allocator
Rs provides a built-in arena type for cases where dynamic-count-but-bounded allocation is needed:
// Arena with compile-time maximum capacity
let arena: = new;
// Allocate returns Option — None if arena is full
let tx: &mut Transaction = arena.alloc?;
// All allocations freed when arena goes out of scope
// No individual deallocation — this is by design
// No fragmentation, no use-after-free, no leaks
Panic Restriction
In edition = "rs", unwinding panics are forbidden:
// edition = "rs"
panic!;
//~^ error[RS506]: unwinding panic forbidden in rs edition
//~| help: use Result for recoverable errors, or abort for unrecoverable
Only panic = "abort" is permitted. This ensures stack unwinding never occurs, simplifying the runtime and making resource cleanup explicit.
Explicit Opt-In
Each restriction has a corresponding allow attribute for interfacing with existing Rust crates:
| Error | Allow Attribute | Scope |
|---|---|---|
| RS501 (heap allocation) | #[allow(rs::heap)] |
Lifts Box restriction |
| RS502 (growable collections) | #[allow(rs::heap)] |
Lifts Vec restriction |
| RS503 (heap strings) | #[allow(rs::heap)] |
Lifts String restriction |
| RS504 (dynamic dispatch) | #[allow(rs::dyn_dispatch)] |
Lifts dyn Trait restriction |
| RS505 (reference counting) | #[allow(rs::heap)] |
Lifts Arc/Rc restriction |
| RS506 (unwinding panic) | No opt-out | Always enforced |
| RS507 (non-deterministic collections) | #[allow(rs::nondeterministic)] |
Lifts HashMap/HashSet restriction |
#[allow(rs::heap)] covers RS501, RS502, RS503, and RS505 — all heap allocation restrictions. Apply at module or function scope:
Implementation: ~400 lines (lint passes: no-heap ~200L, no-dyn ~50L, no-panic-unwind ~50L, diagnostics ~100L).
Error Reference
See errors/restrictions.md for detailed descriptions of RS501–RS507.