You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello, it is perfectly sound to move out of &'static mut T and have that reference consumed, as no safe code can access T under the reference after that point.
@Ddystopia your take does not move out, it does a typed copy. The demonstration you want to write cannot be written in surface Rust because you can't get past the compiler frontend. That's the whole point of this issue.
In any case, I think the basic reasoning here is wrong: The 'static bound doesn't help because you can reborrow a &'static mut into another &'static mut.
If the following entirely safe code were to be allowed to compile, we would have access to a moved-from value:
#[derive(Debug)]structNotCopy(u8);fnmain(){let x:&'staticmutNotCopy = Box::leak(Box::new(NotCopy(0u8)));let y:&'staticmutNotCopy = &mut*x;let z = *y;println!("{:?}",*x);// oops, use of moved-from value}
The reborrow used to create y makes x unsuable for 'static (forever). The state of x after the move is akin to how replace_with functions. Or std::mem::replace (for the duration of the method body), for that matter.
I personally don't feel there are strong enough upsides for language support, e.g. DerefMove for &'static mut T. But either (the originally posted) fn take is sound or replace_with is unsound.
replace_with isn't available on the playground or I'd link a runnable example. But an example usage is
let foo:&'staticmutNotDefaultNotCopy = Box::leak(Box::new(NotDefaultNotCopy([1;20])));let reborrowed_even = &mut*foo;let foo_taken = take(reborrowed_even);println!("{:?}", foo_taken.0);// Trying to use `foo` is an error because `*foo` is exclusively reborrowed forever
Reacted by Ben Kimock, e2-71828, Aurelia Molzer and Giacomo Stevanato
which will not break anything and apparently sound.
There was a potentially breaking use case in the RFC thread, depending on how the decision goes. As far as I know there hasn't been an FCP on the topic. That said, opinions did seem favorable on the side of this being sound.
That RFC was closed in part due to concerns about adding an API that aborts. I will note that a proposal to add a function like take in the OP (which is limited to the &'static mut _ case) also gives an opportunity to bless the operation as sound without introducing an aborting API (and without trying to tackle unwinding as a whole).
Blessing this operation means that every &'static mut T can bet converted into a newtype which is analogous to a &'static mut Option<T> (which you can move T into and, conditionally, out of; conditionally borrow; etc).
Activity
workingjubilee commentedon Jun 1, 2024
Miri also doesn't complain about this program, one which is surely not what you intend: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=4a15c73887bce9565554ebf5b12e3627
saethlin commentedon Jun 1, 2024
@Ddystopia your
takedoes not move out, it does a typed copy. The demonstration you want to write cannot be written in surface Rust because you can't get past the compiler frontend. That's the whole point of this issue.To write the demo you want, you must use custom MIR: https://doc.rust-lang.org/nightly/std/intrinsics/mir/index.html
QuineDot commentedon Jun 1, 2024
Original(?) discussion started here.
saethlin commentedon Jun 1, 2024
In any case, I think the basic reasoning here is wrong: The
'staticbound doesn't help because you can reborrow a&'static mutinto another&'static mut.If the following entirely safe code were to be allowed to compile, we would have access to a moved-from value:
QuineDot commentedon Jun 2, 2024
The reborrow used to create
ymakesxunsuable for'static(forever). The state ofxafter the move is akin to howreplace_withfunctions. Orstd::mem::replace(for the duration of the method body), for that matter.There's more discussion in this RFC thread.
I personally don't feel there are strong enough upsides for language support, e.g.
DerefMovefor&'static mut T. But either (the originally posted)fn takeis sound orreplace_withis unsound.replace_withisn't available on the playground or I'd link a runnable example. But an example usage issaethlin commentedon Jun 2, 2024
Thanks for the correction!
Ddystopia commentedon Jun 2, 2024
I do agree that there might not be urging need for this, but it sometimes might be useful during embedded development and if something will change with borrow checker's attitude to moving out of mutable references, then it might not take a lot of extra work to consider adding this feature, which will not break anything and apparently sound.
QuineDot commentedon Jun 2, 2024
There was a potentially breaking use case in the RFC thread, depending on how the decision goes. As far as I know there hasn't been an FCP on the topic. That said, opinions did seem favorable on the side of this being sound.
That RFC was closed in part due to concerns about adding an API that aborts. I will note that a proposal to add a function like
takein the OP (which is limited to the&'static mut _case) also gives an opportunity to bless the operation as sound without introducing an aborting API (and without trying to tackle unwinding as a whole).Blessing this operation means that every
&'static mut Tcan bet converted into a newtype which is analogous to a&'static mut Option<T>(which you can moveTinto and, conditionally, out of; conditionally borrow; etc).LunarLambda commentedon Jun 2, 2024
WaffleLapkin commentedon Jun 2, 2024
LunarLambda commentedon Jun 2, 2024
WaffleLapkin commentedon Jun 2, 2024
LunarLambda commentedon Jun 2, 2024
WaffleLapkin commentedon Jun 2, 2024
LunarLambda commentedon Jun 2, 2024
Ddystopia commentedon Jun 2, 2024
Thank you for note! Here is another example, which is closer to what I wanted to demonstrate playground
I also tried custom MIR, but compiler kept ICE-ing and I gave up
RalfJung commentedon Jun 10, 2024
I agree that this is sound:
It would be fairly easy to prove this in Rustbelt as well.
Not sure if it's worth having special support for this in the borrow checker, a dedicated method seems more clear / less magic to me.