From 3cff9d5082bf491666c9e67685850f9c735d98a9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 22 May 2023 18:12:35 -0700 Subject: [PATCH 01/10] Document layout semver compatibility. --- src/doc/src/reference/semver.md | 106 ++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index 86353f6bbd3..49b7e98cf1c 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -59,6 +59,8 @@ considered incompatible. * Items * [Major: renaming/moving/removing any public items](#item-remove) * [Minor: adding new public items](#item-new) + * Types + * [Major: Changing the alignment, layout, or size of a well-defined type](#type-layout) * Structs * [Major: adding a private struct field when all current fields are public](#struct-add-private-field-when-public) * [Major: adding a public field when no private field exists](#struct-add-public-field-when-no-private) @@ -204,6 +206,110 @@ This is not considered a major change because conventionally glob imports are a known forwards-compatibility hazard. Glob imports of items from external crates should be avoided. +### Major: Changing the alignment, layout, or size of a well-defined type {#type-layout} + +It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined. + +In general, nominal types that use the [the default representation] do not have a well-defined alignment, layout, or size. +The compiler is free to alter the alignment or layout, so code should not make any assumptions about it. + +> **Note**: It may be possible for external crates to break if they make assumptions about the alignment, layout, or size of a type even if it is not well-defined. +> This is not considered a SemVer breaking change since those assumptions should not be made. + +Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated): + +* Adding, removing, or changing fields of a default representation struct, union, or enum. +* Adding variants to a default representation enum. + This may change the alignment or size of the enumeration, but those are not well-defined. +* Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum. + Note that this may be a breaking change since it may change the size and alignment of the type. + Care should be taken in this case. + Public fields may be added if there are private fields, or it is `non_exhaustive`, and the addition does not alter the layout of the other fields. +* Adding variants to a `repr(C)` enum. + Note that this may be a breaking change since it may change the size and alignment of the type. + Care should be taken in this case. +* Adding `repr(C)` to a default representation struct, union, or enum. +* Adding `repr()` [primitive representation] to an enum. +* Adding `repr(transparent)` to a default representation struct or enum. + +Nominal types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. + +Some examples of changes that are a breaking change are: + +* Adding `repr(packed)` to a struct or union. + + Making a type `repr(packed)` makes changes that can break code, such as being invalid to take a reference to a field, or causing truncation of disjoint closure captures. + + + +* Adding `repr(align)` to a struct, union, or enum. + + Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed. + + + +* Removing `repr(packed)` from a struct or union. + + This may change the alignment or layout that extern crates are relying on. + + If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work. + In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures]. + +* Changing the value N of `repr(packed(N))` if that changes the alignment or layout. + + This may change the alignment or layout that external crates are relying on. + + If the value N is lowered below the alignment of a public field, then that would break any code that attempts to take a reference of that field. + +* Changing the value N of `repr(align(N))` if that changes the alignment. + + This may change the alignment that external crates are relying on. + + This change should be safe to make if the type is not well-defined as discussed below (such as having any private fields and having an undocumented alignment or layout). + +* Removing `repr(align)` from a struct, union, or enum. + + This may change the alignment or layout that external crates are relying on. + + This change should be safe to make if the type is not well-defined as discussed below (such as having any private fields and having an undocumented alignment). + +* Changing the order of public fields of a `repr(C)` type. + + External crates may be relying on the specific ordering of the fields. + +* Removing `repr(C)` from a struct, union, or enum. + + External crates may be relying on the specific layout of the type. + +* Removing `repr()` from an enum. + + External crates may be assuming that the discriminant is a specific size. + + For example, [`std::mem::transmute`] of an enum may fail. + +* Changing the primitive representation of a `repr()` enum. + + External crates may be assuming that the discriminant is a specific size. + + For example, [`std::mem::transmute`] of an enum may fail. + +* Removing `repr(transparent)` from a struct or enum. + + External crates may be relying on the type having the alignment, layout, or size of the transparent field. + +In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. +In these cases, it may be safe to make changes to the types, though care should be exercised. +For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. + +A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, and which is documented as being transparent to the generic type. + + +[the default representation]: ../../reference/type-layout.html#the-default-representation +[primitive representation]: ../../reference/type-layout.html#primitive-representations +[`repr` attribute]: ../../reference/type-layout.html#representations +[edition-closures]: ../../edition-guide/rust-2021/disjoint-capture-in-closures.html +[`std::mem::transmute`]: ../../std/mem/fn.transmute.html + ### Major: adding a private struct field when all current fields are public {#struct-add-private-field-when-public} When a private field is added to a struct that previously had all public fields, From 661287e6bd50dacb869342ac5d56d97fcbe2f867 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 13 Jun 2023 20:10:10 -0700 Subject: [PATCH 02/10] Apply some edits from review to try to clarify things. --- src/doc/src/reference/semver.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index 49b7e98cf1c..b03f7a979fe 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -210,7 +210,7 @@ crates should be avoided. It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined. -In general, nominal types that use the [the default representation] do not have a well-defined alignment, layout, or size. +In general, types that use the [the default representation] do not have a well-defined alignment, layout, or size. The compiler is free to alter the alignment or layout, so code should not make any assumptions about it. > **Note**: It may be possible for external crates to break if they make assumptions about the alignment, layout, or size of a type even if it is not well-defined. @@ -218,14 +218,15 @@ The compiler is free to alter the alignment or layout, so code should not make a Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated): -* Adding, removing, or changing fields of a default representation struct, union, or enum. -* Adding variants to a default representation enum. +* Adding, removing, or changing fields of a default representation struct, union, or enum in such a way that the change follows the other rules in this guide (for example, using `non_exhaustive` to allow those changes, or changes to private fields that are already private). +* Adding variants to a default representation enum, if the enum uses `non_exhaustive`. This may change the alignment or size of the enumeration, but those are not well-defined. * Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum. Note that this may be a breaking change since it may change the size and alignment of the type. Care should be taken in this case. + Adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`. Public fields may be added if there are private fields, or it is `non_exhaustive`, and the addition does not alter the layout of the other fields. -* Adding variants to a `repr(C)` enum. +* Adding variants to a `repr(C)` enum, if the enum uses `non_exhastive`. Note that this may be a breaking change since it may change the size and alignment of the type. Care should be taken in this case. * Adding `repr(C)` to a default representation struct, union, or enum. @@ -234,7 +235,7 @@ Some examples of changes that are not a breaking change are (assuming no other r Nominal types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. -Some examples of changes that are a breaking change are: +Some examples of a breaking change are: * Adding `repr(packed)` to a struct or union. From 4c1d8f13641c5ae9f4eaa4750c3697386874f94f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jun 2023 13:43:05 -0700 Subject: [PATCH 03/10] Document the special code block annotations. --- crates/semver-check/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/semver-check/src/main.rs b/crates/semver-check/src/main.rs index fa4639eb79b..ea254e2fa1e 100644 --- a/crates/semver-check/src/main.rs +++ b/crates/semver-check/src/main.rs @@ -7,6 +7,11 @@ //! An example with the word "MINOR" at the top is expected to successfully //! build against the before and after. Otherwise it should fail. A comment of //! "// Error:" will check that the given message appears in the error output. +//! +//! The code block can also include the annotations: +//! - `run-fail`: The test should fail at runtime, not compiletime. +//! - `dont-deny`: By default tests have a `#![deny(warnings)]`. This option +//! avoids this attribute. Note that `#![allow(unused)]` is always added. use std::error::Error; use std::fs; From 96da3c487292172185d486c82e2b4717d471de94 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jun 2023 13:43:46 -0700 Subject: [PATCH 04/10] Support hidden lines. --- crates/semver-check/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/semver-check/src/main.rs b/crates/semver-check/src/main.rs index ea254e2fa1e..1ba405f576a 100644 --- a/crates/semver-check/src/main.rs +++ b/crates/semver-check/src/main.rs @@ -62,7 +62,13 @@ fn doit() -> Result<(), Box> { if line.trim() == "```" { break; } - block.push(line); + // Support rustdoc/mdbook hidden lines. + let line = line.strip_prefix("# ").unwrap_or(line); + if line == "#" { + block.push(""); + } else { + block.push(line); + } } None => { return Err(format!( From 406f43493155e049adb7ebddd5d901dc16aacac2 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jun 2023 15:06:55 -0700 Subject: [PATCH 05/10] Split out all layout rules into separate sections with examples. --- src/doc/src/reference/semver.md | 748 ++++++++++++++++++++++++++++++-- 1 file changed, 702 insertions(+), 46 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index b03f7a979fe..be625d6532c 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -211,7 +211,7 @@ crates should be avoided. It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined. In general, types that use the [the default representation] do not have a well-defined alignment, layout, or size. -The compiler is free to alter the alignment or layout, so code should not make any assumptions about it. +The compiler is free to alter the alignment, layout or size, so code should not make any assumptions about it. > **Note**: It may be possible for external crates to break if they make assumptions about the alignment, layout, or size of a type even if it is not well-defined. > This is not considered a SemVer breaking change since those assumptions should not be made. @@ -219,97 +219,753 @@ The compiler is free to alter the alignment or layout, so code should not make a Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated): * Adding, removing, or changing fields of a default representation struct, union, or enum in such a way that the change follows the other rules in this guide (for example, using `non_exhaustive` to allow those changes, or changes to private fields that are already private). + See [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new). * Adding variants to a default representation enum, if the enum uses `non_exhaustive`. This may change the alignment or size of the enumeration, but those are not well-defined. -* Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum. - Note that this may be a breaking change since it may change the size and alignment of the type. - Care should be taken in this case. - Adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`. - Public fields may be added if there are private fields, or it is `non_exhaustive`, and the addition does not alter the layout of the other fields. + See [enum-variant-new](#enum-variant-new). +* Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum, following the other rules in this guide (for example, using `non_exhaustive`, or adding private fields when other private fields already exist). + See [repr-c-private-change](#repr-c-private-change). * Adding variants to a `repr(C)` enum, if the enum uses `non_exhastive`. - Note that this may be a breaking change since it may change the size and alignment of the type. - Care should be taken in this case. + See [repr-c-enum-variant-new](#repr-c-enum-variant-new). * Adding `repr(C)` to a default representation struct, union, or enum. + See [repr-c-add](#repr-c-add). * Adding `repr()` [primitive representation] to an enum. + See [repr-int-enum-add](#repr-int-enum-add). * Adding `repr(transparent)` to a default representation struct or enum. + See [repr-transparent-add](#repr-transparent-add). Nominal types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. Some examples of a breaking change are: * Adding `repr(packed)` to a struct or union. + See [repr-packed-add](#repr-packed-add). +* Adding `repr(align)` to a struct, union, or enum. + See [repr-align-add](#repr-align-add). +* Removing `repr(packed)` from a struct or union. + See [repr-packed-remove](#repr-packed-remove). +* Changing the value N of `repr(packed(N))` if that changes the alignment or layout. + See [repr-packed-n-change](#repr-packed-n-change). +* Changing the value N of `repr(align(N))` if that changes the alignment. + See [repr-align-n-change](#repr-align-n-change). +* Removing `repr(align)` from a struct, union, or enum. + See [repr-align-remove](#repr-align-remove). +* Changing the order of public fields of a `repr(C)` type. + See [repr-c-shuffle](#repr-c-shuffle). +* Removing `repr(C)` from a struct, union, or enum. + See [repr-c-remove](#repr-c-remove). +* Removing `repr()` from an enum. + See [repr-int-enum-remove](#repr-int-enum-remove). +* Changing the primitive representation of a `repr()` enum. + See [repr-int-enum-change](#repr-int-enum-change). +* Removing `repr(transparent)` from a struct or enum. + See [repr-transparent-remove](#repr-transparent-remove). - Making a type `repr(packed)` makes changes that can break code, such as being invalid to take a reference to a field, or causing truncation of disjoint closure captures. +In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. +In these cases, it may be safe to make changes to the types, though care should be exercised. +For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. - +A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, and which is documented as being transparent to the generic type. +For example, see [`UnsafeCell`]. -* Adding `repr(align)` to a struct, union, or enum. +[the default representation]: ../../reference/type-layout.html#the-default-representation +[primitive representation]: ../../reference/type-layout.html#primitive-representations +[`repr` attribute]: ../../reference/type-layout.html#representations +[`std::mem::transmute`]: ../../std/mem/fn.transmute.html +[`UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html#memory-layout - Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed. + +#### Minor: `repr(C)` add, remove, or change a private field - +It is usually safe to add, remove, or change a private field of a `repr(C)` struct, union, or enum, assuming it follows the other guidelines in this guide (see [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new)). -* Removing `repr(packed)` from a struct or union. +For example, adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`. +Public fields may be added if there are private fields, or it is `non_exhaustive`, and the addition does not alter the layout of the other fields. - This may change the alignment or layout that extern crates are relying on. +However, this may change the size and alignment of the type. +Care should be taken if the size or alignment changes. +Code should not make assumptions about the size or alignment of types with private fields or `non_exhaustive` unless it has a documented size or alignment. - If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work. - In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures]. +```rust,ignore +// MINOR CHANGE -* Changing the value N of `repr(packed(N))` if that changes the alignment or layout. +/////////////////////////////////////////////////////////// +// Before +#[derive(Default)] +#[repr(C)] +pub struct Example { + pub f1: i32, + f2: i32, // a private field +} - This may change the alignment or layout that external crates are relying on. +/////////////////////////////////////////////////////////// +// After +#[derive(Default)] +#[repr(C)] +pub struct Example { + pub f1: i32, + f2: i32, + f3: i32, // a new field +} - If the value N is lowered below the alignment of a public field, then that would break any code that attempts to take a reference of that field. +/////////////////////////////////////////////////////////// +// Example use of the library that will safely work. +fn main() { + // NOTE: Users should not make assumptions about the size or alignment + // since they are not documented. + let f = updated_crate::Example::default(); +} +``` -* Changing the value N of `repr(align(N))` if that changes the alignment. + +#### Minor: `repr(C)` add enum variant - This may change the alignment that external crates are relying on. +It is usually safe to add variants to a `repr(C)` enum, if the enum uses `non_exhastive`. +See [enum-variant-new](#enum-variant-new) for more discussion. - This change should be safe to make if the type is not well-defined as discussed below (such as having any private fields and having an undocumented alignment or layout). +Note that this may be a breaking change since it changes the size and alignment of the type. +See [repr-c-private-change](#repr-c-private-change) for similar concerns. -* Removing `repr(align)` from a struct, union, or enum. +```rust,ignore +// MINOR CHANGE - This may change the alignment or layout that external crates are relying on. +/////////////////////////////////////////////////////////// +// Before +#[repr(C)] +#[non_exhaustive] +pub enum Example { + Variant1 { f1: i16 }, + Variant2 { f1: i32 }, +} - This change should be safe to make if the type is not well-defined as discussed below (such as having any private fields and having an undocumented alignment). +/////////////////////////////////////////////////////////// +// After +#[repr(C)] +#[non_exhaustive] +pub enum Example { + Variant1 { f1: i16 }, + Variant2 { f1: i32 }, + Variant3 { f1: i64 }, // added +} -* Changing the order of public fields of a `repr(C)` type. +/////////////////////////////////////////////////////////// +// Example use of the library that will safely work. +fn main() { + // NOTE: Users should not make assumptions about the size or alignment + // since they are not specified. For example, this raised the size from 8 + // to 16 bytes. + let f = updated_crate::Example::Variant2 { f1: 123 }; +} +``` - External crates may be relying on the specific ordering of the fields. + +#### Minor: Adding `repr(C)` to a default representation -* Removing `repr(C)` from a struct, union, or enum. +It is safe to add `repr(C)` to a struct, union, or enum with [the default representation]. +This is safe because users should not make assumptions about the alignment, layout, or size of types with with the default representation. - External crates may be relying on the specific layout of the type. +```rust,ignore +// MINOR CHANGE -* Removing `repr()` from an enum. +/////////////////////////////////////////////////////////// +// Before +pub struct Example { + pub f1: i32, + pub f2: i16, +} - External crates may be assuming that the discriminant is a specific size. +/////////////////////////////////////////////////////////// +// After +#[repr(C)] // added +pub struct Example { + pub f1: i32, + pub f2: i16, +} - For example, [`std::mem::transmute`] of an enum may fail. +/////////////////////////////////////////////////////////// +// Example use of the library that will safely work. +fn main() { + let f = updated_crate::Example { f1: 123, f2: 456 }; +} +``` -* Changing the primitive representation of a `repr()` enum. + +#### Minor: Adding `repr()` to an enum - External crates may be assuming that the discriminant is a specific size. +It is safe to add `repr()` [primitive representation] to an enum with [the default representation]. +This is safe because users should not make assumptions about the alignment, layout, or size of an enum with the default representation. - For example, [`std::mem::transmute`] of an enum may fail. +```rust,ignore +// MINOR CHANGE -* Removing `repr(transparent)` from a struct or enum. +/////////////////////////////////////////////////////////// +// Before +pub enum E { + Variant1, + Variant2(i32), + Variant3 { f1: f64 }, +} - External crates may be relying on the type having the alignment, layout, or size of the transparent field. +/////////////////////////////////////////////////////////// +// After +#[repr(i32)] // added +pub enum E { + Variant1, + Variant2(i32), + Variant3 { f1: f64 }, +} -In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. -In these cases, it may be safe to make changes to the types, though care should be exercised. -For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. +/////////////////////////////////////////////////////////// +// Example use of the library that will safely work. +fn main() { + let x = updated_crate::E::Variant3 { f1: 1.23 }; +} +``` -A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, and which is documented as being transparent to the generic type. + +#### Minor: Adding `repr(transparent)` to a default representation struct or enum +It is safe to add `repr(transparent)` to a struct or enum with [the default representation]. +This is safe because users should not make assumptions about the alignment, layout, or size of a struct or enum with the default representation. + +```rust,ignore +// MINOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[derive(Default)] +pub struct Example(T); + +/////////////////////////////////////////////////////////// +// After +#[derive(Default)] +#[repr(transparent)] // added +pub struct Example(T); + +/////////////////////////////////////////////////////////// +// Example use of the library that will safely work. +fn main() { + let x = updated_crate::Example::::default(); +} +``` + + +#### Major: Adding `repr(packed)` to a struct or union + +It is a breaking change to add `repr(packed)` to a struct or union. +Making a type `repr(packed)` makes changes that can break code, such as being invalid to take a reference to a field, or causing truncation of disjoint closure captures. + + + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub struct Example { + pub f1: u8, + pub f2: u16, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(packed)] // added +pub struct Example { + pub f1: u8, + pub f2: u16, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +fn main() { + let f = updated_crate::Example { f1: 1, f2: 2 }; + let x = &f.f2; // Error: reference to packed field is unaligned +} +``` + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub struct Example(pub i32, pub i32); + +/////////////////////////////////////////////////////////// +// After +#[repr(packed)] +pub struct Example(pub i32, pub i32); + +/////////////////////////////////////////////////////////// +// Example usage that will break. +fn main() { + let mut f = updated_crate::Example(123, 456); + let c = || { + // Without repr(packed), the closure precisely captures `&f.0`. + // With repr(packed), the closure captures `&f` to avoid undefined behavior. + let a = f.0; + }; + f.1 = 789; // Error: cannot assign to `f.1` because it is borrowed + c(); +} +``` + + +#### Major: Adding `repr(align)` to a struct, union, or enum + +It is a breaking change to add `repr(align)` to a struct, union, or enum. +Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed. + + + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub struct Aligned { + pub a: i32, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(align(8))] // added +pub struct Aligned { + pub a: i32, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Aligned; + +#[repr(packed)] +pub struct Packed { // Error: packed type cannot transitively contain a `#[repr(align)]` type + f1: Aligned, +} + +fn main() { + let p = Packed { + f1: Aligned { a: 123 }, + }; +} +``` + + +#### Major: Removing `repr(packed)` from a struct or union + +It is a breaking change to remove `repr(packed)` from a struct or union. +This may change the alignment or layout that extern crates are relying on. + +If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work. +In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures]. -[the default representation]: ../../reference/type-layout.html#the-default-representation -[primitive representation]: ../../reference/type-layout.html#primitive-representations -[`repr` attribute]: ../../reference/type-layout.html#representations [edition-closures]: ../../edition-guide/rust-2021/disjoint-capture-in-closures.html -[`std::mem::transmute`]: ../../std/mem/fn.transmute.html + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(C, packed)] +pub struct Packed { + pub a: u8, + pub b: u16, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(C)] // removed packed +pub struct Packed { + pub a: u8, + pub b: u16, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Packed; + +fn main() { + let p = Packed { a: 1, b: 2 }; + // Some assumption about the size of the type. + // Without `packed`, this fails since the size is 4. + const _: () = assert!(std::mem::size_of::() == 3); // Error: evaluation of constant value failed +} +``` + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(C, packed)] +pub struct Packed { + pub a: *mut i32, + pub b: i32, +} +unsafe impl Send for Packed {} + +/////////////////////////////////////////////////////////// +// After +#[repr(C)] // removed packed +pub struct Packed { + pub a: *mut i32, + pub b: i32, +} +unsafe impl Send for Packed {} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Packed; + +fn main() { + let mut x = 123; + + let p = Packed { + a: &mut x as *mut i32, + b: 456, + }; + + // When the structure was packed, the closure captures `p` which is Send. + // When `packed` is removed, this ends up capturing `p.a` which is not Send. + std::thread::spawn(move || unsafe { + *(p.a) += 1; // Error: cannot be sent between threads safely + }); +} +``` + + +#### Major: Changing the value N of `repr(packed(N))` if that changes the alignment or layout + +It is a breaking change to change the value of N of `repr(packed(N))` if that changes the alignment or layout. +This may change the alignment or layout that external crates are relying on. + +If the value `N` is lowered below the alignment of a public field, then that would break any code that attempts to take a reference of that field. + +Note that some changes to `N` may not change the alignment or layout, for example increasing it when the current value is already equal to the natural alignment of the type. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(packed(4))] +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(packed(2))] // changed to 2 +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Packed; + +fn main() { + let p = Packed { a: 1, b: 2 }; + let x = &p.b; // Error: reference to packed field is unaligned +} +``` + + +#### Major: Changing the value N of `repr(align(N))` if that changes the alignment + +It is a breaking change to change the value `N` of `repr(align(N))` if that changes the alignment. +This may change the alignment that external crates are relying on. + +This change should be safe to make if the type is not well-defined as discussed in [type layout](#type-layout) (such as having any private fields and having an undocumented alignment or layout). + +Note that some changes to `N` may not change the alignment or layout, for example decreasing it when the current value is already equal to or less than the natural alignment of the type. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(align(8))] +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(align(4))] // changed to 4 +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Packed; + +fn main() { + let p = Packed { a: 1, b: 2 }; + // Some assumption about the size of the type. + // The alignment has changed from 8 to 4. + const _: () = assert!(std::mem::align_of::() == 8); // Error: evaluation of constant value failed +} +``` + + +#### Major: Removing `repr(align)` from a struct, union, or enum + +It is a breaking change to remove `repr(align)` from a struct, union, or enum. +This may change the alignment or layout that external crates are relying on. + +This change should be safe to make if the type is not well-defined as discussed in [type layout](#type-layout) (such as having any private fields and having an undocumented alignment). + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(C, align(8))] +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(C)] // removed align +pub struct Packed { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::Packed; + +fn main() { + let p = Packed { a: 1, b: 2 }; + // Some assumption about the size of the type. + // The alignment has changed from 8 to 4. + const _: () = assert!(std::mem::align_of::() == 8); // Error: evaluation of constant value failed +} +``` + + +#### Major: Changing the order of public fields of a `repr(C)` type + +It is a breaking change to change the order of public fields of a `repr(C)` type. +External crates may be relying on the specific ordering of the fields. + +```rust,ignore,run-fail +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(C)] +pub struct SpecificLayout { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(C)] +pub struct SpecificLayout { + pub b: u32, // changed order + pub a: u8, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::SpecificLayout; + +extern "C" { + // This C function is assuming a specific layout defined in a C header. + fn c_fn_get_b(x: &SpecificLayout) -> u32; +} + +fn main() { + let p = SpecificLayout { a: 1, b: 2 }; + unsafe { assert_eq!(c_fn_get_b(&p), 2) } // Error: value not equal to 2 +} + +# mod cdep { +# // This simulates what would normally be something included from a build script. +# // This definition would be in a C header. +# #[repr(C)] +# pub struct SpecificLayout { +# pub a: u8, +# pub b: u32, +# } +# +# #[no_mangle] +# pub fn c_fn_get_b(x: &SpecificLayout) -> u32 { +# x.b +# } +# } +``` + + +#### Major: Removing `repr(C)` from a struct, union, or enum + +It is a breaking change to remove `repr(C)` from a struct, union, or enum. +External crates may be relying on the specific layout of the type. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(C)] +pub struct SpecificLayout { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// After +// removed repr(C) +pub struct SpecificLayout { + pub a: u8, + pub b: u32, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::SpecificLayout; + +extern "C" { + // This C function is assuming a specific layout defined in a C header. + fn c_fn_get_b(x: &SpecificLayout) -> u32; // Error: is not FFI-safe +} + +fn main() { + let p = SpecificLayout { a: 1, b: 2 }; + unsafe { assert_eq!(c_fn_get_b(&p), 2) } +} + +# mod cdep { +# // This simulates what would normally be something included from a build script. +# // This definition would be in a C header. +# #[repr(C)] +# pub struct SpecificLayout { +# pub a: u8, +# pub b: u32, +# } +# +# #[no_mangle] +# pub fn c_fn_get_b(x: &SpecificLayout) -> u32 { +# x.b +# } +# } +``` + + +#### Major: Removing `repr()` from an enum + +It is a breaking change to remove `repr()` from an enum. +External crates may be assuming that the discriminant is a specific size. +For example, [`std::mem::transmute`] of an enum may fail. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(u16)] +pub enum Example { + Variant1, + Variant2, + Variant3, +} + +/////////////////////////////////////////////////////////// +// After +// removed repr(u16) +pub enum Example { + Variant1, + Variant2, + Variant3, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. + +fn main() { + let e = updated_crate::Example::Variant2; + let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes +} +``` + + +#### Major: Changing the primitive representation of a `repr()` enum + +It is a breaking change to change the primitive representation of a `repr()` enum. +External crates may be assuming that the discriminant is a specific size. +For example, [`std::mem::transmute`] of an enum may fail. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(u16)] +pub enum Example { + Variant1, + Variant2, + Variant3, +} + +/////////////////////////////////////////////////////////// +// After +#[repr(u8)] // changed repr size +pub enum Example { + Variant1, + Variant2, + Variant3, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. + +fn main() { + let e = updated_crate::Example::Variant2; + let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes +} +``` + + +#### Major: Removing `repr(transparent)` from a struct or enum + +It is a breaking change to remove `repr(transparent)` from a struct or enum. +External crates may be relying on the type having the alignment, layout, or size of the transparent field. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +#[repr(transparent)] +pub struct Transparent(T); + +/////////////////////////////////////////////////////////// +// After +// removed repr +pub struct Transparent(T); + +/////////////////////////////////////////////////////////// +// Example usage that will break. +#![deny(improper_ctypes)] +use updated_crate::Transparent; + +extern "C" { + fn c_fn() -> Transparent; // Error: is not FFI-safe +} + +fn main() {} +``` + ### Major: adding a private struct field when all current fields are public {#struct-add-private-field-when-public} From 99d2aa91593f8dae67ed7ae690b9265e93524d84 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Jul 2023 07:12:09 -0700 Subject: [PATCH 06/10] Clarify what it means "to document" a transparent type. --- src/doc/src/reference/semver.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index be625d6532c..17280190727 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -265,7 +265,8 @@ In some cases, types with a `repr` attribute may not have an alignment, layout, In these cases, it may be safe to make changes to the types, though care should be exercised. For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. -A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, and which is documented as being transparent to the generic type. +A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, +and the prose of the documentation discusses that it is transparent to the generic type. For example, see [`UnsafeCell`]. [the default representation]: ../../reference/type-layout.html#the-default-representation From 9e274d07bd8482f91d0ec06bdbd2497a46ae8b8c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 6 Aug 2023 09:09:20 -0700 Subject: [PATCH 07/10] Apply changes from review from obi1kenobi. --- src/doc/src/reference/semver.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index 17280190727..7830063a69d 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -716,7 +716,7 @@ fn main() { #### Major: Removing `repr(align)` from a struct, union, or enum -It is a breaking change to remove `repr(align)` from a struct, union, or enum. +It is a breaking change to remove `repr(align)` from a struct, union, or enum, if their layout was well-defined. This may change the alignment or layout that external crates are relying on. This change should be safe to make if the type is not well-defined as discussed in [type layout](#type-layout) (such as having any private fields and having an undocumented alignment). @@ -967,7 +967,6 @@ extern "C" { fn main() {} ``` - ### Major: adding a private struct field when all current fields are public {#struct-add-private-field-when-public} When a private field is added to a struct that previously had all public fields, From 58aef649ddb1ac2dd3be3f9404403fdcd3fa7aa4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 12 Aug 2023 12:38:59 -0700 Subject: [PATCH 08/10] Add "reordering" to list of changes. Co-authored-by: the8472 --- src/doc/src/reference/semver.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index 7830063a69d..cfbe88a8af1 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -218,12 +218,12 @@ The compiler is free to alter the alignment, layout or size, so code should not Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated): -* Adding, removing, or changing fields of a default representation struct, union, or enum in such a way that the change follows the other rules in this guide (for example, using `non_exhaustive` to allow those changes, or changes to private fields that are already private). +* Adding, removing, reordering, or changing fields of a default representation struct, union, or enum in such a way that the change follows the other rules in this guide (for example, using `non_exhaustive` to allow those changes, or changes to private fields that are already private). See [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new). * Adding variants to a default representation enum, if the enum uses `non_exhaustive`. This may change the alignment or size of the enumeration, but those are not well-defined. See [enum-variant-new](#enum-variant-new). -* Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum, following the other rules in this guide (for example, using `non_exhaustive`, or adding private fields when other private fields already exist). +* Adding, removing, reordering, or changing private fields of a `repr(C)` struct, union, or enum, following the other rules in this guide (for example, using `non_exhaustive`, or adding private fields when other private fields already exist). See [repr-c-private-change](#repr-c-private-change). * Adding variants to a `repr(C)` enum, if the enum uses `non_exhastive`. See [repr-c-enum-variant-new](#repr-c-enum-variant-new). From a2b36f69377002b9e3540933ed28f00daa115153 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 17 Aug 2023 18:07:44 -0700 Subject: [PATCH 09/10] Updates from review from joshtriplett --- src/doc/src/reference/semver.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index cfbe88a8af1..ccb12d22227 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -211,7 +211,7 @@ crates should be avoided. It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined. In general, types that use the [the default representation] do not have a well-defined alignment, layout, or size. -The compiler is free to alter the alignment, layout or size, so code should not make any assumptions about it. +The compiler is free to alter the alignment, layout, or size, so code should not make any assumptions about it. > **Note**: It may be possible for external crates to break if they make assumptions about the alignment, layout, or size of a type even if it is not well-defined. > This is not considered a SemVer breaking change since those assumptions should not be made. @@ -225,7 +225,7 @@ Some examples of changes that are not a breaking change are (assuming no other r See [enum-variant-new](#enum-variant-new). * Adding, removing, reordering, or changing private fields of a `repr(C)` struct, union, or enum, following the other rules in this guide (for example, using `non_exhaustive`, or adding private fields when other private fields already exist). See [repr-c-private-change](#repr-c-private-change). -* Adding variants to a `repr(C)` enum, if the enum uses `non_exhastive`. +* Adding variants to a `repr(C)` enum, if the enum uses `non_exhaustive`. See [repr-c-enum-variant-new](#repr-c-enum-variant-new). * Adding `repr(C)` to a default representation struct, union, or enum. See [repr-c-add](#repr-c-add). @@ -234,9 +234,17 @@ Some examples of changes that are not a breaking change are (assuming no other r * Adding `repr(transparent)` to a default representation struct or enum. See [repr-transparent-add](#repr-transparent-add). -Nominal types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. +Types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. -Some examples of a breaking change are: +In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. +In these cases, it may be safe to make changes to the types, though care should be exercised. +For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. + +A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, +and the prose of the documentation discusses that it is transparent to the generic type. +For example, see [`UnsafeCell`]. + +Some examples of breaking changes are: * Adding `repr(packed)` to a struct or union. See [repr-packed-add](#repr-packed-add). @@ -261,14 +269,6 @@ Some examples of a breaking change are: * Removing `repr(transparent)` from a struct or enum. See [repr-transparent-remove](#repr-transparent-remove). -In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. -In these cases, it may be safe to make changes to the types, though care should be exercised. -For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. - -A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, -and the prose of the documentation discusses that it is transparent to the generic type. -For example, see [`UnsafeCell`]. - [the default representation]: ../../reference/type-layout.html#the-default-representation [primitive representation]: ../../reference/type-layout.html#primitive-representations [`repr` attribute]: ../../reference/type-layout.html#representations From 5dc86dc5f8e96b4f0ee58c0a4b3ae42f99e96429 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 17 Aug 2023 18:21:54 -0700 Subject: [PATCH 10/10] Use header IDs --- src/doc/src/reference/semver.md | 48 +++++++++++---------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/src/doc/src/reference/semver.md b/src/doc/src/reference/semver.md index ccb12d22227..69d983078b5 100644 --- a/src/doc/src/reference/semver.md +++ b/src/doc/src/reference/semver.md @@ -275,8 +275,7 @@ Some examples of breaking changes are: [`std::mem::transmute`]: ../../std/mem/fn.transmute.html [`UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html#memory-layout - -#### Minor: `repr(C)` add, remove, or change a private field +#### Minor: `repr(C)` add, remove, or change a private field {#repr-c-private-change} It is usually safe to add, remove, or change a private field of a `repr(C)` struct, union, or enum, assuming it follows the other guidelines in this guide (see [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new)). @@ -318,8 +317,7 @@ fn main() { } ``` - -#### Minor: `repr(C)` add enum variant +#### Minor: `repr(C)` add enum variant {#repr-c-enum-variant-new} It is usually safe to add variants to a `repr(C)` enum, if the enum uses `non_exhastive`. See [enum-variant-new](#enum-variant-new) for more discussion. @@ -359,8 +357,7 @@ fn main() { } ``` - -#### Minor: Adding `repr(C)` to a default representation +#### Minor: Adding `repr(C)` to a default representation {#repr-c-add} It is safe to add `repr(C)` to a struct, union, or enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of types with with the default representation. @@ -390,8 +387,7 @@ fn main() { } ``` - -#### Minor: Adding `repr()` to an enum +#### Minor: Adding `repr()` to an enum {#repr-int-enum-add} It is safe to add `repr()` [primitive representation] to an enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of an enum with the default representation. @@ -423,8 +419,7 @@ fn main() { } ``` - -#### Minor: Adding `repr(transparent)` to a default representation struct or enum +#### Minor: Adding `repr(transparent)` to a default representation struct or enum {#repr-transparent-add} It is safe to add `repr(transparent)` to a struct or enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of a struct or enum with the default representation. @@ -450,8 +445,7 @@ fn main() { } ``` - -#### Major: Adding `repr(packed)` to a struct or union +#### Major: Adding `repr(packed)` to a struct or union {#repr-packed-add} It is a breaking change to add `repr(packed)` to a struct or union. Making a type `repr(packed)` makes changes that can break code, such as being invalid to take a reference to a field, or causing truncation of disjoint closure captures. @@ -510,8 +504,7 @@ fn main() { } ``` - -#### Major: Adding `repr(align)` to a struct, union, or enum +#### Major: Adding `repr(align)` to a struct, union, or enum {#repr-align-add} It is a breaking change to add `repr(align)` to a struct, union, or enum. Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed. @@ -550,8 +543,7 @@ fn main() { } ``` - -#### Major: Removing `repr(packed)` from a struct or union +#### Major: Removing `repr(packed)` from a struct or union {#repr-packed-remove} It is a breaking change to remove `repr(packed)` from a struct or union. This may change the alignment or layout that extern crates are relying on. @@ -633,8 +625,7 @@ fn main() { } ``` - -#### Major: Changing the value N of `repr(packed(N))` if that changes the alignment or layout +#### Major: Changing the value N of `repr(packed(N))` if that changes the alignment or layout {#repr-packed-n-change} It is a breaking change to change the value of N of `repr(packed(N))` if that changes the alignment or layout. This may change the alignment or layout that external crates are relying on. @@ -672,8 +663,7 @@ fn main() { } ``` - -#### Major: Changing the value N of `repr(align(N))` if that changes the alignment +#### Major: Changing the value N of `repr(align(N))` if that changes the alignment {#repr-align-n-change} It is a breaking change to change the value `N` of `repr(align(N))` if that changes the alignment. This may change the alignment that external crates are relying on. @@ -713,8 +703,7 @@ fn main() { } ``` - -#### Major: Removing `repr(align)` from a struct, union, or enum +#### Major: Removing `repr(align)` from a struct, union, or enum {#repr-align-remove} It is a breaking change to remove `repr(align)` from a struct, union, or enum, if their layout was well-defined. This may change the alignment or layout that external crates are relying on. @@ -752,8 +741,7 @@ fn main() { } ``` - -#### Major: Changing the order of public fields of a `repr(C)` type +#### Major: Changing the order of public fields of a `repr(C)` type {#repr-c-shuffle} It is a breaking change to change the order of public fields of a `repr(C)` type. External crates may be relying on the specific ordering of the fields. @@ -807,8 +795,7 @@ fn main() { # } ``` - -#### Major: Removing `repr(C)` from a struct, union, or enum +#### Major: Removing `repr(C)` from a struct, union, or enum {#repr-c-remove} It is a breaking change to remove `repr(C)` from a struct, union, or enum. External crates may be relying on the specific layout of the type. @@ -862,8 +849,7 @@ fn main() { # } ``` - -#### Major: Removing `repr()` from an enum +#### Major: Removing `repr()` from an enum {#repr-int-enum-remove} It is a breaking change to remove `repr()` from an enum. External crates may be assuming that the discriminant is a specific size. @@ -899,8 +885,7 @@ fn main() { } ``` - -#### Major: Changing the primitive representation of a `repr()` enum +#### Major: Changing the primitive representation of a `repr()` enum {#repr-int-enum-change} It is a breaking change to change the primitive representation of a `repr()` enum. External crates may be assuming that the discriminant is a specific size. @@ -936,8 +921,7 @@ fn main() { } ``` - -#### Major: Removing `repr(transparent)` from a struct or enum +#### Major: Removing `repr(transparent)` from a struct or enum {#repr-transparent-remove} It is a breaking change to remove `repr(transparent)` from a struct or enum. External crates may be relying on the type having the alignment, layout, or size of the transparent field.