Skip to content

Commit 4939f6c

Browse files
committed
Clarify MIR semantics of storage statements
1 parent 7665c35 commit 4939f6c

File tree

2 files changed

+20
-14
lines changed

2 files changed

+20
-14
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
205205
}
206206

207207
if self.reachable_blocks.contains(location.block) && context.is_use() {
208-
// Uses of locals must occur while the local's storage is allocated.
208+
// We check that the local is live whenever it is used. Technically, violating this
209+
// restriction is only UB and not actually indicative of not well-formed MIR. This means
210+
// that an optimization which turns MIR that already has UB into MIR that fails this
211+
// check is not necessarily wrong. However, we have no such optimizations at the moment,
212+
// and so we include this check anyway to help us catch bugs. If you happen to write an
213+
// optimization that might cause this to incorrectly fire, feel free to remove this
214+
// check.
209215
self.storage_liveness.seek_after_primary_effect(location);
210216
let locals_with_storage = self.storage_liveness.get();
211217
if !locals_with_storage.contains(local) {

compiler/rustc_middle/src/mir/syntax.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -237,19 +237,19 @@ pub enum StatementKind<'tcx> {
237237

238238
/// `StorageLive` and `StorageDead` statements mark the live range of a local.
239239
///
240-
/// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These
241-
/// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead`
242-
/// statements for a particular local, the local is always considered live.
243-
///
244-
/// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to
245-
/// check validity of each use of a local. I believe this is equivalent to requiring for every
246-
/// use of a local, there exist at least one path from the root to that use that contains a
247-
/// `StorageLive` more recently than a `StorageDead`.
248-
///
249-
/// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening
250-
/// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison,
251-
/// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to
252-
/// have a path in the CFG that might do this?
240+
/// At any point during the execution of a function, each local is either allocated or
241+
/// unallocated. Except as noted below, all locals except function parameters are initially
242+
/// unallocated. `StorageLive` statements cause memory to be allocated for the local while
243+
/// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only
244+
/// reading/writing from it) while it is unallocated is UB.
245+
///
246+
/// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body.
247+
/// These locals are implicitly allocated for the full duration of the function. There is a
248+
/// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for
249+
/// computing these locals.
250+
///
251+
/// If the local is already allocated, calling `StorageLive` again is UB. However, for an
252+
/// unallocated local an additional `StorageDead` all is simply a nop.
253253
StorageLive(Local),
254254

255255
/// See `StorageLive` above.

0 commit comments

Comments
 (0)