X-Git-Url: https://git.ralfj.de/web.git/blobdiff_plain/ca35978dfabe2aa7500ee810fc5deb80078afc68..84910fa9a1ba32d4c948ebe7a1e88f8cd4e79fa4:/ralf/_posts/2019-04-30-stacked-borrows-2.md?ds=sidebyside diff --git a/ralf/_posts/2019-04-30-stacked-borrows-2.md b/ralf/_posts/2019-04-30-stacked-borrows-2.md index dec44ed..669d49d 100644 --- a/ralf/_posts/2019-04-30-stacked-borrows-2.md +++ b/ralf/_posts/2019-04-30-stacked-borrows-2.md @@ -16,13 +16,13 @@ Before we start, let me give a brief overview over the posts on Stacked Borrows I didn't plan this out in advance, so things are a bit more messy than I would like. * [Stacked Borrows: An Aliasing Model For Rust]({% post_url 2018-08-07-stacked-borrows %}) is the first post of the series and describes my initial ideas of what Stacked Borrows would look like before I started implementing them. It might be interesting for some of the context it gives, but is largely superseded by the next post. -* [Stacked Borrows Implemented]({% post_url 2018-11-16-stacked-borrows-implementation %}) describes Stacked Borrows 1 and my experience implementing it. It is self-contained; I was not happy with some of my explanations in the original post so I decided to give it another shot. This is the best post to start with, if you are catching up. +* [Stacked Borrows Implemented]({% post_url 2018-11-16-stacked-borrows-implementation %}) describes Stacked Borrows 1 and my experience implementing it. It is self-contained; I was not happy with some of my explanations in the original post so I decided to give it another shot. **This is the post to read if you are catching up.** * [Barriers and Two-phase Borrows in Stacked Borrows]({% post_url 2018-12-26-stacked-borrows-barriers %}) describes how I extended Stacked Borrows 1 with partial support for two-phase borrows and explains the idea of "barriers". You do not have to have read that post to understand Stacked Borrows 2, except for the parts that specifically refer to barriers and two-phase borrows. ## The problem The problem I wanted to solve with Stacked Borrows 2 was that the first version of Stacked Borrows only performed very little tracking of shared references. -My thinking was, if the location is read-only anyway, then it does not harm to grant anyone read access. +My thinking was, if the location is read-only anyway, then it is not harmful to grant anyone read access. However, [as @arielby noted](https://github.com/rust-lang/unsafe-code-guidelines/issues/87), this leads to loss of optimization potential in cases where a function receives a mutable reference (which is supposed to have no aliases) and then creates a shared reference from it: {% highlight rust %} fn main() { @@ -35,7 +35,7 @@ fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; // This freezes `*a`. Frozen locations can be read by any raw pointer. let _val = unsafe { *y; }; // Hence, this legal in Stacked Borrows. - *a = 2; // But we might want to drop the earlier `*a = 1` because it gets overwritten by this! + *a = 2; // But we might want to drop the earlier `*a = 1` because it gets overwritten! _val } {% endhighlight %} @@ -80,7 +80,7 @@ pub struct Stack { {% endhighlight %} The *tag* is also simpler than it was before: there are no longer separate tags for mutable and shared references. {% highlight rust %} -pub type PtrId = NonZeroU64; +pub type PtrId = u64; pub enum Tag { Tagged(PtrId), Untagged, @@ -209,7 +209,7 @@ fn foo(a: &mut u32, y: *mut u32) -> u32 { {% endhighlight %} Initially, `x` with tag `Tagged(0)` is the only reference, and the stack says that this is the only pointer with any kind of permission. Next, we cast `x` to a raw pointer. -The raw retagging of `p` turns `p` into an `Untagged` pointer, and adds a new item granting thusly tagged pointers `SharedReadWrite` permission. +The raw retagging of `p` turns `p` into an `Untagged` pointer, and adds a new item granting `Untagged` pointers `SharedReadWrite` permission. (Really, in the MIR it will say `&mut *x as *mut u32`, so there will be an additional `Unique` permission for the temporary mutable reference, but that makes no difference and I hope [we will change that eventually](https://github.com/rust-lang/rfcs/pull/2582).) Then `foo` gets called, which starts with the usual retagging of all reference arguments.