|
|
|
|
|
by Arnavion
1911 days ago
|
|
Not amelius, but one case that happened to me is that Rust requires wrapping a `T` in a `RefCell` if two closures use it as `&mut T`. This happens even if you the caller know that the closures are invoked from a single thread and do not invoke each other, and thus only one `&mut T` will be in effect at any time. This is because closures are effectively structs with the captures as fields, so both struct values (and thus both `&mut` borrows) exist at the same time even though their respective fields are not used at the same time. Not only do you have to use `RefCell`, but you now also have panicking code when the `RefCell` borrow "fails", even though you know it can't. rustc is also not smart enough to notice the exclusivity at compile-time and elid away the RefCell borrow flag test and the panic branch. fn foo(mut cb1: impl FnMut(), mut cb2: impl FnMut()) {
for _ in 0..10 {
cb1();
cb2();
}
}
let mut x = String::new();
foo(|| x.push_str("cb1,"), || x.push_str("cb2,"));
https://play.rust-lang.org/?version=stable&mode=debug&editio...Fixed using `RefCell`: https://play.rust-lang.org/?version=stable&mode=release&edit... . Inspect the ASM and trace the use of the string constant "already borrowed"; you'll see it being used for the borrow flag test because it wasn't elided. The equivalent non-Rust program could use String pointers for the two closures. I'm not sure whether they could be noalias or not, but at the very least they wouldn't need to generate any panicking code. |
|