summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/syntax.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir/syntax.rs')
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs151
1 files changed, 79 insertions, 72 deletions
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index ae09562a8..93800d484 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -3,7 +3,7 @@
//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
//! The intention is that this file only contains datatype declarations, no code.
-use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection};
+use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection};
use crate::mir::coverage::{CodeRegion, CoverageKind};
use crate::traits::Reveal;
@@ -16,7 +16,8 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir};
use rustc_hir::{self, GeneratorKind};
-use rustc_target::abi::VariantIdx;
+use rustc_index::vec::IndexVec;
+use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_ast::Mutability;
use rustc_span::def_id::LocalDefId;
@@ -78,7 +79,8 @@ pub enum MirPhase {
/// MIR, this is UB.
/// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
/// that Rust itself has them. Where exactly these are is generally subject to change, and so we
- /// don't document this here. Runtime MIR has all retags explicit.
+ /// don't document this here. Runtime MIR has most retags explicit (though implicit retags
+ /// can still occur at `Rvalue::{Ref,AddrOf}`).
/// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has
/// access to. This occurs in generator bodies. Such locals do not behave like other locals,
/// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
@@ -133,7 +135,6 @@ pub enum AnalysisPhase {
pub enum RuntimePhase {
/// In addition to the semantic changes, beginning with this phase, the following variants are
/// disallowed:
- /// * [`TerminatorKind::DropAndReplace`]
/// * [`TerminatorKind::Yield`]
/// * [`TerminatorKind::GeneratorDrop`]
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
@@ -219,6 +220,11 @@ pub enum BorrowKind {
/// immutable, but not aliasable. This solves the problem. For
/// simplicity, we don't give users the way to express this
/// borrow, it's just used when translating closures.
+ ///
+ // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except
+ // that they do not require their pointee to be marked as a mutable.
+ // They should still be treated as mutable borrows in every other way,
+ // e.g. for variance or overlap checking.
Unique,
/// Data is mutable and not aliasable.
@@ -326,6 +332,15 @@ pub enum StatementKind<'tcx> {
/// Only `RetagKind::Default` and `RetagKind::FnEntry` are permitted.
Retag(RetagKind, Box<Place<'tcx>>),
+ /// This statement exists to preserve a trace of a scrutinee matched against a wildcard binding.
+ /// This is especially useful for `let _ = PLACE;` bindings that desugar to a single
+ /// `PlaceMention(PLACE)`.
+ ///
+ /// When executed at runtime this is a nop.
+ ///
+ /// Disallowed after drop elaboration.
+ PlaceMention(Box<Place<'tcx>>),
+
/// Encodes a user's type ascription. These need to be preserved
/// intact so that NLL can respect them. For example:
/// ```ignore (illustrative)
@@ -505,15 +520,15 @@ pub struct CopyNonOverlapping<'tcx> {
///
/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
-/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
-/// once the current function is reached, execution continues at the given basic block, if any. If
-/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
-/// equivalent to the execution of a `Resume` terminator.
+/// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then
+/// once the current function is reached, an action will be taken based on the `unwind` field.
+/// If the action is `Cleanup`, then the execution continues at the given basic block. If the
+/// action is `Continue` then no cleanup is performed, and the stack continues unwinding.
///
-/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
-/// basic blocks have a couple restrictions:
-/// 1. All `cleanup` fields in them must be `None`.
-/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
+/// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set.
+/// `cleanup` basic blocks have a couple restrictions:
+/// 1. All `unwind` fields in them must be `UnwindAction::Terminate` or `UnwindAction::Unreachable`.
+/// 2. `Return` terminators are not allowed in them. `Terminate` and `Resume` terminators are.
/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
/// must also be `cleanup`. This is a part of the type system and checked statically, so it is
/// still an error to have such an edge in the CFG even if it's known that it won't be taken at
@@ -555,11 +570,11 @@ pub enum TerminatorKind<'tcx> {
/// deaggregation runs.
Resume,
- /// Indicates that the landing pad is finished and that the process should abort.
+ /// Indicates that the landing pad is finished and that the process should terminate.
///
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
/// cleanup blocks.
- Abort,
+ Terminate,
/// Returns from the function.
///
@@ -594,44 +609,7 @@ pub enum TerminatorKind<'tcx> {
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
/// > consider indirect assignments.
- Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
-
- /// Drops the place and assigns a new value to it.
- ///
- /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
- /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
- /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
- /// explained by the elaboration:
- ///
- /// ```ignore (MIR)
- /// BB0 {
- /// DropAndReplace(P <- V, goto BB1, unwind BB2)
- /// }
- /// ```
- ///
- /// becomes
- ///
- /// ```ignore (MIR)
- /// BB0 {
- /// Drop(P, goto BB1, unwind BB2)
- /// }
- /// BB1 {
- /// // P is now uninitialized
- /// P <- V
- /// }
- /// BB2 {
- /// // P is now uninitialized -- its dtor panicked
- /// P <- V
- /// }
- /// ```
- ///
- /// Disallowed after drop elaboration.
- DropAndReplace {
- place: Place<'tcx>,
- value: Operand<'tcx>,
- target: BasicBlock,
- unwind: Option<BasicBlock>,
- },
+ Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
/// the referred to function. The operand types must match the argument types of the function.
@@ -655,8 +633,8 @@ pub enum TerminatorKind<'tcx> {
destination: Place<'tcx>,
/// Where to go after this call returns. If none, the call necessarily diverges.
target: Option<BasicBlock>,
- /// Cleanups to be done if the call unwinds.
- cleanup: Option<BasicBlock>,
+ /// Action to be taken if the call unwinds.
+ unwind: UnwindAction,
/// `true` if this is from a call in HIR rather than from an overloaded
/// operator. True for overloaded function call.
from_hir_call: bool,
@@ -675,14 +653,13 @@ pub enum TerminatorKind<'tcx> {
/// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR
/// that is used for CTFE), the following variants of this terminator behave as `goto target`:
/// - `OverflowNeg(..)`,
- /// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT
- /// div or rem).
+ /// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem.
Assert {
cond: Operand<'tcx>,
expected: bool,
msg: AssertMessage<'tcx>,
target: BasicBlock,
- cleanup: Option<BasicBlock>,
+ unwind: UnwindAction,
},
/// Marks a suspend point.
@@ -748,9 +725,8 @@ pub enum TerminatorKind<'tcx> {
/// in practice, but in order to avoid fragility we want to always
/// consider it in borrowck. We don't want to accept programs which
/// pass borrowck only when `panic=abort` or some assertions are disabled
- /// due to release vs. debug mode builds. This needs to be an `Option` because
- /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
- unwind: Option<BasicBlock>,
+ /// due to release vs. debug mode builds.
+ unwind: UnwindAction,
},
/// Block ends with an inline assembly block. This is a terminator since
@@ -773,12 +749,31 @@ pub enum TerminatorKind<'tcx> {
/// diverging (InlineAsmOptions::NORETURN).
destination: Option<BasicBlock>,
- /// Cleanup to be done if the inline assembly unwinds. This is present
+ /// Action to be taken if the inline assembly unwinds. This is present
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
- cleanup: Option<BasicBlock>,
+ unwind: UnwindAction,
},
}
+/// Action to be taken when a stack unwind happens.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum UnwindAction {
+ /// No action is to be taken. Continue unwinding.
+ ///
+ /// This is similar to `Cleanup(bb)` where `bb` does nothing but `Resume`, but they are not
+ /// equivalent, as presence of `Cleanup(_)` will make a frame non-POF.
+ Continue,
+ /// Triggers undefined behavior if unwind happens.
+ Unreachable,
+ /// Terminates the execution if unwind happens.
+ ///
+ /// Depending on the platform and situation this may cause a non-unwindable panic or abort.
+ Terminate,
+ /// Cleanups to be done.
+ Cleanup(BasicBlock),
+}
+
/// Information about an assertion failure.
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
pub enum AssertKind<O> {
@@ -789,6 +784,7 @@ pub enum AssertKind<O> {
RemainderByZero(O),
ResumedAfterReturn(GeneratorKind),
ResumedAfterPanic(GeneratorKind),
+ MisalignedPointerDereference { required: O, found: O },
}
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -917,7 +913,15 @@ pub struct Place<'tcx> {
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub enum ProjectionElem<V, T> {
Deref,
- Field(Field, T),
+
+ /// A field (e.g., `f` in `_1.f`) is one variant of [`ProjectionElem`]. Conceptually,
+ /// rustc can identify that a field projection refers to either two different regions of memory
+ /// or the same one between the base and the 'projection element'.
+ /// Read more about projections in the [rustc-dev-guide][mir-datatypes]
+ ///
+ /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types
+ Field(FieldIdx, T),
+
/// Index into a slice/array.
///
/// Note that this does not also dereference, and so it does not exactly correspond to slice
@@ -1110,11 +1114,7 @@ pub enum Rvalue<'tcx> {
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
///
/// For addition, subtraction, and multiplication on integers the error condition is set when
- /// the infinite precision result would be unequal to the actual result.
- ///
- /// For shift operations on integers the error condition is set when the value of right-hand
- /// side is greater than or equal to the number of bits in the type of the left-hand side, or
- /// when the value of right-hand side is negative.
+ /// the infinite precision result would not be equal to the actual result.
///
/// Other combinations of types and operators are unsupported.
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
@@ -1149,7 +1149,7 @@ pub enum Rvalue<'tcx> {
///
/// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
/// generator lowering, `Generator` aggregate kinds are disallowed too.
- Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
+ Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>),
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
///
@@ -1189,6 +1189,13 @@ pub enum CastKind {
IntToFloat,
PtrToPtr,
FnPtrToPtr,
+ /// Reinterpret the bits of the input as a different type.
+ ///
+ /// MIR is well-formed if the input and output types have different sizes,
+ /// but running a transmute between differently-sized types is UB.
+ ///
+ /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`].
+ Transmute,
}
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -1199,11 +1206,11 @@ pub enum AggregateKind<'tcx> {
Tuple,
/// The second field is the variant index. It's equal to 0 for struct
- /// and union expressions. The fourth field is
+ /// and union expressions. The last field is the
/// active field number and is present only for union expressions
/// -- e.g., for a union expression `SomeUnion { c: .. }`, the
/// active field index would identity the field `c`
- Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
+ Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
Closure(DefId, SubstsRef<'tcx>),
Generator(DefId, SubstsRef<'tcx>, hir::Movability),
@@ -1280,7 +1287,7 @@ pub enum BinOp {
mod size_asserts {
use super::*;
// tidy-alphabetical-start
- static_assert_size!(AggregateKind<'_>, 40);
+ static_assert_size!(AggregateKind<'_>, 32);
static_assert_size!(Operand<'_>, 24);
static_assert_size!(Place<'_>, 16);
static_assert_size!(PlaceElem<'_>, 24);