Skip to content

Commit 74d46dd

Browse files
committed
Document layout semver compatibility.
1 parent e5e68c4 commit 74d46dd

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

src/doc/src/reference/semver.md

+107
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ considered incompatible.
5959
* Items
6060
* [Major: renaming/moving/removing any public items](#item-remove)
6161
* [Minor: adding new public items](#item-new)
62+
* Types
63+
* [Major: Changing the alignment, layout, or size of a well-defined type](#type-layout)
6264
* Structs
6365
* [Major: adding a private struct field when all current fields are public](#struct-add-private-field-when-public)
6466
* [Major: adding a public field when no private field exists](#struct-add-public-field-when-no-private)
@@ -206,6 +208,111 @@ This is not considered a major change because conventionally glob imports are
206208
a known forwards-compatibility hazard. Glob imports of items from external
207209
crates should be avoided.
208210

211+
<a id="type-layout"></a>
212+
### Major: Changing the alignment, layout, or size of a well-defined type
213+
214+
It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined.
215+
216+
In general, nominal types that use the [the default representation] do not have a well-defined alignment, layout, or size.
217+
The compiler is free to alter the alignment or layout, so code should not make any assumptions about it.
218+
219+
> **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.
220+
> This is not considered a SemVer breaking change since those assumptions should not be made.
221+
222+
Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated):
223+
224+
* Adding, removing, or changing fields of a default representation struct, union, or enum.
225+
* Adding variants to a default representation enum.
226+
This may change the alignment or size of the enumeration, but those are not well-defined.
227+
* Adding, removing, or changing private fields of a `repr(C)` struct, union, or enum.
228+
Note that this may be a breaking change since it may change the size and alignment of the type.
229+
Care should be taken in this case.
230+
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.
231+
* Adding variants to a `repr(C)` enum.
232+
Note that this may be a breaking change since it may change the size and alignment of the type.
233+
Care should be taken in this case.
234+
* Adding `repr(C)` to a default representation struct, union, or enum.
235+
* Adding `repr(<int>)` [primitive representation] to an enum.
236+
* Adding `repr(transparent)` to a default representation struct or enum.
237+
238+
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.
239+
240+
Some examples of changes that are a breaking change are:
241+
242+
* Adding `repr(packed)` to a struct or union.
243+
244+
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.
245+
246+
<!-- TODO: If all fields are private, should this be safe to do? -->
247+
248+
* Adding `repr(align)` to a struct, union, or enum.
249+
250+
Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed.
251+
252+
<!-- TODO: This seems like it should be extraordinarily rare. Should there be any exceptions carved out for this? -->
253+
254+
* Removing `repr(packed)` from a struct or union.
255+
256+
This may change the alignment or layout that extern crates are relying on.
257+
258+
If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work.
259+
In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures].
260+
261+
* Changing the value N of `repr(packed(N))` if that changes the alignment or layout.
262+
263+
This may change the alignment or layout that external crates are relying on.
264+
265+
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.
266+
267+
* Changing the value N of `repr(align(N))` if that changes the alignment.
268+
269+
This may change the alignment that external crates are relying on.
270+
271+
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).
272+
273+
* Removing `repr(align)` from a struct, union, or enum.
274+
275+
This may change the alignment or layout that external crates are relying on.
276+
277+
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).
278+
279+
* Changing the order of public fields of a `repr(C)` type.
280+
281+
External crates may be relying on the specific ordering of the fields.
282+
283+
* Removing `repr(C)` from a struct, union, or enum.
284+
285+
External crates may be relying on the specific layout of the type.
286+
287+
* Removing `repr(<int>)` from an enum.
288+
289+
External crates may be assuming that the discriminant is a specific size.
290+
291+
For example, [`std::mem::transmute`] of an enum may fail.
292+
293+
* Changing the primitive representation of a `repr(<int>)` enum.
294+
295+
External crates may be assuming that the discriminant is a specific size.
296+
297+
For example, [`std::mem::transmute`] of an enum may fail.
298+
299+
* Removing `repr(transparent)` from a struct or enum.
300+
301+
External crates may be relying on the type having the alignment, layout, or size of the transparent field.
302+
303+
In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined.
304+
In these cases, it may be safe to make changes to the types, though care should be exercised.
305+
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.
306+
307+
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.
308+
309+
310+
[the default representation]: ../../reference/type-layout.html#the-default-representation
311+
[primitive representation]: ../../reference/type-layout.html#primitive-representations
312+
[`repr` attribute]: ../../reference/type-layout.html#representations
313+
[edition-closures]: ../../edition-guide/rust-2021/disjoint-capture-in-closures.html
314+
[`std::mem::transmute`]: ../../std/mem/fn.transmute.html
315+
209316
<a id="struct-add-private-field-when-public"></a>
210317
### Major: adding a private struct field when all current fields are public
211318

0 commit comments

Comments
 (0)