Repository navigation
MIR-borrowck: behavior around Box<T> is different from AST borrowck #45696
Description
Activity
- addedA-borrow-checkerArea: The borrow checkerArea: The borrow checker
on Nov 1, 2017 I think we have to decide how we are going to handle
Box<T>in MIR borrowck. I would prefer not to introduce hacks into borrowck the way we did in the AST -- if we're going to impose some limitations onBox<T>, I would prefer to do it in the MIR lowering phase (e.g., by loweringlet x = &mut box.foomore faithfully into something that uses theDerefMutimpl).What do you think @arielb1 ? I imagine this will cause more backwards incompatibility on the various corner cases that AST borrow check gets wrong, is one concern.
An alternative of course is to restore the "full knowledge" to
Box<T>-- it's already somewhat special -- with the assumption that we will someday allow user-written types to "opt-in" to such semantics.I would prefer to have "full
DerefPure" semantics forBox. We already have fairly builtin move semantics, and the AST borrowck semantics are terrible in a few places.@arielb1 I agree. It seems like then there is not a lot of work to do here, right? Or are there places where MIR borrowck enforces rules that are too strict?
I think MIR borrowck currently has an even stupider version of the Box borrow rules, which needs to be removed.
I'm going to try writing out some tests here in the comments and their current behavior.
Access field 1 while field 0 is borrowed
fn main() { let mut data = Box::new((1, 2)); let p = &data.0; data.1 += 1; }
This gives an Ast error, but no Mir error, as expected.
Drop box while field 0 is borrowed
fn main() { let mut data = Box::new((1, 2)); let p = &data.0; drop(data); println!("{}", p); }This gives an error in both AST / MIR, as expected.
Access field 1 when field 0 is borrowed
fn main() { let data = Box::new((format!("Hello"), format!("World"))); drop(data.0); println!("{}", data.1); }This gives an error only in AST, as expected.
Return reborrowed mutable ref in field 0
fn return_borrowed<'a>(x: Box<(&'a mut u32, &mut u32)>) -> &'a mut u32 { &mut *x.0 } fn main() { }This gives an error only in MIR. Seems wrong.
(Ironically, both AST and MIR seem wrong here. That is, to be consistent, AST should error, but doesn't. And MIR should not, but does.)
The last error is of course nikomatsakis/nll-rfc#40. I still like the dangly paths answer there, but I do appreciate and understand @arielb1's trepidation. Perhaps we just do some kind of limited variant hard-coded to
Boxfor now. =)The last error is of course nikomatsakis/nll-rfc#40
It is. However, luckily for us,
BoxisDerefPure, which means that we "known" its destructor can't access the interior (after all, the interior could have been moved), so this looks like a clearer place to special-case.20 remaining items
(okay now PR #52782 is a change I'm pretty confident in. And as a bonus it also passes the test suite.)
- added a commit that references this issue
on Aug 2, 2018 see also some follow-up discussion here #43234 (comment)
MIR borrowck treats
Box<T>differently from AST borrowck (not that AST borrowck is terribly consistent there), for example, in the (simplified) test for #17263:AST borrowck reports an error on both lines, but MIR borrowck lets the code pass:
This should be investigated and solved