Allow references to interior mutable data behind a feature gate by oli-obk · Pull Request #80418 · rust-lang/rust (original) (raw)
Having no
StorageDead
can also arise because there was noStorageLive
, either.
Afaict, in constants, that's not an issue, and even if it were, all that would mean is that our check forbids more things than we want. That's ok, we can be more permissive later.
And how does the referent matter, isn't if the reference for which we care if it ends up in the final value? When we see an expression
let _x = &var.field.field
, we care about whether the reference ends up in the final value, so how does looking atvar
tell us anything about that...?!? I am confused.^^Unless you mean we are checking the
_x
(I haven't though that one though), but you keep saying "reference of locals that have no StorageDead", which to me means you are checkingvar
, not_x
.Some examples could help. :)
Heh, ok, yea, I see the misunderstanding, and it is exactly the problem I had with building a static analyis for this until eddyb gave me the enlightening clue. Let's start with an example:
const FOO: &Cell = &Cell::new(42);
expands to something like the following MIR:
StorageLive(_2) _2 = 42; StorageLIve(_1) _1 = Cell::new(42) -> bb2
bb2: StorageDead(_2) _0 = &_1 return
Now, you are right, _0
has neither StorageLive
nor StorageDead
, as its storage is handled by the "caller" (at least in a normal function). Similarly function arguments have no storage markers. The problematic operation in the above example is the &_1
, as that creates a &'static Cell<i32>
within a constant. And we know it's 'static
, because of the escaping scopes rule: _1
's scope is 'static
, because it is a temporary in the trailing expression of a constant. Thus it also has no StorageDead
marker. All this PR does is forbid Rvalue::Ref
if the local (_1
in our case) has no StorageDead
markers and the local's type (Cell::<i32>
in this case) has interior mutability. By the way MIR is built, we know that this can only happen for the escaping locals. Our dynamic checks for dangling pointers do the same thing, but dynamically. They check whether the allocation still exists at the end. The only way that can happen is if they do not have a StorageDead
statement.
So with this new analysis, you either get a hard error because you tried to take a reference to a local that has interior mutability and lives forever, or you get a validation error later because you created a dangling pointer. We can talk about dangling pointers independently, they are entirely orthogonal to preventing references to interior mutable data in constants. You can create the easily without having to do anything related to (interior) mutability.