-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
repr(transparent) should not consider non_exhaustive types as 1-ZSTs outside their crate #78586
Comments
I'm going to nominate for lang, because I think (perhaps with a future compat lint) we should not look at foreign types' size unless that type is repr(transparent) for the purposes of checking here. |
Note that this also applies to the way this was done before
As that private field also keeps others from constructing or exhaustively matching it, but it would still be accepted as 1-ZST by We discussed this in the lang team meeting today. The consensus was that this is an accidental semver hazard that we'd like to do something about. @rustbot modify labels: +E-help-wanted +E-medium It'd be great to get a PR we could use to determine the impact of this. Ideally this isn't happening in the wild and can just be an error (maybe for one case or the other, if one is common and the other isn't) but it'll probably need at least a future imcompatibility lint. |
Hello folks, can I take this issue? I am kinda new to the community but I want to start contributing. :-) |
@jsomedon Absolutely! Unfortunately I don't really know the code here, so don't have suggestions for where to start, but you could always try tracing through the code around |
Should a |
@jsomedon Yes, I think that's ok, like how one can exhaustively match it inside its own defining crate. |
@jsomedon do you plan to continue working on this? |
No, probably too overwhelming to my rust level. I would rather see someone else fixing this and read their code instead. |
@rustbot claim |
If we should not look at foreign types' sizes, should it be allowed to use an opaque zero-sized type as the single non-zero-sized field in a Crate A: #[non_exhaustive]
struct Unit; Crate B: #[repr(transparent)]
struct Transparent(Unit, ()); This is currently rejected, but I think the zero-sizedness of opaque types (i.e. types with Edit: Note that this is also a potential semver hazard: If a crate contains a struct with only private fields, removing all fields should not be an API-breaking change. |
@Areredify Are you still working on this? |
Btw, I just noticed we have a somewhat similar restricting in |
If adding Granted, adding |
@TheWastl I can't work on this, but I was close to completing it if you want to pick it up. The issue was that I was traversing type contents incorrectly, iirc. It's at |
@rustbot release-assignment |
…non_exhaustive, r=oli-obk check non_exhaustive attr and private fields for transparent types Fixes rust-lang#78586.
…non_exhaustive, r=oli-obk check non_exhaustive attr and private fields for transparent types Fixes rust-lang#78586.
…non_exhaustive, r=oli-obk check non_exhaustive attr and private fields for transparent types Fixes rust-lang#78586.
This is probably not complete; we need to track it becoming a hard error in the future. |
This comment was marked as resolved.
This comment was marked as resolved.
``` error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types --> openrr-plugin/src/gen/proxy.rs:10:1 | 10 | #[sabi_trait] | ^^^^^^^^^^^^^ | = note: `-D repr-transparent-external-private-fields` implied by `-D warnings` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 <rust-lang/rust#78586> = note: this struct contains `UnsafeIgnoredType<SyncSend>`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. = note: this error originates in the attribute macro `sabi_trait` (in Nightly builds, run with -Z macro-backtrace for more info) ```
``` error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types --> openrr-plugin/src/gen/proxy.rs:10:1 | 10 | #[sabi_trait] | ^^^^^^^^^^^^^ | = note: `-D repr-transparent-external-private-fields` implied by `-D warnings` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 <rust-lang/rust#78586> = note: this struct contains `UnsafeIgnoredType<SyncSend>`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. = note: this error originates in the attribute macro `sabi_trait` (in Nightly builds, run with -Z macro-backtrace for more info) ```
Is there a way for types to opt-in to a semver guarantee that they will remain ZSTs? As a basic example:
OR
Currently this hits this warning, but if Is there a way to mark |
I think we could make it accept |
Document that adding `#[non_exhaustive]` on existing items is breaking. ### What does this PR try to resolve? Adding `#[non_exhaustive]` to an existing struct, enum, or variant is almost always a breaking change and requires a major version bump for semver purposes. This PR adds a section to the semver reference page that describes this and provides examples showing how `#[non_exhaustive]` can break code. ### Additional information Adding `#[non_exhaustive]` to a unit struct currently has no effect on whether that struct can be constructed in downstream crates. This is inconsistent with the behavior of `#[non_exhaustive]` on unit enum variants, which may not be constructed outside their own crate. This might be due to a similar underlying cause as: rust-lang/rust#78586 The confusing "variant is private" error messages for non-exhaustive unit and tuple variants are a known issue tracked in: rust-lang/rust#82788 Checking for the struct portion of this semver rule is done in: obi1kenobi/cargo-semver-checks#4
The below struct definitions trip this lint. I see no reason why they must be illegal, and the first one could even be useful: #[repr(transparent)]
pub struct Foo(usize, core::mem::ManuallyDrop<()>);
#[repr(transparent)]
pub struct Bar(usize, std::cell::UnsafeCell<()>);
#[repr(transparent)]
pub struct Baz(usize, core::mem::MaybeUninit<()>);
I think that is the right choice. |
This comment was marked as resolved.
This comment was marked as resolved.
…d code Live dangerously. rust-lang/rust#78586
warning: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> src/token.rs:378:17 | 378 | pub spans: [Span; $len], | ^^^^^^^^^^^^^^^^^^^^^^^ ... 560 | / define_punctuation_structs! { 561 | | "_" pub struct Underscore/1 /// wildcard patterns, inferred types, unnamed items in constants, extern c... 562 | | } | |_- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 <rust-lang/rust#78586> = note: this struct contains `proc_macro2::Span`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. = note: `#[warn(repr_transparent_external_private_fields)]` on by default = note: this warning originates in the macro `define_punctuation_structs` (in Nightly builds, run with -Z macro-backtrace for more info) warning: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> src/token.rs:378:17 | 378 | pub spans: [Span; $len], | ^^^^^^^^^^^^^^^^^^^^^^^ ... 785 | / define_punctuation! { 786 | | "&" pub struct And/1 /// bitwise and logical AND, borrow, references, reference patterns 787 | | "&&" pub struct AndAnd/2 /// lazy AND, borrow, references, reference patterns 788 | | "&=" pub struct AndEq/2 /// bitwise AND assignment ... | 831 | | "~" pub struct Tilde/1 /// unused since before Rust 1.0 832 | | } | |_- in this macro invocation | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 <rust-lang/rust#78586> = note: this struct contains `proc_macro2::Span`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. = note: this warning originates in the macro `define_punctuation_structs` which comes from the expansion of the macro `define_punctuation` (in Nightly builds, run with -Z macro-backtrace for more info) warning: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> src/token.rs:147:9 | 147 | pub span: Span, | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 <rust-lang/rust#78586> = note: this struct contains `proc_macro2::Span`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
In crate A:
In crate B:
I expected that to fail in crate B, because the reason crate A put
#[non_exhaustive]
on the type was to allow it to get additional fields in the future, which would no longer allow it to work inrepr(transparent)
.But this actually compiles today, creating what I would consider an accidental semver hazard.
https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Stability.20of.201-ZSTness/near/215120408
The text was updated successfully, but these errors were encountered: