diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index 209e6f7ac9fe4..4acf47e75a57e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -1,6 +1,7 @@ //! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow //! analysis. +use crate::lattice::{FactArray, FactCache}; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::vec::Idx; use std::fmt; @@ -124,6 +125,30 @@ where } } +impl DebugWithContext for FactArray +where + T: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map() + .entries( + self.arr + .iter() + .enumerate() + .map(|(i, ref v)| (i, DebugWithAdapter { this: *v, ctxt })), + ) + .finish() + } +} + +impl + DebugWithContext for FactCache +{ + fn fmt_with(&self, _: &C, _: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!(); + } +} + fn fmt_diff( inserted: &HybridBitSet, removed: &HybridBitSet, diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index d6b89eb82275e..0a13ae32f0b9b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -250,3 +250,196 @@ impl MeetSemiLattice for FlatSet { true } } + +macro_rules! packed_int_join_semi_lattice { + ($name: ident, $base: ty) => { + #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] + pub struct $name($base); + impl $name { + pub const TOP: Self = Self(<$base>::MAX); + #[inline] + pub const fn new(v: $base) -> Self { + Self(v) + } + + /// `saturating_new` will convert an arbitrary value (i.e. u32) into a Fact which + /// may have a smaller internal representation (i.e. u8). If the value is too large, + /// it will be converted to `TOP`, which is safe because `TOP` is the most + /// conservative estimate, assuming no information. Note, it is _not_ safe to + /// assume `BOT`, since this assumes information about the value. + #[inline] + pub fn saturating_new(v: impl TryInto<$base>) -> Self { + v.try_into().map(|v| Self(v)).unwrap_or(Self::TOP) + } + + pub const fn inner(self) -> $base { + self.0 + } + } + + impl JoinSemiLattice for $name { + #[inline] + fn join(&mut self, other: &Self) -> bool { + match (*self, *other) { + (Self::TOP, _) => false, + (a, b) if a == b => false, + _ => { + *self = Self::TOP; + true + } + } + } + } + + impl crate::fmt::DebugWithContext for $name { + fn fmt_with(&self, _: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if *self == Self::TOP { write!(f, "TOP") } else { write!(f, "{}", self.inner()) } + } + } + }; +} + +packed_int_join_semi_lattice!(PackedU8JoinSemiLattice, u8); + +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub struct FactArray { + // FIXME(julianknodt): maybe map Idxs to each N element? + pub arr: [T; N], +} + +impl FactArray { + #[inline] + pub fn insert(&mut self, i: impl Idx, fact: T) { + let Some(v) = self.arr.get_mut(i.index()) else { return }; + *v = fact; + } + #[inline] + pub fn get(&self, i: &impl Idx) -> Option<&T> { + self.arr.get(i.index()) + } +} + +impl JoinSemiLattice for FactArray { + fn join(&mut self, other: &Self) -> bool { + let mut changed = false; + for (a, b) in self.arr.iter_mut().zip(other.arr.iter()) { + changed |= a.join(b); + } + changed + } +} + +impl MeetSemiLattice for FactArray { + fn meet(&mut self, other: &Self) -> bool { + let mut changed = false; + for (a, b) in self.arr.iter_mut().zip(other.arr.iter()) { + changed |= a.meet(b); + } + changed + } +} + +/// FactCache is a struct that contains `N` recent facts (of type F) from dataflow analysis, +/// where a fact is information about some component of a program, such as the possible values a +/// variable can take. Variables are indexed by `I: Idx` (i.e. mir::Local), and `L` represents +/// location/recency, so that when merging two fact caches, the more recent information takes +/// precedence. +/// This representation is used because it takes constant memory, and assumes that recent facts +/// will have temporal locality (i.e. will be used closed to where they are generated). Thus, it +/// is more conservative than a complete analysis, but should be fast. +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub struct FactCache { + facts: [F; N], + ord: [(I, L); N], + len: usize, +} + +impl FactCache { + pub fn new(empty_i: I, empty_l: L, empty_f: F) -> Self + where + F: Copy, + { + Self { facts: [empty_f; N], ord: [(empty_i, empty_l); N], len: 0 } + } + /// (nserts a fact into the cache, evicting the oldest one, + /// Or updating it if there is information on one already. If the new fact being + /// inserted is older than the previous fact, it will not be inserted. + pub fn insert(&mut self, i: I, l: L, fact: F) { + let mut idx = None; + for (j, (ci, _cl)) in self.ord[..self.len].iter_mut().enumerate() { + if *ci == i { + // if an older fact is inserted, still update the cache: i.e. cl <= l usually + // but this is broken during apply switch int edge effects, because the engine + // may choose an arbitrary order for basic blocks to apply it to. + idx = Some(j); + break; + } + } + if idx.is_none() && self.len < N { + let new_len = self.len + 1; + idx = Some(std::mem::replace(&mut self.len, new_len)); + }; + if let Some(idx) = idx { + self.facts[idx] = fact; + self.ord[idx] = (i, l); + return; + }; + let (p, (_, old_l)) = self.ord.iter().enumerate().min_by_key(|k| k.1.1).unwrap(); + // FIXME(julianknodt) maybe don't make this an assert but just don't update? + assert!(*old_l <= l); + self.ord[p] = (i, l); + self.facts[p] = fact; + } + pub fn get(&self, i: I) -> Option<(&L, &F)> { + let (p, (_, loc)) = + self.ord[..self.len].iter().enumerate().find(|(_, iloc)| iloc.0 == i)?; + Some((loc, &self.facts[p])) + } + pub fn remove(&mut self, i: I) -> bool { + let Some(pos) = self.ord[..self.len].iter().position(|(ci, _)| *ci == i) + else { return false }; + + self.remove_idx(pos); + return true; + } + #[inline] + fn remove_idx(&mut self, i: usize) { + assert!(i < self.len); + self.ord.swap(i, self.len); + self.facts.swap(i, self.len); + self.len -= 1; + } + + fn drain_filter(&mut self, mut should_rm: impl FnMut(&I, &mut L, &mut F) -> bool) { + let mut i = 0; + while i < self.len { + let (idx, l) = &mut self.ord[i]; + let f = &mut self.facts[i]; + if should_rm(idx, l, f) { + self.remove_idx(i); + continue; + } + i += 1; + } + } +} + +impl JoinSemiLattice for FactCache { + fn join(&mut self, other: &Self) -> bool { + let mut changed = false; + self.drain_filter(|i, l, f| { + let Some((other_loc, other_fact)) = other.get(*i) else { + changed = true; + return true; + }; + if other_fact == f { + *l = (*l).max(*other_loc); + return false; + } + changed = true; + return true; + }); + + changed + } +} diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index af6a1bb1545ea..77f088fd00550 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -21,6 +21,7 @@ use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; mod borrowed_locals; mod init_locals; mod liveness; +mod single_enum_variant; mod storage_liveness; pub use self::borrowed_locals::borrowed_locals; @@ -28,6 +29,7 @@ pub use self::borrowed_locals::MaybeBorrowedLocals; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; pub use self::liveness::MaybeTransitiveLiveLocals; +pub use self::single_enum_variant::SingleEnumVariant; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; /// `MaybeInitializedPlaces` tracks all places that might be diff --git a/compiler/rustc_mir_dataflow/src/impls/single_enum_variant.rs b/compiler/rustc_mir_dataflow/src/impls/single_enum_variant.rs new file mode 100644 index 0000000000000..a23badf4a3444 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/impls/single_enum_variant.rs @@ -0,0 +1,216 @@ +use super::*; +//use crate::lattice::PackedU8JoinSemiLattice as Fact; + +//use crate::lattice::FactArray; +use crate::lattice::FactCache; +use rustc_target::abi::VariantIdx; + +use rustc_middle::mir::*; + +use crate::{Analysis, AnalysisDomain}; + +/// A dataflow analysis that tracks whether an enum can hold exactly 1, or more than 1 variants. +/// +/// Specifically, if a local is constructed with a value of `Some(1)`, +/// We should be able to optimize it under the assumption that it has the `Some` variant. +/// If a local can be multiple variants, then we assume nothing. +/// This analysis returns whether or not an enum will have a specific discriminant +/// at a given time, associating that local with exactly the 1 discriminant it is. +pub struct SingleEnumVariant<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, +} + +impl<'tcx> AnalysisDomain<'tcx> for SingleEnumVariant<'_, 'tcx> { + /// For each local, keep track of which enum index it is, if its uninhabited, or unknown. + type Domain = FactCache; + + const NAME: &'static str = "single_enum_variant"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + FactCache::new(Local::from_u32(0), Location::START, VariantIdx::MAX) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { + // assume everything is TOP initially (i.e. it can be any variant). + let local_decls = body.local_decls(); + for (l, _) in local_decls.iter_enumerated() { + state.remove(l); + } + } +} + +impl<'tcx> SingleEnumVariant<'_, 'tcx> { + pub fn new<'a>(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> SingleEnumVariant<'a, 'tcx> { + SingleEnumVariant { tcx, body } + } + #[inline] + pub fn is_tracked(&self, place: &Place<'tcx>) -> bool { + place.ty(self.body, self.tcx).ty.is_enum() + } + fn assign( + &self, + state: &mut >::Domain, + lhs: &Place<'tcx>, + rhs: &Operand<'tcx>, + location: Location, + ) { + let _: Option<_> = try { + if !self.is_tracked(lhs) { + return; + } + let lhs_local = lhs.as_local()?; + + let new_fact = match rhs { + Operand::Copy(rhs) | Operand::Move(rhs) => { + if let Some(rhs_local) = rhs.as_local() { + state.get(rhs_local).map(|f| f.1).copied() + } else { + debug_assert!( + rhs.ty(self.body, self.tcx) + .variant_index + .map(|var_idx| var_idx) + .is_none() + ); + None + } + } + // For now, assume that assigning a constant removes known facts. + // More conservative than necessary, but a temp placeholder, + // rather than extracting an enum variant from a constant. + Operand::Constant(_c) => None, + }; + if let Some(new_fact) = new_fact { + state.insert(lhs_local, location, new_fact); + } else { + state.remove(lhs_local); + } + }; + } +} + +impl<'tcx> Analysis<'tcx> for SingleEnumVariant<'_, 'tcx> { + fn apply_statement_effect( + &self, + state: &mut Self::Domain, + statement: &Statement<'tcx>, + loc: Location, + ) { + // (place = location which has new information, + // fact = None if we no longer know what variant a value has + // OR fact = Some(var_idx) if we know what variant a value has). + let (place, fact) = match &statement.kind { + StatementKind::Deinit(box place) => (place, None), + StatementKind::SetDiscriminant { box place, variant_index } => { + (place, Some(*variant_index)) + } + StatementKind::Assign(box (lhs, Rvalue::Use(op))) => { + return self.assign(state, lhs, op, loc); + } + /* may alias/mutate RHS need to specify that it is no longer a single value */ + StatementKind::Assign(box ( + _, + Rvalue::Ref(_, BorrowKind::Mut { .. }, rhs) + | Rvalue::AddressOf(Mutability::Mut, rhs), + )) => (rhs, None), + StatementKind::CopyNonOverlapping(box ref copy) => { + let place = match ©.dst { + Operand::Copy(p) | Operand::Move(p) => p, + _ => return, + }; + (place, None) + } + _ => return, + }; + if !self.is_tracked(place) { + return; + } + let Some(local) = place.as_local() else { return }; + if let Some(fact) = fact { + state.insert(local, loc, fact); + } else { + state.remove(local); + } + } + fn apply_terminator_effect( + &self, + state: &mut Self::Domain, + terminator: &Terminator<'tcx>, + loc: Location, + ) { + match &terminator.kind { + TerminatorKind::DropAndReplace { place, value, .. } => { + self.assign(state, place, value, loc) + } + TerminatorKind::Drop { place, .. } if self.is_tracked(place) => { + let Some(local) = place.as_local() else { return }; + state.remove(local); + } + _ => {} + } + } + + fn apply_call_return_effect( + &self, + _: &mut Self::Domain, + _: BasicBlock, + _: CallReturnPlaces<'_, 'tcx>, + ) { + } + + fn apply_switch_int_edge_effects( + &self, + from_block: BasicBlock, + discr: &Operand<'tcx>, + apply_edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + let Some(switch_on) = discr.place() else { return }; + + let mut src_place = None; + let mut adt_def = None; + for stmt in self.body[from_block].statements.iter().rev() { + match stmt.kind { + StatementKind::Assign(box (lhs, Rvalue::Discriminant(disc))) + if lhs == switch_on => + { + match disc.ty(self.body, self.tcx).ty.kind() { + ty::Adt(adt, _) => { + src_place = Some(disc); + adt_def = Some(adt); + break; + } + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => return, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } + StatementKind::Coverage(_) => continue, + _ => return, + }; + } + + let Some(src_place) = src_place else { return }; + let Some(adt_def) = adt_def else { return }; + if !self.is_tracked(&src_place) { + return; + } + let Some(local) = src_place.as_local() else { return }; + + apply_edge_effects.apply(|state, target| { + let new_fact = target.value.and_then(|discr| { + adt_def.discriminants(self.tcx).find(|(_, d)| d.val == discr).map(|(vi, _)| vi) + }); + + if let Some(new_fact) = new_fact { + let loc = Location { block: target.target, statement_index: 0 }; + state.insert(local, loc, new_fact); + } else { + state.remove(local); + } + }); + } +} diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index e4c130f0807dd..e13ac96b1fb16 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -6,6 +6,7 @@ #![feature(once_cell)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] +#![feature(try_blocks)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0887775aae5ed..519e52e9fcf5d 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -82,6 +82,7 @@ mod required_consts; mod reveal_all; mod separate_const_switch; mod shim; +mod single_enum; // This pass is public to allow external drivers to perform MIR cleanup pub mod simplify; mod simplify_branches; @@ -491,6 +492,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. &const_debuginfo::ConstDebugInfo, + &single_enum::SingleEnum, &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, diff --git a/compiler/rustc_mir_transform/src/single_enum.rs b/compiler/rustc_mir_transform/src/single_enum.rs new file mode 100644 index 0000000000000..d0943c1e2532f --- /dev/null +++ b/compiler/rustc_mir_transform/src/single_enum.rs @@ -0,0 +1,61 @@ +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::*; +use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_mir_dataflow::impls::SingleEnumVariant; +use rustc_mir_dataflow::Analysis; +use rustc_span::DUMMY_SP; + +use crate::MirPass; + +pub struct SingleEnum; + +impl<'tcx> MirPass<'tcx> for SingleEnum { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut single_enum_variants = SingleEnumVariant::new(tcx, body) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let mut discrs = vec![]; + + for (bb, block) in body.basic_blocks().iter_enumerated() { + for (i, stmt) in block.statements.iter().enumerate() { + let stmt_loc = Location { block: bb.clone(), statement_index: i }; + let StatementKind::Assign(box(_, Rvalue::Discriminant(src))) = stmt.kind + else { continue }; + if !src.ty(body, tcx).ty.is_enum() { + continue; + } + let Some(src_local) = src.local_or_deref_local() else { continue }; + + single_enum_variants.seek_before_primary_effect(stmt_loc); + match single_enum_variants.get().get(src_local) { + None => {} + Some((_, &v)) => discrs.push((stmt_loc, v)), + }; + } + } + + for (Location { block, statement_index }, val) in discrs { + let local_decls = &body.local_decls; + let bbs = body.basic_blocks.as_mut(); + + let stmt = &mut bbs[block].statements[statement_index]; + let Some((lhs, rval)) = stmt.kind.as_assign_mut() else { unreachable!() }; + let Rvalue::Discriminant(rhs) = rval else { unreachable!() }; + + let Some(disc) = rhs.ty(local_decls, tcx).ty.discriminant_for_variant(tcx, val) + else { continue }; + + let scalar_ty = lhs.ty(local_decls, tcx).ty; + let layout = tcx.layout_of(ParamEnv::empty().and(scalar_ty)).unwrap().layout; + let ct = Operand::const_from_scalar( + tcx, + scalar_ty, + Scalar::from_uint(disc.val, layout.size()), + DUMMY_SP, + ); + *rval = Rvalue::Use(ct); + } + } +} diff --git a/src/test/mir-opt/enum_prop.main.SingleEnum.diff b/src/test/mir-opt/enum_prop.main.SingleEnum.diff new file mode 100644 index 0000000000000..c19488493e298 --- /dev/null +++ b/src/test/mir-opt/enum_prop.main.SingleEnum.diff @@ -0,0 +1,360 @@ +- // MIR for `main` before SingleEnum ++ // MIR for `main` after SingleEnum + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/enum_prop.rs:3:11: 3:11 + let _1: i32; // in scope 0 at $DIR/enum_prop.rs:4:7: 4:8 + let mut _2: std::option::Option>; // in scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + let mut _3: std::boxed::Box; // in scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + let mut _4: isize; // in scope 0 at $DIR/enum_prop.rs:5:5: 5:12 + let _5: std::boxed::Box; // in scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + let _6: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _7: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _9: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _10: i32; // in scope 0 at $DIR/enum_prop.rs:10:16: 10:18 + let mut _13: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _15: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _16: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _17: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _20: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _21: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _22: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _25: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _27: std::option::Option; // in scope 0 at $DIR/enum_prop.rs:13:17: 13:24 + let mut _28: isize; // in scope 0 at $DIR/enum_prop.rs:14:14: 14:21 + let _30: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _31: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _32: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _33: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _34: i32; // in scope 0 at $DIR/enum_prop.rs:17:17: 17:18 + let mut _37: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _38: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _39: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _40: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _41: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _43: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _44: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _45: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _46: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _47: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _48: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _49: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _53: bool; // in scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + let mut _54: isize; // in scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + let mut _55: isize; // in scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + let mut _56: isize; // in scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + let mut _57: *const i32; // in scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + let mut _58: *const i32; // in scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + let mut _59: i32; // in scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + scope 1 { + debug v => _1; // in scope 1 at $DIR/enum_prop.rs:4:7: 4:8 + let _11: &i32; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _12: &i32; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _26: i32; // in scope 1 at $DIR/enum_prop.rs:13:7: 13:8 + let _29: &std::option::Option; // in scope 1 at $DIR/enum_prop.rs:14:5: 14:21 + let mut _51: &std::option::Option; // in scope 1 at $DIR/enum_prop.rs:14:5: 14:21 + let mut _52: &i32; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + scope 3 { + debug left_val => _11; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _12; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _18: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + scope 4 { + debug kind => _18; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + } + scope 5 { + debug x => _26; // in scope 5 at $DIR/enum_prop.rs:13:7: 13:8 + let _35: &i32; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _36: &i32; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _50: &i32; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + scope 7 { + debug left_val => _35; // in scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug right_val => _36; // in scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let _42: core::panicking::AssertKind; // in scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + scope 8 { + debug kind => _42; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + } + } + scope 6 { + debug _y => _29; // in scope 6 at $DIR/enum_prop.rs:14:5: 14:21 + } + } + scope 2 { + debug x => _5; // in scope 2 at $DIR/enum_prop.rs:5:10: 5:11 + } + scope 9 (inlined Box::::new) { // at $DIR/enum_prop.rs:4:22: 4:34 + debug x => _59; // in scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _60: usize; // in scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _61: usize; // in scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _62: *mut u8; // in scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _63: *const i32; // in scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + scope 10 { + } + } + + bb0: { + _53 = const false; // scope 0 at $DIR/enum_prop.rs:4:7: 4:8 + StorageLive(_1); // scope 0 at $DIR/enum_prop.rs:4:7: 4:8 + StorageLive(_2); // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + StorageLive(_3); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageLive(_59); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + _59 = const 10_i32; // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageLive(_60); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageLive(_61); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageLive(_62); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + _60 = const 4_usize; // scope 10 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _61 = const 4_usize; // scope 10 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _62 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> [return: bb17, unwind: bb18]; // scope 10 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/alloc/src/boxed.rs:LL:COL + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } + } + + bb1: { + _1 = const 3_i32; // scope 0 at $DIR/enum_prop.rs:8:10: 8:11 + goto -> bb15; // scope 0 at $DIR/enum_prop.rs:8:10: 8:11 + } + + bb2: { + StorageLive(_5); // scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + _53 = const false; // scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + _5 = move ((_2 as Some).0: std::boxed::Box); // scope 0 at $DIR/enum_prop.rs:5:10: 5:11 + StorageLive(_57); // scope 2 at $DIR/enum_prop.rs:6:7: 6:9 + _57 = (((_5.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 2 at $DIR/enum_prop.rs:6:7: 6:9 + _1 = (*_57); // scope 2 at $DIR/enum_prop.rs:6:7: 6:9 + StorageDead(_57); // scope 0 at $DIR/enum_prop.rs:7:5: 7:6 + drop(_5) -> [return: bb3, unwind: bb16]; // scope 0 at $DIR/enum_prop.rs:7:5: 7:6 + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/enum_prop.rs:7:5: 7:6 + goto -> bb15; // scope 0 at $DIR/enum_prop.rs:7:5: 7:6 + } + + bb4: { + StorageLive(_18); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_18); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + discriminant(_18) = 0; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = const core::panicking::AssertKind::Eq; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } + StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_22); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _22 = _11; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _21 = _22; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_23); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_24); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = _12; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _23 = _24; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + discriminant(_25) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _19 = core::panicking::assert_failed::(const core::panicking::AssertKind::Eq, move _21, move _23, move _25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option>) -> ! {core::panicking::assert_failed::}, val: Value() } + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } + } + + bb5: { + StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_7); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_6); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_26); // scope 1 at $DIR/enum_prop.rs:13:7: 13:8 + StorageLive(_27); // scope 1 at $DIR/enum_prop.rs:13:17: 13:24 + Deinit(_27); // scope 1 at $DIR/enum_prop.rs:13:17: 13:24 + ((_27 as Some).0: i32) = const 1_i32; // scope 1 at $DIR/enum_prop.rs:13:17: 13:24 + discriminant(_27) = 1; // scope 1 at $DIR/enum_prop.rs:13:17: 13:24 + _28 = const 1_isize; // scope 1 at $DIR/enum_prop.rs:13:17: 13:24 + switchInt(const 1_isize) -> [0_isize: bb6, otherwise: bb7]; // scope 1 at $DIR/enum_prop.rs:13:11: 13:24 + } + + bb6: { + _26 = const 2_i32; // scope 1 at $DIR/enum_prop.rs:15:13: 15:14 + goto -> bb8; // scope 1 at $DIR/enum_prop.rs:15:13: 15:14 + } + + bb7: { + StorageLive(_29); // scope 1 at $DIR/enum_prop.rs:14:5: 14:21 + _51 = const main::promoted[1]; // scope 1 at $DIR/enum_prop.rs:14:5: 14:21 + // mir::Constant + // + span: $DIR/enum_prop.rs:14:5: 14:21 + // + literal: Const { ty: &Option, val: Unevaluated(main, [], Some(promoted[1])) } + _29 = _51; // scope 1 at $DIR/enum_prop.rs:14:5: 14:21 + _26 = const 1_i32; // scope 6 at $DIR/enum_prop.rs:14:25: 14:26 + StorageDead(_29); // scope 1 at $DIR/enum_prop.rs:14:25: 14:26 + goto -> bb8; // scope 1 at $DIR/enum_prop.rs:14:25: 14:26 + } + + bb8: { + StorageDead(_27); // scope 1 at $DIR/enum_prop.rs:16:4: 16:5 + StorageLive(_30); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_31); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_32); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _32 = &_26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_33); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _50 = const main::promoted[0]; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } + _33 = _50; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_31); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_31.0: &i32) = move _32; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_31.1: &i32) = move _33; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_33); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_32); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _35 = (_31.0: &i32); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _36 = (_31.1: &i32); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_37); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_38); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_39); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _39 = (*_35); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_40); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _40 = const 1_i32; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _38 = Eq(move _39, const 1_i32); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_40); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_39); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _37 = Not(move _38); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_38); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(move _37) -> [false: bb10, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb9: { + StorageLive(_42); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_42); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + discriminant(_42) = 0; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_43); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_44); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _44 = const core::panicking::AssertKind::Eq; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } + StorageLive(_45); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_46); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _46 = _35; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _45 = _46; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_47); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_48); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _48 = _36; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _47 = _48; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_49); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_49); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + discriminant(_49) = 0; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _43 = core::panicking::assert_failed::(const core::panicking::AssertKind::Eq, move _45, move _47, move _49); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option>) -> ! {core::panicking::assert_failed::}, val: Value() } + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } + } + + bb10: { + StorageDead(_37); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_31); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_30); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_26); // scope 1 at $DIR/enum_prop.rs:19:1: 19:2 + StorageDead(_1); // scope 0 at $DIR/enum_prop.rs:19:1: 19:2 + return; // scope 0 at $DIR/enum_prop.rs:19:2: 19:2 + } + + bb11 (cleanup): { + resume; // scope 0 at $DIR/enum_prop.rs:3:1: 19:2 + } + + bb12: { + _53 = const false; // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + StorageDead(_2); // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + StorageLive(_6); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_7); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _8 = &_1; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _52 = const main::promoted[2]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[2])) } + _9 = _52; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_7); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_7.0: &i32) = move _8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_7.1: &i32) = move _9; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _11 = (_7.0: &i32); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _12 = (_7.1: &i32); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_15); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _15 = (*_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _16 = const 10_i32; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = Eq(move _15, const 10_i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_16); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_15); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _13 = Not(move _14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(move _13) -> [false: bb5, otherwise: bb4]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb13: { + switchInt(_53) -> [false: bb12, otherwise: bb14]; // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + } + + bb14: { + drop(((_2 as Some).0: std::boxed::Box)) -> [return: bb12, unwind: bb11]; // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + } + + bb15: { + _54 = discriminant(_2); // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + switchInt(move _54) -> [1_isize: bb13, otherwise: bb12]; // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + } + + bb16 (cleanup): { + _56 = discriminant(_2); // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + goto -> bb11; // scope 0 at $DIR/enum_prop.rs:9:4: 9:5 + } + + bb17: { + _3 = ShallowInitBox(move _62, i32); // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageLive(_63); // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _63 = (((_3.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32); // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + (*_63) = const 10_i32; // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageDead(_63); // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageDead(_62); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageDead(_61); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageDead(_60); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + StorageDead(_59); // scope 0 at $DIR/enum_prop.rs:4:22: 4:34 + _53 = const true; // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + Deinit(_2); // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + ((_2 as Some).0: std::boxed::Box) = move _3; // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + discriminant(_2) = 1; // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + StorageDead(_3); // scope 0 at $DIR/enum_prop.rs:4:34: 4:35 +- _4 = discriminant(_2); // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 ++ _4 = const 1_isize; // scope 0 at $DIR/enum_prop.rs:4:17: 4:35 + switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/enum_prop.rs:4:11: 4:35 + } + + bb18 (cleanup): { + resume; // scope 9 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + } + } + diff --git a/src/test/mir-opt/enum_prop.rs b/src/test/mir-opt/enum_prop.rs new file mode 100644 index 0000000000000..8d88fb7f3e825 --- /dev/null +++ b/src/test/mir-opt/enum_prop.rs @@ -0,0 +1,19 @@ +// EMIT_MIR enum_prop.main.SingleEnum.diff + +fn main() { + let v = match Some(Box::new(10)) { + Some(x) => { + *x + }, + _ => 3, + }; + assert_eq!(v,10); + + + let x = match Some(1) { + ref _y @ Some(_) => 1, + None => 2, + }; + assert_eq!(x, 1); + +} diff --git a/src/test/ui/drop/issue-90752.rs b/src/test/ui/drop/issue-90752.rs index 4395e45e7733a..d1e9742867ab1 100644 --- a/src/test/ui/drop/issue-90752.rs +++ b/src/test/ui/drop/issue-90752.rs @@ -14,14 +14,14 @@ fn test(drops: &RefCell>) { let mut foo = None; match foo { None => (), - _ => return, + _ => panic!(), } *(&mut foo) = Some((S(0, drops), S(1, drops))); // Both S(0) and S(1) should be dropped match foo { Some((_x, _)) => {} - _ => {} + _ => panic!("Should not match"), } } diff --git a/src/test/ui/let-else/let-else-run-pass.rs b/src/test/ui/let-else/let-else-run-pass.rs index 5d96623236dab..187a23a76a866 100644 --- a/src/test/ui/let-else/let-else-run-pass.rs +++ b/src/test/ui/let-else/let-else-run-pass.rs @@ -11,7 +11,7 @@ fn main() { } // ref binding to non-copy value and or-pattern let (MyEnum::A(ref x) | MyEnum::B { f: ref x }) = (MyEnum::B { f: String::new() }) else { - panic!(); + panic!("Shouldn't have matched enum"); }; assert_eq!(x, ""); @@ -25,11 +25,11 @@ fn main() { }; break; }; - panic!(); + panic!("Shouldn't have matched int"); } assert_eq!(x, 3); // else return let Some(1) = Some(2) else { return }; - panic!(); + panic!("Shouldn't have matched"); }