From 2368fdc86e9372ea179a99c1cba7e3f1e148f02e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 8 Jul 2026 11:17:32 -0500 Subject: [PATCH 1/5] Add layout guarantees for never type `!` --- src/glossary.md | 1 + src/type-layout.md | 2 ++ src/types/never.md | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/src/glossary.md b/src/glossary.md index af9dc4cecb..8414082a49 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -266,6 +266,7 @@ r[glossary.zst] A type is zero sized (a ZST) if its size is 0. Such types have at most one possible value. Examples include: - The [unit type] (see [layout.tuple.unit]). +- The [never type] `!` (see [type.never.layout]). - [Function items] (see [type.fn-item.intro]). - The constructors of [tuple-like structs] (see [type.fn-item.intro]). - The constructors of [tuple-like enum variants] (see [type.fn-item.intro]). diff --git a/src/type-layout.md b/src/type-layout.md index daec57f9ea..27c517b751 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -42,6 +42,7 @@ The size of most primitives is given in this table. | `f32` | 4 | | `f64` | 8 | | `char` | 4 | +| [`!`][never-type] | 0 | r[layout.primitive.size-minimum] `usize` and `isize` have a size big enough to contain every address on the target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64 bit target, this is 8 bytes. @@ -724,3 +725,4 @@ Because this representation delegates type layout to another type, it cannot be [unit-struct-like variant]: EnumVariant [`Layout`]: std::alloc::Layout [uninhabited]: glossary.uninhabited +[never-type]: types/never.md diff --git a/src/types/never.md b/src/types/never.md index 414862fe52..0fd7aba28e 100644 --- a/src/types/never.md +++ b/src/types/never.md @@ -52,6 +52,10 @@ NeverType -> `!` r[type.never.coercion] Expressions of type `!` can be coerced into any type. + +r[type.never.layout] +The `!` type has a size of 0 and an alignment of 1. + > [!NOTE] > The standard library type [`Infallible`] is a type alias for `!`. From 77b15d59963fee0e61d447ba87b29e033b8e8872 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 2 Sep 2026 00:04:35 -0500 Subject: [PATCH 2/5] Fix spacing in never type docs, and add never type `size_of` example. --- src/glossary.md | 1 + src/types/never.md | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/glossary.md b/src/glossary.md index 8414082a49..ba8ac7baf8 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -341,6 +341,7 @@ enum E6 { enum E7 {} assert_eq!(0, size_of::<()>()); +assert_eq!(0, size_of::()); assert_eq!(0, size_of_val(&f)); assert_eq!(0, size_of_val(&S)); assert_eq!(0, size_of_val(&E::V)); diff --git a/src/types/never.md b/src/types/never.md index 0fd7aba28e..6228795ff7 100644 --- a/src/types/never.md +++ b/src/types/never.md @@ -52,7 +52,6 @@ NeverType -> `!` r[type.never.coercion] Expressions of type `!` can be coerced into any type. - r[type.never.layout] The `!` type has a size of 0 and an alignment of 1. From b07db38e96c5b75f26e3bf7f1a6eaef616b3fd31 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 11 Oct 2026 08:23:47 +0000 Subject: [PATCH 3/5] Fix mentions of the never type in the glossary We'd referred to "the never type `!`". Mostly we should say either "the never type" or "`!`"; using parentheses sparingly, as in "the never type (`!`)", is also OK. Let's fix this and a related case. --- src/glossary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/glossary.md b/src/glossary.md index ba8ac7baf8..b07ccf539a 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -255,7 +255,7 @@ Compile-time or run-time behavior that is not specified. This may result in, but r[glossary.uninhabited] ### Uninhabited -A type is uninhabited if it has no constructors and therefore can never be instantiated. An uninhabited type is "empty" in the sense that there are no values of the type. The canonical example of an uninhabited type is the [never type] `!`, or an enum with no variants `enum Never { }`. Opposite of [Inhabited](#inhabited). +A type is uninhabited if it has no constructors and therefore can never be instantiated. An uninhabited type is "empty" in the sense that there are no values of the type. The canonical example of an uninhabited type is the [never type] (`!`), or an enum with no variants (e.g., `enum Never { }`). Opposite of [Inhabited](#inhabited). > [!NOTE] > Uninhabited types are not necessarily [zero sized]. For example, `enum Never { }` is uninhabited and zero sized, but `(u8, Never)` is uninhabited and not zero sized. @@ -266,7 +266,7 @@ r[glossary.zst] A type is zero sized (a ZST) if its size is 0. Such types have at most one possible value. Examples include: - The [unit type] (see [layout.tuple.unit]). -- The [never type] `!` (see [type.never.layout]). +- The [never type] (see [type.never.layout]). - [Function items] (see [type.fn-item.intro]). - The constructors of [tuple-like structs] (see [type.fn-item.intro]). - The constructors of [tuple-like enum variants] (see [type.fn-item.intro]). From fb0abeafda90b49ed1cef51da6813688886047f8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 23:57:36 +0000 Subject: [PATCH 4/5] Add `!` to list of 1-ZSTs in the glossary Since we're guaranteeing the alignment of the never type, let's add it as an example of a 1-ZST in the glossary. --- src/glossary.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/glossary.md b/src/glossary.md index b07ccf539a..24f9bd3d0d 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -119,6 +119,7 @@ An *n-ZST* refers to a type that is zero sized (a [ZST]) and has an [alignment] Examples of 1-ZSTs include: - The [unit type] (see [layout.tuple.unit]). +- The [never type] (see [type.never.layout]). - `repr(C)` [structs] with no fields or where all fields are 1-ZSTs (see [layout.repr.c.struct.align] and [layout.repr.c.struct.size-field-offset]). - `repr(transparent)` [structs] with no fields or where all fields are 1-ZSTs (see [layout.repr.transparent.layout-abi]). - [Arrays] of 1-ZSTs (see [layout.array]). @@ -148,6 +149,7 @@ fn is_1_zst() -> bool { } assert!(is_1_zst::<()>()); +assert!(is_1_zst::()); assert!(is_1_zst::()); assert!(is_1_zst::()); assert!(is_1_zst::<[(); 10]>()); From 956d1bd03d2a8934fc5041ecb04b33e55159c655 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 10 Oct 2026 23:57:36 +0000 Subject: [PATCH 5/5] Remove link from `!` row in primitive size table It might be a good idea to link to the pages for the types listed in this table, but we don't do it for the others, so let's not do it for the never type. --- src/type-layout.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 27c517b751..9d56ea7570 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -42,7 +42,7 @@ The size of most primitives is given in this table. | `f32` | 4 | | `f64` | 8 | | `char` | 4 | -| [`!`][never-type] | 0 | +| `!` | 0 | r[layout.primitive.size-minimum] `usize` and `isize` have a size big enough to contain every address on the target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64 bit target, this is 8 bytes. @@ -725,4 +725,3 @@ Because this representation delegates type layout to another type, it cannot be [unit-struct-like variant]: EnumVariant [`Layout`]: std::alloc::Layout [uninhabited]: glossary.uninhabited -[never-type]: types/never.md