diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 7d0814b67fba..52a50333f457 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -68,7 +68,7 @@ use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior}; use rustc::ty::subst::{Kind, Substs}; use util::dump_mir; -use util::liveness; +use util::liveness::{self, LivenessMode}; use rustc_const_math::ConstInt; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_set::IdxSetBuf; @@ -348,7 +348,10 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ignored.visit_mir(mir); let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); - let liveness = liveness::liveness_of_locals(mir); + let liveness = liveness::liveness_of_locals(mir, LivenessMode { + include_regular_use: true, + include_drops: true, + }); liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness); let mut storage_liveness_map = HashMap::new(); diff --git a/src/librustc_mir/transform/nll/constraint_generation.rs b/src/librustc_mir/transform/nll/constraint_generation.rs index 1c0c3b6fc33f..518e140b5dd1 100644 --- a/src/librustc_mir/transform/nll/constraint_generation.rs +++ b/src/librustc_mir/transform/nll/constraint_generation.rs @@ -10,24 +10,30 @@ use rustc::mir::Mir; use rustc::infer::InferCtxt; -use util::liveness::LivenessResult; +use super::LivenessResults; use super::ToRegionIndex; use super::region_infer::RegionInferenceContext; -pub fn generate_constraints<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - regioncx: &mut RegionInferenceContext, - mir: &Mir<'tcx>, - liveness: &LivenessResult) -{ - ConstraintGeneration { infcx, regioncx, mir, liveness }.add_constraints(); +pub(super) fn generate_constraints<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + regioncx: &mut RegionInferenceContext, + mir: &Mir<'tcx>, + liveness: &LivenessResults, +) { + ConstraintGeneration { + infcx, + regioncx, + mir, + liveness, + }.add_constraints(); } struct ConstraintGeneration<'constrain, 'gcx: 'tcx, 'tcx: 'constrain> { infcx: &'constrain InferCtxt<'constrain, 'gcx, 'tcx>, regioncx: &'constrain mut RegionInferenceContext, mir: &'constrain Mir<'tcx>, - liveness: &'constrain LivenessResult, + liveness: &'constrain LivenessResults, } impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> { @@ -47,18 +53,23 @@ impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> { for bb in self.mir.basic_blocks().indices() { debug!("add_liveness_constraints: bb={:?}", bb); - self.liveness.simulate_block(self.mir, bb, |location, live_locals| { - debug!("add_liveness_constraints: location={:?} live_locals={:?}", - location, live_locals); + self.liveness + .regular + .simulate_block(self.mir, bb, |location, live_locals| { + debug!( + "add_liveness_constraints: location={:?} live_locals={:?}", + location, + live_locals + ); - for live_local in live_locals.iter() { - let live_local_ty = self.mir.local_decls[live_local].ty; - tcx.for_each_free_region(&live_local_ty, |live_region| { - let vid = live_region.to_region_index(); - self.regioncx.add_live_point(vid, location); - }) - } - }); + for live_local in live_locals.iter() { + let live_local_ty = self.mir.local_decls[live_local].ty; + tcx.for_each_free_region(&live_local_ty, |live_region| { + let vid = live_region.to_region_index(); + self.regioncx.add_live_point(vid, location); + }) + } + }); } } } diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index 273972f69379..131f088d91c7 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -16,7 +16,7 @@ use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use std::collections::BTreeSet; use std::fmt; -use util::liveness::{self, LivenessResult}; +use util::liveness::{self, LivenessResult, LivenessMode}; use util as mir_util; use self::mir_util::PassWhere; @@ -50,7 +50,17 @@ impl MirPass for NLL { let num_region_variables = renumber::renumber_mir(infcx, mir); // Compute what is live where. - let liveness = &liveness::liveness_of_locals(mir); + let liveness = &LivenessResults { + regular: liveness::liveness_of_locals(mir, LivenessMode { + include_regular_use: true, + include_drops: false, + }), + + drop: liveness::liveness_of_locals(mir, LivenessMode { + include_regular_use: false, + include_drops: true, + }) + }; // Create the region inference context, generate the constraints, // and then solve them. @@ -64,9 +74,14 @@ impl MirPass for NLL { } } +struct LivenessResults { + regular: LivenessResult, + drop: LivenessResult, +} + fn dump_mir_results<'a, 'gcx, 'tcx>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, - liveness: &LivenessResult, + liveness: &LivenessResults, source: MirSource, regioncx: &RegionInferenceContext, mir: &Mir<'tcx>, @@ -75,11 +90,22 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( return; } - let liveness_per_location: FxHashMap<_, _> = mir.basic_blocks() + let regular_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks() .indices() .flat_map(|bb| { let mut results = vec![]; - liveness.simulate_block(&mir, bb, |location, local_set| { + liveness.regular.simulate_block(&mir, bb, |location, local_set| { + results.push((location, local_set.clone())); + }); + results + }) + .collect(); + + let drop_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks() + .indices() + .flat_map(|bb| { + let mut results = vec![]; + liveness.drop.simulate_block(&mir, bb, |location, local_set| { results.push((location, local_set.clone())); }); results @@ -96,16 +122,17 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( // Before each basic block, dump out the values // that are live on entry to the basic block. PassWhere::BeforeBlock(bb) => { - let local_set = &liveness.ins[bb]; - writeln!(out, " | Variables live on entry to the block {:?}:", bb)?; - for local in local_set.iter() { - writeln!(out, " | - {:?}", local)?; - } + writeln!(out, " | Variables regular-live on entry to the block {:?}: {:?}", + bb, liveness.regular.ins[bb])?; + writeln!(out, " | Variables drop-live on entry to the block {:?}: {:?}", + bb, liveness.drop.ins[bb])?; } PassWhere::InCFG(location) => { - let local_set = &liveness_per_location[&location]; - writeln!(out, " | Live variables here: {:?}", local_set)?; + let local_set = ®ular_liveness_per_location[&location]; + writeln!(out, " | Regular-Live variables here: {:?}", local_set)?; + let local_set = &drop_liveness_per_location[&location]; + writeln!(out, " | Drop-Live variables here: {:?}", local_set)?; } PassWhere::AfterCFG => {} diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 514ff2ab830c..7658e49ea5eb 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -35,29 +35,60 @@ use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::indexed_set::IdxSetBuf; -use util::pretty::{write_basic_block, dump_enabled, write_mir_intro}; +use util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; use rustc::mir::transform::MirSource; use rustc::ty::item_path; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use std::fs; use rustc::ty::TyCtxt; use std::io::{self, Write}; pub type LocalSet = IdxSetBuf; -// This gives the result of the liveness analysis at the boundary of basic blocks +/// This gives the result of the liveness analysis at the boundary of +/// basic blocks. You can use `simulate_block` to obtain the +/// intra-block results. pub struct LivenessResult { + /// Liveness mode in use when these results were computed. + pub mode: LivenessMode, + + /// Live variables on entry to each basic block. pub ins: IndexVec, + + /// Live variables on exit to each basic block. This is equal to + /// the union of the `ins` for each successor. pub outs: IndexVec, } -pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { +#[derive(Copy, Clone, Debug)] +pub struct LivenessMode { + /// If true, then we will consider "regular uses" of a variable to be live. + /// For example, if the user writes `foo(x)`, then this is a regular use of + /// the variable `x`. + pub include_regular_use: bool, + + /// If true, then we will consider (implicit) drops of a variable + /// to be live. For example, if the user writes `{ let x = + /// vec![...]; .. }`, then the drop at the end of the block is an + /// implicit drop. + /// + /// NB. Despite its name, a call like `::std::mem::drop(x)` is + /// **not** considered a drop for this purposes, but rather a + /// regular use. + pub include_drops: bool, +} + +/// Compute which local variables are live within the given function +/// `mir`. The liveness mode `mode` determines what sorts of uses are +/// considered to make a variable live (e.g., do drops count?). +pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> LivenessResult { let locals = mir.local_decls.len(); - let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| { - block(b, locals) - }).collect(); + let def_use: IndexVec<_, _> = mir.basic_blocks() + .iter() + .map(|b| block(mode, b, locals)) + .collect(); let mut ins: IndexVec<_, _> = mir.basic_blocks() .indices() @@ -89,10 +120,7 @@ pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { } } - LivenessResult { - ins, - outs, - } + LivenessResult { mode, ins, outs } } impl LivenessResult { @@ -100,11 +128,9 @@ impl LivenessResult { /// basic block `block`. At each point within `block`, invokes /// the callback `op` with the current location and the set of /// variables that are live on entry to that location. - pub fn simulate_block<'tcx, OP>(&self, - mir: &Mir<'tcx>, - block: BasicBlock, - mut callback: OP) - where OP: FnMut(Location, &LocalSet) + pub fn simulate_block<'tcx, OP>(&self, mir: &Mir<'tcx>, block: BasicBlock, mut callback: OP) + where + OP: FnMut(Location, &LocalSet), { let data = &mir[block]; @@ -116,7 +142,10 @@ impl LivenessResult { let mut statement_index = data.statements.len(); // Compute liveness right before terminator and invoke callback. - let terminator_location = Location { block, statement_index }; + let terminator_location = Location { + block, + statement_index, + }; let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator); terminator_defs_uses.apply(&mut bits); callback(terminator_location, &bits); @@ -124,7 +153,10 @@ impl LivenessResult { // Compute liveness before each statement (in rev order) and invoke callback. for statement in data.statements.iter().rev() { statement_index -= 1; - let statement_location = Location { block, statement_index }; + let statement_location = Location { + block, + statement_index, + }; let statement_defs_uses = self.defs_uses(mir, statement_location, statement); statement_defs_uses.apply(&mut bits); callback(statement_location, &bits); @@ -133,27 +165,32 @@ impl LivenessResult { assert_eq!(bits, self.ins[block]); } - fn defs_uses<'tcx, V>(&self, - mir: &Mir<'tcx>, - location: Location, - thing: &V) - -> DefsUses - where V: MirVisitable<'tcx>, + fn defs_uses<'tcx, V>(&self, mir: &Mir<'tcx>, location: Location, thing: &V) -> DefsUses + where + V: MirVisitable<'tcx>, { let locals = mir.local_decls.len(); - let mut visitor = DefsUses { - defs: LocalSet::new_empty(locals), - uses: LocalSet::new_empty(locals), + let mut visitor = DefsUsesVisitor { + mode: self.mode, + defs_uses: DefsUses { + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }, }; // Visit the various parts of the basic block in reverse. If we go // forward, the logic in `add_def` and `add_use` would be wrong. thing.apply(location, &mut visitor); - visitor + visitor.defs_uses } } +struct DefsUsesVisitor { + mode: LivenessMode, + defs_uses: DefsUses, +} + #[derive(Eq, PartialEq, Clone)] struct DefsUses { defs: LocalSet, @@ -195,18 +232,15 @@ impl DefsUses { } } -impl<'tcx> Visitor<'tcx> for DefsUses { - fn visit_local(&mut self, - &local: &Local, - context: LvalueContext<'tcx>, - _: Location) { +impl<'tcx> Visitor<'tcx> for DefsUsesVisitor { + fn visit_local(&mut self, &local: &Local, context: LvalueContext<'tcx>, _: Location) { match context { /////////////////////////////////////////////////////////////////////////// // DEFS LvalueContext::Store | - // We let Call defined the result in both the success and + // We let Call define the result in both the success and // unwind cases. This is not really correct, however it // does not seem to be observable due to the way that we // generate MIR. See the test case @@ -220,11 +254,15 @@ impl<'tcx> Visitor<'tcx> for DefsUses { // values that come before them. LvalueContext::StorageLive | LvalueContext::StorageDead => { - self.add_def(local); + self.defs_uses.add_def(local); } /////////////////////////////////////////////////////////////////////////// - // USES + // REGULAR USES + // + // These are uses that occur *outside* of a drop. For the + // purposes of NLL, these are special in that **all** the + // lifetimes appearing in the variable must be live for each regular use. LvalueContext::Projection(..) | @@ -236,25 +274,42 @@ impl<'tcx> Visitor<'tcx> for DefsUses { LvalueContext::Inspect | LvalueContext::Consume | - LvalueContext::Validate | + LvalueContext::Validate => { + if self.mode.include_regular_use { + self.defs_uses.add_use(local); + } + } + + /////////////////////////////////////////////////////////////////////////// + // DROP USES + // + // These are uses that occur in a DROP (a MIR drop, not a + // call to `std::mem::drop()`). For the purposes of NLL, + // uses in drop are special because `#[may_dangle]` + // attributes can affect whether lifetimes must be live. - // We consider drops to always be uses of locals. - // Drop eloboration should be run before this analysis otherwise - // the results might be too pessimistic. LvalueContext::Drop => { - self.add_use(local); + if self.mode.include_drops { + self.defs_uses.add_use(local); + } } } } } -fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses { - let mut visitor = DefsUses { - defs: LocalSet::new_empty(locals), - uses: LocalSet::new_empty(locals), +fn block<'tcx>(mode: LivenessMode, b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses { + let mut visitor = DefsUsesVisitor { + mode, + defs_uses: DefsUses { + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }, }; - let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 }; + let dummy_location = Location { + block: BasicBlock::new(0), + statement_index: 0, + }; // Visit the various parts of the basic block in reverse. If we go // forward, the logic in `add_def` and `add_use` would be wrong. @@ -263,62 +318,64 @@ fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses { visitor.visit_statement(BasicBlock::new(0), statement, dummy_location); } - visitor + visitor.defs_uses } trait MirVisitable<'tcx> { fn apply(&self, location: Location, visitor: &mut V) - where V: Visitor<'tcx>; + where + V: Visitor<'tcx>; } impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { fn apply(&self, location: Location, visitor: &mut V) - where V: Visitor<'tcx> + where + V: Visitor<'tcx>, { - visitor.visit_statement(location.block, - self, - location) + visitor.visit_statement(location.block, self, location) } } impl<'tcx> MirVisitable<'tcx> for Option> { fn apply(&self, location: Location, visitor: &mut V) - where V: Visitor<'tcx> + where + V: Visitor<'tcx>, { - visitor.visit_terminator(location.block, - self.as_ref().unwrap(), - location) + visitor.visit_terminator(location.block, self.as_ref().unwrap(), location) } } -pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - source: MirSource, - mir: &Mir<'tcx>, - result: &LivenessResult) { +pub fn dump_mir<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult, +) { if !dump_enabled(tcx, pass_name, source) { return; } - let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below + let node_path = item_path::with_forced_impl_filename_line(|| { + // see notes on #41697 below tcx.item_path_str(tcx.hir.local_def_id(source.item_id())) }); - dump_matched_mir_node(tcx, pass_name, &node_path, - source, mir, result); + dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result); } -fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - node_path: &str, - source: MirSource, - mir: &Mir<'tcx>, - result: &LivenessResult) { +fn dump_matched_mir_node<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + node_path: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult, +) { let mut file_path = PathBuf::new(); if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { let p = Path::new(file_dir); file_path.push(p); }; - let file_name = format!("rustc.node{}{}-liveness.mir", - source.item_id(), pass_name); + let file_name = format!("rustc.node{}{}-liveness.mir", source.item_id(), pass_name); file_path.push(&file_name); let _ = fs::File::create(&file_path).and_then(|mut file| { writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; @@ -330,16 +387,18 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - w: &mut Write, - result: &LivenessResult) - -> io::Result<()> { +pub fn write_mir_fn<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + w: &mut Write, + result: &LivenessResult, +) -> io::Result<()> { write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { let print = |w: &mut Write, prefix, result: &IndexVec| { - let live: Vec = mir.local_decls.indices() + let live: Vec = mir.local_decls + .indices() .filter(|i| result[block].contains(i)) .map(|i| format!("{:?}", i)) .collect(); @@ -356,4 +415,3 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(w, "}}")?; Ok(()) } - diff --git a/src/test/mir-opt/nll/liveness-call-subtlety.rs b/src/test/mir-opt/nll/liveness-call-subtlety.rs index f0d56db0573b..e9af37a1f64c 100644 --- a/src/test/mir-opt/nll/liveness-call-subtlety.rs +++ b/src/test/mir-opt/nll/liveness-call-subtlety.rs @@ -26,21 +26,26 @@ fn main() { // // END RUST SOURCE // START rustc.node12.nll.0.mir -// | Variables live on entry to the block bb0: +// | Variables regular-live on entry to the block bb0: [] +// | Variables drop-live on entry to the block bb0: [] // bb0: { -// | Live variables here: [] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [] // StorageLive(_1); -// | Live variables here: [] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [] // _1 = const >::new(const 22usize) -> bb1; // } // END rustc.node12.nll.0.mir // START rustc.node12.nll.0.mir -// | Variables live on entry to the block bb1: -// | - _1 +// | Variables regular-live on entry to the block bb1: [] +// | Variables drop-live on entry to the block bb1: [_1] // bb1: { -// | Live variables here: [_1] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [_1] // StorageLive(_2); -// | Live variables here: [_1] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [_1] // _2 = const can_panic() -> [return: bb2, unwind: bb4]; // } // END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-drop-intra-block.rs b/src/test/mir-opt/nll/liveness-drop-intra-block.rs index 1fac9484bdb3..957a57428e3b 100644 --- a/src/test/mir-opt/nll/liveness-drop-intra-block.rs +++ b/src/test/mir-opt/nll/liveness-drop-intra-block.rs @@ -25,17 +25,23 @@ fn main() { // END RUST SOURCE // START rustc.node12.nll.0.mir -// | Variables live on entry to the block bb1: +// | Variables regular-live on entry to the block bb1: [] +// | Variables drop-live on entry to the block bb1: [] // bb1: { -// | Live variables here: [] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [] // _1 = const 55usize; -// | Live variables here: [_1] +// | Regular-Live variables here: [_1] +// | Drop-Live variables here: [] // StorageLive(_3); -// | Live variables here: [_1] +// | Regular-Live variables here: [_1] +// | Drop-Live variables here: [] // StorageLive(_4); -// | Live variables here: [_1] +// | Regular-Live variables here: [_1] +// | Drop-Live variables here: [] // _4 = _1; -// | Live variables here: [_4] +// | Regular-Live variables here: [_4] +// | Drop-Live variables here: [] // _3 = const use_x(_4) -> bb2; // } // END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-interblock.rs b/src/test/mir-opt/nll/liveness-interblock.rs index 4380698e704f..f5a2a25a9b0c 100644 --- a/src/test/mir-opt/nll/liveness-interblock.rs +++ b/src/test/mir-opt/nll/liveness-interblock.rs @@ -29,21 +29,26 @@ fn main() { // END RUST SOURCE // START rustc.node18.nll.0.mir -// | Variables live on entry to the block bb2: -// | - _1 +// | Variables regular-live on entry to the block bb2: [_1] +// | Variables drop-live on entry to the block bb2: [] // bb2: { -// | Live variables here: [_1] +// | Regular-Live variables here: [_1] +// | Drop-Live variables here: [] // StorageLive(_4); -// | Live variables here: [_1] +// | Regular-Live variables here: [_1] +// | Drop-Live variables here: [] // _4 = _1; -// | Live variables here: [_4] +// | Regular-Live variables here: [_4] +// | Drop-Live variables here: [] // _3 = const make_live(_4) -> bb4; // } // END rustc.node18.nll.0.mir // START rustc.node18.nll.0.mir -// | Variables live on entry to the block bb3: +// | Variables regular-live on entry to the block bb3: [] +// | Variables drop-live on entry to the block bb3: [] // bb3: { -// | Live variables here: [] +// | Regular-Live variables here: [] +// | Drop-Live variables here: [] // _5 = const make_dead() -> bb5; // } // END rustc.node18.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index d1ef08cf00d7..67e16c2fe6fc 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -37,19 +37,24 @@ fn main() { // END rustc.node12.nll.0.mir // START rustc.node12.nll.0.mir // bb1: { -// | Live variables here: [_1, _3] +// | Regular-Live variables here: [_1, _3] +// | Drop-Live variables here: [] // _2 = &'_#0r _1[_3]; -// | Live variables here: [_2] +// | Regular-Live variables here: [_2] +// | Drop-Live variables here: [] // switchInt(const true) -> [0u8: bb3, otherwise: bb2]; // } // END rustc.node12.nll.0.mir // START rustc.node12.nll.0.mir // bb2: { -// | Live variables here: [_2] +// | Regular-Live variables here: [_2] +// | Drop-Live variables here: [] // StorageLive(_7); -// | Live variables here: [_2] +// | Regular-Live variables here: [_2] +// | Drop-Live variables here: [] // _7 = (*_2); -// | Live variables here: [_7] +// | Regular-Live variables here: [_7] +// | Drop-Live variables here: [] // _6 = const use_x(_7) -> bb4; // } // END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs new file mode 100644 index 000000000000..7482288e9117 --- /dev/null +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -0,0 +1,48 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] +#![feature(dropck_eyepatch)] +#![feature(generic_param_attrs)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let p: Wrap<& /* R4 */ usize> = Wrap { value: &v[0] }; + if true { + use_x(*p.value); + } else { + use_x(22); + } + + // `p` will get dropped here. However, because of the + // `#[may_dangle]` attribute, we do not need to consider R4 live. +} + +struct Wrap { + value: T +} + +unsafe impl<#[may_dangle] T> Drop for Wrap { + fn drop(&mut self) { } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | R4: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1]} +// END rustc.node12.nll.0.mir