-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 ZeroablePrimitive
trait unsafe.
#121850
Make ZeroablePrimitive
trait unsafe.
#121850
Conversation
Not dtolnay, but this is obviously correct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was correct before this PR. The boundary for unsafety to have any meaning in Rust in a public API is the module level. core::num
exposes a sound API without this trait being an unsafe trait. Unsafe traits are for when implementing a trait from outside the module can cause unsoundness.
core::any
is similar. Implementing Any
with a bogus type_id
method would cause unsoundness, but it is impossible to do so from outside the module, so there is no need for Any
to be an unsafe trait.
Even if it was correct already, I think this makes it more obvious why the trait needs to exist in the first place. This feels a bit different to |
I don't think it's necessarily wrong to not make it unsafe, but I think making it unsafe is clearer |
The fact that the standard library needs to be careful with impls for this trait is an internal implementation detail of the standard library, which doesn't have bearing on consumers of the standard library. It's a shame that rustdoc would end up emphasizing this implementation detail in public-facing docs. Ideally there would be a way for a trait to be unsafe internally for the purpose of requiring Would it be just as good if |
…iaskrgr Rollup of 12 pull requests Successful merges: - rust-lang#120646 (Fix incorrect suggestion for uninitialized binding in pattern) - rust-lang#121416 (Improve error messages for generics with default parameters) - rust-lang#121475 (Add tidy check for .stderr/.stdout files for non-existent test revisions) - rust-lang#121580 (make unused_imports less assertive in test modules) - rust-lang#121736 (Remove `Mutex::unlock` Function) - rust-lang#121784 (Make the success arms of `if lhs || rhs` meet up in a separate block) - rust-lang#121818 (CFI: Remove unused `typeid_for_fnsig`) - rust-lang#121819 (Handle stashing of delayed bugs) - rust-lang#121828 (Remove unused fluent messages) - rust-lang#121831 (Fix typo in comment) - rust-lang#121850 (Make `ZeroablePrimitive` trait unsafe.) - rust-lang#121853 (normalizes-to: handle negative impls) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#121850 - reitermarkus:generic-nonzero-unsafe-trait, r=Nilstrieb Make `ZeroablePrimitive` trait unsafe. Tracking issue: rust-lang#120257 r? `@dtolnay`
The way I see it is: If it was stable and not sealed, it would need to be unsafe. Sealing isn't the unsafe part, it's only for forwards compatibility. I can understand the argument for “it is safe if it is sealed”, but it doesn't feel quite as intuitive to me. |
Got it. What do you think of whether |
How would it be unsound? The safety requirement currently states types implementing it must be primitives that are valid when zero. So technically any implementation outside Of course if that requirement is relaxed at some point to allow non-primitives, the trait most likely wouldn't be sealed anymore. And at that point it would probably also be renamed to |
It's not unsound — you are right. Good call. This is the kind of case I had been thinking of: #![feature(generic_nonzero, nonzero_internals)]
use std::num::{NonZero, ZeroablePrimitive};
#[derive(Copy, Clone)]
#[repr(transparent)]
struct Thing([u8; 3]);
unsafe impl ZeroablePrimitive for Thing {}
fn main() {
let _ = NonZero::new(Thing([1, 1, 1]));
} where the existence of a genuinely unnameable diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
@@ -20,4 +20,11 @@ mod private {
#[const_trait]
pub trait Sealed {}
+
+ #[unstable(
+ feature = "nonzero_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "none"
+ )]
+ impl<T> const Sealed for T {}
}
@@ -39,10 +46,3 @@ pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {}
macro_rules! impl_zeroable_primitive {
($primitive:ty) => {
- #[unstable(
- feature = "nonzero_internals",
- reason = "implementation detail which may disappear or be replaced at any time",
- issue = "none"
- )]
- impl const private::Sealed for $primitive {}
-
#[unstable( it would make thread 'rustc' panicked at /git/rust/compiler/rustc_abi/src/layout.rs:432:14:
nonscalar layout for layout_scalar_valid_range type: Layout {
...
query stack during panic:
#0 [layout_of] computing layout of `core::num::nonzero::NonZero<Thing>`
#1 [layout_of] computing layout of `core::option::Option<core::num::nonzero::NonZero<Thing>>`
#2 [mir_drops_elaborated_and_const_checked] elaborating drops for `main`
#3 [analysis] running analysis passes on this crate
end of query stack But a safe standard library code change turning a compiler error into an ICE is not a soundness issue, and I am sure there must be lots of other standard library safe code changes that would do similar. A prerequisite for the standard library being unsound is that user code containing only correct unsafe code would need to compile successfully into a runnable program, instead of And I then noticed that the same code even without // cargo +nightly-2024-03-17 build
use std::num::{NonZero, ZeroablePrimitive};
#[derive(Copy, Clone)]
#[repr(transparent)]
struct Thing([u8; 3]);
unsafe impl ZeroablePrimitive for Thing {}
fn main() {
let _ = NonZero::new(Thing([1, 1, 1]));
} Thanks for the responses! |
Tracking issue: #120257
r? @dtolnay