make repr_transparent_non_zst_fields a hard error#155299
make repr_transparent_non_zst_fields a hard error#155299RalfJung wants to merge 1 commit intorust-lang:mainfrom
Conversation
|
rustbot has assigned @jdonszelmann. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
@bors try |
This comment has been minimized.
This comment has been minimized.
…try> make repr_transparent_non_zst_fields a hard error
This comment has been minimized.
This comment has been minimized.
5b074cf to
3bb6c15
Compare
|
@craterbot check |
|
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
This looks nice Ralf, indeed let's nominate for lang after this completes |
This comment has been minimized.
This comment has been minimized.
|
Note that this also forbids The custom phantom variance markers in See also CAD97/generativity#13 where this was first reported as an issue with my crate. I didn't say anything at that point as I presumed it wouldn't be made into a hard error without some way to opt-in to being a trivial type for |
|
Uh, that's interesting that you would assume that when the error very clearly states what our plans are and nothing in the tracking issue indicates other plans either... why did you wait years until the literal last moment before raising this concern upstream? You could have saved me a bunch of work by posting this any time in the last 3 years. :( |
use std::marker::PhantomData;
#[repr(transparent)]
pub struct Phantomish<T>(PhantomData<T>);
#[repr(transparent)]
pub struct Transparent<T>(u8, Phantomish<T>);Edit: ah, I see, you need two crates… |
|
FWIW I don't think it's necessary to block turning this into a hard error on some way to make 1ZST with private members. I just want to ensure that this knowingly effects It's ultimately quite minor. |
|
@CAD97 is there an issue tracking that? It'd be nice to have a good self-contained writeup for what you think is currently missing. |
|
FWIW I'd also be fine with only making the repr(C) part of this a hard error, and letting the part that is motivated by semver concerns bake for longer. But there hasn't been any movement on that semver side nor even any suggestions for how the rules should be relaxed so that's not very actionable. Let's see what crater says. Last time we tried this, we found only 2 regressions due to the semver rule; your crate did not show up. So either crater bugged out a bit (spurious failure in the baseline build?) or nothing covered by crater uses your crate with this pattern you mention. |
3bb6c15 to
3dfa7ea
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
Cc @obi1kenobi as this is about removing a currently-existing semver hazard 🎉 |
|
Another breakage: the FCW currently triggers when one tries to use a |
|
That's exactly #155925 isn't it? |
|
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
Not just, |
|
That sounds like a bug in that crate then, |
|
IIUC, |
|
Yeah, I can see how they got there, but sadly it doesn't work... I filed an issue: dtolnay/ghost#41. |
|
This is why I think we should hold the hard error until the |
|
🎉 Experiment
Footnotes
|
|
Regression analysis:
|
|
I updated the PR description and nominated this for lang team discussion. |
View all comments
This lint is about which fields we consider "trivial" for
repr(transparent). Forrepr(transparent)to be valid, there can be at most one non-trivial field. In other words, trivial fields are those that we promise do not affect the layout or ABI of therepr(transparent)type. Historically we considered all types with size 0 and alignment 1 (i.e., all 1-ZST) to be trivial. However we'd like to take some of that back:#[non_exhaustive](except when we are in the same crate as that type).repr(C)and who knows what the C ABI does. In particular on MSVC a struct whose only field is a 0-length array has size 1. Rust incorrectly gives it size 0. With repr(ordered_fields) rfcs#3845 we can hopefully fix the layout, which would make "is that type a 1-ZST" target-dependent, and we ideally should reject such code on all targets.This was a deny-by-default FCW since #147185, which landed almost 6 months ago and shipped with Rust 1.93. (If this PR lands now it will ship with 1.97.) Already back then we found hardly any crater impact. The tracking issue has had no new relevant backrefs since that PR landed.
So, I think it is time to make this a hard error.
Fixes #78586 (tracking issue)
Fixes rust-lang/unsafe-code-guidelines#552 because this means the
repr(transparent)ABI compatibility rule no longer ever "ignores"repr(C)fields.@rust-lang/lang What do you think? See here for the crater analysis; the summary is that there's no relevant regressions found in the wild. But some points have been raised by people:
ghostcrate offers a macro to definePhantomData-like types, and those types involve arepr(C). If someone uses such a type as a marker inside arepr(transparent), that will no longer work. Apparently nobody does that in the code checked by crater. A new version of the crate has been released that fixes this.#[rustc_pub_transparent]). That means it is not possible for a crate to expose a semantically relevant maker type (likeGhostToken) that is "trivial" forrepr(transparent)purposes. Apparently currently nobody does this in the ecosystem (the parts crater can see, anyway), but it seems like a sensible thing to do. If we are concerned about this, we could limit this PR to only make therepr(C)and#[non_exhaustive]part of the check a hard error, and leave the "has private fields" part as a warning.Also note that the private field check is technically a bit odd: we literally check "is the type defined in this crate or are all fields public". We do not check if the current module can access those fields. So if a type has private fields then one can rely on it being "trivial" everywhere in the current crate, even outside the module that defined the type. This is not how field privacy usually works. If we want to restrict this to "only modules that can 'see' the fields are allowed to rely on the type being a 1-ZST", that's technically a breaking change. I don't know if this was a deliberate choice or just the easiest thing to implement. @scottmcm do you remember?