-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Add semver guidelines for changing the repr
of structs/enums to ref…
#10276
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. Please see the contribution instructions for more information. |
I'm having a problem with the struct change, since it isn't a compiler error which causes CI to fail. I could just do a dirty size assertion which would fix it, but that's a bad example imo const _: () = assert_foo_size(); // Error: evaluation of constant value failed
const fn assert_foo_size() {
let size = std::mem::size_of::<Foo>();
if size != 6 {
panic!("Foo has changed size!");
}
} Is there a flag to tell CI that it doesn't matter that this isn't a compiler error? Or do you know a better example that causes a compiler error? |
I can’t find any other flag in the current implementation. cargo/src/doc/semver-check/src/main.rs Lines 183 to 185 in 0655dd2
Maybe adapt semver-check to run the output executable, though that requires some efforts. |
I think it would be useful to extend semver-check to be able to have a "run-fail" mode. I think it shouldn't be too difficult to add. I would mark the example's language tag with something like
And then check for that flag, and just run the code. From your example, I think that should be relatively safe. Another possibility is to go with your static assert, but use rustdoc's hidden-line feature (using |
Add `run-fail` to semver-check for docs I encountered this missing feature in #10276 and therefore added it here in this separate PR. If the breaking change does not involve a compilation error but a change in runtime behaviour, you can add `run-fail` to the codeblock. The "before" code must return exit code 0, and the "after" code must be nonzero (like a panic). Example case that I tested (ignore the trailing dot, it's for github markdown to not hate me) ``` ```rust,ignore,run-fail // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo() {} /////////////////////////////////////////////////////////// // After pub fn foo() { panic!("hey!"); } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { updated_crate::foo(); } ```. ```
3f8245c
to
c576e1f
Compare
…erence The current semver guidelines do not mention `repr` at all. Changing the `repr` of a struct/enum will break code, especially unsafe code relying on layout. These breaking changes will rarely manifest themselves as compiler errors, which makes them all the more dangerous. The new guidelines mention removing a well-defined repr from a struct or enum to be a breaking change.
c576e1f
to
eaf7720
Compare
That took some git magic, but let's see whether this passes now 😅 |
In general, I think there are a number of other possible ways that repr can be a breaking change. I think it'd be good to generalize:
|
While I like there being hard rules, I agree with you that it is a bit more nuanced with But it is really hard to come up with hard rules, and these general guidelines sound nice, but I'd still like to direct towards telling that only changing from well-defined reprs should be breaking. |
let foo_ptr = &foo as *const Foo as *const u8; | ||
|
||
// this is now unsound because of the change | ||
// SAFETY: Foo is repr(C), so we are guaranteed that there will be `3` at this offset (u8, 8 pad, u16) |
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 is what was meant?
// SAFETY: Foo is repr(C), so we are guaranteed that there will be `3` at this offset (u8, 8 pad, u16) | |
// SAFETY: Foo is repr(C), so we are guaranteed that there will be `5` at this offset (u8, 8 pad, u16) |
When a struct has a well-defined repr (`transparent`, `C`) and only public fields, this will break unsafe code relying on | ||
that repr. |
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.
Just to try to reword this for clarity.
When a struct has a well-defined repr (`transparent`, `C`) and only public fields, this will break unsafe code relying on | |
that repr. | |
When a struct has a well-defined repr (`transparent`, `C`) and only public fields, changing the repr will break unsafe code relying on the original repr. |
<a id="struct-change-repr-when-public"></a> | ||
### Major: change a from well-defined repr to another when all fields are public | ||
|
||
When a struct has a well-defined repr (`transparent`, `C`) and only public fields, this will break unsafe code relying on |
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.
Just to clarify, is this qualified on "only public fields" because changes to private fields can potentially change the alignment, and that's explicitly hidden from the user?
I'm wondering if this can be generalized to a single "Major" change that is "Changing the layout of a well-defined type" or something like that. Instead of trying to have separate sections for every For example, list out what kinds of types have well-defined layouts:
And say any change to the And also mention: Any change to (Note: I haven't thought about the specifics of what I wrote above, as I just quickly wrote them down, they may need adjustment.) |
☔ The latest upstream changes (presumably #12339) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm going to close as repr and layout guidelines are now documented via #12169. Thank you for getting this started, though! |
The current semver guidelines do not mention
repr
at all. Changing therepr
of a struct/enum will break code, especially unsafe code relying on layout. These breaking changes will rarely manifest themselves as compiler errors, which makes them all the more dangerous.The new guidelines specify removing a well-defined repr from a struct or enum to be a breaking change.
This is more of a suggestion on how it could be done, and I'm very open for improvements for the wording and other details.
Another thing I'm not sure about is how this interacts with
#[non_exhaustive]
, and therefore don't mention it at all.There are also some other breaking changes that are related to this, like reordering the fields of a
#[repr(C)]
struct, and it's open for discussion whether these should be added as well.discussion on zulip