Rollup merge of #62736 - lqd:polonius_tests3, r=matthewjasper
Polonius: fix some cases of `killed` fact generation, and most of the `ui` test suite Since basic Polonius functionality was re-enabled by @matthewjasper in #54468, some tests were still failing in the polonius compare-mode. This PR fixes all but one test in the `ui` suite by: - fixing some bugs in the fact generation code, related to the `killed` relation: Polonius would incorrectly reject some NLL-accepted code, because of these missing `killed` facts. - ignoring some tests in the polonius compare-mode: a lot of those manually test the NLL or migrate mode, and the failures were mostly artifacts of the test revisions, e.g. that `-Z polonius` requires full NLLs. Some others were also both failing with NLL and succeeding with Polonius, which we can't encode in tests at the moment. - blessing the output of some tests: whenever Polonius and NLL have basically the same errors, except for diagnostics differences, the Polonius output is blessed. Whenever we've advanced into a less experimental phase, we'll want to revisit these cases (much like we did on the NLL test suite last year) to specifically work on diagnostics. Fact generation changes: - we now kill loans on the destination place of `Call` terminators - we now kill loans on the locals destroyed by `StorageDead` - we now also handle assignments to projections: killing the loans on a either a deref-ed local, or the ones whose `borrowed_place` conflicts with the current place. One failing test remains: an overflow during fact generation, on a case of polymorphic recursion (and which I'll continue investigating later). This adds some tests for the fact generation changes, with some simple Polonius cases similar to the existing smoke tests, but also for some cases encountered in the wild (in the `rand` crate for example). A more detailed write-up is available [here](https://hackmd.io/CjYB0fs4Q9CweyeTdKWyEg?view) with an explanation for each test failure, the steps taken to resolve it (as a commit in the current PR), NLL and Polonius outputs (and diff), etc. Since they've worked on this before, and we've discussed some of these failures together: r? @matthewjasper
This commit is contained in:
commit
a676a36662
|
@ -3,12 +3,15 @@ use crate::borrow_check::location::LocationTable;
|
|||
use crate::borrow_check::nll::ToRegionVid;
|
||||
use crate::borrow_check::nll::facts::AllFacts;
|
||||
use crate::borrow_check::nll::region_infer::values::LivenessValues;
|
||||
use crate::borrow_check::places_conflict;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::{BasicBlock, BasicBlockData, Location, Body, Place, PlaceBase, Rvalue};
|
||||
use rustc::mir::{SourceInfo, Statement, Terminator};
|
||||
use rustc::mir::UserTypeProjection;
|
||||
use rustc::mir::{
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
|
||||
ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
UserTypeProjection,
|
||||
};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
|
||||
use rustc::ty::subst::SubstsRef;
|
||||
|
@ -27,6 +30,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
|
|||
liveness_constraints,
|
||||
location_table,
|
||||
all_facts,
|
||||
body,
|
||||
};
|
||||
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
|
@ -41,6 +45,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> {
|
|||
location_table: &'cg LocationTable,
|
||||
liveness_constraints: &'cg mut LivenessValues<RegionVid>,
|
||||
borrow_set: &'cg BorrowSet<'tcx>,
|
||||
body: &'cg Body<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
|
||||
|
@ -114,6 +119,17 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
|
|||
self.location_table
|
||||
.start_index(location.successor_within_block()),
|
||||
));
|
||||
|
||||
// If there are borrows on this now dead local, we need to record them as `killed`.
|
||||
if let StatementKind::StorageDead(ref local) = statement.kind {
|
||||
record_killed_borrows_for_local(
|
||||
all_facts,
|
||||
self.borrow_set,
|
||||
self.location_table,
|
||||
local,
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.super_statement(statement, location);
|
||||
|
@ -127,20 +143,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
|
|||
) {
|
||||
// When we see `X = ...`, then kill borrows of
|
||||
// `(*X).foo` and so forth.
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(temp),
|
||||
projection: None,
|
||||
} = place {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
|
||||
all_facts.killed.reserve(borrow_indices.len());
|
||||
for &borrow_index in borrow_indices {
|
||||
let location_index = self.location_table.mid_index(location);
|
||||
all_facts.killed.push((borrow_index, location_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.record_killed_borrows_for_place(place, location);
|
||||
|
||||
self.super_assign(place, rvalue, location);
|
||||
}
|
||||
|
@ -167,6 +170,14 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// A `Call` terminator's return value can be a local which has borrows,
|
||||
// so we need to record those as `killed` as well.
|
||||
if let TerminatorKind::Call { ref destination, .. } = terminator.kind {
|
||||
if let Some((place, _)) = destination {
|
||||
self.record_killed_borrows_for_place(place, location);
|
||||
}
|
||||
}
|
||||
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
|
||||
|
@ -201,4 +212,96 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
self.liveness_constraints.add_element(vid, location);
|
||||
});
|
||||
}
|
||||
|
||||
/// When recording facts for Polonius, records the borrows on the specified place
|
||||
/// as `killed`. For example, when assigning to a local, or on a call's return destination.
|
||||
fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) {
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
// Depending on the `Place` we're killing:
|
||||
// - if it's a local, or a single deref of a local,
|
||||
// we kill all the borrows on the local.
|
||||
// - if it's a deeper projection, we have to filter which
|
||||
// of the borrows are killed: the ones whose `borrowed_place`
|
||||
// conflicts with the `place`.
|
||||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
} => {
|
||||
debug!(
|
||||
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
||||
local, location
|
||||
);
|
||||
|
||||
record_killed_borrows_for_local(
|
||||
all_facts,
|
||||
self.borrow_set,
|
||||
self.location_table,
|
||||
local,
|
||||
location,
|
||||
);
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Static(_),
|
||||
..
|
||||
} => {
|
||||
// Ignore kills of static or static mut variables.
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(_),
|
||||
} => {
|
||||
// Kill conflicting borrows of the innermost local.
|
||||
debug!(
|
||||
"Recording `killed` facts for borrows of \
|
||||
innermost projected local={:?} at location={:?}",
|
||||
local, location
|
||||
);
|
||||
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
|
||||
for &borrow_index in borrow_indices {
|
||||
let places_conflict = places_conflict::places_conflict(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.borrow_set.borrows[borrow_index].borrowed_place,
|
||||
place,
|
||||
places_conflict::PlaceConflictBias::NoOverlap,
|
||||
);
|
||||
|
||||
if places_conflict {
|
||||
let location_index = self.location_table.mid_index(location);
|
||||
all_facts.killed.push((borrow_index, location_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When recording facts for Polonius, records the borrows on the specified local as `killed`.
|
||||
fn record_killed_borrows_for_local(
|
||||
all_facts: &mut AllFacts,
|
||||
borrow_set: &BorrowSet<'_>,
|
||||
location_table: &LocationTable,
|
||||
local: &Local,
|
||||
location: Location,
|
||||
) {
|
||||
if let Some(borrow_indices) = borrow_set.local_map.get(local) {
|
||||
all_facts.killed.reserve(borrow_indices.len());
|
||||
for &borrow_index in borrow_indices {
|
||||
let location_index = location_table.mid_index(location);
|
||||
all_facts.killed.push((borrow_index, location_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
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`.
|
|
@ -1,5 +1,5 @@
|
|||
warning[E0507]: cannot move out of `foo` in pattern guard
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:25:18
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
||||
|
|
||||
LL | (|| { let bar = foo; bar.take() })();
|
||||
| ^^ ---
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
// just ignore it instead:
|
||||
|
||||
// ignore-compare-mode-nll
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
// revisions: zflag edition
|
||||
//[zflag]compile-flags: -Z borrowck=migrate
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
warning[E0507]: cannot move out of `foo` in pattern guard
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:25:18
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
||||
|
|
||||
LL | (|| { let bar = foo; bar.take() })();
|
||||
| ^^ ---
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: borrowed data cannot be stored outside of its closure
|
||||
--> $DIR/issue-45983.rs:19:27
|
||||
--> $DIR/issue-45983.rs:20:27
|
||||
|
|
||||
LL | let x = None;
|
||||
| - borrowed data cannot be stored into here...
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> $DIR/issue-45983.rs:19:18
|
||||
--> $DIR/issue-45983.rs:20:18
|
||||
|
|
||||
LL | let x = None;
|
||||
| - `x` is declared here, outside of the closure body
|
||||
|
@ -9,7 +9,7 @@ LL | give_any(|y| x = Some(y));
|
|||
| `y` is a reference that is only valid in the closure body
|
||||
|
||||
error[E0594]: cannot assign to `x`, as it is not declared as mutable
|
||||
--> $DIR/issue-45983.rs:19:18
|
||||
--> $DIR/issue-45983.rs:20:18
|
||||
|
|
||||
LL | let x = None;
|
||||
| - help: consider changing this to be mutable: `mut x`
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// revisions, don't worry about the --compare-mode=nll on this test.
|
||||
|
||||
// ignore-compare-mode-nll
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
//[nll]compile-flags: -Z borrowck=mir
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
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`.
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
@ -11,7 +11,7 @@ LL | v.extend(shared);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:29:5
|
||||
|
|
||||
LL | v.extend(&v);
|
||||
| ^^------^--^
|
||||
|
@ -21,7 +21,7 @@ LL | v.extend(&v);
|
|||
| mutable borrow occurs here
|
||||
|
||||
warning: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
@ -11,7 +11,7 @@ LL | v.extend(shared);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:29:5
|
||||
|
|
||||
LL | v.extend(&v);
|
||||
| ^^------^--^
|
||||
|
@ -21,7 +21,7 @@ LL | v.extend(&v);
|
|||
| mutable borrow occurs here
|
||||
|
||||
warning: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
@ -10,7 +10,7 @@ LL | v.extend(shared);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:29:5
|
||||
|
|
||||
LL | v.extend(&v);
|
||||
| ^^------^--^
|
||||
|
@ -20,7 +20,7 @@ LL | v.extend(&v);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
@ -10,7 +10,7 @@ LL | v.extend(shared);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:28:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:29:5
|
||||
|
|
||||
LL | v.extend(&v);
|
||||
| ^^------^--^
|
||||
|
@ -20,7 +20,7 @@ LL | v.extend(&v);
|
|||
| mutable borrow occurs here
|
||||
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:39:5
|
||||
--> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
|
||||
|
|
||||
LL | let shared = &v;
|
||||
| -- immutable borrow occurs here
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// everyone else.
|
||||
|
||||
//ignore-compare-mode-nll
|
||||
//ignore-compare-mode-polonius
|
||||
|
||||
//revisions: migrate2015 migrate2018 nll2015 nll2018
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
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`.
|
|
@ -0,0 +1,29 @@
|
|||
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`.
|
|
@ -0,0 +1,74 @@
|
|||
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 `o2` is dropped and runs the destructor for type `std::boxed::Box<dyn Obj<'_>>`
|
||||
|
||||
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 `o3` is dropped and runs the destructor for type `std::boxed::Box<dyn Obj<'_>>`
|
||||
|
||||
error[E0597]: `o2` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:113:13
|
||||
|
|
||||
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (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<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (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<dyn Obj<'_>>`
|
||||
|
||||
error[E0597]: `o2` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:116:13
|
||||
|
|
||||
LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (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`.
|
|
@ -0,0 +1 @@
|
|||
{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.polonius/libemit_artifact_notifications.rmeta","emit":"metadata"}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
// Don't use compare-mode=nll, since that turns on NLL.
|
||||
// ignore-compare-mode-nll
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
warning[E0502]: cannot borrow `*x.1` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/feature-gate-nll.rs:14:13
|
||||
--> $DIR/feature-gate-nll.rs:15:13
|
||||
|
|
||||
LL | let m = &mut x;
|
||||
| ------ mutable borrow occurs here
|
||||
|
@ -14,7 +14,7 @@ LL | m;
|
|||
= note: for more information, try `rustc --explain E0729`
|
||||
|
||||
error: compilation successful
|
||||
--> $DIR/feature-gate-nll.rs:10:1
|
||||
--> $DIR/feature-gate-nll.rs:11:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | let mut x = (33, &0);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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`.
|
|
@ -1,11 +1,11 @@
|
|||
error: implementation of `Stream` is not general enough
|
||||
--> $DIR/issue-30786.rs:107:22
|
||||
--> $DIR/issue-30786.rs:108:22
|
||||
|
|
||||
LL | let map = source.map(|x: &_| x);
|
||||
| ^^^
|
||||
|
|
||||
= note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:107:26: 107:35]>`, for any lifetime `'0`
|
||||
= note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:107:26: 107:35]>`, for some specific lifetime `'1`
|
||||
= note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`
|
||||
= note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error: higher-ranked subtype error
|
||||
--> $DIR/issue-30786.rs:111:18
|
||||
--> $DIR/issue-30786.rs:112:18
|
||||
|
|
||||
LL | let filter = map.filter(|x: &_| true);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: higher-ranked subtype error
|
||||
--> $DIR/issue-30786.rs:113:17
|
||||
--> $DIR/issue-30786.rs:114:17
|
||||
|
|
||||
LL | let count = filter.count(); // Assert that we still have a valid stream.
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// revisions, don't worry about the --compare-mode=nll on this test.
|
||||
|
||||
// ignore-compare-mode-nll
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
//[nll]compile-flags: -Z borrowck=mir
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
warning[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:51:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:52:5
|
||||
|
|
||||
LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
@ -14,7 +14,7 @@ LL | }
|
|||
= note: for more information, try `rustc --explain E0729`
|
||||
|
||||
warning[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
|
||||
|
|
||||
LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
@ -29,7 +29,7 @@ LL | }
|
|||
= note: for more information, try `rustc --explain E0729`
|
||||
|
||||
warning[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:74:5
|
||||
|
|
||||
LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
@ -44,7 +44,7 @@ LL | }
|
|||
= note: for more information, try `rustc --explain E0729`
|
||||
|
||||
error: compilation successful
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:80:1
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:81:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | let mut x = 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:51:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:52:5
|
||||
|
|
||||
LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
@ -10,7 +10,7 @@ LL | }
|
|||
| - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait
|
||||
|
||||
error[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
|
||||
|
|
||||
LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
@ -21,7 +21,7 @@ LL | }
|
|||
| - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait
|
||||
|
||||
error[E0713]: borrow may still be in use when destructor runs
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
|
||||
--> $DIR/issue-45696-scribble-on-boxed-borrow.rs:74:5
|
||||
|
|
||||
LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
// revisions: nll migrate
|
||||
// ignore-compare-mode-nll
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
// This test is going to pass in the migrate revision, because the AST-borrowck
|
||||
// accepted this code in the past (see notes below). So we use `#[rustc_error]`
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/get_default.rs:32:17
|
||||
|
|
||||
LL | match map.get() {
|
||||
| --- immutable borrow occurs here
|
||||
LL | Some(v) => {
|
||||
LL | map.set(String::new()); // Both AST and MIR error here
|
||||
| ^^^ mutable borrow occurs here
|
||||
LL |
|
||||
LL | return v;
|
||||
| - immutable borrow later used here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0502`.
|
|
@ -1,3 +1,9 @@
|
|||
// This tests passes in Polonius mode, so is skipped in the automated compare-mode.
|
||||
// We will manually check it passes in Polonius tests, as we can't have a test here
|
||||
// which conditionally passes depending on a test revision/compile-flags.
|
||||
|
||||
// ignore-compare-mode-polonius
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0499]: cannot borrow `**other` as mutable more than once at a time
|
||||
--> $DIR/issue-46589.rs:17:21
|
||||
--> $DIR/issue-46589.rs:23:21
|
||||
|
|
||||
LL | *other = match (*other).get_self() {
|
||||
| -------- first mutable borrow occurs here
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
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`.
|
|
@ -0,0 +1,88 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
// This tests the various kinds of assignments there are. Polonius used to generate `killed`
|
||||
// facts only on simple assigments, but not projections, incorrectly causing errors to be emitted
|
||||
// for code accepted by NLL. They are all variations from example code in the NLL RFC.
|
||||
|
||||
// check-pass
|
||||
// compile-flags: -Z borrowck=mir -Z polonius
|
||||
// ignore-compare-mode-nll
|
||||
|
||||
struct List<T> {
|
||||
value: T,
|
||||
next: Option<Box<List<T>>>,
|
||||
}
|
||||
|
||||
// Assignment to a local: the `list` assignment should clear the existing
|
||||
// borrows of `list.value` and `list.next`
|
||||
fn assignment_to_local<T>(mut list: &mut List<T>) -> Vec<&mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut list.value);
|
||||
if let Some(n) = list.next.as_mut() {
|
||||
list = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment to a deref projection: the `*list` assignment should clear the existing
|
||||
// borrows of `list.value` and `list.next`
|
||||
fn assignment_to_deref_projection<T>(mut list: Box<&mut List<T>>) -> Vec<&mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut list.value);
|
||||
if let Some(n) = list.next.as_mut() {
|
||||
*list = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment to a field projection: the `list.0` assignment should clear the existing
|
||||
// borrows of `list.0.value` and `list.0.next`
|
||||
fn assignment_to_field_projection<T>(mut list: (&mut List<T>,)) -> Vec<&mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut list.0.value);
|
||||
if let Some(n) = list.0.next.as_mut() {
|
||||
list.0 = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment to a deref field projection: the `*list.0` assignment should clear the existing
|
||||
// borrows of `list.0.value` and `list.0.next`
|
||||
fn assignment_to_deref_field_projection<T>(mut list: (Box<&mut List<T>>,)) -> Vec<&mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut list.0.value);
|
||||
if let Some(n) = list.0.next.as_mut() {
|
||||
*list.0 = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to `assignment_to_deref_field_projection` but through a longer projection chain
|
||||
fn assignment_through_projection_chain<T>(
|
||||
mut list: (((((Box<&mut List<T>>,),),),),),
|
||||
) -> Vec<&mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut ((((list.0).0).0).0).0.value);
|
||||
if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
|
||||
*((((list.0).0).0).0).0 = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
// Compared to `assignment-kills-loans.rs`, we check here
|
||||
// that we do not kill too many borrows. Assignments to the `.1`
|
||||
// field projections should leave the borrows on `.0` intact.
|
||||
|
||||
// compile-flags: -Z borrowck=mir -Z polonius
|
||||
// ignore-compare-mode-nll
|
||||
|
||||
struct List<T> {
|
||||
value: T,
|
||||
next: Option<Box<List<T>>>,
|
||||
}
|
||||
|
||||
|
||||
fn assignment_to_field_projection<'a, T>(
|
||||
mut list: (&'a mut List<T>, &'a mut List<T>),
|
||||
) -> Vec<&'a mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut (list.0).value);
|
||||
//~^ ERROR cannot borrow `list.0.value` as mutable
|
||||
|
||||
if let Some(n) = (list.0).next.as_mut() {
|
||||
//~^ ERROR cannot borrow `list.0.next` as mutable
|
||||
list.1 = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assignment_through_projection_chain<'a, T>(
|
||||
mut list: (((((Box<&'a mut List<T>>, Box<&'a mut List<T>>),),),),),
|
||||
) -> Vec<&'a mut T> {
|
||||
let mut result = vec![];
|
||||
loop {
|
||||
result.push(&mut ((((list.0).0).0).0).0.value);
|
||||
//~^ ERROR cannot borrow `list.0.0.0.0.0.value` as mutable
|
||||
|
||||
if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
|
||||
//~^ ERROR cannot borrow `list.0.0.0.0.0.next` as mutable
|
||||
*((((list.0).0).0).0).1 = n;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,51 @@
|
|||
error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time
|
||||
--> $DIR/assignment-to-differing-field.rs:21:21
|
||||
|
|
||||
LL | fn assignment_to_field_projection<'a, T>(
|
||||
| -- lifetime `'a` defined here
|
||||
...
|
||||
LL | result.push(&mut (list.0).value);
|
||||
| ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
|
||||
...
|
||||
LL | return result;
|
||||
| ------ returning this value requires that `list.0.value` is borrowed for `'a`
|
||||
|
||||
error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time
|
||||
--> $DIR/assignment-to-differing-field.rs:24:26
|
||||
|
|
||||
LL | fn assignment_to_field_projection<'a, T>(
|
||||
| -- lifetime `'a` defined here
|
||||
...
|
||||
LL | if let Some(n) = (list.0).next.as_mut() {
|
||||
| ^^^^^^^^^^^^^---------
|
||||
| |
|
||||
| mutable borrow starts here in previous iteration of loop
|
||||
| argument requires that `list.0.next` is borrowed for `'a`
|
||||
|
||||
error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
|
||||
--> $DIR/assignment-to-differing-field.rs:38:21
|
||||
|
|
||||
LL | fn assignment_through_projection_chain<'a, T>(
|
||||
| -- lifetime `'a` defined here
|
||||
...
|
||||
LL | result.push(&mut ((((list.0).0).0).0).0.value);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
|
||||
...
|
||||
LL | return result;
|
||||
| ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
|
||||
|
||||
error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time
|
||||
--> $DIR/assignment-to-differing-field.rs:41:26
|
||||
|
|
||||
LL | fn assignment_through_projection_chain<'a, T>(
|
||||
| -- lifetime `'a` defined here
|
||||
...
|
||||
LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------
|
||||
| |
|
||||
| mutable borrow starts here in previous iteration of loop
|
||||
| argument requires that `list.0.0.0.0.0.next` is borrowed for `'a`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
|
@ -0,0 +1,24 @@
|
|||
// `Call` terminators can write to a local which has existing loans
|
||||
// and those need to be killed like a regular assignment to a local.
|
||||
// This is a simplified version of issue 47680, is correctly accepted
|
||||
// by NLL but was incorrectly rejected by Polonius because of these
|
||||
// missing `killed` facts.
|
||||
|
||||
// check-pass
|
||||
// compile-flags: -Z borrowck=mir -Z polonius
|
||||
// ignore-compare-mode-nll
|
||||
|
||||
struct Thing;
|
||||
|
||||
impl Thing {
|
||||
fn next(&mut self) -> &mut Self { unimplemented!() }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut temp = &mut Thing;
|
||||
|
||||
loop {
|
||||
let v = temp.next();
|
||||
temp = v; // accepted by NLL, was incorrectly rejected by Polonius
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// This test is a copy of `ui/nll/issue-46589.rs` which fails in NLL but succeeds in Polonius.
|
||||
// As we can't have a test here which conditionally passes depending on a test
|
||||
// revision/compile-flags. We ensure here that it passes in Polonius mode.
|
||||
|
||||
// check-pass
|
||||
// compile-flags: -Z borrowck=mir -Z polonius
|
||||
// ignore-compare-mode-nll
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn get_self(&mut self) -> Option<&mut Self> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn new_self(&mut self) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
fn trigger_bug(&mut self) {
|
||||
let other = &mut (&mut *self);
|
||||
|
||||
*other = match (*other).get_self() {
|
||||
Some(s) => s,
|
||||
None => (*other).new_self()
|
||||
};
|
||||
|
||||
let c = other;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,29 @@
|
|||
// Whenever a `StorageDead` MIR statement destroys a value `x`,
|
||||
// we should kill all loans of `x`. This is extracted from `rand 0.4.6`,
|
||||
// is correctly accepted by NLL but was incorrectly rejected by
|
||||
// Polonius because of these missing `killed` facts.
|
||||
|
||||
// check-pass
|
||||
// compile-flags: -Z borrowck=mir -Z polonius
|
||||
// ignore-compare-mode-nll
|
||||
|
||||
use std::{io, mem};
|
||||
use std::io::Read;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fill(r: &mut dyn Read, mut buf: &mut [u8]) -> io::Result<()> {
|
||||
while buf.len() > 0 {
|
||||
match r.read(buf).unwrap() {
|
||||
0 => return Err(io::Error::new(io::ErrorKind::Other,
|
||||
"end of file reached")),
|
||||
n => buf = &mut mem::replace(&mut buf, &mut [])[n..],
|
||||
// ^- Polonius had multiple errors on the previous line (where NLL has none)
|
||||
// as it didn't know `buf` was killed here, and would
|
||||
// incorrectly reject both the borrow expression, and the assignment.
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
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`.
|
|
@ -0,0 +1,2 @@
|
|||
{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications.polonius/save-analysis/libemit_notifications.json","emit":"save-analysis"}
|
||||
{"artifact":"$TEST_BUILD_DIR/save-analysis/emit-notifications.polonius/libemit_notifications.rlib","emit":"link"}
|
|
@ -0,0 +1,60 @@
|
|||
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<std::boxed::Box<dyn std::ops::Fn(u32) -> 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<std::boxed::Box<dyn std::ops::Fn(u32) -> 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`.
|
Loading…
Reference in New Issue