From ee09160a5f6afefc3a02f5b9900add21cd3a85d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Sep 2023 12:54:47 +0200 Subject: [PATCH] document ABI compatibility --- library/core/src/primitive_docs.rs | 35 +++++++++++++++++++++++++++++- library/std/src/primitive_docs.rs | 35 +++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 80289ca08c3fc..9f75a5c5ba537 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1501,7 +1501,7 @@ mod prim_ref {} /// /// ### Casting to and from integers /// -/// You cast function pointers directly to integers: +/// You can cast function pointers directly to integers: /// /// ```rust /// let fnptr: fn(i32) -> i32 = |x| x+2; @@ -1527,6 +1527,39 @@ mod prim_ref {} /// Note that all of this is not portable to platforms where function pointers and data pointers /// have different sizes. /// +/// ### ABI compatibility +/// +/// Generally, when a function is declared with one signature and called via a function pointer +/// with a different signature, the two signatures must be *ABI-compatible* or else this call is +/// Undefined Behavior. ABI compatibility is a lot stricter than merely having the same +/// representation in memory; for example, even if `i32` and `f32` have the same size and alignment, +/// they might be passed in different registers and hence not be ABI-compatible. +/// +/// For two signatures to be considered *ABI-compatible*, they must declare the same `extern` ABI +/// string, must take the same number of arguments, and the individual argument types and the return +/// types must be ABI-compatible. +/// The relation of when two types are ABI-compatible is defined as follows: +/// +/// - Every type is ABI-compatible with itself. +/// - If `::Metadata == ()`, then `*const T`, `*mut T`, `&T`, `&mut T`, `Box`, +/// `NonNull` are all ABI-compatible with each other. +/// - Any two `fn()` types with the same `extern` ABI string are ABI-compatible with each other. +/// - Any two 1-ZST types (types with size 0 and alignment 1) are ABI-compatible. +/// - A `repr(transparent)` type `T` that has no private fields and is not `#[non_exhaustive]` is +/// ABI-compatible with its unique non-1-ZST field (if there is such a field). +/// - `i32` is ABI-compatible with `NonZeroI32`, and similar for all other integer types with their +/// matching `NonZero*` type. +/// - If `T` is guaranteed to be subject to the [null pointer +/// optimization](option/index.html#representation), then `T` and `Option` are ABI-compatible. +/// - If `T1` and `T2` are ABI-compatible, then two `repr(C)` types that only differ because one +/// field type was changed from `T1` to `T2` are ABI-compatible. +/// - ABI-compatibility is symmetric and transitive. +/// +/// Noteworthy cases of types *not* being ABI-compatible are `bool` vs `u8`, and `i32` vs `u32`: on +/// some targets, the calling conventions for these types differ in terms of what they guarantee for +/// the remaining bits in the register that are not used by the value. `i32` vs `f32` has already +/// been mentioned above. +/// /// ### Trait implementations /// /// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 80289ca08c3fc..9f75a5c5ba537 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1501,7 +1501,7 @@ mod prim_ref {} /// /// ### Casting to and from integers /// -/// You cast function pointers directly to integers: +/// You can cast function pointers directly to integers: /// /// ```rust /// let fnptr: fn(i32) -> i32 = |x| x+2; @@ -1527,6 +1527,39 @@ mod prim_ref {} /// Note that all of this is not portable to platforms where function pointers and data pointers /// have different sizes. /// +/// ### ABI compatibility +/// +/// Generally, when a function is declared with one signature and called via a function pointer +/// with a different signature, the two signatures must be *ABI-compatible* or else this call is +/// Undefined Behavior. ABI compatibility is a lot stricter than merely having the same +/// representation in memory; for example, even if `i32` and `f32` have the same size and alignment, +/// they might be passed in different registers and hence not be ABI-compatible. +/// +/// For two signatures to be considered *ABI-compatible*, they must declare the same `extern` ABI +/// string, must take the same number of arguments, and the individual argument types and the return +/// types must be ABI-compatible. +/// The relation of when two types are ABI-compatible is defined as follows: +/// +/// - Every type is ABI-compatible with itself. +/// - If `::Metadata == ()`, then `*const T`, `*mut T`, `&T`, `&mut T`, `Box`, +/// `NonNull` are all ABI-compatible with each other. +/// - Any two `fn()` types with the same `extern` ABI string are ABI-compatible with each other. +/// - Any two 1-ZST types (types with size 0 and alignment 1) are ABI-compatible. +/// - A `repr(transparent)` type `T` that has no private fields and is not `#[non_exhaustive]` is +/// ABI-compatible with its unique non-1-ZST field (if there is such a field). +/// - `i32` is ABI-compatible with `NonZeroI32`, and similar for all other integer types with their +/// matching `NonZero*` type. +/// - If `T` is guaranteed to be subject to the [null pointer +/// optimization](option/index.html#representation), then `T` and `Option` are ABI-compatible. +/// - If `T1` and `T2` are ABI-compatible, then two `repr(C)` types that only differ because one +/// field type was changed from `T1` to `T2` are ABI-compatible. +/// - ABI-compatibility is symmetric and transitive. +/// +/// Noteworthy cases of types *not* being ABI-compatible are `bool` vs `u8`, and `i32` vs `u32`: on +/// some targets, the calling conventions for these types differ in terms of what they guarantee for +/// the remaining bits in the register that are not used by the value. `i32` vs `f32` has already +/// been mentioned above. +/// /// ### Trait implementations /// /// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic