Skip to content

Commit bb7fb62

Browse files
committed
glib: Only auto-impl Send+Sync for subclasses if the parent type does
Previously a `Send+Sync` subclass of a `gtk::Widget` would automatically be `Send+Sync` too, which is obviously not allowed. To avoid this, also add the parent type as `PhantomData` to the wrapper struct so that this is considered too. Handle `glib::Object` specially here because while it is not `Send+Sync` itself, subclasses of it can be `Send+Sync` just fine. The only reason why `glib::Object` is not is because there are some subclasses that are not and otherwise this could be circumvented by upcasting.
1 parent e06623f commit bb7fb62

12 files changed

+331
-37
lines changed

glib/src/object.rs

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -598,16 +598,18 @@ impl FromGlibPtrArrayContainerAsVec<*mut GObject, *const *mut GObject> for Objec
598598
}
599599

600600
#[repr(transparent)]
601-
pub struct TypedObjectRef<T> {
601+
pub struct TypedObjectRef<T, P> {
602602
inner: ObjectRef,
603-
phantom: PhantomData<T>,
603+
imp: PhantomData<T>,
604+
parent: PhantomData<P>,
604605
}
605606

606-
impl<T> TypedObjectRef<T> {
607+
impl<T, P> TypedObjectRef<T, P> {
607608
pub unsafe fn new(obj: ObjectRef) -> Self {
608609
Self {
609610
inner: obj,
610-
phantom: PhantomData,
611+
imp: PhantomData,
612+
parent: PhantomData,
611613
}
612614
}
613615

@@ -616,24 +618,25 @@ impl<T> TypedObjectRef<T> {
616618
}
617619
}
618620

619-
impl<T> Clone for TypedObjectRef<T> {
621+
impl<T, P> Clone for TypedObjectRef<T, P> {
620622
fn clone(&self) -> Self {
621623
Self {
622624
inner: self.inner.clone(),
623-
phantom: PhantomData,
625+
imp: PhantomData,
626+
parent: PhantomData,
624627
}
625628
}
626629
}
627630

628-
impl<T> ops::Deref for TypedObjectRef<T> {
631+
impl<T, P> ops::Deref for TypedObjectRef<T, P> {
629632
type Target = ObjectRef;
630633

631634
fn deref(&self) -> &Self::Target {
632635
&self.inner
633636
}
634637
}
635638

636-
impl<T> fmt::Debug for TypedObjectRef<T> {
639+
impl<T, P> fmt::Debug for TypedObjectRef<T, P> {
637640
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638641
let type_ = unsafe {
639642
let klass = (*self.inner.inner.as_ptr()).g_type_instance.g_class as *const ObjectClass;
@@ -647,27 +650,27 @@ impl<T> fmt::Debug for TypedObjectRef<T> {
647650
}
648651
}
649652

650-
impl<T> PartialOrd for TypedObjectRef<T> {
653+
impl<T, P> PartialOrd for TypedObjectRef<T, P> {
651654
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
652655
self.inner.partial_cmp(&other.inner)
653656
}
654657
}
655658

656-
impl<T> Ord for TypedObjectRef<T> {
659+
impl<T, P> Ord for TypedObjectRef<T, P> {
657660
fn cmp(&self, other: &Self) -> cmp::Ordering {
658661
self.inner.cmp(&other.inner)
659662
}
660663
}
661664

662-
impl<T> PartialEq for TypedObjectRef<T> {
665+
impl<T, P> PartialEq for TypedObjectRef<T, P> {
663666
fn eq(&self, other: &Self) -> bool {
664667
self.inner == other.inner
665668
}
666669
}
667670

668-
impl<T> Eq for TypedObjectRef<T> {}
671+
impl<T, P> Eq for TypedObjectRef<T, P> {}
669672

670-
impl<T> hash::Hash for TypedObjectRef<T> {
673+
impl<T, P> hash::Hash for TypedObjectRef<T, P> {
671674
fn hash<H>(&self, state: &mut H)
672675
where
673676
H: hash::Hasher,
@@ -676,18 +679,18 @@ impl<T> hash::Hash for TypedObjectRef<T> {
676679
}
677680
}
678681

679-
unsafe impl<T: Send + Sync> Send for TypedObjectRef<T> {}
680-
unsafe impl<T: Send + Sync> Sync for TypedObjectRef<T> {}
682+
unsafe impl<T: Send + Sync, P: Send + Sync> Send for TypedObjectRef<T, P> {}
683+
unsafe impl<T: Send + Sync, P: Send + Sync> Sync for TypedObjectRef<T, P> {}
681684

682685
// rustdoc-stripper-ignore-next
683686
/// ObjectType implementations for Object types. See `wrapper!`.
684687
#[macro_export]
685688
macro_rules! glib_object_wrapper {
686-
(@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type: ty, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
689+
(@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
687690
$(#[$attr])*
688691
#[repr(transparent)]
689692
$visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? {
690-
inner: $crate::object::TypedObjectRef<$inner_type>,
693+
inner: $crate::object::TypedObjectRef<$impl_type, $parent_type>,
691694
phantom: std::marker::PhantomData<($($($generic),+)?)>,
692695
}
693696

@@ -1182,27 +1185,27 @@ macro_rules! glib_object_wrapper {
11821185

11831186
// This case is only for glib::Object itself below. All other cases have glib::Object in its
11841187
// parent class list
1185-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
1188+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
11861189
$crate::glib_object_wrapper!(
1187-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
1190+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, $ffi_class_name,
11881191
@type_ $get_type_expr);
11891192

11901193
#[doc(hidden)]
11911194
unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsClass for $name $(<$($generic),+>)? { }
11921195
};
11931196

1194-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty,
1197+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty,
11951198
@type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
11961199
$crate::glib_object_wrapper!(
1197-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, @ffi_class std::os::raw::c_void,
1200+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, @ffi_class std::os::raw::c_void,
11981201
@type_ $get_type_expr, @extends [$($extends)*], @implements [$($implements)*]
11991202
);
12001203
};
12011204

1202-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
1205+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
12031206
@type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
12041207
$crate::glib_object_wrapper!(
1205-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
1208+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, $ffi_class_name,
12061209
@type_ $get_type_expr
12071210
);
12081211

@@ -1224,11 +1227,29 @@ macro_rules! glib_object_wrapper {
12241227
unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsClass for $name $(<$($generic),+>)? { }
12251228
};
12261229

1230+
// FIXME: Workaround for `glib::Object` not being `Send+Sync` but subclasses of it being both
1231+
// if the impl struct is.
1232+
(@object_subclass [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $subclass:ty,
1233+
@extends [], @implements [$($implements:tt)*]) => {
1234+
$crate::glib_object_wrapper!(
1235+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?,
1236+
$subclass, (),
1237+
<$subclass as $crate::subclass::types::ObjectSubclass>::Instance,
1238+
@ffi_class <$subclass as $crate::subclass::types::ObjectSubclass>::Class,
1239+
@type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()),
1240+
@extends [], @implements [$($implements)*]
1241+
);
1242+
1243+
unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ObjectSubclassIs for $name $(<$($generic),+>)? {
1244+
type Subclass = $subclass;
1245+
}
1246+
};
1247+
12271248
(@object_subclass [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $subclass:ty,
1228-
@extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
1249+
@extends [$($extends:tt)+], @implements [$($implements:tt)*]) => {
12291250
$crate::glib_object_wrapper!(
12301251
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?,
1231-
$subclass,
1252+
$subclass, <$subclass as $crate::subclass::types::ObjectSubclass>::ParentType,
12321253
<$subclass as $crate::subclass::types::ObjectSubclass>::Instance,
12331254
@ffi_class <$subclass as $crate::subclass::types::ObjectSubclass>::Class,
12341255
@type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()),
@@ -1240,18 +1261,18 @@ macro_rules! glib_object_wrapper {
12401261
}
12411262
};
12421263

1243-
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty,
1264+
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $ffi_name:ty,
12441265
@type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => {
12451266
$crate::glib_object_wrapper!(
1246-
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, @ffi_class std::os::raw::c_void,
1267+
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $ffi_name, @ffi_class std::os::raw::c_void,
12471268
@type_ $get_type_expr, @requires [$($requires)*]
12481269
);
12491270
};
12501271

1251-
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
1272+
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
12521273
@type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => {
12531274
$crate::glib_object_wrapper!(
1254-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
1275+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, (), $ffi_name, $ffi_class_name,
12551276
@type_ $get_type_expr
12561277
);
12571278
$crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($requires)*);
@@ -1273,7 +1294,7 @@ macro_rules! glib_object_wrapper {
12731294

12741295
glib_object_wrapper!(@object
12751296
[doc = "The base class in the object hierarchy."]
1276-
pub Object, *mut std::os::raw::c_void, GObject, @ffi_class GObjectClass, @type_ gobject_ffi::g_object_get_type()
1297+
pub Object, *mut std::os::raw::c_void, (), GObject, @ffi_class GObjectClass, @type_ gobject_ffi::g_object_get_type()
12771298
);
12781299
pub type ObjectClass = Class<Object>;
12791300

glib/src/wrapper.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ macro_rules! wrapper {
363363
}
364364
) => {
365365
$crate::glib_object_wrapper!(
366-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
366+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name,
367367
$( @ffi_class $ffi_class_name ,)?
368368
@type_ $get_type_expr,
369369
@extends [],
@@ -381,7 +381,7 @@ macro_rules! wrapper {
381381
}
382382
) => {
383383
$crate::glib_object_wrapper!(
384-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
384+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name,
385385
$( @ffi_class $ffi_class_name ,)?
386386
@type_ $get_type_expr,
387387
@extends [$($extends),+],

glib/tests/subclass_compiletest.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ pub fn test() {
55
t.pass("tests/subclass_compiletest/01-auto-send-sync.rs");
66
t.compile_fail("tests/subclass_compiletest/02-no-auto-send-sync.rs");
77
t.compile_fail("tests/subclass_compiletest/03-object-no-auto-send-sync.rs");
8+
t.pass("tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs");
9+
t.compile_fail("tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs");
10+
t.compile_fail(
11+
"tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs",
12+
);
813
}

glib/tests/subclass_compiletest/01-auto-send-sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod imp {
1212
type Type = super::TestObject;
1313
}
1414

15-
impl ObjectImpl for TestObject { }
15+
impl ObjectImpl for TestObject {}
1616
}
1717

1818
glib::wrapper! {

glib/tests/subclass_compiletest/02-no-auto-send-sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod imp {
1313
type Type = super::TestObject;
1414
}
1515

16-
impl ObjectImpl for TestObject { }
16+
impl ObjectImpl for TestObject {}
1717
}
1818

1919
glib::wrapper! {

glib/tests/subclass_compiletest/02-no-auto-send-sync.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ note: required because it appears within the type `imp::TestObject`
1212
|
1313
6 | pub struct TestObject {
1414
| ^^^^^^^^^^
15-
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<imp::TestObject>`
15+
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<imp::TestObject, ()>`
1616
note: required because it appears within the type `TestObject`
1717
--> tests/subclass_compiletest/02-no-auto-send-sync.rs:20:16
1818
|

glib/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ error[E0277]: `*mut c_void` cannot be sent between threads safely
77
| required by a bound introduced by this call
88
|
99
= help: the trait `Send` is not implemented for `*mut c_void`
10-
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<*mut c_void>`
10+
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<*mut c_void, ()>`
1111
= note: required because it appears within the type `Object`
1212
note: required by a bound in `main::check`
1313
--> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:2:17
@@ -24,7 +24,7 @@ error[E0277]: `*mut c_void` cannot be shared between threads safely
2424
| required by a bound introduced by this call
2525
|
2626
= help: the trait `Sync` is not implemented for `*mut c_void`
27-
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<*mut c_void>`
27+
= note: required because of the requirements on the impl of `Send` for `TypedObjectRef<*mut c_void, ()>`
2828
= note: required because it appears within the type `Object`
2929
note: required by a bound in `main::check`
3030
--> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:2:17
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
mod imp_parent {
2+
use glib::subclass::prelude::*;
3+
4+
#[derive(Default)]
5+
pub struct TestParent {
6+
s: String,
7+
}
8+
9+
#[glib::object_subclass]
10+
impl ObjectSubclass for TestParent {
11+
const NAME: &'static str = "TestParent";
12+
type Type = super::TestParent;
13+
}
14+
15+
impl ObjectImpl for TestParent {}
16+
}
17+
18+
glib::wrapper! {
19+
pub struct TestParent(ObjectSubclass<imp_parent::TestParent>);
20+
}
21+
22+
pub trait TestParentImpl: glib::subclass::prelude::ObjectImpl + Send + Sync {}
23+
24+
unsafe impl<T: TestParentImpl> glib::subclass::prelude::IsSubclassable<T> for TestParent {}
25+
26+
impl Default for TestParent {
27+
fn default() -> Self {
28+
glib::Object::new(&[]).unwrap()
29+
}
30+
}
31+
32+
mod imp_object {
33+
use glib::subclass::prelude::*;
34+
35+
#[derive(Default)]
36+
pub struct TestObject {
37+
s: String,
38+
}
39+
40+
#[glib::object_subclass]
41+
impl ObjectSubclass for TestObject {
42+
const NAME: &'static str = "TestObject";
43+
type Type = super::TestObject;
44+
type ParentType = super::TestParent;
45+
}
46+
47+
impl ObjectImpl for TestObject {}
48+
impl super::TestParentImpl for TestObject {}
49+
}
50+
51+
glib::wrapper! {
52+
pub struct TestObject(ObjectSubclass<imp_object::TestObject>) @extends TestParent;
53+
}
54+
55+
impl Default for TestObject {
56+
fn default() -> Self {
57+
glib::Object::new(&[]).unwrap()
58+
}
59+
}
60+
61+
fn main() {
62+
fn check<T: Send + Sync>(_obj: &T) {}
63+
64+
let obj = TestParent::default();
65+
check(&obj);
66+
67+
let obj = TestObject::default();
68+
check(&obj);
69+
}

0 commit comments

Comments
 (0)