forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
REMOVE unsound lifetime annotations on
EntityMut
(bevyengine#4096)
Fixes bevyengine#3408 bevyengine#3001 also solves this but I dont see it getting merged any time soon so... # Objective make bevy ecs a lil bit less unsound ## Solution make `EntityMut::get_component_mut` return borrows from self instead of `'w`
- Loading branch information
Showing
4 changed files
with
178 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
crates/bevy_ecs_compile_fail_tests/tests/ui/entity_ref_mut_lifetime_safety.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
use bevy_ecs::prelude::*; | ||
|
||
#[derive(Component, Eq, PartialEq, Debug)] | ||
struct A(Box<usize>); | ||
|
||
#[derive(Component)] | ||
struct B; | ||
|
||
fn main() { | ||
let mut world = World::default(); | ||
let e = world.spawn().insert(A(Box::new(10_usize))).id(); | ||
|
||
let mut e_mut = world.entity_mut(e); | ||
|
||
{ | ||
let gotten: &A = e_mut.get::<A>().unwrap(); | ||
let gotten2: A = e_mut.remove::<A>().unwrap(); | ||
assert_eq!(gotten, &gotten2); // oops UB | ||
} | ||
|
||
e_mut.insert(A(Box::new(12_usize))); | ||
|
||
{ | ||
let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
let mut gotten2: A = e_mut.remove::<A>().unwrap(); | ||
assert_eq!(&mut *gotten, &mut gotten2); // oops UB | ||
} | ||
|
||
e_mut.insert(A(Box::new(14_usize))); | ||
|
||
{ | ||
let gotten: &A = e_mut.get::<A>().unwrap(); | ||
e_mut.despawn(); | ||
assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB | ||
} | ||
|
||
let e = world.spawn().insert(A(Box::new(16_usize))).id(); | ||
let mut e_mut = world.entity_mut(e); | ||
|
||
{ | ||
let gotten: &A = e_mut.get::<A>().unwrap(); | ||
let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
assert_eq!(gotten, &*gotten_mut); // oops UB | ||
} | ||
|
||
{ | ||
let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
let gotten: &A = e_mut.get::<A>().unwrap(); | ||
assert_eq!(gotten, &*gotten_mut); // oops UB | ||
} | ||
|
||
{ | ||
let gotten: &A = e_mut.get::<A>().unwrap(); | ||
e_mut.insert::<B>(B); | ||
assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB | ||
e_mut.remove::<B>(); | ||
} | ||
|
||
{ | ||
let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
e_mut.insert::<B>(B); | ||
assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
crates/bevy_ecs_compile_fail_tests/tests/ui/entity_ref_mut_lifetime_safety.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:17:26 | ||
| | ||
16 | let gotten: &A = e_mut.get::<A>().unwrap(); | ||
| ---------------- immutable borrow occurs here | ||
17 | let gotten2: A = e_mut.remove::<A>().unwrap(); | ||
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ||
18 | assert_eq!(gotten, &gotten2); // oops UB | ||
| ---------------------------- immutable borrow later used here | ||
|
||
error[E0499]: cannot borrow `e_mut` as mutable more than once at a time | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:25:30 | ||
| | ||
24 | let mut gotten: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
| -------------------- first mutable borrow occurs here | ||
25 | let mut gotten2: A = e_mut.remove::<A>().unwrap(); | ||
| ^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here | ||
26 | assert_eq!(&mut *gotten, &mut gotten2); // oops UB | ||
| ------ first borrow later used here | ||
|
||
error[E0505]: cannot move out of `e_mut` because it is borrowed | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:33:9 | ||
| | ||
32 | let gotten: &A = e_mut.get::<A>().unwrap(); | ||
| ---------------- borrow of `e_mut` occurs here | ||
33 | e_mut.despawn(); | ||
| ^^^^^ move out of `e_mut` occurs here | ||
34 | assert_eq!(gotten, &A(Box::new(14_usize))); // oops UB | ||
| ------------------------------------------ borrow later used here | ||
|
||
error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:42:34 | ||
| | ||
41 | let gotten: &A = e_mut.get::<A>().unwrap(); | ||
| ---------------- immutable borrow occurs here | ||
42 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
| ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ||
43 | assert_eq!(gotten, &*gotten_mut); // oops UB | ||
| -------------------------------- immutable borrow later used here | ||
|
||
error[E0502]: cannot borrow `e_mut` as immutable because it is also borrowed as mutable | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:48:26 | ||
| | ||
47 | let gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
| -------------------- mutable borrow occurs here | ||
48 | let gotten: &A = e_mut.get::<A>().unwrap(); | ||
| ^^^^^^^^^^^^^^^^ immutable borrow occurs here | ||
49 | assert_eq!(gotten, &*gotten_mut); // oops UB | ||
| ---------- mutable borrow later used here | ||
|
||
error[E0502]: cannot borrow `e_mut` as mutable because it is also borrowed as immutable | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:54:9 | ||
| | ||
53 | let gotten: &A = e_mut.get::<A>().unwrap(); | ||
| ---------------- immutable borrow occurs here | ||
54 | e_mut.insert::<B>(B); | ||
| ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here | ||
55 | assert_eq!(gotten, &A(Box::new(16_usize))); // oops UB | ||
| ------------------------------------------ immutable borrow later used here | ||
|
||
error[E0499]: cannot borrow `e_mut` as mutable more than once at a time | ||
--> tests/ui/entity_ref_mut_lifetime_safety.rs:61:9 | ||
| | ||
60 | let mut gotten_mut: Mut<A> = e_mut.get_mut::<A>().unwrap(); | ||
| -------------------- first mutable borrow occurs here | ||
61 | e_mut.insert::<B>(B); | ||
| ^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here | ||
62 | assert_eq!(&mut *gotten_mut, &mut A(Box::new(16_usize))); // oops UB | ||
| ---------- first borrow later used here |