From a9cb25b23aace3e8a7db3e64468dd84314a6d867 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Fri, 17 Nov 2017 04:34:02 -0500 Subject: [PATCH] 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. --- .../{borrow_check.rs => borrow_check/mod.rs} | 112 +++++++++++------- .../nll/constraint_generation.rs | 77 +++++++++--- .../nll/free_regions.rs | 0 .../{transform => borrow_check}/nll/mod.rs | 51 ++++++-- .../nll/region_infer.rs | 0 .../nll/renumber.rs | 0 .../nll/subtype_constraint_generation.rs | 0 src/librustc_mir/dataflow/impls/borrows.rs | 10 +- src/librustc_mir/dataflow/move_paths/mod.rs | 4 + src/librustc_mir/transform/mod.rs | 1 - ...initialized-drop-implicit-fragment-drop.rs | 33 ++++++ ...ialized-drop-implicit-fragment-drop.stderr | 11 ++ .../maybe-initialized-drop-uninitialized.rs | 28 +++++ ...aybe-initialized-drop-uninitialized.stderr | 0 .../maybe-initialized-drop-with-fragment.rs | 32 +++++ ...aybe-initialized-drop-with-fragment.stderr | 11 ++ ...lized-drop-with-uninitialized-fragments.rs | 34 ++++++ ...d-drop-with-uninitialized-fragments.stderr | 11 ++ src/test/ui/nll/maybe-initialized-drop.rs | 27 +++++ src/test/ui/nll/maybe-initialized-drop.stderr | 10 ++ 20 files changed, 374 insertions(+), 78 deletions(-) rename src/librustc_mir/{borrow_check.rs => borrow_check/mod.rs} (98%) rename src/librustc_mir/{transform => borrow_check}/nll/constraint_generation.rs (71%) rename src/librustc_mir/{transform => borrow_check}/nll/free_regions.rs (100%) rename src/librustc_mir/{transform => borrow_check}/nll/mod.rs (83%) rename src/librustc_mir/{transform => borrow_check}/nll/region_infer.rs (100%) rename src/librustc_mir/{transform => borrow_check}/nll/renumber.rs (100%) rename src/librustc_mir/{transform => borrow_check}/nll/subtype_constraint_generation.rs (100%) create mode 100644 src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs create mode 100644 src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr create mode 100644 src/test/ui/nll/maybe-initialized-drop-uninitialized.rs create mode 100644 src/test/ui/nll/maybe-initialized-drop-uninitialized.stderr create mode 100644 src/test/ui/nll/maybe-initialized-drop-with-fragment.rs create mode 100644 src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr create mode 100644 src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.rs create mode 100644 src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr create mode 100644 src/test/ui/nll/maybe-initialized-drop.rs create mode 100644 src/test/ui/nll/maybe-initialized-drop.stderr diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check/mod.rs similarity index 98% rename from src/librustc_mir/borrow_check.rs rename to src/librustc_mir/borrow_check/mod.rs index ff38760cce699..446aba3d3d72c 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>, - inits: DataflowResults>, - uninits: DataflowResults>, - move_out: DataflowResults>, - ever_inits: DataflowResults>, + fn new( + borrows: FlowInProgress>, + inits: FlowInProgress>, + uninits: FlowInProgress>, + move_outs: FlowInProgress>, + ever_inits: FlowInProgress>, ) -> 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> { - fn has_any_child_of(&self, mpi: MovePathIndex) -> Option { +impl<'tcx, T> FlowInProgress +where + T: HasMoveData<'tcx> + BitDenotation, +{ + fn has_any_child_of(&self, mpi: T::Idx) -> Option { 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 similarity index 71% rename from src/librustc_mir/transform/nll/constraint_generation.rs rename to src/librustc_mir/borrow_check/nll/constraint_generation.rs index 73d5a610dbd53..460d49af20e51 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>, + 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>, + 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)> = 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 similarity index 100% rename from src/librustc_mir/transform/nll/free_regions.rs rename to 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 similarity index 83% rename from src/librustc_mir/transform/nll/mod.rs rename to src/librustc_mir/borrow_check/nll/mod.rs index 147f061ad113f..213cf52a8eb36 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>, + 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 similarity index 100% rename from src/librustc_mir/transform/nll/region_infer.rs rename to 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 similarity index 100% rename from src/librustc_mir/transform/nll/renumber.rs rename to 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 similarity index 100% rename from src/librustc_mir/transform/nll/subtype_constraint_generation.rs rename to 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 19ab45dda9545..286ca768b16bf 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, region_map: FxHashMap, FxHashSet>, region_span_map: FxHashMap, - nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>, + nonlexical_regioncx: Option>, } // 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>) -> 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, 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 294f48178a8ac..9d91e1344dc37 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 830838c603758..fb9daf07c71dc 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 0000000000000..0047f6d59237c --- /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 or the MIT license +// , 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 0000000000000..389334f9c1d8d --- /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 0000000000000..64a4d39100063 --- /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 or the MIT license +// , 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 0000000000000..e69de29bb2d1d 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 0000000000000..3242136f005e7 --- /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 or the MIT license +// , 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 0000000000000..9edeca2d18801 --- /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 0000000000000..3e32818b8dcf3 --- /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 or the MIT license +// , 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 0000000000000..24d0d6d04c8da --- /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 0000000000000..291fcbd73f3e1 --- /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 or the MIT license +// , 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 0000000000000..7b1b55d133ac5 --- /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 +