From 7eaf7de2bed8ed300d4a9fc23193c5067066ef7a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 22 Dec 2021 01:50:04 +0100 Subject: [PATCH] Add `unstable_extern_types` feature To see what changes we'd have to make in the library to use `extern type` (RFC-1861) (when it's is stabilized). Unfortunately had to change some usage of `ptr::null[_mut]` to `0 as *const/mut X`, see https://github.com/rust-lang/rust/issues/42847. --- objc-sys/Cargo.toml | 3 +++ objc-sys/src/lib.rs | 13 +++++++++++-- objc2-foundation/Cargo.toml | 2 ++ objc2-foundation/src/lib.rs | 1 + objc2/Cargo.toml | 1 + objc2/src/cache.rs | 4 ++-- objc2/src/declare.rs | 3 +-- objc2/src/exception.rs | 4 ++-- objc2/src/lib.rs | 1 + objc2/src/message/mod.rs | 4 ++-- objc2/src/rc/weak_id.rs | 20 +++++++++++--------- objc2/src/runtime.rs | 2 +- 12 files changed, 38 insertions(+), 20 deletions(-) diff --git a/objc-sys/Cargo.toml b/objc-sys/Cargo.toml index c2adc6fb8..6ba032f47 100644 --- a/objc-sys/Cargo.toml +++ b/objc-sys/Cargo.toml @@ -47,6 +47,9 @@ winobjc = ["gnustep-1-8"] # TODO objfw = [] +# Marks opaque types as !Sized +unstable_extern_types = [] + [package.metadata.docs.rs] default-target = "x86_64-apple-darwin" diff --git a/objc-sys/src/lib.rs b/objc-sys/src/lib.rs index 95b8f035b..e8c432a87 100644 --- a/objc-sys/src/lib.rs +++ b/objc-sys/src/lib.rs @@ -13,6 +13,7 @@ //! [objc4-mirror]: https://github.com/madsmtm/objc4-mirror.git #![no_std] +#![cfg_attr(feature = "unstable_extern_types", feature(extern_types))] #![allow(clippy::upper_case_acronyms)] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] @@ -26,8 +27,11 @@ // See https://github.com/japaric/cty/issues/14. extern crate std; -use core::cell::UnsafeCell; -use core::marker::{PhantomData, PhantomPinned}; +#[cfg(not(feature = "unstable_extern_types"))] +use core::{ + cell::UnsafeCell, + marker::{PhantomData, PhantomPinned}, +}; mod class; mod constants; @@ -63,4 +67,9 @@ pub use various::*; /// (It's also less of a breaking change on our part if we re-add these). /// /// TODO: Replace this with `extern type` to also mark it as `!Sized`. +#[cfg(not(feature = "unstable_extern_types"))] type OpaqueData = PhantomData<(UnsafeCell<()>, *const UnsafeCell<()>, PhantomPinned)>; +#[cfg(feature = "unstable_extern_types")] +extern "C" { + type OpaqueData; +} diff --git a/objc2-foundation/Cargo.toml b/objc2-foundation/Cargo.toml index b5883150e..18a882c6a 100644 --- a/objc2-foundation/Cargo.toml +++ b/objc2-foundation/Cargo.toml @@ -23,6 +23,8 @@ default = ["block"] # Provided as a way to cut down on dependencies block = ["block2"] +unstable_extern_types = ["objc2/unstable_extern_types", "objc-sys/unstable_extern_types"] + [dependencies] # Exact dependencies, because block2 and objc2 are expected to change block2 = { path = "../block2", version = "=0.2.0-alpha.1", optional = true } diff --git a/objc2-foundation/src/lib.rs b/objc2-foundation/src/lib.rs index ee4e95ed0..d6810e81d 100644 --- a/objc2-foundation/src/lib.rs +++ b/objc2-foundation/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![cfg_attr(feature = "unstable_extern_types", feature(extern_types))] #![warn(elided_lifetimes_in_paths)] #![deny(non_ascii_idents)] #![warn(unreachable_pub)] diff --git a/objc2/Cargo.toml b/objc2/Cargo.toml index 55d447cb5..6b322b67f 100644 --- a/objc2/Cargo.toml +++ b/objc2/Cargo.toml @@ -37,6 +37,7 @@ malloc = ["malloc_buf"] # Uses nightly features to make AutoreleasePool zero-cost even in debug mode unstable_autoreleasesafe = [] +unstable_extern_types = ["objc-sys/unstable_extern_types"] [dependencies] malloc_buf = { version = "1.0", optional = true } diff --git a/objc2/src/cache.rs b/objc2/src/cache.rs index 0fd2cb950..ec47a6930 100644 --- a/objc2/src/cache.rs +++ b/objc2/src/cache.rs @@ -39,7 +39,7 @@ impl CachedSel { /// Allows storing a [`Class`] reference in a static and lazily loading it. #[doc(hidden)] pub struct CachedClass { - ptr: AtomicPtr, + ptr: AtomicPtr, } impl CachedClass { @@ -56,7 +56,7 @@ impl CachedClass { #[doc(hidden)] pub unsafe fn get(&self, name: &str) -> Option<&'static Class> { // `Relaxed` should be fine since `objc_getClass` is thread-safe. - let ptr = self.ptr.load(Ordering::Relaxed); + let ptr = self.ptr.load(Ordering::Relaxed) as *const Class; if ptr.is_null() { let cls = unsafe { ffi::objc_getClass(name.as_ptr() as *const _) } as *const Class; self.ptr.store(cls as *mut _, Ordering::Relaxed); diff --git a/objc2/src/declare.rs b/objc2/src/declare.rs index 9bdb02f3a..479db5cf8 100644 --- a/objc2/src/declare.rs +++ b/objc2/src/declare.rs @@ -36,7 +36,6 @@ use alloc::format; use alloc::string::ToString; use core::mem; use core::mem::ManuallyDrop; -use core::ptr; use std::ffi::CString; use crate::runtime::{Bool, Class, Imp, Object, Protocol, Sel}; @@ -137,7 +136,7 @@ unsafe impl Sync for ClassDecl {} impl ClassDecl { fn with_superclass(name: &str, superclass: Option<&Class>) -> Option { let name = CString::new(name).unwrap(); - let super_ptr = superclass.map_or(ptr::null(), |c| c) as _; + let super_ptr = superclass.map_or(0 as *const _, |c| c) as _; let cls = unsafe { ffi::objc_allocateClassPair(super_ptr, name.as_ptr(), 0) }; if cls.is_null() { None diff --git a/objc2/src/exception.rs b/objc2/src/exception.rs index cc72649e1..f388ab291 100644 --- a/objc2/src/exception.rs +++ b/objc2/src/exception.rs @@ -45,7 +45,7 @@ extern "C" { pub unsafe fn throw(exception: Option<&Id>) -> ! { let exception = match exception { Some(id) => &**id as *const Object as *mut ffi::objc_object, - None => ptr::null_mut(), + None => ptr::from_raw_parts_mut(ptr::null_mut(), ()), }; unsafe { ffi::objc_exception_throw(exception) } } @@ -63,7 +63,7 @@ unsafe fn try_no_ret(closure: F) -> Result<(), Option = (&**obj as *const Object).cast(); + let obj = &**obj as *const Object as *const ManuallyDrop; let result: u32 = unsafe { msg_send![obj, foo] }; assert_eq!(result, 4); } diff --git a/objc2/src/rc/weak_id.rs b/objc2/src/rc/weak_id.rs index 509e223b2..ed6be98c8 100644 --- a/objc2/src/rc/weak_id.rs +++ b/objc2/src/rc/weak_id.rs @@ -30,7 +30,7 @@ pub struct WeakId { item: PhantomData>, } -impl WeakId { +impl WeakId { /// Construct a new [`WeakId`] referencing the given shared [`Id`]. #[doc(alias = "objc_initWeak")] pub fn new(obj: &Id) -> Self { @@ -45,7 +45,8 @@ impl WeakId { /// /// The object must be valid or null. unsafe fn new_inner(obj: *mut T) -> Self { - let inner = Box::new(UnsafeCell::new(ptr::null_mut())); + let null = ptr::from_raw_parts_mut(ptr::null_mut(), ()); + let inner = Box::new(UnsafeCell::new(null)); // SAFETY: `ptr` will never move, and the caller verifies `obj` let _ = unsafe { ffi::objc_initWeak(inner.get() as _, obj as _) }; Self { @@ -64,7 +65,8 @@ impl WeakId { #[inline] pub fn load(&self) -> Option> { let ptr: *mut *mut ffi::objc_object = self.inner.get() as _; - let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut T; + let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut (); + let obj: *mut T = ptr::from_raw_parts_mut(obj, ()); NonNull::new(obj).map(|obj| unsafe { Id::new(obj) }) } } @@ -77,12 +79,12 @@ impl Drop for WeakId { } } -// TODO: Add ?Sized -impl Clone for WeakId { +impl Clone for WeakId { /// Makes a clone of the `WeakId` that points to the same object. #[doc(alias = "objc_copyWeak")] fn clone(&self) -> Self { - let ptr = Box::new(UnsafeCell::new(ptr::null_mut())); + let null = ptr::from_raw_parts_mut(ptr::null_mut(), ()); + let ptr = Box::new(UnsafeCell::new(null)); unsafe { ffi::objc_copyWeak(ptr.get() as _, self.inner.get() as _) }; Self { inner: ptr, @@ -91,14 +93,14 @@ impl Clone for WeakId { } } -// TODO: Add ?Sized -impl Default for WeakId { +impl Default for WeakId { /// Constructs a new `WeakId` that doesn't reference any object. /// /// Calling [`Self::load`] on the return value always gives [`None`]. fn default() -> Self { + let null = ptr::from_raw_parts_mut(ptr::null_mut(), ()); // SAFETY: The pointer is null - unsafe { Self::new_inner(ptr::null_mut()) } + unsafe { Self::new_inner(null) } } } diff --git a/objc2/src/runtime.rs b/objc2/src/runtime.rs index 3a3e388d9..d60f6ad20 100644 --- a/objc2/src/runtime.rs +++ b/objc2/src/runtime.rs @@ -341,7 +341,7 @@ impl Class { let name = CString::new(name).unwrap(); let ivar = unsafe { ffi::class_getClassVariable(self.as_ptr(), name.as_ptr()) }; // SAFETY: TODO - unsafe { ivar.cast::().as_ref() } + unsafe { (ivar as *const Ivar).as_ref() } } /// Describes the instance methods implemented by self.