Skip to content

Tree Borrows: Two-phase borrows + interior mutability have surprising interactions #501

Open
@RalfJung

Description

@RalfJung

Consider this function:

pub fn f(xr : &mut Cell<i32>) -> i32 {
    *xr = Cell::new(-1);
    shouldnt_escape(&mut *xr);
    *xr = Cell::new(1337); // the write should invalidate all children
    do_something();
    xr.get() // ...so the compiler should be able to optimize
             // this to return 1337
}

If this was an &mut i32 reference, then the *xr = ... assignment would invalidate all child references and hence we could rely on do_something not being able to use anything derived from the reference passed to shouldnt_escape.

But it turns out under current Tree Borrows rules, that optimization would be wrong, as demonstrated by this example (due to @JoJoDeveloping).

The reason this works is that two-phase mutable references to !Freeze types in their reservation stage accept foreign write accesses. This is necessary to make code like this (entirely safe code!) not UB.

This is probably undesirable. But I am not sure what the best way is to make the safe code example allowed but make the counterexample for the optimization above have UB.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-aliasing-modelTopic: Related to the aliasing model (e.g. Stacked/Tree Borrows)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions