Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PinCoerceUnsized trait into core #125048

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dingxiangfei2009
Copy link
Contributor

@dingxiangfei2009 dingxiangfei2009 commented May 12, 2024

cc @Darksonn @wedsonaf @ojeda

This is a PR to introduce a PinCoerceUnsized trait in order to make trait impls generated by the proc-macro #[derive(SmartPointer)], proposed by RFC, sound. There you may find explanation, justification and discussion about the alternatives.

Note that we do not seek stabilization of this PinCoerceUnsized trait in the near future. The stabilisation of this trait does not block the eventual stabilization process of the #[derive(SmartPointer)] macro. Ideally, use of DerefPure is more preferrable except this will actually constitute a breaking change. PinCoerceUnsized emerges as a solution to the said soundness hole while avoiding the breaking change. More details on the DerefPure option have been described in this section of the RFC linked above.

Earlier discussion can be found in this Zulip stream and rust-for-linux thread.

@rustbot
Copy link
Collaborator

rustbot commented May 12, 2024

r? @m-ou-se

rustbot has assigned @m-ou-se.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 12, 2024
@rust-log-analyzer

This comment has been minimized.

#[unstable(feature = "stable_deref_trait", issue = "123430")]
/// # Safety
///
/// Any two calls to `deref` must return the same value at the same address unless
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"same value at the same address" here is pretty vague, and it's unclear to me without reading the RFC thread what exactly that entails and how it compares to the stable deref trait crate. notably, the preconditions on the crate are currently not satisfied by Box because of the special strict aliasing rules imposed by it.

Copy link
Contributor

@Darksonn Darksonn May 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meaning of "same value" is that the concrete type must not change. I copied the explanation in below. Was it unclear?

Here, "same value" means that if deref returns a trait object, then the actual type behind that trait object must not change. Additionally, when you unsize coerce from Self to Unsized, then if you call deref on Unsized and get a trait object, then the underlying type of that trait object must be <Self as Deref>::Target.

Analogous requirements apply to other unsized types. E.g., if deref returns [T], then the length must not change. In other words, the underlying type must not change from [T; N] to [T; M].

The motivation for this requirement is that with trait objects, you could otherwise first return one struct, and then later return some wrapper struct that wraps the original struct using #[repr(transparent)].

@@ -309,3 +309,25 @@ impl<T: ?Sized> Receiver for &T {}

#[unstable(feature = "receiver_trait", issue = "none")]
impl<T: ?Sized> Receiver for &mut T {}

#[lang = "stable_deref"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be made into a lang item until it's actually used by the compiler. I feel like having unused lang items is not desirable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any chance of us somehow managing to check and error in that case?

Copy link
Contributor

@workingjubilee workingjubilee May 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinks okay the moment this left my hands the answer came to me as "probably not usefully" (it would only be one more formality-tier listing somewhere and someone will just add it to that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the use of it is rather imminent. Ideally with #123472 this would go into the trait bounds that #[derive(SmartPointer)] generates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came to my right sense! I have dropped the lang term here.

@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the stable-deref branch 3 times, most recently from 1795d68 to 77f8779 Compare May 13, 2024 19:17
@dingxiangfei2009 dingxiangfei2009 marked this pull request as ready for review May 13, 2024 20:18
@dingxiangfei2009 dingxiangfei2009 changed the title StableDeref trait into core PinCoerceUnsized trait into core May 26, 2024
@rust-log-analyzer

This comment has been minimized.

@Darksonn
Copy link
Contributor

It would make sense to add the following as a test:

use core::cell::{Cell, RefCell, UnsafeCell};
use core::pin::Pin;

pub trait MyTrait {}
impl MyTrait for String {}

pub fn cell(arg: Pin<Cell<Box<String>>>) -> Pin<Cell<Box<dyn MyTrait>>> {
    arg
}
pub fn refcell(arg: Pin<RefCell<Box<String>>>) -> Pin<RefCell<Box<dyn MyTrait>>> {
    arg
}
pub fn ucell(arg: Pin<UnsafeCell<Box<String>>>) -> Pin<UnsafeCell<Box<dyn MyTrait>>> {
    arg
}

This compiles today, so we shouldn't break it.

@dingxiangfei2009
Copy link
Contributor Author

@Darksonn test cases have been added.

@traviscross
Copy link
Contributor

@rustbot labels +I-lang-nominated +T-lang

Nominating as @dingxiangfei2009 requested lang review.

@rustbot rustbot added I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jul 17, 2024
Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit

/// `[T]`, then the length must not change. In other words, the underlying type
/// must not change from `[T; N]` to `[T; M]` with an `N` different from `M`.
///
/// If this type alos implements `DerefMut`, then the same guarantee must be upheld by
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// If this type alos implements `DerefMut`, then the same guarantee must be upheld by
/// If this type also implements `DerefMut`, then the same guarantee must be upheld by

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied

@traviscross
Copy link
Contributor

r? @scottmcm

@traviscross
Copy link
Contributor

traviscross commented Jul 17, 2024

@rustbot labels -I-lang-nominated

We talked about this in the meeting between members of the lang team and RfL. We felt this work was sufficiently covered by the RFC that no lang team decision was needed here for this nightly work. It just needs review, and we'll leave that to @scottmcm as he has context here.

@rustbot rustbot removed the I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. label Jul 17, 2024
Comment on lines +1756 to +1761
#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}

#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should also implement for raw pointers and NonNull. (And add a test.)

@dingxiangfei2009 dingxiangfei2009 force-pushed the stable-deref branch 2 times, most recently from 2248400 to 447bf72 Compare July 18, 2024 09:22
@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the stable-deref branch 2 times, most recently from a380055 to 02ae2b1 Compare July 18, 2024 13:11
Comment on lines 1737 to 1754
/// # Safety
///
/// Implementing this unsafe traits requires the guarantee that any two calls
/// to `Deref::deref` must return the same value at the same address, **even after moves
/// or unsize-coercions of `self`**, with exceptions of mutations to `self`.
///
/// Here, "same value" means that if `deref` returns a trait object, then the actual
/// concrete type behind that trait object must not change.
/// Additionally, when you unsize- coerce from `Self` to `Unsized`,
/// then if you call `deref` on `Unsized` which returns a trait object reference,
/// the underlying type of that trait object must be `<Self as Deref>::Target`.
///
/// Analogous requirements apply to other unsized types. E.g., if `deref` returns
/// `[T]`, then the length must not change. In other words, the underlying type
/// must not change from `[T; N]` to `[T; M]` with an `N` different from `M`.
///
/// If this type also implements `DerefMut`, then the same guarantee must be upheld by
/// calls to `deref_mut`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is using the old safety comment. The RFC was updated to use these safety requirements instead:

/// Trait that indicates that this is a pointer or a wrapper for one, where
/// unsizing can be performed on the pointee when it is pinned.
///
/// # Safety
///
/// If this type implements `Deref`, then the concrete type returned by `deref`
/// and `deref_mut` must not change without a modification. The following
/// operations are not considered modifications:
///
/// * Moving the pointer.
/// * Performing unsizing coercions on the pointer.
/// * Performing dynamic dispatch with the pointer.
/// * Calling `deref` or `deref_mut` on the pointer.
///
/// The concrete type of a trait object is the type that the vtable corresponds
/// to. The concrete type of a slice is an array of the same element type and
/// the length specified in the metadata. The concrete type of a sized type
/// is the type itself.

It gets rid of the requirement that the address is the same, and simplifies it to just requiring that the concrete type is unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-SGX Target: SGX S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet