inform constraint generation using maybe-init
In particular, if we see a variable is DROP-LIVE, but it is not MAYBE-INIT, then we can ignore the drop. This leavess attempt to use more complex refinements of the idea (e.g., for subpaths or subfields) to future work.
This commit is contained in:
parent
08c8d7e919
commit
a9cb25b23a
20 changed files with 374 additions and 78 deletions
|
@ -18,7 +18,6 @@ use rustc::ty::maps::Providers;
|
|||
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Place};
|
||||
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
|
||||
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
|
||||
use transform::nll;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_set::{self, IdxSetBuf};
|
||||
|
@ -39,6 +38,7 @@ use util::borrowck_errors::{BorrowckErrors, Origin};
|
|||
|
||||
use self::MutateMode::{JustWrite, WriteAndRead};
|
||||
|
||||
pub(crate) mod nll;
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
|
@ -77,7 +77,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
.as_local_node_id(def_id)
|
||||
.expect("do_mir_borrowck: non-local DefId");
|
||||
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx) {
|
||||
// Make our own copy of the MIR. This copy will be modified (in place) to
|
||||
// contain non-lexical lifetimes. It will have a lifetime tied
|
||||
// to the inference context.
|
||||
let mut mir: Mir<'tcx> = input_mir.clone();
|
||||
let free_regions = if !tcx.sess.opts.debugging_opts.nll {
|
||||
None
|
||||
} else {
|
||||
let mir = &mut mir;
|
||||
|
||||
// Replace all regions with fresh inference variables.
|
||||
Some(nll::replace_regions_in_mir(infcx, def_id, mir))
|
||||
};
|
||||
let mir = &mir;
|
||||
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
|
||||
Ok(move_data) => move_data,
|
||||
Err((move_data, move_errors)) => {
|
||||
for move_error in move_errors {
|
||||
|
@ -110,34 +124,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
// Make our own copy of the MIR. This copy will be modified (in place) to
|
||||
// contain non-lexical lifetimes. It will have a lifetime tied
|
||||
// to the inference context.
|
||||
let mut mir: Mir<'tcx> = input_mir.clone();
|
||||
let mir = &mut mir;
|
||||
|
||||
// If we are in non-lexical mode, compute the non-lexical lifetimes.
|
||||
let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
|
||||
None
|
||||
} else {
|
||||
Some(nll::compute_regions(infcx, def_id, param_env, mir))
|
||||
};
|
||||
|
||||
let mdpe = MoveDataParamEnv {
|
||||
move_data: move_data,
|
||||
param_env: param_env,
|
||||
};
|
||||
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
|
||||
let flow_borrows = do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
&attributes,
|
||||
&dead_unwinds,
|
||||
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
|
||||
|bd, i| bd.location(i),
|
||||
);
|
||||
let flow_inits = do_dataflow(
|
||||
let mut flow_inits = FlowInProgress::new(do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
|
@ -145,8 +137,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
&dead_unwinds,
|
||||
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|
||||
|bd, i| &bd.move_data().move_paths[i],
|
||||
);
|
||||
let flow_uninits = do_dataflow(
|
||||
));
|
||||
let flow_uninits = FlowInProgress::new(do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
|
@ -154,8 +146,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
&dead_unwinds,
|
||||
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|
||||
|bd, i| &bd.move_data().move_paths[i],
|
||||
);
|
||||
let flow_move_outs = do_dataflow(
|
||||
));
|
||||
let flow_move_outs = FlowInProgress::new(do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
|
@ -163,8 +155,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
&dead_unwinds,
|
||||
MovingOutStatements::new(tcx, mir, &mdpe),
|
||||
|bd, i| &bd.move_data().moves[i],
|
||||
);
|
||||
let flow_ever_inits = do_dataflow(
|
||||
));
|
||||
let flow_ever_inits = FlowInProgress::new(do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
|
@ -172,7 +164,24 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
&dead_unwinds,
|
||||
EverInitializedLvals::new(tcx, mir, &mdpe),
|
||||
|bd, i| &bd.move_data().inits[i],
|
||||
);
|
||||
));
|
||||
|
||||
// If we are in non-lexical mode, compute the non-lexical lifetimes.
|
||||
let opt_regioncx = if let Some(free_regions) = free_regions {
|
||||
Some(nll::compute_regions(
|
||||
infcx,
|
||||
def_id,
|
||||
free_regions,
|
||||
mir,
|
||||
param_env,
|
||||
&mut flow_inits,
|
||||
&mdpe.move_data,
|
||||
))
|
||||
} else {
|
||||
assert!(!tcx.sess.opts.debugging_opts.nll);
|
||||
None
|
||||
};
|
||||
let flow_inits = flow_inits; // remove mut
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
tcx: tcx,
|
||||
|
@ -183,6 +192,16 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
storage_dead_or_drop_error_reported: FxHashSet(),
|
||||
};
|
||||
|
||||
let flow_borrows = FlowInProgress::new(do_dataflow(
|
||||
tcx,
|
||||
mir,
|
||||
id,
|
||||
&attributes,
|
||||
&dead_unwinds,
|
||||
Borrows::new(tcx, mir, opt_regioncx),
|
||||
|bd, i| bd.location(i),
|
||||
));
|
||||
|
||||
let mut state = InProgress::new(
|
||||
flow_borrows,
|
||||
flow_inits,
|
||||
|
@ -2318,19 +2337,19 @@ impl ContextKind {
|
|||
}
|
||||
|
||||
impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
|
||||
pub(super) fn new(
|
||||
borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>,
|
||||
inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
move_out: DataflowResults<MovingOutStatements<'b, 'gcx, 'tcx>>,
|
||||
ever_inits: DataflowResults<EverInitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
fn new(
|
||||
borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
|
||||
inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
|
||||
ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
|
||||
) -> Self {
|
||||
InProgress {
|
||||
borrows: FlowInProgress::new(borrows),
|
||||
inits: FlowInProgress::new(inits),
|
||||
uninits: FlowInProgress::new(uninits),
|
||||
move_outs: FlowInProgress::new(move_out),
|
||||
ever_inits: FlowInProgress::new(ever_inits),
|
||||
borrows,
|
||||
inits,
|
||||
uninits,
|
||||
move_outs,
|
||||
ever_inits,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2436,8 +2455,11 @@ impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'b, 'gcx, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>> {
|
||||
fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
|
||||
impl<'tcx, T> FlowInProgress<T>
|
||||
where
|
||||
T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
|
||||
{
|
||||
fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
|
||||
let move_data = self.base_results.operator().move_data();
|
||||
|
||||
let mut todo = vec![mpi];
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::mir::{Location, Place, Mir, Rvalue};
|
||||
use rustc::mir::{Local, Location, Place, Mir, Rvalue};
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::Place::Projection;
|
||||
use rustc::mir::{PlaceProjection, ProjectionElem};
|
||||
|
@ -20,17 +20,22 @@ use rustc::ty::fold::TypeFoldable;
|
|||
use rustc::util::common::ErrorReported;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use borrow_check::FlowInProgress;
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::{MoveData, HasMoveData};
|
||||
|
||||
use super::LivenessResults;
|
||||
use super::ToRegionVid;
|
||||
use super::region_infer::RegionInferenceContext;
|
||||
|
||||
pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
ConstraintGeneration {
|
||||
infcx,
|
||||
|
@ -38,18 +43,23 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
|
|||
mir,
|
||||
liveness,
|
||||
param_env,
|
||||
flow_inits,
|
||||
move_data,
|
||||
}.add_constraints();
|
||||
}
|
||||
|
||||
struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &'cx mut RegionInferenceContext<'tcx>,
|
||||
mir: &'cx Mir<'tcx>,
|
||||
liveness: &'cx LivenessResults,
|
||||
/// 'cg = the duration of the constraint generation process itself.
|
||||
struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &'cg mut RegionInferenceContext<'tcx>,
|
||||
mir: &'cg Mir<'tcx>,
|
||||
liveness: &'cg LivenessResults,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
flow_inits: &'cg mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &'cg MoveData<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
||||
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
fn add_constraints(&mut self) {
|
||||
self.add_liveness_constraints();
|
||||
self.add_borrow_constraints();
|
||||
|
@ -73,14 +83,51 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
});
|
||||
|
||||
self.liveness
|
||||
.drop
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
for live_local in live_locals.iter() {
|
||||
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
|
||||
self.liveness.drop.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
all_live_locals.push((location, live_locals.iter().collect()));
|
||||
});
|
||||
debug!("add_liveness_constraints: all_live_locals={:#?}", all_live_locals);
|
||||
|
||||
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
|
||||
self.flow_inits.reset_to_entry_of(bb);
|
||||
while let Some((location, live_locals)) = all_live_locals.pop() {
|
||||
for live_local in live_locals {
|
||||
debug!("add_liveness_constraints: location={:?} live_local={:?}", location,
|
||||
live_local);
|
||||
|
||||
self.flow_inits.each_state_bit(|mpi_init| {
|
||||
debug!("add_liveness_constraints: location={:?} initialized={:?}",
|
||||
location,
|
||||
&self.flow_inits
|
||||
.base_results
|
||||
.operator()
|
||||
.move_data()
|
||||
.move_paths[mpi_init]);
|
||||
});
|
||||
|
||||
let mpi = self.move_data.rev_lookup.find_local(live_local);
|
||||
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
|
||||
debug!("add_liveness_constraints: mpi={:?} has initialized child {:?}",
|
||||
self.move_data.move_paths[mpi],
|
||||
self.move_data.move_paths[initialized_child]);
|
||||
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
self.add_drop_live_constraint(live_local_ty, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if location.statement_index == terminator_index {
|
||||
debug!("add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
|
||||
location);
|
||||
self.flow_inits.reconstruct_terminator_effect(location);
|
||||
} else {
|
||||
debug!("add_liveness_constraints: reconstruct_statement_effect from {:#?}",
|
||||
location);
|
||||
self.flow_inits.reconstruct_statement_effect(location);
|
||||
}
|
||||
self.flow_inits.apply_local_effect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +266,7 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
||||
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
|
||||
fn visit_rvalue(&mut self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
|
@ -17,6 +17,9 @@ use std::collections::BTreeSet;
|
|||
use transform::MirSource;
|
||||
use transform::type_check;
|
||||
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
|
||||
use borrow_check::FlowInProgress;
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::MoveData;
|
||||
|
||||
use util as mir_util;
|
||||
use self::mir_util::PassWhere;
|
||||
|
@ -24,27 +27,43 @@ use self::mir_util::PassWhere;
|
|||
mod constraint_generation;
|
||||
mod subtype_constraint_generation;
|
||||
mod free_regions;
|
||||
use self::free_regions::FreeRegions;
|
||||
|
||||
pub(crate) mod region_infer;
|
||||
use self::region_infer::RegionInferenceContext;
|
||||
|
||||
mod renumber;
|
||||
|
||||
/// Rewrites the regions in the MIR to use NLL variables, also
|
||||
/// scraping out the set of free regions (e.g., region parameters)
|
||||
/// declared on the function. That set will need to be given to
|
||||
/// `compute_regions`.
|
||||
pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
mir: &mut Mir<'tcx>,
|
||||
) -> FreeRegions<'tcx> {
|
||||
// Compute named region information.
|
||||
let free_regions = free_regions::free_regions(infcx, def_id);
|
||||
|
||||
// Replace all regions with fresh inference variables.
|
||||
renumber::renumber_mir(infcx, &free_regions, mir);
|
||||
|
||||
free_regions
|
||||
}
|
||||
|
||||
/// Computes the (non-lexical) regions from the input MIR.
|
||||
///
|
||||
/// This may result in errors being reported.
|
||||
pub fn compute_regions<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
free_regions: FreeRegions<'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &mut Mir<'tcx>,
|
||||
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) -> RegionInferenceContext<'tcx> {
|
||||
// Compute named region information.
|
||||
let free_regions = &free_regions::free_regions(infcx, def_id);
|
||||
|
||||
// Replace all regions with fresh inference variables.
|
||||
renumber::renumber_mir(infcx, free_regions, mir);
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir);
|
||||
|
@ -52,8 +71,8 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
|
|||
// Create the region inference context, taking ownership of the region inference
|
||||
// data that was contained in `infcx`.
|
||||
let var_origins = infcx.take_region_var_origins();
|
||||
let mut regioncx = RegionInferenceContext::new(var_origins, free_regions, mir);
|
||||
subtype_constraint_generation::generate(&mut regioncx, free_regions, mir, constraint_sets);
|
||||
let mut regioncx = RegionInferenceContext::new(var_origins, &free_regions, mir);
|
||||
subtype_constraint_generation::generate(&mut regioncx, &free_regions, mir, constraint_sets);
|
||||
|
||||
// Compute what is live where.
|
||||
let liveness = &LivenessResults {
|
||||
|
@ -75,7 +94,15 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
|
|||
};
|
||||
|
||||
// Generate non-subtyping constraints.
|
||||
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, param_env, liveness);
|
||||
constraint_generation::generate_constraints(
|
||||
infcx,
|
||||
&mut regioncx,
|
||||
&mir,
|
||||
param_env,
|
||||
liveness,
|
||||
flow_inits,
|
||||
move_data,
|
||||
);
|
||||
|
||||
// Solve the region constraints.
|
||||
regioncx.solve(infcx, &mir);
|
|
@ -21,8 +21,8 @@ use rustc_data_structures::indexed_vec::{IndexVec};
|
|||
|
||||
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
|
||||
pub use dataflow::indexes::BorrowIndex;
|
||||
use transform::nll::region_infer::RegionInferenceContext;
|
||||
use transform::nll::ToRegionVid;
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
@ -38,7 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||
location_map: FxHashMap<Location, BorrowIndex>,
|
||||
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
|
||||
region_span_map: FxHashMap<RegionKind, Span>,
|
||||
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>,
|
||||
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>,
|
||||
}
|
||||
|
||||
// temporarily allow some dead fields: `kind` and `region` will be
|
||||
|
@ -69,7 +69,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>)
|
||||
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>)
|
||||
-> Self {
|
||||
let mut visitor = GatherBorrows {
|
||||
tcx,
|
||||
|
@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
|||
fn kill_loans_out_of_scope_at_location(&self,
|
||||
sets: &mut BlockSets<BorrowIndex>,
|
||||
location: Location) {
|
||||
if let Some(regioncx) = self.nonlexical_regioncx {
|
||||
if let Some(ref regioncx) = self.nonlexical_regioncx {
|
||||
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
|
||||
let borrow_region = borrow_data.region.to_region_vid();
|
||||
if !regioncx.region_contains_point(borrow_region, location) {
|
||||
|
|
|
@ -263,6 +263,10 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
||||
self.locals[local]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -43,7 +43,6 @@ pub mod instcombine;
|
|||
pub mod copy_prop;
|
||||
pub mod generator;
|
||||
pub mod inline;
|
||||
pub mod nll;
|
||||
pub mod lower_128bit;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2017 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
struct Wrap<'p> { p: &'p mut i32 }
|
||||
|
||||
impl<'p> Drop for Wrap<'p> {
|
||||
fn drop(&mut self) {
|
||||
*self.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo<'p> { a: String, b: Wrap<'p> }
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
let wrap = Wrap { p: &mut x };
|
||||
let s = String::from("str");
|
||||
let foo = Foo { a: s, b: wrap };
|
||||
std::mem::drop(foo.b);
|
||||
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
// FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:31:5
|
||||
|
|
||||
27 | let wrap = Wrap { p: &mut x };
|
||||
| ------ borrow of `x` occurs here
|
||||
...
|
||||
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
28
src/test/ui/nll/maybe-initialized-drop-uninitialized.rs
Normal file
28
src/test/ui/nll/maybe-initialized-drop-uninitialized.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2017 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
struct Wrap<'p> { p: &'p mut i32 }
|
||||
|
||||
impl<'p> Drop for Wrap<'p> {
|
||||
fn drop(&mut self) {
|
||||
*self.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
let wrap = Wrap { p: &mut x };
|
||||
std::mem::drop(wrap);
|
||||
x = 1; // OK, drop is inert
|
||||
}
|
32
src/test/ui/nll/maybe-initialized-drop-with-fragment.rs
Normal file
32
src/test/ui/nll/maybe-initialized-drop-with-fragment.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2017 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
struct Wrap<'p> { p: &'p mut i32 }
|
||||
|
||||
impl<'p> Drop for Wrap<'p> {
|
||||
fn drop(&mut self) {
|
||||
*self.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo<'p> { a: String, b: Wrap<'p> }
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
let wrap = Wrap { p: &mut x };
|
||||
let s = String::from("str");
|
||||
let foo = Foo { a: s, b: wrap };
|
||||
std::mem::drop(foo.a);
|
||||
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
}
|
11
src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr
Normal file
11
src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/maybe-initialized-drop-with-fragment.rs:31:5
|
||||
|
|
||||
27 | let wrap = Wrap { p: &mut x };
|
||||
| ------ borrow of `x` occurs here
|
||||
...
|
||||
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2017 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
struct Wrap<'p> { p: &'p mut i32 }
|
||||
|
||||
impl<'p> Drop for Wrap<'p> {
|
||||
fn drop(&mut self) {
|
||||
*self.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo<'p> { a: String, b: Wrap<'p> }
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
let wrap = Wrap { p: &mut x };
|
||||
let s = String::from("str");
|
||||
let foo = Foo { a: s, b: wrap };
|
||||
std::mem::drop(foo.a);
|
||||
std::mem::drop(foo.b);
|
||||
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
// FIXME ^ This currently errors and it should not.
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/maybe-initialized-drop-with-uninitialized-fragments.rs:32:5
|
||||
|
|
||||
27 | let wrap = Wrap { p: &mut x };
|
||||
| ------ borrow of `x` occurs here
|
||||
...
|
||||
32 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
27
src/test/ui/nll/maybe-initialized-drop.rs
Normal file
27
src/test/ui/nll/maybe-initialized-drop.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2017 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
struct Wrap<'p> { p: &'p mut i32 }
|
||||
|
||||
impl<'p> Drop for Wrap<'p> {
|
||||
fn drop(&mut self) {
|
||||
*self.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
let wrap = Wrap { p: &mut x };
|
||||
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
}
|
10
src/test/ui/nll/maybe-initialized-drop.stderr
Normal file
10
src/test/ui/nll/maybe-initialized-drop.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/maybe-initialized-drop.rs:26:5
|
||||
|
|
||||
25 | let wrap = Wrap { p: &mut x };
|
||||
| ------ borrow of `x` occurs here
|
||||
26 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
|
||||
| ^^^^^ assignment to borrowed `x` occurs here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Add table
Reference in a new issue