Skip to content

Commit 32d21cb

Browse files
authored
Rollup merge of #146509 - RalfJung:res-opt-layout-guarantees, r=traviscross
Result/Option layout guarantee clarifications - It seems worth spelling out that this guarantee allows particular transmutes. - After the `Result` section was written, the `Option` section it referenced gained *more* guarantees, saying that `None` is represented as `[0u8; N]`. Those guarantees were not meant to apply to `Result`. Make the `Result` section more self-contained to make this more clear. - "Type has no fields" is unclear since there is no general definition of what the fields of some arbitrary type are. Replace that by a more accurate description of the actual check implemented [here](https://github.com/rust-lang/rust/blob/e379c7758667f900aaf5551c4553c7d4c121e3e1/compiler/rustc_lint/src/types.rs#L828-L838). r? `@traviscross`
2 parents c8a31b7 + 73f5fe7 commit 32d21cb

File tree

3 files changed

+28
-16
lines changed

3 files changed

+28
-16
lines changed

compiler/rustc_lint/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ fn get_nullable_type<'tcx>(
814814

815815
/// A type is niche-optimization candidate iff:
816816
/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
817-
/// - Has no fields.
817+
/// - Is either a struct/tuple with no fields, or an enum with no variants.
818818
/// - Does not have the `#[non_exhaustive]` attribute.
819819
fn is_niche_optimization_candidate<'tcx>(
820820
tcx: TyCtxt<'tcx>,
@@ -828,7 +828,7 @@ fn is_niche_optimization_candidate<'tcx>(
828828
match ty.kind() {
829829
ty::Adt(ty_def, _) => {
830830
let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
831-
let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
831+
let empty = (ty_def.is_struct() && ty_def.non_enum_variant().fields.is_empty())
832832
|| (ty_def.is_enum() && ty_def.variants().is_empty());
833833

834834
!non_exhaustive && empty

library/core/src/option.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,14 @@
118118
//!
119119
//! # Representation
120120
//!
121-
//! Rust guarantees to optimize the following types `T` such that
122-
//! [`Option<T>`] has the same size, alignment, and [function call ABI] as `T`. In some
123-
//! of these cases, Rust further guarantees the following:
121+
//! Rust guarantees to optimize the following types `T` such that [`Option<T>`]
122+
//! has the same size, alignment, and [function call ABI] as `T`. It is
123+
//! therefore sound, when `T` is one of these types, to transmute a value `t` of
124+
//! type `T` to type `Option<T>` (producing the value `Some(t)`) and to
125+
//! transmute a value `Some(t)` of type `Option<T>` to type `T` (producing the
126+
//! value `t`).
127+
//!
128+
//! In some of these cases, Rust further guarantees the following:
124129
//! - `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and produces
125130
//! `Option::<T>::None`
126131
//! - `transmute::<_, [u8; size_of::<T>()]>(Option::<T>::None)` is sound and produces

library/core/src/result.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -230,24 +230,31 @@
230230
//!
231231
//! # Representation
232232
//!
233-
//! In some cases, [`Result<T, E>`] will gain the same size, alignment, and ABI
234-
//! guarantees as [`Option<U>`] has. One of either the `T` or `E` type must be a
235-
//! type that qualifies for the `Option` [representation guarantees][opt-rep],
236-
//! and the *other* type must meet all of the following conditions:
237-
//! * Is a zero-sized type with alignment 1 (a "1-ZST").
238-
//! * Has no fields.
239-
//! * Does not have the `#[non_exhaustive]` attribute.
233+
//! In some cases, [`Result<T, E>`] comes with size, alignment, and ABI
234+
//! guarantees. Specifically, one of either the `T` or `E` type must be a type
235+
//! that qualifies for the `Option` [representation guarantees][opt-rep] (let's
236+
//! call that type `I`), and the *other* type is a zero-sized type with
237+
//! alignment 1 (a "1-ZST").
238+
//!
239+
//! If that is the case, then `Result<T, E>` has the same size, alignment, and
240+
//! [function call ABI] as `I` (and therefore, as `Option<I>`). If `I` is `T`,
241+
//! it is therefore sound to transmute a value `t` of type `I` to type
242+
//! `Result<T, E>` (producing the value `Ok(t)`) and to transmute a value
243+
//! `Ok(t)` of type `Result<T, E>` to type `I` (producing the value `t`). If `I`
244+
//! is `E`, the same applies with `Ok` replaced by `Err`.
240245
//!
241246
//! For example, `NonZeroI32` qualifies for the `Option` representation
242-
//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and
243-
//! it isn't `non_exhaustive`. This means that both `Result<NonZeroI32, ()>` and
244-
//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees
245-
//! as `Option<NonZeroI32>`. The only difference is the implied semantics:
247+
//! guarantees and `()` is a zero-sized type with alignment 1. This means that
248+
//! both `Result<NonZeroI32, ()>` and `Result<(), NonZeroI32>` have the same
249+
//! size, alignment, and ABI as `NonZeroI32` (and `Option<NonZeroI32>`). The
250+
//! only difference between these is in the implied semantics:
251+
//!
246252
//! * `Option<NonZeroI32>` is "a non-zero i32 might be present"
247253
//! * `Result<NonZeroI32, ()>` is "a non-zero i32 success result, if any"
248254
//! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any"
249255
//!
250256
//! [opt-rep]: ../option/index.html#representation "Option Representation"
257+
//! [function call ABI]: ../primitive.fn.html#abi-compatibility
251258
//!
252259
//! # Method overview
253260
//!

0 commit comments

Comments
 (0)