From 08a60ac6ed68628c4ccdb3fcbb6d780cadd7565a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 21 Sep 2019 16:32:24 +0100 Subject: [PATCH 1/2] Calculate liveness for the same locals with and without -Zpolonius This fixes some test differences and also avoids overflow in issue-38591.rs. --- .../nll/type_check/liveness/local_use_map.rs | 4 + .../nll/type_check/liveness/mod.rs | 52 +++--- .../nll/type_check/liveness/polonius.rs | 11 +- .../nll/type_check/liveness/trace.rs | 37 ++++- ...wck-escaping-closure-error.polonius.stderr | 16 -- ...k-escaping-closure-error-2.polonius.stderr | 16 -- ...ref-mut-in-let-issue-46557.polonius.stderr | 59 ------- ...al-binding-from-desugaring.polonius.stderr | 16 -- ...phase-surprise-no-conflict.polonius.stderr | 148 ------------------ .../consts/promote_const_let.polonius.stderr | 29 ---- ...dropck_trait_cycle_checked.polonius.stderr | 78 --------- ...escapes-but-not-over-yield.polonius.stderr | 20 --- src/test/ui/nll/get_default.polonius.stderr | 5 +- .../loan_ends_mid_block_pair.polonius.stderr | 15 -- .../nll/polonius/polonius-smoke-test.stderr | 4 +- ...return-ref-mut-issue-46557.polonius.stderr | 15 -- ...ures-failed-recursive-fn-1.polonius.stderr | 60 ------- 17 files changed, 84 insertions(+), 501 deletions(-) delete mode 100644 src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr delete mode 100644 src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr delete mode 100644 src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr delete mode 100644 src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr delete mode 100644 src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr delete mode 100644 src/test/ui/consts/promote_const_let.polonius.stderr delete mode 100644 src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr delete mode 100644 src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr delete mode 100644 src/test/ui/nll/loan_ends_mid_block_pair.polonius.stderr delete mode 100644 src/test/ui/nll/return-ref-mut-issue-46557.polonius.stderr delete mode 100644 src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.polonius.stderr diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 7689ece706695..7dee00b3eca67 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -70,6 +70,10 @@ impl LocalUseMap { appearances: IndexVec::new(), }; + if live_locals.is_empty() { + return local_use_map; + } + let mut locals_with_use_data: IndexVec = IndexVec::from_elem_n(false, body.local_decls.len()); live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index 3f2ec1ba97017..a01b528833b2d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -36,31 +36,39 @@ pub(super) fn generate<'tcx>( ) { debug!("liveness::generate"); - let live_locals: Vec = if AllFacts::enabled(typeck.tcx()) { - // If "dump facts from NLL analysis" was requested perform - // the liveness analysis for all `Local`s. This case opens - // the possibility of the variables being analyzed in `trace` - // to be *any* `Local`, not just the "live" ones, so we can't - // make any assumptions past this point as to the characteristics - // of the `live_locals`. - // FIXME: Review "live" terminology past this point, we should - // not be naming the `Local`s as live. - body.local_decls.indices().collect() + let free_regions = regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.borrowck_context.universal_regions, + &typeck.borrowck_context.constraints.outlives_constraints, + ); + let live_locals = compute_live_locals(typeck.tcx(), &free_regions, body); + let facts_enabled = AllFacts::enabled(typeck.tcx()); + + + let polonius_drop_used = if facts_enabled { + let mut drop_used = Vec::new(); + polonius::populate_access_facts( + typeck, + body, + location_table, + move_data, + &mut drop_used, + ); + Some(drop_used) } else { - let free_regions = { - regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &typeck.borrowck_context.universal_regions, - &typeck.borrowck_context.constraints.outlives_constraints, - ) - }; - compute_live_locals(typeck.tcx(), &free_regions, body) + None }; - if !live_locals.is_empty() { - trace::trace(typeck, body, elements, flow_inits, move_data, live_locals); - - polonius::populate_access_facts(typeck, body, location_table, move_data); + if !live_locals.is_empty() || facts_enabled { + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + live_locals, + polonius_drop_used, + ); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs index e37ddbda4be02..526ad7fb905bb 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs @@ -16,7 +16,7 @@ struct UseFactsExtractor<'me> { var_defined: &'me mut VarPointRelations, var_used: &'me mut VarPointRelations, location_table: &'me LocationTable, - var_drop_used: &'me mut VarPointRelations, + var_drop_used: &'me mut Vec<(Local, Location)>, move_data: &'me MoveData<'me>, path_accessed_at: &'me mut MovePathPointRelations, } @@ -39,7 +39,7 @@ impl UseFactsExtractor<'_> { fn insert_drop_use(&mut self, local: Local, location: Location) { debug!("LivenessFactsExtractor::insert_drop_use()"); - self.var_drop_used.push((local, self.location_to_index(location))); + self.var_drop_used.push((local, location)); } fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { @@ -100,6 +100,7 @@ pub(super) fn populate_access_facts( body: &Body<'tcx>, location_table: &LocationTable, move_data: &MoveData<'_>, + drop_used: &mut Vec<(Local, Location)>, ) { debug!("populate_var_liveness_facts()"); @@ -107,12 +108,16 @@ pub(super) fn populate_access_facts( UseFactsExtractor { var_defined: &mut facts.var_defined, var_used: &mut facts.var_used, - var_drop_used: &mut facts.var_drop_used, + var_drop_used: drop_used, path_accessed_at: &mut facts.path_accessed_at, location_table, move_data, } .visit_body(body); + + facts.var_drop_used.extend(drop_used.iter().map(|&(local, location)| { + (local, location_table.mid_index(location)) + })); } for (local, local_decl) in body.local_decls.iter_enumerated() { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 36482a7b13534..eacc4d084dbb8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -13,7 +13,7 @@ use rustc::traits::query::type_op::outlives::DropckOutlives; use rustc::traits::query::type_op::TypeOp; use rustc::ty::{Ty, TypeFoldable}; use rustc_index::bit_set::HybridBitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::rc::Rc; /// This is the heart of the liveness computation. For each variable X @@ -37,6 +37,7 @@ pub(super) fn trace( flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, live_locals: Vec, + polonius_drop_used: Option>, ) { debug!("trace()"); @@ -52,7 +53,13 @@ pub(super) fn trace( drop_data: FxHashMap::default(), }; - LivenessResults::new(cx).compute_for_all_locals(live_locals); + let mut results = LivenessResults::new(cx); + + if let Some(drop_used) = polonius_drop_used { + results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) + } + + results.compute_for_all_locals(live_locals); } /// Contextual state for the type-liveness generator. @@ -145,6 +152,32 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } + /// Add extra drop facts needed for Polonius. + /// + /// Add facts for all locals with free regions, since regions may outlive + /// the function body only at certain nodes in the CFG. + fn add_extra_drop_facts( + &mut self, + drop_used: Vec<(Local, Location)>, + live_locals: FxHashSet, + ) { + let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + + for (local, location) in drop_used { + if !live_locals.contains(&local) { + let local_ty = self.cx.body.local_decls[local].ty; + if local_ty.has_free_regions() { + self.cx.add_drop_live_facts_for( + local, + local_ty, + &[location], + &locations, + ); + } + } + } + } + /// Clear the value of fields that are "per local variable". fn reset_local_state(&mut self) { self.defs.clear(); diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr b/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr deleted file mode 100644 index 5f20367b6aba9..0000000000000 --- a/src/test/ui/async-await/async-borrowck-escaping-closure-error.polonius.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `x` does not live long enough - --> $DIR/async-borrowck-escaping-closure-error.rs:5:24 - | -LL | Box::new((async || x)()) - | -------------------^---- - | | | | - | | | borrowed value does not live long enough - | | value captured here - | borrow later used here -LL | -LL | } - | - `x` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr deleted file mode 100644 index 89af8764557ff..0000000000000 --- a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.polonius.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0597]: `books` does not live long enough - --> $DIR/borrowck-escaping-closure-error-2.rs:11:17 - | -LL | Box::new(|| books.push(4)) - | ------------^^^^^--------- - | | | | - | | | borrowed value does not live long enough - | | value captured here - | borrow later used here -LL | -LL | } - | - `books` dropped here while still borrowed - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr deleted file mode 100644 index a5b2e8762746c..0000000000000 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.polonius.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:5:21 - | -LL | let ref mut x = 1234543; - | ^^^^^^^ creates a temporary which is freed while still in use -LL | x - | - borrow later used here -LL | } - | - temporary value is freed at the end of this statement - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:10:25 - | -LL | let (ref mut x, ) = (1234543, ); - | ^^^^^^^^^^^ creates a temporary which is freed while still in use -LL | x - | - borrow later used here -LL | } - | - temporary value is freed at the end of this statement - | - = note: consider using a `let` binding to create a longer lived value - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5 - | -LL | match 1234543 { - | ^ ------- temporary value created here - | _____| - | | -LL | | ref mut x => x -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return value referencing temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5 - | -LL | match (123443,) { - | ^ --------- temporary value created here - | _____| - | | -LL | | (ref mut x,) => x, -LL | | } - | |_____^ returns a value referencing data owned by the current function - -error[E0515]: cannot return reference to temporary value - --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5 - | -LL | &mut 1234543 - | ^^^^^------- - | | | - | | temporary value created here - | returns a reference to data owned by the current function - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0515, E0716. -For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr b/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr deleted file mode 100644 index c818379762c9d..0000000000000 --- a/src/test/ui/borrowck/return-local-binding-from-desugaring.polonius.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/return-local-binding-from-desugaring.rs:26:18 - | -LL | for ref x in xs { - | ^^ creates a temporary which is freed while still in use -... -LL | } - | - temporary value is freed at the end of this statement -LL | result - | ------ borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr deleted file mode 100644 index 7b246426a2333..0000000000000 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.polonius.stderr +++ /dev/null @@ -1,148 +0,0 @@ -error[E0503]: cannot use `self.cx` because it was mutably borrowed - --> $DIR/two-phase-surprise-no-conflict.rs:21:23 - | -LL | let _mut_borrow = &mut *self; - | ---------- borrow of `*self` occurs here -LL | let _access = self.cx; - | ^^^^^^^ use of borrowed `*self` -LL | -LL | _mut_borrow; - | ----------- borrow later used here - -error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:57:17 - | -LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:119:51 - | -LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:122:54 - | -LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:125:53 - | -LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:128:44 - | -LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:138:5 - | -LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:141:5 - | -LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-surprise-no-conflict.rs:144:5 - | -LL | reg.register_ref(&CapturePass::new(®.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^ - | | | | - | | | immutable borrow occurs here - | | immutable borrow later used by call - | mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:154:5 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:154:54 - | -LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:158:5 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:158:53 - | -LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error[E0499]: cannot borrow `*reg` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:162:5 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ - | | | | - | | | first mutable borrow occurs here - | | first borrow later used by call - | second mutable borrow occurs here - -error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time - --> $DIR/two-phase-surprise-no-conflict.rs:162:44 - | -LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | - | | first borrow later used by call - | first mutable borrow occurs here - -error: aborting due to 15 previous errors - -Some errors have detailed explanations: E0499, E0502, E0503. -For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/consts/promote_const_let.polonius.stderr b/src/test/ui/consts/promote_const_let.polonius.stderr deleted file mode 100644 index cf41bd7bdb1eb..0000000000000 --- a/src/test/ui/consts/promote_const_let.polonius.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0597]: `y` does not live long enough - --> $DIR/promote_const_let.rs:4:9 - | -LL | let x: &'static u32 = { - | - borrow later stored here -LL | let y = 42; -LL | &y - | ^^ borrowed value does not live long enough -LL | }; - | - `y` dropped here while still borrowed - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote_const_let.rs:6:28 - | -LL | let x: &'static u32 = &{ - | ____________------------____^ - | | | - | | type annotation requires that borrow lasts for `'static` -LL | | let y = 42; -LL | | y -LL | | }; - | |_____^ creates a temporary which is freed while still in use -LL | } - | - temporary value is freed at the end of this statement - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr deleted file mode 100644 index 5e93a0234259c..0000000000000 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.polonius.stderr +++ /dev/null @@ -1,78 +0,0 @@ -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:111:13 - | -LL | o1.set0(&o2); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `o2` dropped here while still borrowed - | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:112:13 - | -LL | o1.set1(&o3); - | ^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `o3` dropped here while still borrowed - | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` - | - = note: values in a scope are dropped in the opposite order they are defined - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:113:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o2.set0(&o2); - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o2` dropped here while still borrowed - -error[E0597]: `o3` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:114:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` -... -LL | o2.set1(&o3); - | ^^^ borrowed value does not live long enough -... -LL | } - | - `o3` dropped here while still borrowed - -error[E0597]: `o1` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:115:13 - | -LL | o3.set0(&o1); - | ^^^ borrowed value does not live long enough -LL | o3.set1(&o2); -LL | } - | - - | | - | `o1` dropped here while still borrowed - | borrow might be used here, when `o1` is dropped and runs the destructor for type `std::boxed::Box>` - -error[E0597]: `o2` does not live long enough - --> $DIR/dropck_trait_cycle_checked.rs:116:13 - | -LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` -... -LL | o3.set1(&o2); - | ^^^ borrowed value does not live long enough -LL | } - | - `o2` dropped here while still borrowed - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr deleted file mode 100644 index 530bf368f676e..0000000000000 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.polonius.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0597]: `b` does not live long enough - --> $DIR/ref-escapes-but-not-over-yield.rs:11:13 - | -LL | let mut b = move || { - | _________________- -LL | | yield(); -LL | | let b = 5; -LL | | a = &b; - | | ^^ borrowed value does not live long enough -LL | | -LL | | }; - | | - - | | | - | | `b` dropped here while still borrowed - | |_____... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator - | a temporary with access to the borrow is created here ... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/get_default.polonius.stderr b/src/test/ui/nll/get_default.polonius.stderr index 2df6d5d61fc46..476d86cfba9c3 100644 --- a/src/test/ui/nll/get_default.polonius.stderr +++ b/src/test/ui/nll/get_default.polonius.stderr @@ -1,6 +1,9 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable --> $DIR/get_default.rs:32:17 | +LL | fn err(map: &mut Map) -> &String { + | - let's call the lifetime of this reference `'1` +LL | loop { LL | match map.get() { | --- immutable borrow occurs here LL | Some(v) => { @@ -8,7 +11,7 @@ LL | map.set(String::new()); // Both AST and MIR error here | ^^^ mutable borrow occurs here LL | LL | return v; - | - immutable borrow later used here + | - returning this value requires that `*map` is borrowed for `'1` error: aborting due to previous error diff --git a/src/test/ui/nll/loan_ends_mid_block_pair.polonius.stderr b/src/test/ui/nll/loan_ends_mid_block_pair.polonius.stderr deleted file mode 100644 index eb8442b31d7c7..0000000000000 --- a/src/test/ui/nll/loan_ends_mid_block_pair.polonius.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0506]: cannot assign to `data.0` because it is borrowed - --> $DIR/loan_ends_mid_block_pair.rs:12:5 - | -LL | let c = &mut data.0; - | ----------- borrow of `data.0` occurs here -LL | capitalize(c); -LL | data.0 = 'e'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here -... -LL | capitalize(c); - | - borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/nll/polonius/polonius-smoke-test.stderr b/src/test/ui/nll/polonius/polonius-smoke-test.stderr index dbc5b7a019a69..1faf8e2212aab 100644 --- a/src/test/ui/nll/polonius/polonius-smoke-test.stderr +++ b/src/test/ui/nll/polonius/polonius-smoke-test.stderr @@ -17,12 +17,14 @@ LL | let w = y; error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/polonius-smoke-test.rs:19:13 | +LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 { + | - let's call the lifetime of this reference `'1` LL | let y = &mut *x; | ------- borrow of `*x` occurs here LL | let z = x; | ^ move out of `x` occurs here LL | y - | - borrow later used here + | - returning this value requires that `*x` is borrowed for `'1` error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/polonius-smoke-test.rs:43:5 diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.polonius.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.polonius.stderr deleted file mode 100644 index 8e3cf59cffb44..0000000000000 --- a/src/test/ui/nll/return-ref-mut-issue-46557.polonius.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/return-ref-mut-issue-46557.rs:4:21 - | -LL | let ref mut x = 1234543; - | ^^^^^^^ creates a temporary which is freed while still in use -LL | x - | - borrow later used here -LL | } - | - temporary value is freed at the end of this statement - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.polonius.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.polonius.stderr deleted file mode 100644 index 4b906f75149af..0000000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.polonius.stderr +++ /dev/null @@ -1,60 +0,0 @@ -error[E0597]: `factorial` does not live long enough - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 - | -LL | let f = |x: u32| -> u32 { - | --------------- value captured here -LL | let g = factorial.as_ref().unwrap(); - | ^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `factorial` dropped here while still borrowed - | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` - -error[E0506]: cannot assign to `factorial` because it is borrowed - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 - | -LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here -LL | let g = factorial.as_ref().unwrap(); - | --------- borrow occurs due to use in closure -... -LL | factorial = Some(Box::new(f)); - | ^^^^^^^^^ - | | - | assignment to borrowed `factorial` occurs here - | borrow later used here - -error[E0597]: `factorial` does not live long enough - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 - | -LL | let f = |x: u32| -> u32 { - | --------------- value captured here -LL | let g = factorial.as_ref().unwrap(); - | ^^^^^^^^^ borrowed value does not live long enough -... -LL | } - | - - | | - | `factorial` dropped here while still borrowed - | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` - -error[E0506]: cannot assign to `factorial` because it is borrowed - --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:33:5 - | -LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here -LL | let g = factorial.as_ref().unwrap(); - | --------- borrow occurs due to use in closure -... -LL | factorial = Some(Box::new(f)); - | ^^^^^^^^^ - | | - | assignment to borrowed `factorial` occurs here - | borrow later used here - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0506, E0597. -For more information about an error, try `rustc --explain E0506`. From 2180c243214ebce29c45c37020e929924a8520d8 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 24 Sep 2019 21:55:49 +0100 Subject: [PATCH 2/2] Make lifetimes in constants live at the point of use --- .../borrow_check/nll/type_check/mod.rs | 64 ++++++++++++------- .../ui/hrtb/due-to-where-clause.nll.stderr | 8 +++ src/test/ui/hrtb/due-to-where-clause.rs | 3 - src/test/ui/hrtb/due-to-where-clause.stderr | 2 +- src/test/ui/nll/promoted-liveness.rs | 8 +++ 5 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/hrtb/due-to-where-clause.nll.stderr create mode 100644 src/test/ui/nll/promoted-liveness.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b24ba596d7e93..adc3381a1e762 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -276,7 +276,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - self.sanitize_type(constant, constant.literal.ty); + let ty = self.sanitize_type(constant, constant.literal.ty); + + self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = + self.cx.borrowck_context.universal_regions.to_region_vid(live_region); + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_element(live_region_vid, location); + }); if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( @@ -528,25 +538,37 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let parent_body = mem::replace(&mut self.body, promoted_body); + // Use new sets of constraints and closure bounds so that we can + // modify their locations. let all_facts = &mut None; let mut constraints = Default::default(); let mut closure_bounds = Default::default(); + let mut liveness_constraints = LivenessValues::new( + Rc::new(RegionValueElements::new(promoted_body)), + ); // Don't try to add borrow_region facts for the promoted MIR - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - // Use a new sets of constraints and closure bounds so that we can - // modify their locations. - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + let mut swap_constraints = |this: &mut Self| { + mem::swap(this.cx.borrowck_context.all_facts, all_facts); + mem::swap( + &mut this.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.liveness_constraints, + &mut liveness_constraints + ); + }; + + swap_constraints(self); self.visit_body(promoted_body); + if !self.errors_reported { // if verifier failed, don't do further checks to avoid ICEs self.cx.typeck_mir(promoted_body); @@ -554,23 +576,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { self.body = parent_body; // Merge the outlives constraints back in, at the given location. - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + swap_constraints(self); let locations = location.to_locations(); for constraint in constraints.outlives().iter() { let mut constraint = *constraint; constraint.locations = locations; if let ConstraintCategory::Return - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic = constraint.category { // "Returning" from a promoted is an assigment to a // temporary from the user's point of view. @@ -578,6 +592,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } + for live_region in liveness_constraints.rows() { + self.cx.borrowck_context.constraints.liveness_constraints + .add_element(live_region, location); + } if !closure_bounds.is_empty() { let combined_bounds_mapping = closure_bounds diff --git a/src/test/ui/hrtb/due-to-where-clause.nll.stderr b/src/test/ui/hrtb/due-to-where-clause.nll.stderr new file mode 100644 index 0000000000000..e476047a7a644 --- /dev/null +++ b/src/test/ui/hrtb/due-to-where-clause.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/due-to-where-clause.rs:2:5 + | +LL | test::(&mut 42); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/due-to-where-clause.rs b/src/test/ui/hrtb/due-to-where-clause.rs index 04e2ddd4a6090..1afd15613b51c 100644 --- a/src/test/ui/hrtb/due-to-where-clause.rs +++ b/src/test/ui/hrtb/due-to-where-clause.rs @@ -1,6 +1,3 @@ -// ignore-compare-mode-nll -// ^ This code works in nll mode. - fn main() { test::(&mut 42); //~ ERROR implementation of `Foo` is not general enough } diff --git a/src/test/ui/hrtb/due-to-where-clause.stderr b/src/test/ui/hrtb/due-to-where-clause.stderr index 9fef1e3354399..e4096ec059a6e 100644 --- a/src/test/ui/hrtb/due-to-where-clause.stderr +++ b/src/test/ui/hrtb/due-to-where-clause.stderr @@ -1,5 +1,5 @@ error: implementation of `Foo` is not general enough - --> $DIR/due-to-where-clause.rs:5:5 + --> $DIR/due-to-where-clause.rs:2:5 | LL | test::(&mut 42); | ^^^^^^^^^^^^ implementation of `Foo` is not general enough diff --git a/src/test/ui/nll/promoted-liveness.rs b/src/test/ui/nll/promoted-liveness.rs new file mode 100644 index 0000000000000..e5a8e1e5c2fcc --- /dev/null +++ b/src/test/ui/nll/promoted-liveness.rs @@ -0,0 +1,8 @@ +// Test that promoted that have larger mir bodies than their containing function +// don't cause an ICE. + +// check-pass + +fn main() { + &["0", "1", "2", "3", "4", "5", "6", "7"]; +}