From 1723e6d27ba9a13b5c45589ee4a9f3f3ce61a678 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 26 May 2026 11:35:57 -0700 Subject: [PATCH 1/5] Unwrap "Special types and traits" This unwraps the text to follow our style guide. --- src/special-types-and-traits.md | 81 +++++++++------------------------ 1 file changed, 22 insertions(+), 59 deletions(-) diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 26e03aee8c..dddefda040 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -2,28 +2,22 @@ r[lang-types] # Special types and traits r[lang-types.intro] -Certain types and traits that exist in [the standard library] are known to the -Rust compiler. This chapter documents the special features of these types and -traits. +Certain types and traits that exist in [the standard library] are known to the Rust compiler. This chapter documents the special features of these types and traits. r[lang-types.box] ## `Box` r[lang-types.box.intro] -[`Box`] has a few special features that Rust doesn't currently allow for user -defined types. +[`Box`] has a few special features that Rust doesn't currently allow for user defined types. r[lang-types.box.deref] -* The [dereference operator] for `Box` produces a place which can be [moved - from]. This means that the `*` operator and the destructor of `Box` are - built-in to the language. +* The [dereference operator] for `Box` produces a place which can be [moved from]. This means that the `*` operator and the destructor of `Box` are built-in to the language. r[lang-types.box.receiver] * [Methods] can take `Box` as a receiver. r[lang-types.box.fundamental] -* A trait may be implemented for `Box` in the same crate as `T`, which the - [orphan rules] prevent for other generic types. +* A trait may be implemented for `Box` in the same crate as `T`, which the [orphan rules] prevent for other generic types. @@ -49,37 +43,30 @@ r[lang-types.unsafe-cell] ## `UnsafeCell` r[lang-types.unsafe-cell.interior-mut] -[`std::cell::UnsafeCell`] is used for [interior mutability]. It ensures that -the compiler doesn't perform optimisations that are incorrect for such types. +[`std::cell::UnsafeCell`] is used for [interior mutability]. It ensures that the compiler doesn't perform optimisations that are incorrect for such types. r[lang-types.unsafe-cell.read-only-alloc] -It also ensures that [`static` items] which have a type with interior -mutability aren't placed in memory marked as read only. +It also ensures that [`static` items] which have a type with interior mutability aren't placed in memory marked as read only. r[lang-types.phantom-data] ## `PhantomData` -[`std::marker::PhantomData`] is a [zero-sized], minimum alignment, type that -is considered to own a `T` for the purposes of [variance], [drop check], and -[auto traits](#auto-traits). +[`std::marker::PhantomData`] is a [zero-sized], minimum alignment, type that is considered to own a `T` for the purposes of [variance], [drop check], and [auto traits](#auto-traits). r[lang-types.ops] ## Operator traits -The traits in [`std::ops`] and [`std::cmp`] are used to overload [operators], -[indexing expressions], and [call expressions]. +The traits in [`std::ops`] and [`std::cmp`] are used to overload [operators], [indexing expressions], and [call expressions]. r[lang-types.deref] ## `Deref` and `DerefMut` -As well as overloading the unary `*` operator, [`Deref`] and [`DerefMut`] are -also used in [method resolution] and [deref coercions]. +As well as overloading the unary `*` operator, [`Deref`] and [`DerefMut`] are also used in [method resolution] and [deref coercions]. r[lang-types.drop] ## `Drop` -The [`Drop`] trait provides a [destructor], to be run whenever a value of this -type is to be destroyed. +The [`Drop`] trait provides a [destructor], to be run whenever a value of this type is to be destroyed. r[lang-types.copy] ## `Copy` @@ -91,9 +78,7 @@ r[lang-types.copy.behavior] Values whose type implements `Copy` are copied rather than moved upon assignment. r[lang-types.copy.constraint] -`Copy` can only be implemented for types which do not implement `Drop`, and whose fields are all `Copy`. -For enums, this means all fields of all variants have to be `Copy`. -For unions, this means all variants have to be `Copy`. +`Copy` can only be implemented for types which do not implement `Drop`, and whose fields are all `Copy`. For enums, this means all fields of all variants have to be `Copy`. For unions, this means all variants have to be `Copy`. r[lang-types.copy.builtin-types] `Copy` is implemented by the compiler for @@ -114,8 +99,7 @@ r[lang-types.clone] ## `Clone` r[lang-types.clone.intro] -The [`Clone`] trait is a supertrait of `Copy`, so it also needs compiler -generated implementations. +The [`Clone`] trait is a supertrait of `Copy`, so it also needs compiler generated implementations. r[lang-types.clone.builtin-types] It is implemented by the compiler for the following types: @@ -132,15 +116,13 @@ r[lang-types.clone.closure] r[lang-types.send] ## `Send` -The [`Send`] trait indicates that a value of this type is safe to send from one -thread to another. +The [`Send`] trait indicates that a value of this type is safe to send from one thread to another. r[lang-types.sync] ## `Sync` r[lang-types.sync.intro] -The [`Sync`] trait indicates that a value of this type is safe to share between -multiple threads. +The [`Sync`] trait indicates that a value of this type is safe to share between multiple threads. r[lang-types.sync.static-constraint] This trait must be implemented for all types used in immutable [`static` items]. @@ -153,50 +135,31 @@ The [`Termination`] trait indicates the acceptable return types for the [main fu r[lang-types.auto-traits] ## Auto traits -The [`Send`], [`Sync`], [`Unpin`], [`UnwindSafe`], and [`RefUnwindSafe`] traits are _auto -traits_. Auto traits have special properties. +The [`Send`], [`Sync`], [`Unpin`], [`UnwindSafe`], and [`RefUnwindSafe`] traits are _auto traits_. Auto traits have special properties. r[lang-types.auto-traits.auto-impl] -If no explicit implementation or negative implementation is written out for an -auto trait for a given type, then the compiler implements it automatically -according to the following rules: +If no explicit implementation or negative implementation is written out for an auto trait for a given type, then the compiler implements it automatically according to the following rules: r[lang-types.auto-traits.builtin-composite] -* `&T`, `&mut T`, `*const T`, `*mut T`, `[T; n]`, and `[T]` implement the trait - if `T` does. +* `&T`, `&mut T`, `*const T`, `*mut T`, `[T; n]`, and `[T]` implement the trait if `T` does. r[lang-types.auto-traits.fn-item-pointer] * Function item types and function pointers automatically implement the trait. r[lang-types.auto-traits.aggregate] -* Structs, enums, unions, and tuples implement the trait if all of their fields - do. +* Structs, enums, unions, and tuples implement the trait if all of their fields do. r[lang-types.auto-traits.closure] -* Closures implement the trait if the types of all of their captures do. A - closure that captures a `T` by shared reference and a `U` by value implements - any auto traits that both `&T` and `U` do. +* Closures implement the trait if the types of all of their captures do. A closure that captures a `T` by shared reference and a `U` by value implements any auto traits that both `&T` and `U` do. r[lang-types.auto-traits.generic-impl] -For generic types (counting the built-in types above as generic over `T`), if a -generic implementation is available, then the compiler does not automatically -implement it for types that could use the implementation except that they do not -meet the requisite trait bounds. For instance, the standard library implements -`Send` for all `&T` where `T` is `Sync`; this means that the compiler will not -implement `Send` for `&T` if `T` is `Send` but not `Sync`. +For generic types (counting the built-in types above as generic over `T`), if a generic implementation is available, then the compiler does not automatically implement it for types that could use the implementation except that they do not meet the requisite trait bounds. For instance, the standard library implements `Send` for all `&T` where `T` is `Sync`; this means that the compiler will not implement `Send` for `&T` if `T` is `Send` but not `Sync`. r[lang-types.auto-traits.negative] -Auto traits can also have negative implementations, shown as `impl !AutoTrait -for T` in the standard library documentation, that override the automatic -implementations. For example `*mut T` has a negative implementation of `Send`, -and so `*mut T` is not `Send`, even if `T` is. There is currently no stable way -to specify additional negative implementations; they exist only in the standard -library. +Auto traits can also have negative implementations, shown as `impl !AutoTrait for T` in the standard library documentation, that override the automatic implementations. For example `*mut T` has a negative implementation of `Send`, and so `*mut T` is not `Send`, even if `T` is. There is currently no stable way to specify additional negative implementations; they exist only in the standard library. r[lang-types.auto-traits.trait-object-marker] -Auto traits may be added as an additional bound to any [trait object], even -though normally only one trait is allowed. For instance, `Box` is a valid type. +Auto traits may be added as an additional bound to any [trait object], even though normally only one trait is allowed. For instance, `Box` is a valid type. r[lang-types.sized] ## `Sized` From 5f75caa264ad53f5eed4b44990f466e4658a98aa Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 26 May 2026 11:37:23 -0700 Subject: [PATCH 2/5] Unwrap memory model chapters This unwraps the text to follow our style guide. --- src/memory-allocation-and-lifetime.md | 12 ++---------- src/variables.md | 26 +++++++------------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/memory-allocation-and-lifetime.md b/src/memory-allocation-and-lifetime.md index 2c4f7643ff..a72577b606 100644 --- a/src/memory-allocation-and-lifetime.md +++ b/src/memory-allocation-and-lifetime.md @@ -2,15 +2,7 @@ r[alloc] # Memory allocation and lifetime r[alloc.static] -The _items_ of a program are those functions, modules, and types that have their -value calculated at compile-time and stored uniquely in the memory image of the -rust process. Items are neither dynamically allocated nor freed. +The _items_ of a program are those functions, modules, and types that have their value calculated at compile-time and stored uniquely in the memory image of the rust process. Items are neither dynamically allocated nor freed. r[alloc.dynamic] -The _heap_ is a general term that describes boxes. The lifetime of an -allocation in the heap depends on the lifetime of the box values pointing to -it. Since box values may themselves be passed in and out of frames, or stored -in the heap, heap allocations may outlive the frame they are allocated within. -An allocation in the heap is guaranteed to reside at a single location in the -heap for the whole lifetime of the allocation - it will never be relocated as -a result of moving a box value. +The _heap_ is a general term that describes boxes. The lifetime of an allocation in the heap depends on the lifetime of the box values pointing to it. Since box values may themselves be passed in and out of frames, or stored in the heap, heap allocations may outlive the frame they are allocated within. An allocation in the heap is guaranteed to reside at a single location in the heap for the whole lifetime of the allocation - it will never be relocated as a result of moving a box value. diff --git a/src/variables.md b/src/variables.md index 31836d5840..e20e51e035 100644 --- a/src/variables.md +++ b/src/variables.md @@ -2,33 +2,21 @@ r[variable] # Variables r[variable.intro] -A _variable_ is a component of a stack frame, either a named function parameter, -an anonymous [temporary](expressions.md#temporaries), or a named local -variable. +A _variable_ is a component of a stack frame, either a named function parameter, an anonymous [temporary](expressions.md#temporaries), or a named local variable. r[variable.local] -A _local variable_ (or *stack-local* allocation) holds a value directly, -allocated within the stack's memory. The value is a part of the stack frame. +A _local variable_ (or *stack-local* allocation) holds a value directly, allocated within the stack's memory. The value is a part of the stack frame. r[variable.local-mut] -Local variables are immutable unless declared otherwise. For example: -`let mut x = ...`. +Local variables are immutable unless declared otherwise. For example: `let mut x = ...`. r[variable.param-mut] -Function parameters are immutable unless declared with `mut`. The `mut` keyword -applies only to the following parameter. For example: `|mut x, y|` and -`fn f(mut x: Box, y: Box)` declare one mutable variable `x` and one -immutable variable `y`. +Function parameters are immutable unless declared with `mut`. The `mut` keyword applies only to the following parameter. For example: `|mut x, y|` and `fn f(mut x: Box, y: Box)` declare one mutable variable `x` and one immutable variable `y`. r[variable.init] -Local variables are not initialized when allocated. Instead, the entire frame -worth of local variables are allocated, on frame-entry, in an uninitialized -state. Subsequent statements within a function may or may not initialize the -local variables. Local variables can be used only after they have been -initialized through all reachable control flow paths. - -In this next example, `init_after_if` is initialized after the [`if` expression] -while `uninit_after_if` is not because it is not initialized in the `else` case. +Local variables are not initialized when allocated. Instead, the entire frame worth of local variables are allocated, on frame-entry, in an uninitialized state. Subsequent statements within a function may or may not initialize the local variables. Local variables can be used only after they have been initialized through all reachable control flow paths. + +In this next example, `init_after_if` is initialized after the [`if` expression] while `uninit_after_if` is not because it is not initialized in the `else` case. ```rust # fn random_bool() -> bool { true } From fd3bb57394a6abe2365cc9645ea9c7c2542a6ea7 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 26 May 2026 11:42:44 -0700 Subject: [PATCH 3/5] Unwrap "Linkage" This unwraps the text to follow our style guide. --- src/linkage.md | 191 +++++++++---------------------------------------- 1 file changed, 35 insertions(+), 156 deletions(-) diff --git a/src/linkage.md b/src/linkage.md index 113b189c16..4b4e6edc35 100644 --- a/src/linkage.md +++ b/src/linkage.md @@ -5,177 +5,76 @@ r[link] > This section is described more in terms of the compiler than of the language. r[link.intro] -The compiler supports various methods to link crates together both -statically and dynamically. This section will explore the various methods to -link crates together, and more information about native libraries can be -found in the [FFI section of the book][ffi]. +The compiler supports various methods to link crates together both statically and dynamically. This section will explore the various methods to link crates together, and more information about native libraries can be found in the [FFI section of the book][ffi]. [ffi]: ../book/ch20-01-unsafe-rust.html#using-extern-functions-to-call-external-code r[link.type] -In one session of compilation, the compiler can generate multiple artifacts -through the use of either command line flags or the `crate_type` attribute. -If one or more command line flags are specified, all `crate_type` attributes will -be ignored in favor of only building the artifacts specified by command line. +In one session of compilation, the compiler can generate multiple artifacts through the use of either command line flags or the `crate_type` attribute. If one or more command line flags are specified, all `crate_type` attributes will be ignored in favor of only building the artifacts specified by command line. r[link.bin] -* `--crate-type=bin`, `#![crate_type = "bin"]` - A runnable executable will be - produced. This requires that there is a `main` function in the crate which - will be run when the program begins executing. This will link in all Rust and - native dependencies, producing a single distributable binary. - This is the default crate type. +* `--crate-type=bin`, `#![crate_type = "bin"]` - A runnable executable will be produced. This requires that there is a `main` function in the crate which will be run when the program begins executing. This will link in all Rust and native dependencies, producing a single distributable binary. This is the default crate type. r[link.lib] -* `--crate-type=lib`, `#![crate_type = "lib"]` - A Rust library will be produced. - This is an ambiguous concept as to what exactly is produced because a library - can manifest itself in several forms. The purpose of this generic `lib` option - is to generate the "compiler recommended" style of library. The output library - will always be usable by rustc, but the actual type of library may change from - time-to-time. The remaining output types are all different flavors of - libraries, and the `lib` type can be seen as an alias for one of them (but the - actual one is compiler-defined). +* `--crate-type=lib`, `#![crate_type = "lib"]` - A Rust library will be produced. This is an ambiguous concept as to what exactly is produced because a library can manifest itself in several forms. The purpose of this generic `lib` option is to generate the "compiler recommended" style of library. The output library will always be usable by rustc, but the actual type of library may change from time-to-time. The remaining output types are all different flavors of libraries, and the `lib` type can be seen as an alias for one of them (but the actual one is compiler-defined). r[link.dylib] -* `--crate-type=dylib`, `#![crate_type = "dylib"]` - A dynamic Rust library will - be produced. This is different from the `lib` output type in that this forces - dynamic library generation. The resulting dynamic library can be used as a - dependency for other libraries and/or executables. This output type will - create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on - Windows. +* `--crate-type=dylib`, `#![crate_type = "dylib"]` - A dynamic Rust library will be produced. This is different from the `lib` output type in that this forces dynamic library generation. The resulting dynamic library can be used as a dependency for other libraries and/or executables. This output type will create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on Windows. r[link.staticlib] -* `--crate-type=staticlib`, `#![crate_type = "staticlib"]` - A static system - library will be produced. This is different from other library outputs in that - the compiler will never attempt to link to `staticlib` outputs. The - purpose of this output type is to create a static library containing all of - the local crate's code along with all upstream dependencies. This output type - will create `*.a` files on Linux, macOS and Windows (MinGW), and `*.lib` files - on Windows (MSVC). This format is recommended for use in situations such as - linking Rust code into an existing non-Rust application because it will not - have dynamic dependencies on other Rust code. - - Note that any dynamic dependencies that the static library may have (such as - dependencies on system libraries, or dependencies on Rust libraries that are - compiled as dynamic libraries) will have to be specified manually when - linking that static library from somewhere. The `--print=native-static-libs` flag may help with this. - - Note that, because the resulting static library contains the code of all the - dependencies, including the standard library, and also exports all public - symbols of them, linking the static library into an executable or shared - library may need special care. In case of a shared library the list of - exported symbols will have to be limited via e.g. a linker or symbol version - script, exported symbols list (macOS), or module definition file (Windows). - Additionally, unused sections can be removed to remove all code of - dependencies that is not actually used (e.g. `--gc-sections` or `-dead_strip` - for macOS). +* `--crate-type=staticlib`, `#![crate_type = "staticlib"]` - A static system library will be produced. This is different from other library outputs in that the compiler will never attempt to link to `staticlib` outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. This output type will create `*.a` files on Linux, macOS and Windows (MinGW), and `*.lib` files on Windows (MSVC). This format is recommended for use in situations such as linking Rust code into an existing non-Rust application because it will not have dynamic dependencies on other Rust code. + + Note that any dynamic dependencies that the static library may have (such as dependencies on system libraries, or dependencies on Rust libraries that are compiled as dynamic libraries) will have to be specified manually when linking that static library from somewhere. The `--print=native-static-libs` flag may help with this. + + Note that, because the resulting static library contains the code of all the dependencies, including the standard library, and also exports all public symbols of them, linking the static library into an executable or shared library may need special care. In case of a shared library the list of exported symbols will have to be limited via e.g. a linker or symbol version script, exported symbols list (macOS), or module definition file (Windows). Additionally, unused sections can be removed to remove all code of dependencies that is not actually used (e.g. `--gc-sections` or `-dead_strip` for macOS). r[link.cdylib] -* `--crate-type=cdylib`, `#![crate_type = "cdylib"]` - A dynamic system - library will be produced. This is used when compiling - a dynamic library to be loaded from another language. This output type will - create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on - Windows. +* `--crate-type=cdylib`, `#![crate_type = "cdylib"]` - A dynamic system library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on Windows. r[link.rlib] -* `--crate-type=rlib`, `#![crate_type = "rlib"]` - A "Rust library" file will be - produced. This is used as an intermediate artifact and can be thought of as a - "static Rust library". These `rlib` files, unlike `staticlib` files, are - interpreted by the compiler in future linkage. This essentially means - that `rustc` will look for metadata in `rlib` files like it looks for metadata - in dynamic libraries. This form of output is used to produce statically linked - executables as well as `staticlib` outputs. +* `--crate-type=rlib`, `#![crate_type = "rlib"]` - A "Rust library" file will be produced. This is used as an intermediate artifact and can be thought of as a "static Rust library". These `rlib` files, unlike `staticlib` files, are interpreted by the compiler in future linkage. This essentially means that `rustc` will look for metadata in `rlib` files like it looks for metadata in dynamic libraries. This form of output is used to produce statically linked executables as well as `staticlib` outputs. r[link.proc-macro] -* `--crate-type=proc-macro`, `#![crate_type = "proc-macro"]` - The output - produced is not specified, but if a `-L` path is provided to it then the - compiler will recognize the output artifacts as a macro and it can be loaded - for a program. Crates compiled with this crate type must only export - [procedural macros]. The compiler will automatically set the `proc_macro` - [configuration option]. The crates are always compiled with the same target - that the compiler itself was built with. For example, if you are executing - the compiler from Linux with an `x86_64` CPU, the target will be - `x86_64-unknown-linux-gnu` even if the crate is a dependency of another crate - being built for a different target. +* `--crate-type=proc-macro`, `#![crate_type = "proc-macro"]` - The output produced is not specified, but if a `-L` path is provided to it then the compiler will recognize the output artifacts as a macro and it can be loaded for a program. Crates compiled with this crate type must only export [procedural macros]. The compiler will automatically set the `proc_macro` [configuration option]. The crates are always compiled with the same target that the compiler itself was built with. For example, if you are executing the compiler from Linux with an `x86_64` CPU, the target will be `x86_64-unknown-linux-gnu` even if the crate is a dependency of another crate being built for a different target. r[link.repetition] -Note that these outputs are stackable in the sense that if multiple are -specified, then the compiler will produce each form of output without -having to recompile. However, this only applies for outputs specified by the -same method. If only `crate_type` attributes are specified, then they will all -be built, but if one or more `--crate-type` command line flags are specified, -then only those outputs will be built. +Note that these outputs are stackable in the sense that if multiple are specified, then the compiler will produce each form of output without having to recompile. However, this only applies for outputs specified by the same method. If only `crate_type` attributes are specified, then they will all be built, but if one or more `--crate-type` command line flags are specified, then only those outputs will be built. r[link.dependency] -With all these different kinds of outputs, if crate A depends on crate B, then -the compiler could find B in various different forms throughout the system. The -only forms looked for by the compiler, however, are the `rlib` format and the -dynamic library format. With these two options for a dependent library, the -compiler must at some point make a choice between these two formats. With this -in mind, the compiler follows these rules when determining what format of -dependencies will be used: +With all these different kinds of outputs, if crate A depends on crate B, then the compiler could find B in various different forms throughout the system. The only forms looked for by the compiler, however, are the `rlib` format and the dynamic library format. With these two options for a dependent library, the compiler must at some point make a choice between these two formats. With this in mind, the compiler follows these rules when determining what format of dependencies will be used: r[link.dependency-staticlib] -1. If a static library is being produced, all upstream dependencies are - required to be available in `rlib` formats. This requirement stems from the - reason that a dynamic library cannot be converted into a static format. +1. If a static library is being produced, all upstream dependencies are required to be available in `rlib` formats. This requirement stems from the reason that a dynamic library cannot be converted into a static format. - Note that it is impossible to link in native dynamic dependencies to a static - library, and in this case warnings will be printed about all unlinked native - dynamic dependencies. + Note that it is impossible to link in native dynamic dependencies to a static library, and in this case warnings will be printed about all unlinked native dynamic dependencies. r[link.dependency-rlib] -2. If an `rlib` file is being produced, then there are no restrictions on what - format the upstream dependencies are available in. It is simply required that - all upstream dependencies be available for reading metadata from. +2. If an `rlib` file is being produced, then there are no restrictions on what format the upstream dependencies are available in. It is simply required that all upstream dependencies be available for reading metadata from. - The reason for this is that `rlib` files do not contain any of their upstream - dependencies. It wouldn't be very efficient for all `rlib` files to contain a - copy of `libstd.rlib`! + The reason for this is that `rlib` files do not contain any of their upstream dependencies. It wouldn't be very efficient for all `rlib` files to contain a copy of `libstd.rlib`! r[link.dependency-prefer-dynamic] -3. If an executable is being produced and the `-C prefer-dynamic` flag is not - specified, then dependencies are first attempted to be found in the `rlib` - format. If some dependencies are not available in an rlib format, then - dynamic linking is attempted (see below). +3. If an executable is being produced and the `-C prefer-dynamic` flag is not specified, then dependencies are first attempted to be found in the `rlib` format. If some dependencies are not available in an rlib format, then dynamic linking is attempted (see below). r[link.dependency-dynamic] -4. If a dynamic library or an executable that is being dynamically linked is - being produced, then the compiler will attempt to reconcile the available - dependencies in either the rlib or dylib format to create a final product. +4. If a dynamic library or an executable that is being dynamically linked is being produced, then the compiler will attempt to reconcile the available dependencies in either the rlib or dylib format to create a final product. - A major goal of the compiler is to ensure that a library never appears more - than once in any artifact. For example, if dynamic libraries B and C were - each statically linked to library A, then a crate could not link to B and C - together because there would be two copies of A. The compiler allows mixing - the rlib and dylib formats, but this restriction must be satisfied. + A major goal of the compiler is to ensure that a library never appears more than once in any artifact. For example, if dynamic libraries B and C were each statically linked to library A, then a crate could not link to B and C together because there would be two copies of A. The compiler allows mixing the rlib and dylib formats, but this restriction must be satisfied. - The compiler currently implements no method of hinting what format a library - should be linked with. When dynamically linking, the compiler will attempt to - maximize dynamic dependencies while still allowing some dependencies to be - linked in via an rlib. + The compiler currently implements no method of hinting what format a library should be linked with. When dynamically linking, the compiler will attempt to maximize dynamic dependencies while still allowing some dependencies to be linked in via an rlib. - For most situations, having all libraries available as a dylib is recommended - if dynamically linking. For other situations, the compiler will emit a - warning if it is unable to determine which formats to link each library with. + For most situations, having all libraries available as a dylib is recommended if dynamically linking. For other situations, the compiler will emit a warning if it is unable to determine which formats to link each library with. -In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for -all compilation needs, and the other options are just available if more -fine-grained control is desired over the output format of a crate. +In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for all compilation needs, and the other options are just available if more fine-grained control is desired over the output format of a crate. r[link.crt] ## Static and dynamic C runtimes r[link.crt.intro] -The standard library in general strives to support both statically linked and -dynamically linked C runtimes for targets as appropriate. For example the -`x86_64-pc-windows-msvc` and `x86_64-unknown-linux-musl` targets typically come -with both runtimes and the user selects which one they'd like. All targets in -the compiler have a default mode of linking to the C runtime. Typically targets -are linked dynamically by default, but there are exceptions which are static by -default such as: +The standard library in general strives to support both statically linked and dynamically linked C runtimes for targets as appropriate. For example the `x86_64-pc-windows-msvc` and `x86_64-unknown-linux-musl` targets typically come with both runtimes and the user selects which one they'd like. All targets in the compiler have a default mode of linking to the C runtime. Typically targets are linked dynamically by default, but there are exceptions which are static by default such as: * `arm-unknown-linux-musleabi` * `arm-unknown-linux-musleabihf` @@ -184,10 +83,7 @@ default such as: * `x86_64-unknown-linux-musl` r[link.crt.crt-static] -The linkage of the C runtime is configured to respect the `crt-static` target -feature. These target features are typically configured from the command line -via flags to the compiler itself. For example to enable a static runtime you -would execute: +The linkage of the C runtime is configured to respect the `crt-static` target feature. These target features are typically configured from the command line via flags to the compiler itself. For example to enable a static runtime you would execute: ```sh rustc -C target-feature=+crt-static foo.rs @@ -200,15 +96,10 @@ rustc -C target-feature=-crt-static foo.rs ``` r[link.crt.ineffective] -Targets which do not support switching between linkage of the C runtime will -ignore this flag. It's recommended to inspect the resulting binary to ensure -that it's linked as you would expect after the compiler succeeds. +Targets which do not support switching between linkage of the C runtime will ignore this flag. It's recommended to inspect the resulting binary to ensure that it's linked as you would expect after the compiler succeeds. r[link.crt.target_feature] -Crates may also learn about how the C runtime is being linked. Code on MSVC, for -example, needs to be compiled differently (e.g. with `/MT` or `/MD`) depending -on the runtime being linked. This is exported currently through the -[`cfg` attribute `target_feature` option]: +Crates may also learn about how the C runtime is being linked. Code on MSVC, for example, needs to be compiled differently (e.g. with `/MT` or `/MD`) depending on the runtime being linked. This is exported currently through the [`cfg` attribute `target_feature` option]: ```rust #[cfg(target_feature = "crt-static")] @@ -222,9 +113,7 @@ fn foo() { } ``` -Also note that Cargo build scripts can learn about this feature through -[environment variables][cargo]. In a build script you can detect the linkage -via: +Also note that Cargo build scripts can learn about this feature through [environment variables][cargo]. In a build script you can detect the linkage via: ```rust use std::env; @@ -242,9 +131,7 @@ fn main() { [cargo]: ../cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts -To use this feature locally, you typically will use the `RUSTFLAGS` environment -variable to specify flags to the compiler through Cargo. For example to compile -a statically linked binary on MSVC you would execute: +To use this feature locally, you typically will use the `RUSTFLAGS` environment variable to specify flags to the compiler through Cargo. For example to compile a statically linked binary on MSVC you would execute: ```sh RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-pc-windows-msvc @@ -254,18 +141,10 @@ r[link.foreign-code] ## Mixed Rust and foreign codebases r[link.foreign-code.foreign-linkers] -If you are mixing Rust with foreign code (e.g. C, C++) and wish to make a single -binary containing both types of code, you have two approaches for the final -binary link: - -* Use `rustc`. Pass any non-Rust libraries using `-L ` and `-l` - rustc arguments, and/or `#[link]` directives in your Rust code. If you need to - link against `.o` files you can use `-Clink-arg=file.o`. -* Use your foreign linker. In this case, you first need to generate a Rust `staticlib` - target and pass that into your foreign linker invocation. If you need to link - multiple Rust subsystems, you will need to generate a _single_ `staticlib` - perhaps using lots of `extern crate` statements to include multiple Rust `rlib`s. - Multiple Rust `staticlib` files are likely to conflict. +If you are mixing Rust with foreign code (e.g. C, C++) and wish to make a single binary containing both types of code, you have two approaches for the final binary link: + +* Use `rustc`. Pass any non-Rust libraries using `-L ` and `-l` rustc arguments, and/or `#[link]` directives in your Rust code. If you need to link against `.o` files you can use `-Clink-arg=file.o`. +* Use your foreign linker. In this case, you first need to generate a Rust `staticlib` target and pass that into your foreign linker invocation. If you need to link multiple Rust subsystems, you will need to generate a _single_ `staticlib` perhaps using lots of `extern crate` statements to include multiple Rust `rlib`s. Multiple Rust `staticlib` files are likely to conflict. Passing `rlib`s directly into your foreign linker is currently unsupported. From f7765290767a5840bd23e40b6021e0aa0e8bab56 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 26 May 2026 11:48:34 -0700 Subject: [PATCH 4/5] Unwrap safety chapters This unwraps the text to follow our style guide. --- src/behavior-considered-undefined.md | 119 +++++++------------------- src/behavior-not-considered-unsafe.md | 47 +++------- src/unsafe-keyword.md | 30 ++----- src/unsafety.md | 6 +- 4 files changed, 50 insertions(+), 152 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index cdf53d7c79..a99ae38850 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -2,18 +2,10 @@ r[undefined] # Behavior considered undefined r[undefined.intro] -Rust code is incorrect if it exhibits any of the behaviors in the following -list. This includes code within `unsafe` blocks and `unsafe` functions. -`unsafe` only means that avoiding undefined behavior is on the programmer; it -does not change anything about the fact that Rust programs must never cause -undefined behavior. +Rust code is incorrect if it exhibits any of the behaviors in the following list. This includes code within `unsafe` blocks and `unsafe` functions. `unsafe` only means that avoiding undefined behavior is on the programmer; it does not change anything about the fact that Rust programs must never cause undefined behavior. r[undefined.soundness] -It is the programmer's responsibility when writing `unsafe` code to ensure that -any safe code interacting with the `unsafe` code cannot trigger these -behaviors. `unsafe` code that satisfies this property for any safe client is -called *sound*; if `unsafe` code can be misused by safe code to exhibit -undefined behavior, it is *unsound*. +It is the programmer's responsibility when writing `unsafe` code to ensure that any safe code interacting with the `unsafe` code cannot trigger these behaviors. `unsafe` code that satisfies this property for any safe client is called *sound*; if `unsafe` code can be misused by safe code to exhibit undefined behavior, it is *unsound*. > [!WARNING] > The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything will *definitely* always be undefined in all future Rust versions (but we might make such commitments for some list items in the future). @@ -24,20 +16,17 @@ r[undefined.race] * Data races. r[undefined.pointer-access] -* Accessing (loading from or storing to) a place that is [dangling] or [based on - a misaligned pointer]. +* Accessing (loading from or storing to) a place that is [dangling] or [based on a misaligned pointer]. r[undefined.place-projection] * Performing an offsetting place projection that violates the requirements of [in-bounds pointer arithmetic](pointer#method.offset). An offsetting place projection is a [field expression][project-field], a [tuple index expression][project-tuple], or an [array/slice index expression][project-slice]. r[undefined.alias] * Breaking the pointer aliasing rules. The exact aliasing rules are not determined yet, but here is an outline of the general principles: - `&T` must point to memory that is not mutated while they are live (except for data inside an [`UnsafeCell`]), - and `&mut T` must point to memory that is not read or written by any pointer not derived from the reference and that no other reference points to while they are live. - `Box` is treated similar to `&'static mut T` for the purpose of these rules. - The exact liveness duration is not specified, but some bounds exist: - * For references, the liveness duration is upper-bounded by the syntactic - lifetime assigned by the borrow checker; it cannot be live any *longer* than that lifetime. + + `&T` must point to memory that is not mutated while they are live (except for data inside an [`UnsafeCell`]), and `&mut T` must point to memory that is not read or written by any pointer not derived from the reference and that no other reference points to while they are live. `Box` is treated similar to `&'static mut T` for the purpose of these rules. The exact liveness duration is not specified, but some bounds exist: + + * For references, the liveness duration is upper-bounded by the syntactic lifetime assigned by the borrow checker; it cannot be live any *longer* than that lifetime. * Each time a reference or box is dereferenced or reborrowed, it is considered live. * Each time a reference or box is passed to or returned from a function, it is considered live. * When a reference (but not a `Box`!) is passed to a function, it is live at least as long as that function call, again except if the `&T` contains an [`UnsafeCell`]. @@ -45,9 +34,7 @@ r[undefined.alias] All this also applies when values of these types are passed in a (nested) field of a compound type, but not behind pointer indirections. r[undefined.immutable] -* Mutating immutable bytes. - All bytes reachable through a [const-promoted] expression are immutable, as well as bytes reachable through borrows in `static` and `const` initializers that have been [lifetime-extended] to `'static`. - The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. +* Mutating immutable bytes. All bytes reachable through a [const-promoted] expression are immutable, as well as bytes reachable through borrows in `static` and `const` initializers that have been [lifetime-extended] to `'static`. The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. Moreover, the bytes [pointed to] by a shared reference, including transitively through other references (both shared and mutable) and `Box`es, are immutable; transitivity includes those references stored in fields of compound types. @@ -57,21 +44,16 @@ r[undefined.intrinsic] * Invoking undefined behavior via compiler intrinsics. r[undefined.target-feature] -* Executing code compiled with platform features that the current platform - does not support (see [`target_feature`]), *except* if the platform explicitly documents this to be safe. +* Executing code compiled with platform features that the current platform does not support (see [`target_feature`]), *except* if the platform explicitly documents this to be safe. r[undefined.call] * Calling a function with the wrong [call ABI][abi], or unwinding past a stack frame that does not allow unwinding (e.g. by calling a `"C-unwind"` function imported or transmuted as a `"C"` function or function pointer). r[undefined.invalid] -* Producing an [invalid value][invalid-values]. "Producing" a - value happens any time a value is assigned to or read from a place, passed to - a function/primitive operation or returned from a function/primitive - operation. +* Producing an [invalid value][invalid-values]. "Producing" a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation. r[undefined.asm] -* Incorrect use of inline assembly. For more details, refer to the [rules] to - follow when writing code that uses inline assembly. +* Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. r[undefined.runtime] * Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented. @@ -91,70 +73,44 @@ r[undefined.misaligned] [based on a misaligned pointer]: #places-based-on-misaligned-pointers r[undefined.misaligned.ptr] -A place is said to be "based on a misaligned pointer" if the last `*` projection -during place computation was performed on a pointer that was not aligned for its -type. (If there is no `*` projection in the place expression, then this is -accessing the field of a local or `static` and rustc will guarantee proper alignment. If -there are multiple `*` projections, then each of them incurs a load of the -pointer-to-be-dereferenced itself from memory, and each of these loads is -subject to the alignment constraint. Note that some `*` projections can be -omitted in surface Rust syntax due to automatic dereferencing; we are -considering the fully expanded place expression here.) - -For instance, if `ptr` has type `*const S` where `S` has an alignment of 8, then -`ptr` must be 8-aligned or else `(*ptr).f` is "based on an misaligned pointer". -This is true even if the type of the field `f` is `u8` (i.e., a type with -alignment 1). In other words, the alignment requirement derives from the type of -the pointer that was dereferenced, *not* the type of the field that is being -accessed. +A place is said to be "based on a misaligned pointer" if the last `*` projection during place computation was performed on a pointer that was not aligned for its type. (If there is no `*` projection in the place expression, then this is accessing the field of a local or `static` and rustc will guarantee proper alignment. If there are multiple `*` projections, then each of them incurs a load of the pointer-to-be-dereferenced itself from memory, and each of these loads is subject to the alignment constraint. Note that some `*` projections can be omitted in surface Rust syntax due to automatic dereferencing; we are considering the fully expanded place expression here.) + +For instance, if `ptr` has type `*const S` where `S` has an alignment of 8, then `ptr` must be 8-aligned or else `(*ptr).f` is "based on an misaligned pointer". This is true even if the type of the field `f` is `u8` (i.e., a type with alignment 1). In other words, the alignment requirement derives from the type of the pointer that was dereferenced, *not* the type of the field that is being accessed. r[undefined.misaligned.load-store] -Note that a place based on a misaligned pointer only leads to undefined behavior -when it is loaded from or stored to. +Note that a place based on a misaligned pointer only leads to undefined behavior when it is loaded from or stored to. r[undefined.misaligned.raw] `&raw const`/`&raw mut` on such a place is allowed. r[undefined.misaligned.reference] -`&`/`&mut` on a place requires the alignment of the field type (or -else the program would be "producing an invalid value"), which generally is a -less restrictive requirement than being based on an aligned pointer. +`&`/`&mut` on a place requires the alignment of the field type (or else the program would be "producing an invalid value"), which generally is a less restrictive requirement than being based on an aligned pointer. r[undefined.misaligned.packed] -Taking a reference will lead to a compiler error in cases where the field type might be -more aligned than the type that contains it, i.e., `repr(packed)`. This means -that being based on an aligned pointer is always sufficient to ensure that the -new reference is aligned, but it is not always necessary. +Taking a reference will lead to a compiler error in cases where the field type might be more aligned than the type that contains it, i.e., `repr(packed)`. This means that being based on an aligned pointer is always sufficient to ensure that the new reference is aligned, but it is not always necessary. r[undefined.dangling] ## Dangling pointers [dangling]: #dangling-pointers r[undefined.dangling.def] -A reference/pointer is "dangling" if not all of the bytes it -[points to] are part of the same live allocation (so in particular they all have to be -part of *some* allocation). +A reference/pointer is "dangling" if not all of the bytes it [points to] are part of the same live allocation (so in particular they all have to be part of *some* allocation). r[undefined.dangling.zero-size] -If the [size is 0][zero-sized], then the pointer is trivially never "dangling" -(even if it is a null pointer). +If the [size is 0][zero-sized], then the pointer is trivially never "dangling" (even if it is a null pointer). r[undefined.dangling.dynamic-size] -Note that dynamically sized types (such as slices and strings) point to their -entire range, so it is important that the length metadata is never too large. +Note that dynamically sized types (such as slices and strings) point to their entire range, so it is important that the length metadata is never too large. r[undefined.dangling.alloc-limit] -In particular, the dynamic size of a Rust value (as determined by `size_of_val`) -must never exceed `isize::MAX`, since it is impossible for a single allocation -to be larger than `isize::MAX`. +In particular, the dynamic size of a Rust value (as determined by `size_of_val`) must never exceed `isize::MAX`, since it is impossible for a single allocation to be larger than `isize::MAX`. r[undefined.validity] ## Invalid values [invalid-values]: #invalid-values r[undefined.validity.def] -The Rust compiler assumes that all values produced during program execution are -"valid", and producing an invalid value is hence immediate UB. +The Rust compiler assumes that all values produced during program execution are "valid", and producing an invalid value is hence immediate UB. Whether a value is valid depends on the type: @@ -171,8 +127,7 @@ r[undefined.validity.never] * A `!` value must never exist. r[undefined.validity.scalar] -* An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer must be - initialized, i.e., must not be obtained from uninitialized memory. +* An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer must be initialized, i.e., must not be obtained from uninitialized memory. r[undefined.validity.str] * A `str` value is treated like `[u8]`, i.e. it must be initialized. @@ -184,29 +139,18 @@ r[undefined.validity.struct] * A `struct`, tuple, and array requires all fields/elements to be valid at their respective type. r[undefined.validity.union] -* For a `union`, the exact validity requirements are not decided yet. - Obviously, all values that can be created entirely in safe code are valid. - If the union has a [zero-sized] field, then every possible value is valid. - Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438). +* For a `union`, the exact validity requirements are not decided yet. Obviously, all values that can be created entirely in safe code are valid. If the union has a [zero-sized] field, then every possible value is valid. Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438). r[undefined.validity.reference-box] -* A reference or [`Box`] must be aligned and non-null, it cannot be [dangling], and it must point to a valid value - (in case of dynamically sized types, using the actual dynamic type of the - pointee as determined by the metadata). - Note that the last point (about pointing to a valid value) remains a subject of some debate. +* A reference or [`Box`] must be aligned and non-null, it cannot be [dangling], and it must point to a valid value (in case of dynamically sized types, using the actual dynamic type of the pointee as determined by the metadata). Note that the last point (about pointing to a valid value) remains a subject of some debate. r[undefined.validity.wide] -* The metadata of a wide reference, [`Box`], or raw pointer must match - the type of the unsized tail: - * `dyn Trait` metadata must be a pointer to a compiler-generated vtable for `Trait`. - (For raw pointers, this requirement remains a subject of some debate.) - * Slice (`[T]`) metadata must be a valid `usize`. - Furthermore, for wide references and [`Box`], slice metadata is invalid - if it makes the total size of the pointed-to value bigger than `isize::MAX`. +* The metadata of a wide reference, [`Box`], or raw pointer must match the type of the unsized tail: + * `dyn Trait` metadata must be a pointer to a compiler-generated vtable for `Trait`. (For raw pointers, this requirement remains a subject of some debate.) + * Slice (`[T]`) metadata must be a valid `usize`. Furthermore, for wide references and [`Box`], slice metadata is invalid if it makes the total size of the pointed-to value bigger than `isize::MAX`. r[undefined.validity.valid-range] -* If a type has a custom range of a valid values, then a valid value must be in that range. - In the standard library, this affects [`NonNull`] and [`NonZero`]. +* If a type has a custom range of a valid values, then a valid value must be in that range. In the standard library, this affects [`NonNull`] and [`NonZero`]. > [!NOTE] > `rustc` achieves this with the unstable `rustc_layout_scalar_valid_range_*` attributes. @@ -241,10 +185,7 @@ r[undefined.validity.const-provenance] > ``` r[undefined.validity.undef] -**Note:** Uninitialized memory is also implicitly invalid for any type that has -a restricted set of valid values. In other words, the only cases in which -reading uninitialized memory is permitted are inside `union`s and in "padding" -(the gaps between the fields of a type). +**Note:** Uninitialized memory is also implicitly invalid for any type that has a restricted set of valid values. In other words, the only cases in which reading uninitialized memory is permitted are inside `union`s and in "padding" (the gaps between the fields of a type). [`bool`]: types/boolean.md [`const`]: items/constant-items.md diff --git a/src/behavior-not-considered-unsafe.md b/src/behavior-not-considered-unsafe.md index 94b7d57de7..60f5294578 100644 --- a/src/behavior-not-considered-unsafe.md +++ b/src/behavior-not-considered-unsafe.md @@ -1,8 +1,6 @@ # Behavior not considered `unsafe` -The Rust compiler does not consider the following behaviors _unsafe_, -though a programmer may (should) find them undesirable, unexpected, -or erroneous. +The Rust compiler does not consider the following behaviors _unsafe_, though a programmer may (should) find them undesirable, unexpected, or erroneous. - Deadlocks - Leaks of memory and other resources @@ -11,47 +9,22 @@ or erroneous. ## Integer overflow -If a program contains arithmetic overflow, the programmer has made an -error. In the following discussion, we maintain a distinction between -arithmetic overflow and wrapping arithmetic. The first is erroneous, -while the second is intentional. +If a program contains arithmetic overflow, the programmer has made an error. In the following discussion, we maintain a distinction between arithmetic overflow and wrapping arithmetic. The first is erroneous, while the second is intentional. -When the programmer has enabled `debug_assert!` assertions (for -example, by enabling a non-optimized build), implementations must -insert dynamic checks that `panic` on overflow. Other kinds of builds -may result in `panics` or silently wrapped values on overflow, at the -implementation's discretion. +When the programmer has enabled `debug_assert!` assertions (for example, by enabling a non-optimized build), implementations must insert dynamic checks that `panic` on overflow. Other kinds of builds may result in `panics` or silently wrapped values on overflow, at the implementation's discretion. -In the case of implicitly-wrapped overflow, implementations must -provide well-defined (even if still considered erroneous) results by -using two's complement overflow conventions. +In the case of implicitly-wrapped overflow, implementations must provide well-defined (even if still considered erroneous) results by using two's complement overflow conventions. -The integral types provide inherent methods to allow programmers -explicitly to perform wrapping arithmetic. For example, -`i32::wrapping_add` provides two's complement, wrapping addition. +The integral types provide inherent methods to allow programmers explicitly to perform wrapping arithmetic. For example, `i32::wrapping_add` provides two's complement, wrapping addition. -The standard library also provides a `Wrapping` newtype which -ensures all standard arithmetic operations for `T` have wrapping -semantics. +The standard library also provides a `Wrapping` newtype which ensures all standard arithmetic operations for `T` have wrapping semantics. -See [RFC 560] for error conditions, rationale, and more details about -integer overflow. +See [RFC 560] for error conditions, rationale, and more details about integer overflow. ## Logic errors -Safe code may impose extra logical constraints that can be checked -at neither compile-time nor runtime. If a program breaks such -a constraint, the behavior may be unspecified but will not result in -undefined behavior. This could include panics, incorrect results, -aborts, and non-termination. The behavior may also differ between -runs, builds, or kinds of build. - -For example, implementing both `Hash` and `Eq` requires that values -considered equal have equal hashes. Another example are data structures -like `BinaryHeap`, `BTreeMap`, `BTreeSet`, `HashMap` and `HashSet` -which describe constraints on the modification of their keys while -they are in the data structure. Violating such constraints is not -considered unsafe, yet the program is considered erroneous and -its behavior unpredictable. +Safe code may impose extra logical constraints that can be checked at neither compile-time nor runtime. If a program breaks such a constraint, the behavior may be unspecified but will not result in undefined behavior. This could include panics, incorrect results, aborts, and non-termination. The behavior may also differ between runs, builds, or kinds of build. + +For example, implementing both `Hash` and `Eq` requires that values considered equal have equal hashes. Another example are data structures like `BinaryHeap`, `BTreeMap`, `BTreeSet`, `HashMap` and `HashSet` which describe constraints on the modification of their keys while they are in the data structure. Violating such constraints is not considered unsafe, yet the program is considered erroneous and its behavior unpredictable. [RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index 7658c1f5c5..9153078fc0 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -9,8 +9,7 @@ The `unsafe` keyword is used to create or discharge the obligation to prove some - It is used to mark code that the programmer *asserts* satisfies safety conditions defined elsewhere. - This includes `unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`], `unsafe extern`, and `#[unsafe(attr)]`. -The following discusses each of these cases. -See the [keyword documentation][keyword] for some illustrative examples. +The following discusses each of these cases. See the [keyword documentation][keyword] for some illustrative examples. r[unsafe.positions] The `unsafe` keyword can occur in several different contexts: @@ -27,10 +26,7 @@ r[unsafe.fn] ## Unsafe functions (`unsafe fn`) r[unsafe.fn.intro] -Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs. -We say they have *extra safety conditions*, which are requirements that must be upheld by all callers and that the compiler does not check. -For example, [`get_unchecked`] has the extra safety condition that the index must be in-bounds. -The unsafe function should come with documentation explaining what those extra safety conditions are. +Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs. We say they have *extra safety conditions*, which are requirements that must be upheld by all callers and that the compiler does not check. For example, [`get_unchecked`] has the extra safety condition that the index must be in-bounds. The unsafe function should come with documentation explaining what those extra safety conditions are. r[unsafe.fn.safety] Such a function must be prefixed with the keyword `unsafe` and can only be called from inside an `unsafe` block, or inside `unsafe fn` without the [`unsafe_op_in_unsafe_fn`] lint. @@ -42,23 +38,15 @@ r[unsafe.block.intro] A block of code can be prefixed with the `unsafe` keyword to permit using the unsafe actions as defined in the [Unsafety] chapter, such as calling other unsafe functions or dereferencing raw pointers. r[unsafe.block.fn-body] -By default, the body of an unsafe function is also considered to be an unsafe block; -this can be changed by enabling the [`unsafe_op_in_unsafe_fn`] lint. +By default, the body of an unsafe function is also considered to be an unsafe block; this can be changed by enabling the [`unsafe_op_in_unsafe_fn`] lint. By putting operations into an unsafe block, the programmer states that they have taken care of satisfying the extra safety conditions of all operations inside that block. -Unsafe blocks are the logical dual to unsafe functions: -where unsafe functions define a proof obligation that callers must uphold, unsafe blocks state that all relevant proof obligations of functions or operations called inside the block have been discharged. -There are many ways to discharge proof obligations; -for example, there could be run-time checks or data structure invariants that guarantee that certain properties are definitely true, or the unsafe block could be inside an `unsafe fn`, in which case the block can use the proof obligations of that function to discharge the proof obligations arising inside the block. +Unsafe blocks are the logical dual to unsafe functions: where unsafe functions define a proof obligation that callers must uphold, unsafe blocks state that all relevant proof obligations of functions or operations called inside the block have been discharged. There are many ways to discharge proof obligations; for example, there could be run-time checks or data structure invariants that guarantee that certain properties are definitely true, or the unsafe block could be inside an `unsafe fn`, in which case the block can use the proof obligations of that function to discharge the proof obligations arising inside the block. -Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features not directly present in the language. -For example, Rust provides the language features necessary to implement memory-safe concurrency in the language but the implementation of threads and message passing in the standard library uses unsafe blocks. +Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features not directly present in the language. For example, Rust provides the language features necessary to implement memory-safe concurrency in the language but the implementation of threads and message passing in the standard library uses unsafe blocks. -Rust's type system is a conservative approximation of the dynamic safety requirements, so in some cases there is a performance cost to using safe code. -For example, a doubly-linked list is not a tree structure and can only be represented with reference-counted pointers in safe code. -By using `unsafe` blocks to represent the reverse links as raw pointers, it can be implemented without reference counting. -(See ["Learn Rust With Entirely Too Many Linked Lists"](https://rust-unofficial.github.io/too-many-lists/) for a more in-depth exploration of this particular example.) +Rust's type system is a conservative approximation of the dynamic safety requirements, so in some cases there is a performance cost to using safe code. For example, a doubly-linked list is not a tree structure and can only be represented with reference-counted pointers in safe code. By using `unsafe` blocks to represent the reverse links as raw pointers, it can be implemented without reference counting. (See ["Learn Rust With Entirely Too Many Linked Lists"](https://rust-unofficial.github.io/too-many-lists/) for a more in-depth exploration of this particular example.) [Unsafety]: unsafety.md @@ -66,8 +54,7 @@ r[unsafe.trait] ## Unsafe traits (`unsafe trait`) r[unsafe.trait.intro] -An unsafe trait is a trait that comes with extra safety conditions that must be upheld by *implementations* of the trait. -The unsafe trait should come with documentation explaining what those extra safety conditions are. +An unsafe trait is a trait that comes with extra safety conditions that must be upheld by *implementations* of the trait. The unsafe trait should come with documentation explaining what those extra safety conditions are. r[unsafe.trait.safety] Such a trait must be prefixed with the keyword `unsafe` and can only be implemented by `unsafe impl` blocks. @@ -75,8 +62,7 @@ Such a trait must be prefixed with the keyword `unsafe` and can only be implemen r[unsafe.impl] ## Unsafe trait implementations (`unsafe impl`) -When implementing an unsafe trait, the implementation needs to be prefixed with the `unsafe` keyword. -By writing `unsafe impl`, the programmer states that they have taken care of satisfying the extra safety conditions required by the trait. +When implementing an unsafe trait, the implementation needs to be prefixed with the `unsafe` keyword. By writing `unsafe impl`, the programmer states that they have taken care of satisfying the extra safety conditions required by the trait. Unsafe trait implementations are the logical dual to unsafe traits: where unsafe traits define a proof obligation that implementations must uphold, unsafe implementations state that all relevant proof obligations have been discharged. diff --git a/src/unsafety.md b/src/unsafety.md index 7353bcc600..2e3be72280 100644 --- a/src/unsafety.md +++ b/src/unsafety.md @@ -2,12 +2,10 @@ r[safety] # Unsafety r[safety.intro] -Unsafe operations are those that can potentially violate the memory-safety -guarantees of Rust's static semantics. +Unsafe operations are those that can potentially violate the memory-safety guarantees of Rust's static semantics. r[safety.unsafe-ops] -The following language level features cannot be used in the safe subset of -Rust: +The following language level features cannot be used in the safe subset of Rust: r[safety.unsafe-deref] - Dereferencing a [raw pointer]. From 6ace9ab7d7f2ea38b8372ff17c6716b07fd4aec6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 26 May 2026 11:51:07 -0700 Subject: [PATCH 5/5] Unwrap ABI chapter This unwraps the text to follow our style guide. --- src/abi.md | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/abi.md b/src/abi.md index 0ddd93b88f..cf6f32c90e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -2,12 +2,9 @@ r[abi] # Application binary interface (ABI) r[abi.intro] -This section documents features that affect the ABI of the compiled output of -a crate. +This section documents features that affect the ABI of the compiled output of a crate. -See *[extern functions]* for information on specifying the ABI for exporting -functions. See *[external blocks]* for information on specifying the ABI for -linking external libraries. +See *[extern functions]* for information on specifying the ABI for exporting functions. See *[external blocks]* for information on specifying the ABI for linking external libraries. r[abi.used] @@ -68,17 +65,13 @@ r[abi.no_mangle] ## The `no_mangle` attribute r[abi.no_mangle.intro] -The *`no_mangle` attribute* may be used on any [item] to disable standard -symbol name mangling. The symbol for the item will be the identifier of the -item's name. +The *`no_mangle` attribute* may be used on any [item] to disable standard symbol name mangling. The symbol for the item will be the identifier of the item's name. r[abi.no_mangle.publicly-exported] -Additionally, the item will be publicly exported from the produced library or -object file, similar to the [`used` attribute](#the-used-attribute). +Additionally, the item will be publicly exported from the produced library or object file, similar to the [`used` attribute](#the-used-attribute). r[abi.no_mangle.unsafe] -This attribute is unsafe as an unmangled symbol may collide with another symbol -with the same name (or with a well-known symbol), leading to undefined behavior. +This attribute is unsafe as an unmangled symbol may collide with another symbol with the same name (or with a well-known symbol), leading to undefined behavior. ```rust #[unsafe(no_mangle)] @@ -93,8 +86,7 @@ r[abi.link_section] ## The `link_section` attribute r[abi.link_section.intro] -The *`link_section` attribute* specifies the section of the object file that a -[function] or [static]'s content will be placed into. +The *`link_section` attribute* specifies the section of the object file that a [function] or [static]'s content will be placed into. r[abi.link_section.syntax] The `link_section` attribute uses the [MetaNameValueStr] syntax to specify the section name. @@ -109,8 +101,7 @@ pub static VAR1: u32 = 1; ``` r[abi.link_section.unsafe] -This attribute is unsafe as it allows users to place data and code into sections -of memory not expecting them, such as mutable data into read-only areas. +This attribute is unsafe as it allows users to place data and code into sections of memory not expecting them, such as mutable data into read-only areas. r[abi.link_section.duplicates] Only the first use of `link_section` on an item has effect. @@ -126,8 +117,7 @@ r[abi.export_name] ## The `export_name` attribute r[abi.export_name.intro] -The *`export_name` attribute* specifies the name of the symbol that will be -exported on a [function] or [static]. +The *`export_name` attribute* specifies the name of the symbol that will be exported on a [function] or [static]. r[abi.export_name.syntax] The `export_name `attribute uses the [MetaNameValueStr] syntax to specify the symbol name. @@ -138,9 +128,7 @@ pub fn name_in_rust() { } ``` r[abi.export_name.unsafe] -This attribute is unsafe as a symbol with a custom name may collide with another -symbol with the same name (or with a well-known symbol), leading to undefined -behavior. +This attribute is unsafe as a symbol with a custom name may collide with another symbol with the same name (or with a well-known symbol), leading to undefined behavior. r[abi.export_name.duplicates] Only the first use of `export_name` on an item has effect.