Borrow Checker
Move semantics, borrow regions, aliasing rules, dangling references, drops, and MIR refinement.
Copy vs move
The checker separates trivial copyable values from values that transfer ownership.
- Scalars, references, raw pointers, slices, ranges, and function values are copyable.
- Strings, collections, structs, enums, and aggregates containing owned values move by default.
- Moving a non-copy value makes the old binding unavailable.
- Reinitializing a binding clears the moved state.
Move sites
The compiler only marks a move where the syntax and callee signature make consumption clear.
- Binding one non-copy value to another can move it.
- Passing a value to a by-value parameter can move it.
- A
selformut selfreceiver consumes the receiver. - A
moveclosure owns captured non-copy values.
Borrow regions
Current checking is sound and lexical, with more precision planned on MIR.
The frontend borrow checker treats a let-bound borrow as live until the end of its block. That can reject some safe programs, but it avoids accepting programs that could dangle or mutate through aliases.
&mut xforbids other access toxwhile live.&xforbids writes toxwhile live.- Field-granular places let
&user.nameavoid lockinguser.age. - Returning a reference to a local is rejected.
MIR refinement
Non-lexical lifetimes and reborrows need a control-flow graph.
Some borrow facts cannot be computed soundly from the surface tree alone. Loops, back-edges, and reborrow chains need explicit control-flow and place information, which is why the more precise pass belongs on MIR.
- NLL ends a borrow at last use instead of end of block.
- Reborrows track that a new reference reaches through an older one.
- The lexical pass remains the conservative guard until all relevant programs lower to MIR.