Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
outlives_constraints,
scc_annotations,
type_tests,
mut liveness_constraints,
liveness_constraints,
universe_causes,
placeholder_indices,
} = lowered_constraints;
Expand Down Expand Up @@ -376,9 +376,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match definition.origin {
// For each free, universally quantified region X:
NllRegionVariableOrigin::FreeRegion => {
// Add all nodes in the CFG to liveness constraints
liveness_constraints.add_all_points(region);

// Add `end(X)` into the set for X.
scc_values.add_free_region(scc, region);
}
Expand All @@ -396,8 +393,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// has them, setting `scc_values[scc(region)] |= liveness_constraints[region]`.
//
// These values will later be propagated during [`Self::propagate_constraints()`].
// The values include any live-at-all-points constraints added above
// for free regions.
// The values include any live-at-all-points constraints added previously in `liveness::generate`.
if let Some(liveness) = liveness_constraints.point_liveness(region) {
scc_values.merge_liveness(scc, liveness)
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_borrowck/src/type_check/liveness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ pub(super) fn generate<'tcx>(
debug!("liveness::generate");
let _timer = typeck.tcx().prof.generic_activity("borrowck_liveness");

// Universal regions are live at every point.
for region in typeck.universal_regions.universal_regions_iter() {
typeck.constraints.liveness_constraints.add_all_points(region);
}

let mut free_regions = regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
&typeck.universal_regions,
Expand Down
32 changes: 32 additions & 0 deletions tests/ui/nll/polonius/boring-local-drop-liveness.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-drop-liveness.rs:28:5
|
LL | fn assigning_under_a_live_destructor<'a>(
| -- lifetime `'a` defined here
...
LL | *slot = Some(d.0);
| ----------------- assignment requires that `*x` is borrowed for `'a`
LL | d = D(&*x);
| --- `*x` is borrowed here
LL | *x = String::new();
| ^^ `*x` is assigned to here but it was already borrowed

error[E0597]: `local` does not live long enough
--> $DIR/boring-local-drop-liveness.rs:35:11
|
LL | fn dropping_under_a_live_destructor<'a>(x: &'a String, slot: &mut Option<&'a String>) {
| -- lifetime `'a` defined here
LL | let mut d = D(x);
LL | *slot = Some(d.0);
| ----------------- assignment requires that `local` is borrowed for `'a`
LL | let local = String::from("gone");
| ----- binding `local` declared here
LL | d = D(&local);
| ^^^^^^ borrowed value does not live long enough
LL | }
| - `local` dropped here while still borrowed

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0506, E0597.
For more information about an error, try `rustc --explain E0506`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-drop-liveness.rs:28:5
|
LL | fn assigning_under_a_live_destructor<'a>(
| -- lifetime `'a` defined here
...
LL | *slot = Some(d.0);
| ----------------- assignment requires that `*x` is borrowed for `'a`
LL | d = D(&*x);
| --- `*x` is borrowed here
LL | *x = String::new();
| ^^ `*x` is assigned to here but it was already borrowed

error[E0597]: `local` does not live long enough
--> $DIR/boring-local-drop-liveness.rs:35:11
|
LL | fn dropping_under_a_live_destructor<'a>(x: &'a String, slot: &mut Option<&'a String>) {
| -- lifetime `'a` defined here
LL | let mut d = D(x);
LL | *slot = Some(d.0);
| ----------------- assignment requires that `local` is borrowed for `'a`
LL | let local = String::from("gone");
| ----- binding `local` declared here
LL | d = D(&local);
| ^^^^^^ borrowed value does not live long enough
LL | }
| - `local` dropped here while still borrowed

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0506, E0597.
For more information about an error, try `rustc --explain E0506`.
38 changes: 38 additions & 0 deletions tests/ui/nll/polonius/boring-local-drop-liveness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Polonius requires liveness for some locals that NLL leaves "boring": locals
// containing some region that outlives a universal region but is not universal itself.
//
// This test checks that we correctly compute liveness for NLL-boring locals that
// are live only because of their drop.

//@ ignore-compare-mode-polonius (explicit revisions)
//@ revisions: nll polonius_next
//@ [nll] compile-flags: -Zpolonius=off
//@ [polonius_next] compile-flags: -Zpolonius=next

struct D<'a>(&'a String);

impl<'a> Drop for D<'a> {
fn drop(&mut self) {
println!("{}", self.0);
}
}

fn assigning_under_a_live_destructor<'a>(
x: &'a mut String,
slot: &mut Option<&'a String>,
y: &'a String,
) {
let mut d = D(y);
*slot = Some(d.0);
d = D(&*x);
*x = String::new(); //~ ERROR cannot assign to `*x` because it is borrowed
}

fn dropping_under_a_live_destructor<'a>(x: &'a String, slot: &mut Option<&'a String>) {
let mut d = D(x);
*slot = Some(d.0);
let local = String::from("gone");
d = D(&local); //~ ERROR `local` does not live long enough
}

fn main() {}
30 changes: 30 additions & 0 deletions tests/ui/nll/polonius/boring-local-liveness.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-liveness.rs:22:5
|
LL | fn assigning_into_a_slot<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
| -- lifetime `'a` defined here
LL | let r: &'a u32 = &*x;
| ------- --- `*x` is borrowed here
| |
| type annotation requires that `*x` is borrowed for `'a`
LL | *slot = Some(D(r));
LL | *x = 1;
| ^^^^^^ `*x` is assigned to here but it was already borrowed

error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-liveness.rs:32:5
|
LL | fn clearing_the_slot_does_not_release_it<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
| -- lifetime `'a` defined here
LL | {
LL | let r: &'a u32 = &*x;
| ------- --- `*x` is borrowed here
| |
| type annotation requires that `*x` is borrowed for `'a`
...
LL | *x = 1;
| ^^^^^^ `*x` is assigned to here but it was already borrowed

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0506`.
30 changes: 30 additions & 0 deletions tests/ui/nll/polonius/boring-local-liveness.polonius_next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-liveness.rs:22:5
|
LL | fn assigning_into_a_slot<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
| -- lifetime `'a` defined here
LL | let r: &'a u32 = &*x;
| ------- --- `*x` is borrowed here
| |
| type annotation requires that `*x` is borrowed for `'a`
LL | *slot = Some(D(r));
LL | *x = 1;
| ^^^^^^ `*x` is assigned to here but it was already borrowed

error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/boring-local-liveness.rs:32:5
|
LL | fn clearing_the_slot_does_not_release_it<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
| -- lifetime `'a` defined here
LL | {
LL | let r: &'a u32 = &*x;
| ------- --- `*x` is borrowed here
| |
| type annotation requires that `*x` is borrowed for `'a`
...
LL | *x = 1;
| ^^^^^^ `*x` is assigned to here but it was already borrowed

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0506`.
35 changes: 35 additions & 0 deletions tests/ui/nll/polonius/boring-local-liveness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Polonius requires liveness for some locals that NLL leaves "boring": locals
// containing some region that outlives a universal region but is not universal itself.
//
// This test checks that we correctly compute liveness for NLL-boring locals that
// are live because of a use.

//@ ignore-compare-mode-polonius (explicit revisions)
//@ revisions: nll polonius_next
//@ [nll] compile-flags: -Zpolonius=off
//@ [polonius_next] compile-flags: -Zpolonius=next

struct D<'a>(&'a u32);

impl<'a> Drop for D<'a> {
fn drop(&mut self) {}
}

// The loan of `*x` flows into `slot`'s region, which outlives `'a` and so is boring to NLLs.
fn assigning_into_a_slot<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
let r: &'a u32 = &*x;
*slot = Some(D(r));
*x = 1; //~ ERROR cannot assign to `*x` because it is borrowed
}

// The same, with the borrow confined to an inner scope and the slot cleared afterwards.
fn clearing_the_slot_does_not_release_it<'a>(x: &'a mut u32, slot: &mut Option<D<'a>>) {
{
let r: &'a u32 = &*x;
*slot = Some(D(r));
}
*slot = None;
*x = 1; //~ ERROR cannot assign to `*x` because it is borrowed
}

fn main() {}
Loading