Skip to content

Commit 81a33a3

Browse files
committed
Test subtyping relation break (skipped) + Gd::eq() on dead objects
1 parent 48b509a commit 81a33a3

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

godot-core/src/obj/gd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl<T: GodotClass> Gd<T> {
220220
// Initialize instance ID cache
221221
let id = unsafe { interface_fn!(object_get_instance_id)(obj.obj_sys()) };
222222
let instance_id = InstanceId::try_from_u64(id)
223-
.expect("instance ID must be non-zero at time of initialization");
223+
.expect("Gd initialization failed; did you call share() on a dead instance?");
224224
obj.cached_instance_id.set(Some(instance_id));
225225

226226
obj
@@ -452,7 +452,7 @@ where
452452
// If ref_counted returned None, that means the instance was destroyed
453453
assert!(
454454
ref_counted == Some(false) && self.is_instance_valid(),
455-
"called free() on already destroyed obj"
455+
"called free() on already destroyed object"
456456
);
457457

458458
// This destroys the Storage instance, no need to run destructor again

itest/rust/src/object_test.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use godot::obj::{Inherits, Share};
1515
use godot::sys::GodotFfi;
1616

1717
use std::cell::RefCell;
18+
use std::mem;
1819
use std::rc::Rc;
1920

2021
// TODO:
@@ -33,6 +34,39 @@ fn object_construct_value() {
3334
assert_eq!(obj.bind().value, 222);
3435
}
3536

37+
// TODO(#23): DerefMut on Gd pointer may be used to break subtyping relations
38+
#[itest(skip)]
39+
fn object_subtype_swap() {
40+
let mut a: Gd<Node> = Node::new_alloc();
41+
let mut b: Gd<Node3D> = Node3D::new_alloc();
42+
43+
/*
44+
let a_id = a.instance_id();
45+
let b_id = b.instance_id();
46+
let a_class = a.get_class();
47+
let b_class = b.get_class();
48+
49+
dbg!(a_id);
50+
dbg!(b_id);
51+
dbg!(&a_class);
52+
dbg!(&b_class);
53+
println!("..swap..");
54+
*/
55+
56+
mem::swap(&mut *a, &mut *b);
57+
58+
/*
59+
dbg!(a_id);
60+
dbg!(b_id);
61+
dbg!(&a_class);
62+
dbg!(&b_class);
63+
*/
64+
65+
// This should not panic
66+
a.free();
67+
b.free();
68+
}
69+
3670
#[itest]
3771
fn object_user_roundtrip_return() {
3872
let value: i16 = 17943;
@@ -192,6 +226,31 @@ fn object_engine_eq() {
192226
b1.free();
193227
}
194228

229+
#[itest]
230+
fn object_dead_eq() {
231+
let a = Node3D::new_alloc();
232+
let b = Node3D::new_alloc();
233+
let b2 = b.share();
234+
235+
// Destroy b1 without consuming it
236+
b.share().free();
237+
238+
{
239+
let lhs = a.share();
240+
expect_panic("Gd::eq() panics when one operand is dead", move || {
241+
let _ = lhs == b;
242+
});
243+
}
244+
{
245+
let rhs = a.share();
246+
expect_panic("Gd::ne() panics when one operand is dead", move || {
247+
let _ = b2 != rhs;
248+
});
249+
}
250+
251+
a.free();
252+
}
253+
195254
#[itest]
196255
fn object_user_convert_variant() {
197256
let value: i16 = 17943;
@@ -485,7 +544,7 @@ fn object_engine_refcounted_free() {
485544
let node = RefCounted::new();
486545
let node2 = node.share().upcast::<Object>();
487546

488-
expect_panic("calling free() on RefCounted obj", || node2.free())
547+
expect_panic("calling free() on RefCounted object", || node2.free())
489548
}
490549

491550
#[itest]

0 commit comments

Comments
 (0)