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

Make Any an unsafe trait #67562

Closed
wants to merge 1 commit into from

Conversation

Mark-Simulacrum
Copy link
Member

Follow-up to #67519 per popular request that making it an unsafe trait is actually desirable.

@rust-highfive
Copy link
Collaborator

r? @dtolnay

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 23, 2019
@Mark-Simulacrum
Copy link
Member Author

cc @Centril

I think we might want to at least FCP this with the libs team (since it does look different in public docs) but I don't personally think that a crater run here is necessary, we don't expect any regressions and if they do happen then we can catch them in beta.

@Centril
Copy link
Contributor

Centril commented Dec 23, 2019

Imo this is just a bug-fix so I wouldn't bother with FCP but that's just me.

@Mark-Simulacrum
Copy link
Member Author

It is at a high level just a bug fix but it would also be the first major unsafe trait that we expose (joining primarily TrustedLen). I think as such we should be a little careful here, but if e.g. @dtolnay as the auto-assigned reviewer deems this good to go then we can proceed without FCP of course.

@jonas-schievink jonas-schievink added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Dec 23, 2019
@dtolnay
Copy link
Member

dtolnay commented Dec 24, 2019

I can't say that I am excited about this. I follow the justification, but I disagree with it on the basis that the boundary at which Rust is designed to contain unsafe code is at the module level. The std::any module uses careful library design to perfectly contain its unsafe internals in a way that can't be misused outside the module. From the point of view of library design at the module level, Any as a safe trait is correct and I am happy to encourage libraries that follow a similar design to also document such traits as safe traits.

I think whatever teaching benefits there are to publicly associating the Any trait with unsafety are far less than the downsides of publicly associating the Any trait with unsafety.

Thanks anyway!

@rfcbot fcp close

@rfcbot
Copy link

rfcbot commented Dec 24, 2019

Team member @dtolnay has proposed to close this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. labels Dec 24, 2019
@dtolnay
Copy link
Member

dtolnay commented Dec 24, 2019

To give an example on why the library design perspective on this differs from the comments on #67519 (review) which are from the language perspective: suppose the trait in question were:

pub trait Example {}
impl<T: ?Sized> Example for T {}

and we were adding a private implementation detail which is unsafe to implement:

pub trait Example {
    // unsafe to implement
    #[doc(hidden)]
    fn f();
}

Why should this affect anything in the public facing documentation of the trait? The function is an implementation detail while the the docs are for documenting the public API, which has not changed. The logic is the same for Any.

@Mark-Simulacrum
Copy link
Member Author

I am fairly ambivalent, I can definitely see both downsides and benefits to either approach. The "private" hidden method is convincing, though. It might be worth asking folks to take a look at the (just added) reasoning comment this PR removes as well, to see if anyone has changes to suggest there.

Comment on lines +76 to +78
/// This trait is notably `unsafe`. However, this does not affect any use of
/// this trait in downstream code, as it is always safe to use `Any`. The reason
/// that `Any` is unsafe is that the standard library relies on its
Copy link
Member

Choose a reason for hiding this comment

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

This makes it sound like there'd be something odd here, but this is entirely normal for unsafe traits: they are unsafe to implement but safe to use.

@RalfJung
Copy link
Member

I can't say that I am excited about this. I follow the justification, but I disagree with it on the basis that the boundary at which Rust is designed to contain unsafe code is at the module level. The std::any module uses careful library design to perfectly contain its unsafe internals in a way that can't be misused outside the module.

I would argue it is bad style to have a private safe function that ought to be unsafe because it is not actually safe to call under all situations. I would not accept such code in my own projects.

"safety works at the module level" means that when verifying that something is safe, we have to consider all code inside the module. It does not mean that we should stop caring about properly marking things as unsafe within a module.

The same reasoning applies here.

@petertodd
Copy link
Contributor

The unstable TrustedLen trait puts the notes re: trait guarantees under a "Safety" header; I noticed there doesn't seem to be much guidance on how to document unsafe traits.

How about we mark these notes as "Unsafe Guarantees" or "Safety Guarantees" and word it something along the lines of:

Unsafe Guarantees

Unsafe code can rely Any implementations returning a stable TypeId that is unique for the type. This guarantee is why the Any trait is marked unsafe; normally unsafe code may not rely on traits being implementing correctly for memory safety. Having said that because Any is implemented for all types, it currently isn't actually possible for Any to be implemented outside of the standard library.

Similarly, we could word TrustedLen along the lines of:

Unsafe Guarantees

Unsafe code may rely on the .size_hint's upper bound being correctly implemented for memory safety.

I looked around and it doesn't look like there's an accepted standard for how to document unsafe traits. Clippy for instance doesn't have any lints related to unsafe traits for instance.

@petertodd
Copy link
Contributor

It is at a high level just a bug fix but it would also be the first major unsafe trait that we expose (joining primarily TrustedLen).

Actually, there's two very important unsafe traits that we expose: Send and Sync.

@withoutboats
Copy link
Contributor

I don't really care what we do here, I agree in principle that Any should be marked unsafe, but that has no impact on users since users cannot implement it, and its more likely to just confuse people than anything so it doesn't seem great.

This is a good example of how the trait system is leaky around implementation details.

@withoutboats
Copy link
Contributor

what I want to see is:

  1. Internally, Any is marked as unsafe, so the code is pedantically correct.
  2. In rustdoc, Any is shown as impossible for users to implement, rather than unsafe to implement. This would depend on having sealed traits as a feature or rustdoc being able to figure out that the impls of Any make it impossible to add another impl.

@petertodd
Copy link
Contributor

petertodd commented Jan 8, 2020 via email

@withoutboats
Copy link
Contributor

you can rely on type_id being implemented correctly for the same reason the other code in the Any module can rely on that

@petertodd
Copy link
Contributor

petertodd commented Jan 8, 2020 via email

@withoutboats
Copy link
Contributor

You mean, I can rely on it because it has a blanket implementation that we assume to be correct?

yes. if that were not true the entire API would be unsound.

@petertodd
Copy link
Contributor

petertodd commented Jan 8, 2020 via email

@dtolnay
Copy link
Member

dtolnay commented Jan 10, 2020

+1 for something along the lines of #67562 (comment). I am on board with Any requiring unsafe impl inside of libcore as long as rustdoc shows it as safe but unimplementable rather than an unsafe trait. It would be great to get an issue filed to track this.

@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Jan 11, 2020
@rfcbot
Copy link

rfcbot commented Jan 11, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Jan 11, 2020
@Mark-Simulacrum
Copy link
Member Author

I will look into filing an issue to that effect, though I believe it (as @withoutboats notes) would require some notion of sealed traits. I don't think it needs it as a end-user exposed feature, though, possibly just a #[rustdoc_sealed] annotation or something like that, so I imagine we might be able to do that without RFC and so forth.

@Mark-Simulacrum
Copy link
Member Author

I have filed #68235 and am closing this out (I guess in theory we could wait for FCP, but I don't think there's much point. If folks feel otherwise, feel free to reopen).

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Jan 21, 2020
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Jan 29, 2020
… r=Mark-Simulacrum

Minor: note how Any is an unsafe trait in SAFETY comments

Motivation: helpful to people like myself reading the standard library source to better understand how to use Any, especially if we do go ahead with rust-lang#67562 and make it an unsafe trait.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants