diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir/mod.rs')
| -rw-r--r-- | compiler/rustc_middle/src/mir/mod.rs | 184 |
1 files changed, 103 insertions, 81 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index da3be223690..b1ab0f5b533 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -7,15 +7,17 @@ use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; + use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; use rustc_hir::{self as hir, HirId}; +use rustc_session::Session; use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; @@ -29,6 +31,9 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; + +use either::Either; + use std::borrow::Cow; use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; @@ -99,7 +104,21 @@ pub trait MirPass<'tcx> { } } + /// Returns `true` if this pass is enabled with the current combination of compiler flags. + fn is_enabled(&self, _sess: &Session) -> bool { + true + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); + + /// If this pass causes the MIR to enter a new phase, return that phase. + fn phase_change(&self) -> Option<MirPhase> { + None + } + + fn is_mir_dump_enabled(&self) -> bool { + true + } } /// The various "big phases" that MIR goes through. @@ -143,7 +162,7 @@ impl MirPhase { } /// Where a specific `mir::Body` comes from. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)] pub struct MirSource<'tcx> { pub instance: InstanceDef<'tcx>, @@ -269,7 +288,6 @@ pub struct Body<'tcx> { impl<'tcx> Body<'tcx> { pub fn new( - tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, @@ -312,7 +330,7 @@ impl<'tcx> Body<'tcx> { predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), }; - body.is_polymorphic = body.definitely_has_param_types_or_consts(tcx); + body.is_polymorphic = body.has_param_types_or_consts(); body } @@ -322,7 +340,7 @@ impl<'tcx> Body<'tcx> { /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { - Body { + let mut body = Body { phase: MirPhase::Build, source: MirSource::item(DefId::local(CRATE_DEF_INDEX)), basic_blocks, @@ -338,7 +356,9 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, predecessor_cache: PredecessorCache::new(), is_cyclic: GraphIsCyclicCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } #[inline] @@ -488,6 +508,16 @@ impl<'tcx> Body<'tcx> { Location { block: bb, statement_index: self[bb].statements.len() } } + pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> { + let Location { block, statement_index } = location; + let block_data = &self.basic_blocks[block]; + block_data + .statements + .get(statement_index) + .map(Either::Left) + .unwrap_or_else(|| Either::Right(block_data.terminator())) + } + #[inline] pub fn predecessors(&self) -> &Predecessors { self.predecessor_cache.compute(&self.basic_blocks) @@ -589,20 +619,20 @@ impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate } impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> { #[inline] - fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> { + fn decode(d: &mut D) -> ClearCrossCrate<T> { if D::CLEAR_CROSS_CRATE { - return Ok(ClearCrossCrate::Clear); + return ClearCrossCrate::Clear; } - let discr = u8::decode(d)?; + let discr = u8::decode(d); match discr { - TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear), + TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear, TAG_CLEAR_CROSS_CRATE_SET => { - let val = T::decode(d)?; - Ok(ClearCrossCrate::Set(val)) + let val = T::decode(d); + ClearCrossCrate::Set(val) } - tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))), + tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag), } } } @@ -1225,17 +1255,7 @@ pub enum AssertKind<O> { ResumedAfterPanic(GeneratorKind), } -#[derive( - Clone, - Debug, - PartialEq, - PartialOrd, - TyEncodable, - TyDecodable, - Hash, - HashStable, - TypeFoldable -)] +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -1504,6 +1524,7 @@ impl Statement<'_> { } /// Changes a statement to a nop and returns the original statement. + #[must_use = "If you don't need the statement, use `make_nop` instead"] pub fn replace_nop(&mut self) -> Self { Statement { source_info: self.source_info, @@ -1535,10 +1556,6 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Local), - /// Executes a piece of inline Assembly. Stored in a Box to keep the size - /// of `StatementKind` low. - LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>), - /// Retag references in the given place, ensuring they got fresh tags. This is /// part of the Stacked Borrows model. These statements are currently only interpreted /// by miri and only generated when "-Z mir-emit-retag" is passed. @@ -1658,13 +1675,6 @@ pub enum FakeReadCause { ForIndex, } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] -pub struct LlvmInlineAsm<'tcx> { - pub asm: hir::LlvmInlineAsmInner, - pub outputs: Box<[Place<'tcx>]>, - pub inputs: Box<[(Span, Operand<'tcx>)]>, -} - impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; @@ -1689,9 +1699,6 @@ impl Debug for Statement<'_> { SetDiscriminant { ref place, variant_index } => { write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) } - LlvmInlineAsm(ref asm) => { - write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) - } AscribeUserType(box (ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } @@ -1730,7 +1737,7 @@ pub struct CopyNonOverlapping<'tcx> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] pub struct Place<'tcx> { pub local: Local, @@ -1803,6 +1810,16 @@ impl<V, T> ProjectionElem<V, T> { | Self::Downcast(_, _) => false, } } + + /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`. + pub fn is_downcast_to(&self, v: VariantIdx) -> bool { + matches!(*self, Self::Downcast(_, x) if x == v) + } + + /// Returns `true` if this is a `Field` projection with the given index. + pub fn is_field_to(&self, f: Field) -> bool { + matches!(*self, Self::Field(x, _) if x == f) + } } /// Alias for projections as they appear in places, where the base is a place @@ -1993,7 +2010,7 @@ impl SourceScope { /// Finds the original HirId this MIR item came from. /// This is necessary after MIR optimizations, as otherwise we get a HirId /// from the function that was inlined instead of the function call site. - pub fn lint_root( + pub fn lint_root<'tcx>( self, source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>, ) -> Option<HirId> { @@ -2045,7 +2062,7 @@ pub struct SourceScopeLocalData { /// These are values that can appear inside an rvalue. They are intentionally /// limited to prevent rvalues from being nested in one another. -#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum Operand<'tcx> { /// Copy: The value must be available for use afterwards. /// @@ -2228,7 +2245,7 @@ pub enum AggregateKind<'tcx> { /// 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(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), + Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), Closure(DefId, SubstsRef<'tcx>), Generator(DefId, SubstsRef<'tcx>, hir::Movability), @@ -2246,8 +2263,12 @@ pub enum BinOp { /// The `*` operator (multiplication) Mul, /// The `/` operator (division) + /// + /// Division by zero is UB. Div, /// The `%` operator (modulus) + /// + /// Using zero as the modulus (second operand) is UB. Rem, /// The `^` operator (bitwise xor) BitXor, @@ -2256,8 +2277,12 @@ pub enum BinOp { /// The `|` operator (bitwise or) BitOr, /// The `<<` operator (shift left) + /// + /// The offset is truncated to the size of the first operand before shifting. Shl, /// The `>>` operator (shift right) + /// + /// The offset is truncated to the size of the first operand before shifting. Shr, /// The `==` operator (equality) Eq, @@ -2288,8 +2313,6 @@ pub enum NullOp { SizeOf, /// Returns the minimum alignment of a type AlignOf, - /// Creates a new uninitialized box for a value of that type - Box, } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -2379,33 +2402,30 @@ impl<'tcx> Debug for Rvalue<'tcx> { } } - AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { - let variant_def = &adt_def.variants[variant]; - - let name = ty::tls::with(|tcx| { + AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => { + ty::tls::with(|tcx| { let mut name = String::new(); + let variant_def = &tcx.adt_def(adt_did).variants[variant]; let substs = tcx.lift(substs).expect("could not lift for printing"); FmtPrinter::new(tcx, &mut name, Namespace::ValueNS) .print_def_path(variant_def.def_id, substs)?; - Ok(name) - })?; - - match variant_def.ctor_kind { - CtorKind::Const => fmt.write_str(&name), - CtorKind::Fn => fmt_tuple(fmt, &name), - CtorKind::Fictive => { - let mut struct_fmt = fmt.debug_struct(&name); - for (field, place) in iter::zip(&variant_def.fields, places) { - struct_fmt.field(&field.ident.as_str(), place); + + match variant_def.ctor_kind { + CtorKind::Const => fmt.write_str(&name), + CtorKind::Fn => fmt_tuple(fmt, &name), + CtorKind::Fictive => { + let mut struct_fmt = fmt.debug_struct(&name); + for (field, place) in iter::zip(&variant_def.fields, places) { + struct_fmt.field(field.name.as_str(), place); + } + struct_fmt.finish() } - struct_fmt.finish() } - } + }) } AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { if let Some(def_id) = def_id.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let name = if tcx.sess.opts.debugging_opts.span_free_formats { let substs = tcx.lift(substs).unwrap(); format!( @@ -2413,7 +2433,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { tcx.def_path_str_with_substs(def_id.to_def_id(), substs), ) } else { - let span = tcx.hir().span(hir_id); + let span = tcx.def_span(def_id); format!( "[closure@{}]", tcx.sess.source_map().span_to_diagnostic_string(span) @@ -2425,7 +2445,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); - struct_fmt.field(&var_name.as_str(), place); + struct_fmt.field(var_name.as_str(), place); } } @@ -2437,15 +2457,14 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { if let Some(def_id) = def_id.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); + let name = format!("[generator@{:?}]", tcx.def_span(def_id)); let mut struct_fmt = fmt.debug_struct(&name); // FIXME(project-rfc-2229#48): This should be a list of capture names/places if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); - struct_fmt.field(&var_name.as_str(), place); + struct_fmt.field(var_name.as_str(), place); } } @@ -2471,7 +2490,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// this does not necessarily mean that they are `==` in Rust. In /// particular, one must be wary of `NaN`! -#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub struct Constant<'tcx> { pub span: Span, @@ -2485,7 +2504,7 @@ pub struct Constant<'tcx> { pub literal: ConstantKind<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] #[derive(Lift)] pub enum ConstantKind<'tcx> { /// This constant came from the type system @@ -2495,7 +2514,7 @@ pub enum ConstantKind<'tcx> { Val(interpret::ConstValue<'tcx>, Ty<'tcx>), } -impl Constant<'tcx> { +impl<'tcx> Constant<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { match self.literal.const_for_ty()?.val.try_to_scalar() { Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { @@ -2514,14 +2533,14 @@ impl Constant<'tcx> { } } -impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { +impl<'tcx> From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { #[inline] fn from(ct: &'tcx ty::Const<'tcx>) -> Self { Self::Ty(ct) } } -impl ConstantKind<'tcx> { +impl<'tcx> ConstantKind<'tcx> { /// Returns `None` if the constant is not trivially safe for use in the type system. pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> { match self { @@ -2741,7 +2760,7 @@ impl UserTypeProjection { field: Field, ) -> Self { self.projs.push(ProjectionElem::Downcast( - Some(adt_def.variants[variant_index].ident.name), + Some(adt_def.variants[variant_index].name), variant_index, )); self.projs.push(ProjectionElem::Field(field, ())); @@ -2752,11 +2771,14 @@ impl UserTypeProjection { TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { - fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { - UserTypeProjection { - base: self.base.fold_with(folder), - projs: self.projs.fold_with(folder), - } + fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(UserTypeProjection { + base: self.base.try_fold_with(folder)?, + projs: self.projs.try_fold_with(folder)?, + }) } fn super_visit_with<Vs: TypeVisitor<'tcx>>( @@ -2800,7 +2822,7 @@ impl<'tcx> Display for ConstantKind<'tcx> { } } -fn pretty_print_const( +fn pretty_print_const<'tcx>( c: &ty::Const<'tcx>, fmt: &mut Formatter<'_>, print_types: bool, @@ -2815,7 +2837,7 @@ fn pretty_print_const( }) } -fn pretty_print_const_value( +fn pretty_print_const_value<'tcx>( val: interpret::ConstValue<'tcx>, ty: Ty<'tcx>, fmt: &mut Formatter<'_>, @@ -2862,12 +2884,12 @@ impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { type Iter = iter::Cloned<Successors<'b>>; } -impl graph::GraphPredecessors<'graph> for Body<'tcx> { +impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> { type Item = BasicBlock; type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>; } -impl graph::WithPredecessors for Body<'tcx> { +impl<'tcx> graph::WithPredecessors for Body<'tcx> { #[inline] fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { self.predecessors()[node].iter().copied() |
