Skip to content

Commit

Permalink
Disallow Drop impls in extern_class!
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Nov 22, 2024
1 parent cba6c97 commit b43b4be
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 1 deletion.
20 changes: 20 additions & 0 deletions crates/objc2/src/__macro_helpers/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ impl<Cls: ?Sized + MainThreadOnly + Send> MainThreadOnlyDoesNotImplSendSync<Impl
struct ImplsSync;
impl<Cls: ?Sized + MainThreadOnly + Sync> MainThreadOnlyDoesNotImplSendSync<ImplsSync> for Cls {}

/// Check that class does not implement `Drop`.
///
/// This is not needed for soundness, it's just a nice footgun to avoid (since
/// it wouldn't ever get called).
///
/// Check implemented using type inference:
/// let _ = <MyType as DoesNotImplDrop<_>>::check
pub trait DoesNotImplDrop<Inferred> {
// Required to reference the trait.
fn check() {}
}

// Type inference will find this blanket impl...
impl<Cls: ?Sized> DoesNotImplDrop<()> for Cls {}

// ... unless this impl also applies, then type inference fails.
struct ImplsDrop;
#[allow(drop_bounds)] // We're intentionally using `Drop` as a bound.
impl<Cls: ?Sized + Drop> DoesNotImplDrop<ImplsDrop> for Cls {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/__macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod sync_unsafe_cell;
mod writeback;

pub use self::cache::{CachedClass, CachedSel};
pub use self::class::{MainThreadOnlyDoesNotImplSendSync, ValidThreadKind};
pub use self::class::{DoesNotImplDrop, MainThreadOnlyDoesNotImplSendSync, ValidThreadKind};
pub use self::common_selectors::{alloc_sel, dealloc_sel, init_sel, new_sel};
pub use self::convert::{ConvertArgument, ConvertArguments, ConvertReturn, TupleExtender};
pub use self::declare_class::{
Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/macros/extern_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ macro_rules! __extern_class_inner {
fn class() -> &'static $crate::runtime::AnyClass {
let _ = <Self as $crate::__macro_helpers::ValidThreadKind<<Self as $crate::ClassType>::ThreadKind>>::check;
let _ = <Self as $crate::__macro_helpers::MainThreadOnlyDoesNotImplSendSync<_>>::check;
let _ = <Self as $crate::__macro_helpers::DoesNotImplDrop<_>>::check;

$crate::__class_inner!($crate::__fallback_if_not_set! {
($($name)*)
Expand Down
14 changes: 14 additions & 0 deletions crates/test-ui/ui/extern_class_impls_drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Test that implementing Drop for a class created with extern_class! fails.
use objc2::extern_class;
use objc2::runtime::NSObject;

extern_class!(
#[unsafe(super(NSObject))]
struct MyClass;
);

impl Drop for MyClass {
fn drop(&mut self) {}
}

fn main() {}
15 changes: 15 additions & 0 deletions crates/test-ui/ui/extern_class_impls_drop.stderr

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b43b4be

Please sign in to comment.