Skip to content

Commit 6343691

Browse files
committed
Add documentation for the semantics of MIR rvalues
1 parent 2f4a7a0 commit 6343691

File tree

2 files changed

+101
-23
lines changed

2 files changed

+101
-23
lines changed

compiler/rustc_middle/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#![feature(unwrap_infallible)]
6060
#![feature(decl_macro)]
6161
#![feature(drain_filter)]
62+
#![feature(intra_doc_pointers)]
6263
#![recursion_limit = "512"]
6364
#![allow(rustc::potential_query_instability)]
6465

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,57 +2388,134 @@ impl<'tcx> Operand<'tcx> {
23882388
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
23892389
/// The various kinds of rvalues that can appear in MIR.
23902390
///
2391-
/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
2392-
/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
2393-
/// causing an ICE if they are violated.
2391+
/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below.
2392+
///
2393+
/// Computing any rvalue begins by evaluating the places and operands in the rvalue in the order in
2394+
/// which they appear. These are then used to produce a "value" - the same kind of value that an
2395+
/// [`Operand`] is.
23942396
pub enum Rvalue<'tcx> {
2395-
/// x (either a move or copy, depending on type of x)
2397+
/// Yields the operand unchanged
23962398
Use(Operand<'tcx>),
23972399

2398-
/// [x; 32]
2400+
/// Creates an array where each element is the value of the operand. This currently does not
2401+
/// drop the value even if the number of repetitions is zero, see [#74836].
2402+
///
2403+
/// Corresponds to source code like `[x; 32]`.
2404+
///
2405+
/// [#74836]: https://github.com/rust-lang/rust/issues/74836
23992406
Repeat(Operand<'tcx>, ty::Const<'tcx>),
24002407

2401-
/// &x or &mut x
2408+
/// Creates a reference of the indicated kind to the place.
2409+
///
2410+
/// There is not much to document here, because besides the obvious parts the semantics of this
2411+
/// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
2412+
/// exactly what the behavior of this operation should be.
2413+
///
2414+
/// `Shallow` borrows are disallowed after drop lowering.
24022415
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
24032416

2404-
/// Accessing a thread local static. This is inherently a runtime operation, even if llvm
2405-
/// treats it as an access to a static. This `Rvalue` yields a reference to the thread local
2406-
/// static.
2417+
/// Returns a pointer/reference to the given thread local.
2418+
///
2419+
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
2420+
/// `*const T`, and if neither of those apply a `&T`.
2421+
///
2422+
/// **Note:** This is a runtime operation that actually executes code and is in this sense more
2423+
/// like a function call. Also, DSEing these causes `fn main() {}` to SIGILL for some reason
2424+
/// that I never got a chance to look into.
2425+
///
2426+
/// **Needs clarification**: Are there weird additional semantics here related to the runtime
2427+
/// nature of this operation?
24072428
ThreadLocalRef(DefId),
24082429

2409-
/// Create a raw pointer to the given place
2410-
/// Can be generated by raw address of expressions (`&raw const x`),
2411-
/// or when casting a reference to a raw pointer.
2430+
/// Creates a pointer with the indicated mutability to the place.
2431+
///
2432+
/// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
2433+
/// `&raw v` or `addr_of!(v)`.
2434+
///
2435+
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
2436+
/// model.
24122437
AddressOf(Mutability, Place<'tcx>),
24132438

2414-
/// length of a `[X]` or `[X;n]` value
2439+
/// Yields the length of the place, as a `usize`.
2440+
///
2441+
/// If the type of the place is an array, this is the array length. This also works for slices
2442+
/// (`[T]`, not `&[T]`) through some mechanism that depends on how exactly places work (see
2443+
/// there for more details).
24152444
Len(Place<'tcx>),
24162445

2446+
/// Performs essentially all of the casts that can be performed via `as`.
2447+
///
2448+
/// This allows for casts from/to a variety of types.
2449+
///
2450+
/// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
2451+
/// `ArrayToPointer` and `MutToConstPointer` are special.
24172452
Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
24182453

2454+
/// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
2455+
/// paramter may be a `usize` as well.
2456+
/// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
2457+
/// raw pointers, or function pointers and return a `bool`.
2458+
/// * Left and right shift operations accept signed or unsigned integers not necessarily of the
2459+
/// same type and return a value of the same type as their LHS. For all other operations, the
2460+
/// types of the operands must match.
2461+
/// * The `Bit*` operations accept signed integers, unsigned integers, or bools and return a
2462+
/// value of that type.
2463+
/// * The remaining operations accept signed integers, unsigned integers, or floats of any
2464+
/// matching type and return a value of that type.
24192465
BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
2466+
2467+
/// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the
2468+
/// same computation as the matching `BinaryOp`, checks if the infinite precison result would be
2469+
/// unequal to the actual result and sets the `bool` if this is the case. `BinOp::Offset` is not
2470+
/// allowed here.
2471+
///
2472+
/// **FIXME**: What about division/modulo? Are they allowed here at all? Are zero divisors still
2473+
/// UB? Also, which other combinations of types are disallowed?
24202474
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
24212475

2476+
/// Yields the size or alignment of the type as a `usize`.
24222477
NullaryOp(NullOp, Ty<'tcx>),
2478+
2479+
/// Exactly like `BinaryOp`, but less operands.
2480+
///
2481+
/// Also does two's-complement arithmetic. Negation requires a signed integer or a float; binary
2482+
/// not requires a signed integer, unsigned integer, or bool. Both operation kinds return a
2483+
/// value with the same type as their operand.
24232484
UnaryOp(UnOp, Operand<'tcx>),
24242485

2425-
/// Read the discriminant of an ADT.
2486+
/// Computes the discriminant of the place, returning it as an integer of type
2487+
/// [`discriminant_ty`].
2488+
///
2489+
/// The validity requirements for the underlying value are undecided for this rvalue, see
2490+
/// [#91095]. Note too that the value of the discriminant is not the same thing as the
2491+
/// variant index; use [`discriminant_for_variant`] to convert.
2492+
///
2493+
/// For types defined in the source code as enums, this is well behaved. This is also well
2494+
/// formed for other types, but yields no particular value - there is no reason it couldn't be
2495+
/// defined to yield eg zero though.
24262496
///
2427-
/// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot
2428-
/// be defined to return, say, a 0) if ADT is not an enum.
2497+
/// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
2498+
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
2499+
/// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
24292500
Discriminant(Place<'tcx>),
24302501

2431-
/// Creates an aggregate value, like a tuple or struct. This is
2432-
/// only needed because we want to distinguish `dest = Foo { x:
2433-
/// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
2434-
/// that `Foo` has a destructor. These rvalues can be optimized
2435-
/// away after type-checking and before lowering.
2502+
/// Creates an aggregate value, like a tuple or struct.
2503+
///
2504+
/// This is needed because dataflow analysis needs to distinguish
2505+
/// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
2506+
/// has a destructor.
2507+
///
2508+
/// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
2509+
/// generator lowering, `Generator` aggregate kinds are disallowed too.
24362510
Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
24372511

24382512
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
24392513
///
2440-
/// This is different a normal transmute because dataflow analysis will treat the box
2441-
/// as initialized but its content as uninitialized.
2514+
/// This is different a normal transmute because dataflow analysis will treat the box as
2515+
/// initialized but its content as uninitialized. Like other pointer casts, this in general
2516+
/// affects alias analysis.
2517+
///
2518+
/// Disallowed after drop elaboration.
24422519
ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
24432520
}
24442521

0 commit comments

Comments
 (0)