Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d105f9d

Browse files
committedJun 15, 2023
Split out all layout rules into separate sections with examples.
1 parent 4881da1 commit d105f9d

File tree

1 file changed

+702
-46
lines changed

1 file changed

+702
-46
lines changed
 

‎src/doc/src/reference/semver.md

Lines changed: 702 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -214,105 +214,761 @@ crates should be avoided.
214214
It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined.
215215

216216
In general, 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.
217+
The compiler is free to alter the alignment, layout or size, so code should not make any assumptions about it.
218218

219219
> **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.
220220
> This is not considered a SemVer breaking change since those assumptions should not be made.
221221
222222
Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated):
223223

224224
* 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).
225+
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).
225226
* Adding variants to a default representation enum, if the enum uses `non_exhaustive`.
226227
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-
Adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`.
231-
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.
228+
See [enum-variant-new](#enum-variant-new).
229+
* 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).
230+
See [repr-c-private-change](#repr-c-private-change).
232231
* Adding variants to a `repr(C)` enum, if the enum uses `non_exhastive`.
233-
Note that this may be a breaking change since it may change the size and alignment of the type.
234-
Care should be taken in this case.
232+
See [repr-c-enum-variant-new](#repr-c-enum-variant-new).
235233
* Adding `repr(C)` to a default representation struct, union, or enum.
234+
See [repr-c-add](#repr-c-add).
236235
* Adding `repr(<int>)` [primitive representation] to an enum.
236+
See [repr-int-enum-add](#repr-int-enum-add).
237237
* Adding `repr(transparent)` to a default representation struct or enum.
238+
See [repr-transparent-add](#repr-transparent-add).
238239

239240
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.
240241

241242
Some examples of a breaking change are:
242243

243244
* Adding `repr(packed)` to a struct or union.
245+
See [repr-packed-add](#repr-packed-add).
246+
* Adding `repr(align)` to a struct, union, or enum.
247+
See [repr-align-add](#repr-align-add).
248+
* Removing `repr(packed)` from a struct or union.
249+
See [repr-packed-remove](#repr-packed-remove).
250+
* Changing the value N of `repr(packed(N))` if that changes the alignment or layout.
251+
See [repr-packed-n-change](#repr-packed-n-change).
252+
* Changing the value N of `repr(align(N))` if that changes the alignment.
253+
See [repr-align-n-change](#repr-align-n-change).
254+
* Removing `repr(align)` from a struct, union, or enum.
255+
See [repr-align-remove](#repr-align-remove).
256+
* Changing the order of public fields of a `repr(C)` type.
257+
See [repr-c-shuffle](#repr-c-shuffle).
258+
* Removing `repr(C)` from a struct, union, or enum.
259+
See [repr-c-remove](#repr-c-remove).
260+
* Removing `repr(<int>)` from an enum.
261+
See [repr-int-enum-remove](#repr-int-enum-remove).
262+
* Changing the primitive representation of a `repr(<int>)` enum.
263+
See [repr-int-enum-change](#repr-int-enum-change).
264+
* Removing `repr(transparent)` from a struct or enum.
265+
See [repr-transparent-remove](#repr-transparent-remove).
244266

245-
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.
267+
In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined.
268+
In these cases, it may be safe to make changes to the types, though care should be exercised.
269+
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.
246270

247-
<!-- TODO: If all fields are private, should this be safe to do? -->
271+
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.
272+
For example, see [`UnsafeCell`].
248273

249-
* Adding `repr(align)` to a struct, union, or enum.
274+
[the default representation]: ../../reference/type-layout.html#the-default-representation
275+
[primitive representation]: ../../reference/type-layout.html#primitive-representations
276+
[`repr` attribute]: ../../reference/type-layout.html#representations
277+
[`std::mem::transmute`]: ../../std/mem/fn.transmute.html
278+
[`UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html#memory-layout
250279

251-
Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed.
280+
<a id="repr-c-private-change"></a>
281+
#### Minor: `repr(C)` add, remove, or change a private field
252282

253-
<!-- TODO: This seems like it should be extraordinarily rare. Should there be any exceptions carved out for this? -->
283+
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)).
254284

255-
* Removing `repr(packed)` from a struct or union.
285+
For example, adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`.
286+
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.
256287

257-
This may change the alignment or layout that extern crates are relying on.
288+
However, this may change the size and alignment of the type.
289+
Care should be taken if the size or alignment changes.
290+
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.
258291

259-
If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work.
260-
In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures].
292+
```rust,ignore
293+
// MINOR CHANGE
261294
262-
* Changing the value N of `repr(packed(N))` if that changes the alignment or layout.
295+
///////////////////////////////////////////////////////////
296+
// Before
297+
#[derive(Default)]
298+
#[repr(C)]
299+
pub struct Example {
300+
pub f1: i32,
301+
f2: i32, // a private field
302+
}
263303
264-
This may change the alignment or layout that external crates are relying on.
304+
///////////////////////////////////////////////////////////
305+
// After
306+
#[derive(Default)]
307+
#[repr(C)]
308+
pub struct Example {
309+
pub f1: i32,
310+
f2: i32,
311+
f3: i32, // a new field
312+
}
265313
266-
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.
314+
///////////////////////////////////////////////////////////
315+
// Example use of the library that will safely work.
316+
fn main() {
317+
// NOTE: Users should not make assumptions about the size or alignment
318+
// since they are not documented.
319+
let f = updated_crate::Example::default();
320+
}
321+
```
267322

268-
* Changing the value N of `repr(align(N))` if that changes the alignment.
323+
<a id="repr-c-enum-variant-new"></a>
324+
#### Minor: `repr(C)` add enum variant
269325

270-
This may change the alignment that external crates are relying on.
326+
It is usually safe to add variants to a `repr(C)` enum, if the enum uses `non_exhastive`.
327+
See [enum-variant-new](#enum-variant-new) for more discussion.
271328

272-
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).
329+
Note that this may be a breaking change since it changes the size and alignment of the type.
330+
See [repr-c-private-change](#repr-c-private-change) for similar concerns.
273331

274-
* Removing `repr(align)` from a struct, union, or enum.
332+
```rust,ignore
333+
// MINOR CHANGE
275334
276-
This may change the alignment or layout that external crates are relying on.
335+
///////////////////////////////////////////////////////////
336+
// Before
337+
#[repr(C)]
338+
#[non_exhaustive]
339+
pub enum Example {
340+
Variant1 { f1: i16 },
341+
Variant2 { f1: i32 },
342+
}
277343
278-
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).
344+
///////////////////////////////////////////////////////////
345+
// After
346+
#[repr(C)]
347+
#[non_exhaustive]
348+
pub enum Example {
349+
Variant1 { f1: i16 },
350+
Variant2 { f1: i32 },
351+
Variant3 { f1: i64 }, // added
352+
}
279353
280-
* Changing the order of public fields of a `repr(C)` type.
354+
///////////////////////////////////////////////////////////
355+
// Example use of the library that will safely work.
356+
fn main() {
357+
// NOTE: Users should not make assumptions about the size or alignment
358+
// since they are not specified. For example, this raised the size from 8
359+
// to 16 bytes.
360+
let f = updated_crate::Example::Variant2 { f1: 123 };
361+
}
362+
```
281363

282-
External crates may be relying on the specific ordering of the fields.
364+
<a id="repr-c-add"></a>
365+
#### Minor: Adding `repr(C)` to a default representation
283366

284-
* Removing `repr(C)` from a struct, union, or enum.
367+
It is safe to add `repr(C)` to a struct, union, or enum with [the default representation].
368+
This is safe because users should not make assumptions about the alignment, layout, or size of types with with the default representation.
285369

286-
External crates may be relying on the specific layout of the type.
370+
```rust,ignore
371+
// MINOR CHANGE
287372
288-
* Removing `repr(<int>)` from an enum.
373+
///////////////////////////////////////////////////////////
374+
// Before
375+
pub struct Example {
376+
pub f1: i32,
377+
pub f2: i16,
378+
}
289379
290-
External crates may be assuming that the discriminant is a specific size.
380+
///////////////////////////////////////////////////////////
381+
// After
382+
#[repr(C)] // added
383+
pub struct Example {
384+
pub f1: i32,
385+
pub f2: i16,
386+
}
291387
292-
For example, [`std::mem::transmute`] of an enum may fail.
388+
///////////////////////////////////////////////////////////
389+
// Example use of the library that will safely work.
390+
fn main() {
391+
let f = updated_crate::Example { f1: 123, f2: 456 };
392+
}
393+
```
293394

294-
* Changing the primitive representation of a `repr(<int>)` enum.
395+
<a id="repr-int-enum-add"></a>
396+
#### Minor: Adding `repr(<int>)` to an enum
295397

296-
External crates may be assuming that the discriminant is a specific size.
398+
It is safe to add `repr(<int>)` [primitive representation] to an enum with [the default representation].
399+
This is safe because users should not make assumptions about the alignment, layout, or size of an enum with the default representation.
297400

298-
For example, [`std::mem::transmute`] of an enum may fail.
401+
```rust,ignore
402+
// MINOR CHANGE
299403
300-
* Removing `repr(transparent)` from a struct or enum.
404+
///////////////////////////////////////////////////////////
405+
// Before
406+
pub enum E {
407+
Variant1,
408+
Variant2(i32),
409+
Variant3 { f1: f64 },
410+
}
301411
302-
External crates may be relying on the type having the alignment, layout, or size of the transparent field.
412+
///////////////////////////////////////////////////////////
413+
// After
414+
#[repr(i32)] // added
415+
pub enum E {
416+
Variant1,
417+
Variant2(i32),
418+
Variant3 { f1: f64 },
419+
}
303420
304-
In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined.
305-
In these cases, it may be safe to make changes to the types, though care should be exercised.
306-
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.
421+
///////////////////////////////////////////////////////////
422+
// Example use of the library that will safely work.
423+
fn main() {
424+
let x = updated_crate::E::Variant3 { f1: 1.23 };
425+
}
426+
```
307427

308-
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.
428+
<a id="repr-transparent-add"></a>
429+
#### Minor: Adding `repr(transparent)` to a default representation struct or enum
309430

431+
It is safe to add `repr(transparent)` to a struct or enum with [the default representation].
432+
This is safe because users should not make assumptions about the alignment, layout, or size of a struct or enum with the default representation.
433+
434+
```rust,ignore
435+
// MINOR CHANGE
436+
437+
///////////////////////////////////////////////////////////
438+
// Before
439+
#[derive(Default)]
440+
pub struct Example<T>(T);
441+
442+
///////////////////////////////////////////////////////////
443+
// After
444+
#[derive(Default)]
445+
#[repr(transparent)] // added
446+
pub struct Example<T>(T);
447+
448+
///////////////////////////////////////////////////////////
449+
// Example use of the library that will safely work.
450+
fn main() {
451+
let x = updated_crate::Example::<i32>::default();
452+
}
453+
```
454+
455+
<a id="repr-packed-add"></a>
456+
#### Major: Adding `repr(packed)` to a struct or union
457+
458+
It is a breaking change to add `repr(packed)` to a struct or union.
459+
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.
460+
461+
<!-- TODO: If all fields are private, should this be safe to do? -->
462+
463+
```rust,ignore
464+
// MAJOR CHANGE
465+
466+
///////////////////////////////////////////////////////////
467+
// Before
468+
pub struct Example {
469+
pub f1: u8,
470+
pub f2: u16,
471+
}
472+
473+
///////////////////////////////////////////////////////////
474+
// After
475+
#[repr(packed)] // added
476+
pub struct Example {
477+
pub f1: u8,
478+
pub f2: u16,
479+
}
480+
481+
///////////////////////////////////////////////////////////
482+
// Example usage that will break.
483+
fn main() {
484+
let f = updated_crate::Example { f1: 1, f2: 2 };
485+
let x = &f.f2; // Error: reference to packed field is unaligned
486+
}
487+
```
488+
489+
```rust,ignore
490+
// MAJOR CHANGE
491+
492+
///////////////////////////////////////////////////////////
493+
// Before
494+
pub struct Example(pub i32, pub i32);
495+
496+
///////////////////////////////////////////////////////////
497+
// After
498+
#[repr(packed)]
499+
pub struct Example(pub i32, pub i32);
500+
501+
///////////////////////////////////////////////////////////
502+
// Example usage that will break.
503+
fn main() {
504+
let mut f = updated_crate::Example(123, 456);
505+
let c = || {
506+
// Without repr(packed), the closure precisely captures `&f.0`.
507+
// With repr(packed), the closure captures `&f` to avoid undefined behavior.
508+
let a = f.0;
509+
};
510+
f.1 = 789; // Error: cannot assign to `f.1` because it is borrowed
511+
c();
512+
}
513+
```
514+
515+
<a id="repr-align-add"></a>
516+
#### Major: Adding `repr(align)` to a struct, union, or enum
517+
518+
It is a breaking change to add `repr(align)` to a struct, union, or enum.
519+
Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed.
520+
521+
<!-- TODO: This seems like it should be extraordinarily rare. Should there be any exceptions carved out for this? -->
522+
523+
```rust,ignore
524+
// MAJOR CHANGE
525+
526+
///////////////////////////////////////////////////////////
527+
// Before
528+
pub struct Aligned {
529+
pub a: i32,
530+
}
531+
532+
///////////////////////////////////////////////////////////
533+
// After
534+
#[repr(align(8))] // added
535+
pub struct Aligned {
536+
pub a: i32,
537+
}
538+
539+
///////////////////////////////////////////////////////////
540+
// Example usage that will break.
541+
use updated_crate::Aligned;
542+
543+
#[repr(packed)]
544+
pub struct Packed { // Error: packed type cannot transitively contain a `#[repr(align)]` type
545+
f1: Aligned,
546+
}
547+
548+
fn main() {
549+
let p = Packed {
550+
f1: Aligned { a: 123 },
551+
};
552+
}
553+
```
554+
555+
<a id="repr-packed-remove"></a>
556+
#### Major: Removing `repr(packed)` from a struct or union
557+
558+
It is a breaking change to remove `repr(packed)` from a struct or union.
559+
This may change the alignment or layout that extern crates are relying on.
560+
561+
If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work.
562+
In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures].
310563

311-
[the default representation]: ../../reference/type-layout.html#the-default-representation
312-
[primitive representation]: ../../reference/type-layout.html#primitive-representations
313-
[`repr` attribute]: ../../reference/type-layout.html#representations
314564
[edition-closures]: ../../edition-guide/rust-2021/disjoint-capture-in-closures.html
315-
[`std::mem::transmute`]: ../../std/mem/fn.transmute.html
565+
566+
```rust,ignore
567+
// MAJOR CHANGE
568+
569+
///////////////////////////////////////////////////////////
570+
// Before
571+
#[repr(C, packed)]
572+
pub struct Packed {
573+
pub a: u8,
574+
pub b: u16,
575+
}
576+
577+
///////////////////////////////////////////////////////////
578+
// After
579+
#[repr(C)] // removed packed
580+
pub struct Packed {
581+
pub a: u8,
582+
pub b: u16,
583+
}
584+
585+
///////////////////////////////////////////////////////////
586+
// Example usage that will break.
587+
use updated_crate::Packed;
588+
589+
fn main() {
590+
let p = Packed { a: 1, b: 2 };
591+
// Some assumption about the size of the type.
592+
// Without `packed`, this fails since the size is 4.
593+
const _: () = assert!(std::mem::size_of::<Packed>() == 3); // Error: evaluation of constant value failed
594+
}
595+
```
596+
597+
```rust,ignore
598+
// MAJOR CHANGE
599+
600+
///////////////////////////////////////////////////////////
601+
// Before
602+
#[repr(C, packed)]
603+
pub struct Packed {
604+
pub a: *mut i32,
605+
pub b: i32,
606+
}
607+
unsafe impl Send for Packed {}
608+
609+
///////////////////////////////////////////////////////////
610+
// After
611+
#[repr(C)] // removed packed
612+
pub struct Packed {
613+
pub a: *mut i32,
614+
pub b: i32,
615+
}
616+
unsafe impl Send for Packed {}
617+
618+
///////////////////////////////////////////////////////////
619+
// Example usage that will break.
620+
use updated_crate::Packed;
621+
622+
fn main() {
623+
let mut x = 123;
624+
625+
let p = Packed {
626+
a: &mut x as *mut i32,
627+
b: 456,
628+
};
629+
630+
// When the structure was packed, the closure captures `p` which is Send.
631+
// When `packed` is removed, this ends up capturing `p.a` which is not Send.
632+
std::thread::spawn(move || unsafe {
633+
*(p.a) += 1; // Error: cannot be sent between threads safely
634+
});
635+
}
636+
```
637+
638+
<a id="repr-packed-n-change"></a>
639+
#### Major: Changing the value N of `repr(packed(N))` if that changes the alignment or layout
640+
641+
It is a breaking change to change the value of N of `repr(packed(N))` if that changes the alignment or layout.
642+
This may change the alignment or layout that external crates are relying on.
643+
644+
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.
645+
646+
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.
647+
648+
```rust,ignore
649+
// MAJOR CHANGE
650+
651+
///////////////////////////////////////////////////////////
652+
// Before
653+
#[repr(packed(4))]
654+
pub struct Packed {
655+
pub a: u8,
656+
pub b: u32,
657+
}
658+
659+
///////////////////////////////////////////////////////////
660+
// After
661+
#[repr(packed(2))] // changed to 2
662+
pub struct Packed {
663+
pub a: u8,
664+
pub b: u32,
665+
}
666+
667+
///////////////////////////////////////////////////////////
668+
// Example usage that will break.
669+
use updated_crate::Packed;
670+
671+
fn main() {
672+
let p = Packed { a: 1, b: 2 };
673+
let x = &p.b; // Error: reference to packed field is unaligned
674+
}
675+
```
676+
677+
<a id="repr-align-n-change"></a>
678+
#### Major: Changing the value N of `repr(align(N))` if that changes the alignment
679+
680+
It is a breaking change to change the value `N` of `repr(align(N))` if that changes the alignment.
681+
This may change the alignment that external crates are relying on.
682+
683+
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).
684+
685+
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.
686+
687+
```rust,ignore
688+
// MAJOR CHANGE
689+
690+
///////////////////////////////////////////////////////////
691+
// Before
692+
#[repr(align(8))]
693+
pub struct Packed {
694+
pub a: u8,
695+
pub b: u32,
696+
}
697+
698+
///////////////////////////////////////////////////////////
699+
// After
700+
#[repr(align(4))] // changed to 4
701+
pub struct Packed {
702+
pub a: u8,
703+
pub b: u32,
704+
}
705+
706+
///////////////////////////////////////////////////////////
707+
// Example usage that will break.
708+
use updated_crate::Packed;
709+
710+
fn main() {
711+
let p = Packed { a: 1, b: 2 };
712+
// Some assumption about the size of the type.
713+
// The alignment has changed from 8 to 4.
714+
const _: () = assert!(std::mem::align_of::<Packed>() == 8); // Error: evaluation of constant value failed
715+
}
716+
```
717+
718+
<a id="repr-align-remove"></a>
719+
#### Major: Removing `repr(align)` from a struct, union, or enum
720+
721+
It is a breaking change to remove `repr(align)` from a struct, union, or enum.
722+
This may change the alignment or layout that external crates are relying on.
723+
724+
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).
725+
726+
```rust,ignore
727+
// MAJOR CHANGE
728+
729+
///////////////////////////////////////////////////////////
730+
// Before
731+
#[repr(C, align(8))]
732+
pub struct Packed {
733+
pub a: u8,
734+
pub b: u32,
735+
}
736+
737+
///////////////////////////////////////////////////////////
738+
// After
739+
#[repr(C)] // removed align
740+
pub struct Packed {
741+
pub a: u8,
742+
pub b: u32,
743+
}
744+
745+
///////////////////////////////////////////////////////////
746+
// Example usage that will break.
747+
use updated_crate::Packed;
748+
749+
fn main() {
750+
let p = Packed { a: 1, b: 2 };
751+
// Some assumption about the size of the type.
752+
// The alignment has changed from 8 to 4.
753+
const _: () = assert!(std::mem::align_of::<Packed>() == 8); // Error: evaluation of constant value failed
754+
}
755+
```
756+
757+
<a id="repr-c-shuffle"></a>
758+
#### Major: Changing the order of public fields of a `repr(C)` type
759+
760+
It is a breaking change to change the order of public fields of a `repr(C)` type.
761+
External crates may be relying on the specific ordering of the fields.
762+
763+
```rust,ignore,run-fail
764+
// MAJOR CHANGE
765+
766+
///////////////////////////////////////////////////////////
767+
// Before
768+
#[repr(C)]
769+
pub struct SpecificLayout {
770+
pub a: u8,
771+
pub b: u32,
772+
}
773+
774+
///////////////////////////////////////////////////////////
775+
// After
776+
#[repr(C)]
777+
pub struct SpecificLayout {
778+
pub b: u32, // changed order
779+
pub a: u8,
780+
}
781+
782+
///////////////////////////////////////////////////////////
783+
// Example usage that will break.
784+
use updated_crate::SpecificLayout;
785+
786+
extern "C" {
787+
// This C function is assuming a specific layout defined in a C header.
788+
fn c_fn_get_b(x: &SpecificLayout) -> u32;
789+
}
790+
791+
fn main() {
792+
let p = SpecificLayout { a: 1, b: 2 };
793+
unsafe { assert_eq!(c_fn_get_b(&p), 2) } // Error: value not equal to 2
794+
}
795+
796+
# mod cdep {
797+
# // This simulates what would normally be something included from a build script.
798+
# // This definition would be in a C header.
799+
# #[repr(C)]
800+
# pub struct SpecificLayout {
801+
# pub a: u8,
802+
# pub b: u32,
803+
# }
804+
#
805+
# #[no_mangle]
806+
# pub fn c_fn_get_b(x: &SpecificLayout) -> u32 {
807+
# x.b
808+
# }
809+
# }
810+
```
811+
812+
<a id="repr-c-remove"></a>
813+
#### Major: Removing `repr(C)` from a struct, union, or enum
814+
815+
It is a breaking change to remove `repr(C)` from a struct, union, or enum.
816+
External crates may be relying on the specific layout of the type.
817+
818+
```rust,ignore
819+
// MAJOR CHANGE
820+
821+
///////////////////////////////////////////////////////////
822+
// Before
823+
#[repr(C)]
824+
pub struct SpecificLayout {
825+
pub a: u8,
826+
pub b: u32,
827+
}
828+
829+
///////////////////////////////////////////////////////////
830+
// After
831+
// removed repr(C)
832+
pub struct SpecificLayout {
833+
pub a: u8,
834+
pub b: u32,
835+
}
836+
837+
///////////////////////////////////////////////////////////
838+
// Example usage that will break.
839+
use updated_crate::SpecificLayout;
840+
841+
extern "C" {
842+
// This C function is assuming a specific layout defined in a C header.
843+
fn c_fn_get_b(x: &SpecificLayout) -> u32; // Error: is not FFI-safe
844+
}
845+
846+
fn main() {
847+
let p = SpecificLayout { a: 1, b: 2 };
848+
unsafe { assert_eq!(c_fn_get_b(&p), 2) }
849+
}
850+
851+
# mod cdep {
852+
# // This simulates what would normally be something included from a build script.
853+
# // This definition would be in a C header.
854+
# #[repr(C)]
855+
# pub struct SpecificLayout {
856+
# pub a: u8,
857+
# pub b: u32,
858+
# }
859+
#
860+
# #[no_mangle]
861+
# pub fn c_fn_get_b(x: &SpecificLayout) -> u32 {
862+
# x.b
863+
# }
864+
# }
865+
```
866+
867+
<a id="repr-int-enum-remove"></a>
868+
#### Major: Removing `repr(<int>)` from an enum
869+
870+
It is a breaking change to remove `repr(<int>)` from an enum.
871+
External crates may be assuming that the discriminant is a specific size.
872+
For example, [`std::mem::transmute`] of an enum may fail.
873+
874+
```rust,ignore
875+
// MAJOR CHANGE
876+
877+
///////////////////////////////////////////////////////////
878+
// Before
879+
#[repr(u16)]
880+
pub enum Example {
881+
Variant1,
882+
Variant2,
883+
Variant3,
884+
}
885+
886+
///////////////////////////////////////////////////////////
887+
// After
888+
// removed repr(u16)
889+
pub enum Example {
890+
Variant1,
891+
Variant2,
892+
Variant3,
893+
}
894+
895+
///////////////////////////////////////////////////////////
896+
// Example usage that will break.
897+
898+
fn main() {
899+
let e = updated_crate::Example::Variant2;
900+
let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes
901+
}
902+
```
903+
904+
<a id="repr-int-enum-change"></a>
905+
#### Major: Changing the primitive representation of a `repr(<int>)` enum
906+
907+
It is a breaking change to change the primitive representation of a `repr(<int>)` enum.
908+
External crates may be assuming that the discriminant is a specific size.
909+
For example, [`std::mem::transmute`] of an enum may fail.
910+
911+
```rust,ignore
912+
// MAJOR CHANGE
913+
914+
///////////////////////////////////////////////////////////
915+
// Before
916+
#[repr(u16)]
917+
pub enum Example {
918+
Variant1,
919+
Variant2,
920+
Variant3,
921+
}
922+
923+
///////////////////////////////////////////////////////////
924+
// After
925+
#[repr(u8)] // changed repr size
926+
pub enum Example {
927+
Variant1,
928+
Variant2,
929+
Variant3,
930+
}
931+
932+
///////////////////////////////////////////////////////////
933+
// Example usage that will break.
934+
935+
fn main() {
936+
let e = updated_crate::Example::Variant2;
937+
let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes
938+
}
939+
```
940+
941+
<a id="repr-transparent-remove"></a>
942+
#### Major: Removing `repr(transparent)` from a struct or enum
943+
944+
It is a breaking change to remove `repr(transparent)` from a struct or enum.
945+
External crates may be relying on the type having the alignment, layout, or size of the transparent field.
946+
947+
```rust,ignore
948+
// MAJOR CHANGE
949+
950+
///////////////////////////////////////////////////////////
951+
// Before
952+
#[repr(transparent)]
953+
pub struct Transparent<T>(T);
954+
955+
///////////////////////////////////////////////////////////
956+
// After
957+
// removed repr
958+
pub struct Transparent<T>(T);
959+
960+
///////////////////////////////////////////////////////////
961+
// Example usage that will break.
962+
#![deny(improper_ctypes)]
963+
use updated_crate::Transparent;
964+
965+
extern "C" {
966+
fn c_fn() -> Transparent<f64>; // Error: is not FFI-safe
967+
}
968+
969+
fn main() {}
970+
```
971+
316972

317973
<a id="struct-add-private-field-when-public"></a>
318974
### Major: adding a private struct field when all current fields are public

0 commit comments

Comments
 (0)
Please sign in to comment.