Skip to content

Commit

Permalink
Disallow &mut message receivers
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 6, 2024
1 parent 3d67e91 commit 8912e1f
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 136 deletions.
3 changes: 3 additions & 0 deletions crates/objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* **BREAKING**: Removed `ffi` exception function pointer aliases.
* **BREAKING**: Removed `mutability::HasStableHash`.
* **BREAKING**: Removed `DeclaredClass::ivars_mut`.
* **BREAKING**: Disallow `&mut` message receivers (except in the special case
when the object is `AnyObject`, for better backwards compatibility with
`objc`).

### Fixed
* Remove an incorrect assertion when adding protocols to classes in an unexpected
Expand Down
10 changes: 0 additions & 10 deletions crates/objc2/src/__macro_helpers/msg_send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use core::mem::ManuallyDrop;
use core::ptr;

use crate::encode::RefEncode;
use crate::mutability::IsMutable;
use crate::rc::Retained;
use crate::runtime::{AnyClass, AnyObject, MessageReceiver, Sel};
use crate::{ClassType, Encode, Message};
Expand Down Expand Up @@ -172,15 +171,6 @@ impl<'a, T: ?Sized + Message> MsgSend for &'a Retained<T> {
}
}

impl<'a, T: ?Sized + Message + IsMutable> MsgSend for &'a mut Retained<T> {
type Inner = T;

#[inline]
fn into_raw_receiver(self) -> *mut AnyObject {
Retained::as_mut_ptr(self).cast()
}
}

impl<T: ?Sized + Message> MsgSend for ManuallyDrop<Retained<T>> {
type Inner = T;

Expand Down
46 changes: 21 additions & 25 deletions crates/objc2/src/runtime/message_receiver.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use core::ptr::NonNull;

use crate::encode::{EncodeArguments, EncodeReturn, RefEncode};
use crate::mutability::IsAllowedMutable;
use crate::runtime::{AnyClass, AnyObject, Sel};
use crate::Message;

Expand Down Expand Up @@ -521,14 +520,18 @@ unsafe impl<'a, T: ?Sized + Message> MessageReceiver for &'a T {
}
}

impl<'a, T: ?Sized + Message + IsAllowedMutable> private::Sealed for &'a mut T {}
unsafe impl<'a, T: ?Sized + Message + IsAllowedMutable> MessageReceiver for &'a mut T {
type __Inner = T;
impl<'a> private::Sealed for &'a mut AnyObject {}
/// `&mut AnyObject` is allowed as mutable, for easier transition from `objc`,
/// even though it's basically always incorrect to hold `&mut AnyObject`.
///
/// Use `*mut AnyObject` instead if you know for certain you need mutability,
/// and cannot make do with interior mutability.
unsafe impl<'a> MessageReceiver for &'a mut AnyObject {
type __Inner = AnyObject;

#[inline]
fn __as_raw_receiver(self) -> *mut AnyObject {
let ptr: *mut T = self;
ptr.cast()
self
}
}

Expand Down Expand Up @@ -558,37 +561,30 @@ mod tests {
use core::ptr;

use super::*;
use crate::mutability;
use crate::rc::{Allocated, Retained};
use crate::runtime::NSObject;
use crate::test_utils;
use crate::{declare_class, msg_send, msg_send_id, ClassType, DeclaredClass};

declare_class!(
struct MutableObject;

unsafe impl ClassType for MutableObject {
type Super = NSObject;
type Mutability = mutability::Mutable;
const NAME: &'static str = "TestMutableObject";
}

impl DeclaredClass for MutableObject {}
);
use crate::{msg_send, msg_send_id};

#[allow(unused)]
fn test_different_receivers(mut obj: Retained<MutableObject>) {
fn test_different_receivers(obj: &mut AnyObject) {
unsafe {
let x = &mut obj;
let x = &mut *obj;
let _: () = msg_send![x, mutable1];
// `x` is consumed by the above, so this won't work:
// let _: () = msg_send![x, mutable2];

// It is only possible if we reborrow:
let _: () = msg_send![&mut *obj, mutable1];
let _: () = msg_send![&mut *obj, mutable2];
#[allow(clippy::needless_borrow)]
let obj: NonNull<MutableObject> = (&mut *obj).into();

// Test NonNull
let obj = NonNull::from(obj);
let _: () = msg_send![obj, mutable1];
let _: () = msg_send![obj, mutable2];
let obj: *mut MutableObject = obj.as_ptr();

// And test raw pointers
let obj: *mut AnyObject = obj.as_ptr();
let _: () = msg_send![obj, mutable1];
let _: () = msg_send![obj, mutable2];
}
Expand Down
20 changes: 10 additions & 10 deletions crates/test-ui/ui/declare_class_invalid_receiver.stderr

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

89 changes: 50 additions & 39 deletions crates/test-ui/ui/declare_class_mut_self_not_mutable.stderr

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

Loading

0 comments on commit 8912e1f

Please sign in to comment.