diff options
| author | Paul Daniel Faria <nashenas88@users.noreply.github.com> | 2017-11-17 04:34:02 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-12-04 08:51:11 -0500 |
| commit | a9cb25b23aace3e8a7db3e64468dd84314a6d867 (patch) | |
| tree | bbc932afb29cce1b628aab2700ca54c4181bccf5 | |
| parent | 08c8d7e91917dd7265042d6ccf204e241f17db32 (diff) | |
| download | rust-a9cb25b23aace3e8a7db3e64468dd84314a6d867.tar.gz rust-a9cb25b23aace3e8a7db3e64468dd84314a6d867.zip | |
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.
20 files changed, 374 insertions, 78 deletions
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check/mod.rs index ff38760cce6..446aba3d3d7 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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]; diff --git a/src/librustc_mir/transform/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 73d5a610dbd..460d49af20e 100644 --- a/src/librustc_mir/transform/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -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) { diff --git a/src/librustc_mir/transform/nll/free_regions.rs b/src/librustc_mir/borrow_check/nll/free_regions.rs index 92a8a714d52..92a8a714d52 100644 --- a/src/librustc_mir/transform/nll/free_regions.rs +++ b/src/librustc_mir/borrow_check/nll/free_regions.rs diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 147f061ad11..213cf52a8eb 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -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; -/// 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>, +/// 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, - param_env: ty::ParamEnv<'gcx>, mir: &mut Mir<'tcx>, -) -> RegionInferenceContext<'tcx> { +) -> FreeRegions<'tcx> { // Compute named region information. - let free_regions = &free_regions::free_regions(infcx, def_id); + let free_regions = free_regions::free_regions(infcx, def_id); // Replace all regions with fresh inference variables. - renumber::renumber_mir(infcx, free_regions, mir); + 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(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>, + flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>, + move_data: &MoveData<'tcx>, +) -> RegionInferenceContext<'tcx> { // 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); diff --git a/src/librustc_mir/transform/nll/region_infer.rs b/src/librustc_mir/borrow_check/nll/region_infer.rs index f60bd3c6ece..f60bd3c6ece 100644 --- a/src/librustc_mir/transform/nll/region_infer.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer.rs diff --git a/src/librustc_mir/transform/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 1076b774de6..1076b774de6 100644 --- a/src/librustc_mir/transform/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs diff --git a/src/librustc_mir/transform/nll/subtype_constraint_generation.rs b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs index c1850c76541..c1850c76541 100644 --- a/src/librustc_mir/transform/nll/subtype_constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 19ab45dda95..286ca768b16 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -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) { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 294f48178a8..9d91e1344dc 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -263,6 +263,10 @@ impl<'tcx> MovePathLookup<'tcx> { } } } + + pub fn find_local(&self, local: Local) -> MovePathIndex { + self.locals[local] + } } #[derive(Debug)] diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 830838c6037..fb9daf07c71 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -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) { diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs new file mode 100644 index 00000000000..0047f6d5923 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs @@ -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 +} diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr new file mode 100644 index 00000000000..389334f9c1d --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr @@ -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 + diff --git a/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs b/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs new file mode 100644 index 00000000000..64a4d391000 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-uninitialized.rs @@ -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 +} diff --git a/src/test/ui/nll/maybe-initialized-drop-uninitialized.stderr b/src/test/ui/nll/maybe-initialized-drop-uninitialized.stderr new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-uninitialized.stderr diff --git a/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs b/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs new file mode 100644 index 00000000000..3242136f005 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-with-fragment.rs @@ -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] +} diff --git a/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr b/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr new file mode 100644 index 00000000000..9edeca2d188 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr @@ -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 + diff --git a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs new file mode 100644 index 00000000000..3e32818b8dc --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs @@ -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. +} diff --git a/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr new file mode 100644 index 00000000000..24d0d6d04c8 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr @@ -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 + diff --git a/src/test/ui/nll/maybe-initialized-drop.rs b/src/test/ui/nll/maybe-initialized-drop.rs new file mode 100644 index 00000000000..291fcbd73f3 --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop.rs @@ -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] +} diff --git a/src/test/ui/nll/maybe-initialized-drop.stderr b/src/test/ui/nll/maybe-initialized-drop.stderr new file mode 100644 index 00000000000..7b1b55d133a --- /dev/null +++ b/src/test/ui/nll/maybe-initialized-drop.stderr @@ -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 + |
