From 81dadf65f2c7f6b70eb433a46c8dfb56875d8711 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Sep 2023 09:57:06 +0200 Subject: [PATCH] the call ABI does not have to be fully equal; explicilty discuss incompleteness --- library/core/src/primitive_docs.rs | 29 ++++++++++++++++++----------- library/std/src/primitive_docs.rs | 29 ++++++++++++++++++----------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 795ae16c8119..23b4d4eb6a5a 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1529,16 +1529,20 @@ mod prim_ref {} /// /// ### 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 +/// 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: +/// For two signatures to be considered *ABI-compatible*, they must use a compatible call ABI (as +/// declared via `extern "ABI"`), must take the same number of arguments, and the individual +/// argument types and the return types must be ABI-compatible. +/// +/// The call ABIs are guaranteed to be compatible if they are the same, or if the caller ABI is +/// `$X-unwind` and the callee ABI is `$X`. +/// +/// The following types are guaranteed to be ABI-compatible: /// /// - Every type is ABI-compatible with itself. /// - If `::Metadata == ()`, then `*const T`, `*mut T`, `&T`, `&mut T`, `Box`, @@ -1555,17 +1559,20 @@ mod prim_ref {} /// 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. +/// More signatures can be ABI-compatible on specific targets, but that should not be relied upon +/// since it is not portable and not a stable guarantee. +/// +/// Noteworthy cases of types *not* being ABI-compatible in general 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. /// /// Note that these rules describe when two completely known types are ABI-compatible. When /// considering ABI compatibility of a type declared in another crate (including the standard /// library), consider that any type that has a private field or the `#[non_exhaustive]` attribute /// may change its layout as a non-breaking update unless documented otherwise -- so for instance, /// even if such a type is a 1-ZST or `repr(transparent)` right now, this might change with any -/// library version change. +/// library version bump. /// /// ### Trait implementations /// diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 795ae16c8119..23b4d4eb6a5a 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1529,16 +1529,20 @@ mod prim_ref {} /// /// ### 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 +/// 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: +/// For two signatures to be considered *ABI-compatible*, they must use a compatible call ABI (as +/// declared via `extern "ABI"`), must take the same number of arguments, and the individual +/// argument types and the return types must be ABI-compatible. +/// +/// The call ABIs are guaranteed to be compatible if they are the same, or if the caller ABI is +/// `$X-unwind` and the callee ABI is `$X`. +/// +/// The following types are guaranteed to be ABI-compatible: /// /// - Every type is ABI-compatible with itself. /// - If `::Metadata == ()`, then `*const T`, `*mut T`, `&T`, `&mut T`, `Box`, @@ -1555,17 +1559,20 @@ mod prim_ref {} /// 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. +/// More signatures can be ABI-compatible on specific targets, but that should not be relied upon +/// since it is not portable and not a stable guarantee. +/// +/// Noteworthy cases of types *not* being ABI-compatible in general 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. /// /// Note that these rules describe when two completely known types are ABI-compatible. When /// considering ABI compatibility of a type declared in another crate (including the standard /// library), consider that any type that has a private field or the `#[non_exhaustive]` attribute /// may change its layout as a non-breaking update unless documented otherwise -- so for instance, /// even if such a type is a 1-ZST or `repr(transparent)` right now, this might change with any -/// library version change. +/// library version bump. /// /// ### Trait implementations ///