Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two cases of confusing borrow over-extension #55085

Closed
yuriks opened this issue Oct 15, 2018 · 4 comments · Fixed by #59114
Closed

Two cases of confusing borrow over-extension #55085

yuriks opened this issue Oct 15, 2018 · 4 comments · Fixed by #59114
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-NLL Area: Non-lexical lifetimes (NLL) NLL-fixed-by-NLL Bugs fixed, but only when NLL is enabled.

Comments

@yuriks
Copy link
Contributor

yuriks commented Oct 15, 2018

Using rustc nightly 2018-10-13 4699283 (from playpen).

I found two cases where lifetimes appear to be extended where they shouldn't:

use std::cell::RefCell;
use std::collections::binary_heap::PeekMut;
use std::collections::BinaryHeap;

fn main() {
    let heap: RefCell<BinaryHeap<u32>> = RefCell::new(BinaryHeap::new());

    let mut heap_ref = heap.borrow_mut();
    let entry = if let Some(entry) = heap_ref.peek_mut() {
        entry
    } else {
        panic!();
    };
    let task = PeekMut::pop(entry);

    //drop(entry);

    drop(heap_ref);
    println!("We made it {:?}, {:?}", heap.borrow_mut(), task);
}

Playpen link

Which gives this error:

error[E0505]: cannot move out of `heap_ref` because it is borrowed
  --> src/main.rs:18:10
   |
9  |     let entry = if let Some(entry) = heap_ref.peek_mut() {
   |                                      -------- borrow of `heap_ref` occurs here
...
18 |     drop(heap_ref);
   |          ^^^^^^^^ move out of `heap_ref` occurs here

Even though the only thing that could be borrowing heap_ref is entry, which has already been moved into the pop() call.


use std::cell::RefCell;
use std::collections::binary_heap::PeekMut;
use std::collections::BinaryHeap;

fn main() {
    let heap: RefCell<BinaryHeap<u32>> = RefCell::new(BinaryHeap::new());

    let task = {
        let mut heap_ref = heap.borrow_mut();
        if let Some(entry) = heap_ref.peek_mut() {
            PeekMut::pop(entry)
        } else {
            panic!();
        }
    };

    println!("We made it {:?}, {:?}", heap.borrow_mut(), task);
}

Playpen link

Which gives this error:

error[E0597]: `heap_ref` does not live long enough
  --> src/main.rs:10:30
   |
10 |         if let Some(entry) = heap_ref.peek_mut() {
   |                              ^^^^^^^^ borrowed value does not live long enough
...
15 |     };
   |     -- borrowed value needs to live until here
   |     |
   |     `heap_ref` dropped here while still borrowed

Where it's complaining that a borrow needs to live until the same point where it's dropped.

@yuriks yuriks changed the title Two cases of confusing lifetime over-extension Two cases of confusing borrow over-extension Oct 15, 2018
@memoryruins
Copy link
Contributor

The first case successfully compiles with #![feature(nll)] or 2018 edition enabled, and the second case gives a more thorough diagnostic when enabled.

15 |     };
   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::option::Option<std::collections::binary_heap::PeekMut<'_, u32>>`
   |     |
   |     `heap_ref` dropped here while still borrowed
   |
   = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.

@pnkfelix
Copy link
Member

There is something about the second diagnostic that is true with and without NLL, and its something I'd like to try to figure out a way to fix:

The presentation of the two different adjacent annotations looks like a single point when you see:

15 |     };
   |     -- borrowed value needs to live until here
   |     |
   |     `heap_ref` dropped here while still borrowed

The diagnostic becomes (IMO) much clearer if you add some spaces between the } and the ;:

15 |     }  ;
   |     -  - borrowed value needs to live until here
   |     |
   |     `heap_ref` dropped here while still borrowed

since now it is much clearer that the usage point comes after the point where it is dropped.

@pnkfelix pnkfelix added the A-NLL Area: Non-lexical lifetimes (NLL) label Oct 16, 2018
@pnkfelix
Copy link
Member

pnkfelix commented Oct 16, 2018

There is also a problem in the presentation of this diagnostic (this time from NLL):

10 |         if let Some(entry) = heap_ref.peek_mut() {
   |                              ^^^^^^^^-----------
   |                              |
   |                              borrowed value does not live long enough
   |                              a temporary with access to the borrow is created here ...

At least to my eye, it is not sufficiently clear which of the two messages one is meant to apply to each of the two overlapping ranges (the ^^^ vs the -----)

@pnkfelix
Copy link
Member

Having said that, I am mostly tempted to tag this with NLL-fixed-by-NLL.

I'll double check with others, perhaps at the meeting tonight.

@pnkfelix pnkfelix added NLL-fixed-by-NLL Bugs fixed, but only when NLL is enabled. A-diagnostics Area: Messages for errors, warnings, and lints labels Oct 16, 2018
bors added a commit that referenced this issue Mar 11, 2019
Enable NLL migrate mode on the 2015 edition

Blocked on #58739

## What is in this PR?

* Remove the `-Zborrowck=ast` flag option from rustc.
* The default in the 2015 edition is now `-Zborrowck=migrate`.
* The 2018 edition default is unchanged: it's still `-Zborrowck=migrate`.
* Enable the `-Ztwo-phase-borrows` flag on all editions.
* Remove most dead code that handled these options.
* Update tests for the above changes.

## What is *not* in this PR?

These are left for future PRs

* Use `-Zborrowck=mir` in NLL compare mode tests
* Remove the `-Zborrowck=compare` option
* Remove the `-Ztwo-phase-borrows` flag. It's kept so that perf.rlo has time to stop using it (cc @Mark-Simulacrum)
* Remove MIR typeck as its own MIR pass - it's now run by NLL.
* Enabling `-Zborrowck=mir` by default

Soundness issues that are fixed by NLL will stay open until full NLL is emitting hard errors. However, these diagnostics and completeness issues can now be closed:

Closes #18330
Closes #22323
Closes #23591
Closes #26736
Closes #27487
Closes #28092
Closes #28970
Closes #29733
Closes #30104
Closes #38915
Closes #39908
Closes #43407
Closes #47524
Closes #48540
Closes #49073
Closes #52614
Closes #55085
Closes #56093
Closes #56496
Closes #57804

cc #43234

r? @pnkfelix
cc @rust-lang/lang
cc @rust-lang/wg-compiler-nll
bors added a commit that referenced this issue Apr 22, 2019
Enable NLL migrate mode on the 2015 edition

## What is in this PR?

* Remove the `-Zborrowck=ast` flag option from rustc.
* The default in the 2015 edition is now `-Zborrowck=migrate`.
* The 2018 edition default is unchanged: it's still `-Zborrowck=migrate`.
* Enable two-phase borrows (currently toggled via the `-Ztwo-phase-borrows` flag) on all editions.
* Remove most dead code that handled these options.
* Update tests for the above changes.

## What is *not* in this PR?

These are left for future PRs

* Use `-Zborrowck=mir` in NLL compare mode tests (#56993)
* Remove the `-Zborrowck=compare` option (#59193)
* Remove the `-Ztwo-phase-borrows` flag. It's kept, as a flag that does nothing so that perf.rlo has time to stop using it (cc @Mark-Simulacrum)
* Remove MIR typeck as its own MIR pass - it's now run by NLL.
* Enabling `-Zborrowck=mir` by default (#58781)
* Replace `allow_bind_by_move_patterns_with_guards` and `check_for_mutation_in_guard_via_ast_walk` with just using the feature gate. (#59192)

Soundness issues that are fixed by NLL will stay open until full NLL is emitting hard errors. However, these diagnostics and completeness issues can now be closed:

Closes #18330
Closes #22323
Closes #23591
Closes #26736
Closes #27487
Closes #28092
Closes #28970
Closes #29733
Closes #30104
Closes #38915
Closes #39908
Closes #43407
Closes #47524
Closes #48540
Closes #49073
Closes #52614
Closes #55085
Closes #56093
Closes #56496
Closes #57804

cc #43234

r? @pnkfelix
cc @rust-lang/lang
cc @rust-lang/wg-compiler-nll
bors added a commit that referenced this issue Apr 22, 2019
Enable NLL migrate mode on the 2015 edition

## What is in this PR?

* Remove the `-Zborrowck=ast` flag option from rustc.
* The default in the 2015 edition is now `-Zborrowck=migrate`.
* The 2018 edition default is unchanged: it's still `-Zborrowck=migrate`.
* Enable two-phase borrows (currently toggled via the `-Ztwo-phase-borrows` flag) on all editions.
* Remove most dead code that handled these options.
* Update tests for the above changes.

## What is *not* in this PR?

These are left for future PRs

* Use `-Zborrowck=mir` in NLL compare mode tests (#56993)
* Remove the `-Zborrowck=compare` option (#59193)
* Remove the `-Ztwo-phase-borrows` flag. It's kept, as a flag that does nothing so that perf.rlo has time to stop using it (cc @Mark-Simulacrum)
* Remove MIR typeck as its own MIR pass - it's now run by NLL.
* Enabling `-Zborrowck=mir` by default (#58781)
* Replace `allow_bind_by_move_patterns_with_guards` and `check_for_mutation_in_guard_via_ast_walk` with just using the feature gate. (#59192)

Soundness issues that are fixed by NLL will stay open until full NLL is emitting hard errors. However, these diagnostics and completeness issues can now be closed:

Closes #18330
Closes #22323
Closes #23591
Closes #26736
Closes #27487
Closes #28092
Closes #28970
Closes #29733
Closes #30104
Closes #38915
Closes #39908
Closes #43407
Closes #47524
Closes #48540
Closes #49073
Closes #52614
Closes #55085
Closes #56093
Closes #56496
Closes #57804

cc #43234

r? @pnkfelix
cc @rust-lang/lang
cc @rust-lang/wg-compiler-nll
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-NLL Area: Non-lexical lifetimes (NLL) NLL-fixed-by-NLL Bugs fixed, but only when NLL is enabled.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants