Skip to content

Commit 8e01cd6

Browse files
committed
Improve documentation for MIR statement kinds.
1 parent 9ac5e98 commit 8e01cd6

File tree

1 file changed

+76
-16
lines changed
  • compiler/rustc_middle/src/mir

1 file changed

+76
-16
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,18 +1573,44 @@ impl Statement<'_> {
15731573
/// causing an ICE if they are violated.
15741574
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
15751575
pub enum StatementKind<'tcx> {
1576-
/// Write the RHS Rvalue to the LHS Place.
1576+
/// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
1577+
/// without the possibility of dropping the previous value (that must be done separately, if at
1578+
/// all). The *exact* way this works is undecided. It probably does something like evaluating
1579+
/// the LHS and RHS, and then doing the inverse of a place to value conversion to write the
1580+
/// resulting value into memory. Various parts of this may do type specific things that are more
1581+
/// complicated than simply copying over the bytes depending on the types.
15771582
///
1578-
/// The LHS place may not overlap with any memory accessed on the RHS.
1583+
/// **Needs clarification**: The implication of the above idea would be that assignment implies
1584+
/// that the resulting value is initialized. I believe we could commit to this separately from
1585+
/// committing to whatever part of the memory model we would need to decide on to make the above
1586+
/// paragragh precise. Do we want to?
1587+
///
1588+
/// Assignments in which the types of the place and rvalue differ are not well-formed.
1589+
///
1590+
/// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for
1591+
/// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we
1592+
/// could meaningfully require this anyway. How about free lifetimes? Is ignoring this
1593+
/// interesting for optimizations? Do we want to allow such optimizations?
1594+
///
1595+
/// **Needs clarification**: We currently require that the LHS place not overlap with any place
1596+
/// read as part of computation of the RHS. This requirement is under discussion in [#68364]. As
1597+
/// a part of this discussion, it is also unclear in what order the components are evaluated.
1598+
///
1599+
/// [#68364]: https://github.com/rust-lang/rust/issues/68364
1600+
///
1601+
/// See [`Rvalue`] documentation for details on each of those.
15791602
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
15801603

1581-
/// This represents all the reading that a pattern match may do
1582-
/// (e.g., inspecting constants and discriminant values), and the
1583-
/// kind of pattern it comes from. This is in order to adapt potential
1584-
/// error messages to these specific patterns.
1604+
/// This represents all the reading that a pattern match may do (e.g., inspecting constants and
1605+
/// discriminant values), and the kind of pattern it comes from. This is in order to adapt
1606+
/// potential error messages to these specific patterns.
15851607
///
15861608
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
15871609
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
1610+
///
1611+
/// When executed at runtime this is a nop.
1612+
///
1613+
/// Disallowed after drop elaboration.
15881614
FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
15891615

15901616
/// Write the discriminant for a variant to the enum Place.
@@ -1599,17 +1625,36 @@ pub enum StatementKind<'tcx> {
15991625
/// This writes `uninit` bytes to the entire place.
16001626
Deinit(Box<Place<'tcx>>),
16011627

1602-
/// Start a live range for the storage of the local.
1628+
/// `StorageLive` and `StorageDead` statements mark the live range of a local.
1629+
///
1630+
/// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These
1631+
/// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead`
1632+
/// statements for a particular local, the local is always considered live.
1633+
///
1634+
/// More precisely, the MIR validator currently does a `MaybeLiveLocals` analysis to check
1635+
/// validity of each use of a local. I believe this is equivalent to requiring for every use of
1636+
/// a local, there exist at least one path from the root to that use that contains a
1637+
/// `StorageLive` more recently than a `StorageDead`.
1638+
///
1639+
/// **Needs clarification**: Is it permitted to `StorageLive` a local for which we previously
1640+
/// executed `StorageDead`? How about two `StorageLive`s without an intervening `StorageDead`?
1641+
/// Two `StorageDead`s without an intervening `StorageLive`? LLVM says yes, poison, yes. If the
1642+
/// answer to any of these is "no," is breaking that rule UB or is it an error to have a path in
1643+
/// the CFG that might do this?
16031644
StorageLive(Local),
16041645

1605-
/// End the current live range for the storage of the local.
1646+
/// See `StorageLive` above.
16061647
StorageDead(Local),
16071648

1608-
/// Retag references in the given place, ensuring they got fresh tags. This is
1609-
/// part of the Stacked Borrows model. These statements are currently only interpreted
1610-
/// by miri and only generated when "-Z mir-emit-retag" is passed.
1611-
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
1612-
/// for more details.
1649+
/// Retag references in the given place, ensuring they got fresh tags.
1650+
///
1651+
/// This is part of the Stacked Borrows model. These statements are currently only interpreted
1652+
/// by miri and only generated when `-Z mir-emit-retag` is passed. See
1653+
/// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for
1654+
/// more details.
1655+
///
1656+
/// For code that is not specific to stacked borrows, you should consider statements to read
1657+
/// and modify the place in an opaque way.
16131658
Retag(RetagKind, Box<Place<'tcx>>),
16141659

16151660
/// Encodes a user's type ascription. These need to be preserved
@@ -1624,6 +1669,10 @@ pub enum StatementKind<'tcx> {
16241669
/// - `Contravariant` -- requires that `T_y :> T`
16251670
/// - `Invariant` -- requires that `T_y == T`
16261671
/// - `Bivariant` -- no effect
1672+
///
1673+
/// When executed at runtime this is a nop.
1674+
///
1675+
/// Disallowed after drop elaboration.
16271676
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
16281677

16291678
/// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
@@ -1633,9 +1682,20 @@ pub enum StatementKind<'tcx> {
16331682
/// executed.
16341683
Coverage(Box<Coverage>),
16351684

1636-
/// Denotes a call to the intrinsic function copy_overlapping, where `src_dst` denotes the
1637-
/// memory being read from and written to(one field to save memory), and size
1638-
/// indicates how many bytes are being copied over.
1685+
/// Denotes a call to the intrinsic function `copy_overlapping`.
1686+
///
1687+
/// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
1688+
/// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and
1689+
/// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of
1690+
/// the `src` place are copied to the continguous range of bytes beginning with the first byte
1691+
/// of `dest`.
1692+
///
1693+
/// **Needs clarification**: In what order are operands computed and dereferenced? It should
1694+
/// probably match the order for assignment, but that is also undecided.
1695+
///
1696+
/// **Needs clarification**: Is this typed or not, ie is there a place to value and back
1697+
/// conversion involved? I vaguely remember Ralf saying somewhere that he thought it should not
1698+
/// be.
16391699
CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
16401700

16411701
/// No-op. Useful for deleting instructions without affecting statement indices.

0 commit comments

Comments
 (0)