Rust project goals: Immobile types and guaranteed destructors
Rust Project Goals: Immobile Types and Guaranteed Destructors
📌 Metadata
| Field | Detail |
|---|---|
| Point of Contact | @lcnr |
| Current Status | Accepted |
| Timeline | 2026–2027 |
| Roadmap | Just add async |
| Primary Tracking | #635 |
| Secondary Tracking | rust-lang/rust#149607 |
| Zulip Channel | #t-lang/move-trait |
| Champions | @lcnr (types), @jackh726 (lang) |
🎯 Summary
We intend to introduce a set of new traits that explicitly define which operations are permissible for a given type. Currently, the Rust compiler operates under the blanket assumption that every type can be moved (relocated in memory) and forgotten (via
std::mem::forget). By introducing traits likeMoveandForget, we allow types to opt out of these behaviors.
This initiative mirrors the logic used in the Sized hierarchy project, which moved away from the assumption that all types possess a known size at compile time. The plan involves developing MVPs within the compiler, drafting RFCs, and validating the implementation through the Rust for Linux project.
💡 Motivation
Historically, Rust has relied on two fundamental assumptions:
All values can be relocated in memory (moved).All values can be discarded without running their destructors (mem::forget).
These are not just conventions; they are baked into the language's core. For example, a simple assignment is treated as a move, and mem::forget is globally safe. However, certain use cases make these assumptions problematic:
1. Immobile Types
Many async futures are self-referential. If a type contains a pointer to its own data, moving that type in memory invalidates the pointer.
- Current Fix: We use
Pin. However,Pintreats immovability as a property of the location (the place) rather than the type itself. - The Problem: As noted in the Safe Pinned Initialization Problem, this approach is cumbersome for systems like the Linux kernel.
2. Guaranteed Destructors
Some types must be destroyed to maintain system integrity.
- Example: A
Transactiontype that requires acommit()orrollback()call during cleanup. - The Problem: Because
mem::forgetis always safe, Rust cannot strictly guarantee that a destructor will execute. This prevents the implementation of safe scoped spawns for async tasks, where a spawned task must be joined before the parent scope closes.
🛠️ The Proposal
We propose expanding the type system with auto-traits that describe operational capabilities. Mathematically, we are moving from a state where: To a state where these are conditional properties:
Proposed Traits
Move: Indicates the type can be relocated in memory.Destruct: Indicates the type can be implicitly dropped when it leaves scope.Forget: Indicates the type can be passed tomem::forgetwithout running its destructor.
The Move Trait
By making movability a property of the type, we simplify the logic compared to Pin.
#[lang = "move"]
unsafe auto trait Move { }
If a type is marked as !Move, it is forbidden from being relocated and must maintain a stable memory address for its entire lifetime. This will integrate with ongoing work in #t-lang/in-place-init.
The Forget Trait
This allows types to mandate that their destructors must run.
// This type cannot be forgotten; its destructor is guaranteed to execute.
unsafe impl !Forget for ScopedTaskHandle { }
Impact: With !Forget, a ScopedTaskHandle can guarantee that its destructor joins the associated task, enabling safe scoped async spawns.
Visualizing the Change
📅 Work Items (Next 12 Months)
📦 Move Trait Implementation
Goal: Encode immovability as a type property.
| Task | Owner(s) | Notes |
|---|---|---|
| Compiler implementation | @lcnr, @nia-e | Core logic for Move |
| Draft Move RFC | @yoshuawuyts | Formalize the specification |
| Linux Kernel Testing | @BennoLossin | Validate with self-referential structures |
Iterator & !Move interaction | @yoshuawuyts | Ensure generator-based effects work |
- Implement
Movein compiler - Finalize RFC
- Verify
impl Trait + !Movefor generators
🛡️ Guaranteed Destructors
Goal: Prevent mem::forget for specific types.
| Task | Owner(s) | Notes |
|---|---|---|
| Design Exploration | @nikomatsakis | Hierarchy and feature interactions |
⚠️ Out of Scope: We are not updating the
Futuretrait this year. WhileFuturerelies onPinand would benefit fromMove, it has too many other issues (13+ tracked) and requires a dedicated migration strategy.
👥 Team Requirements
| Team | Support Level | Role |
|---|---|---|
[lang] | Large | Required for high-level design sessions |
[types] | Large | Required for implementation and review |
❓ FAQ
How does this relate to the Sized hierarchy work?
The Sized hierarchy established the architectural pattern for this project: it proved that Rust can successfully relax a global assumption (that all types have a known size) by introducing a trait-based system to handle the exceptions. We are applying that same logic to movability and forgettability.