From 13cfa689227f4926cb2ff5e0cac319af4120e25e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 26 Sep 2016 10:51:54 +0200 Subject: [PATCH 1/2] Specify #[repr(transparent)] --- text/0000-repr-transparent.md | 191 ++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 text/0000-repr-transparent.md diff --git a/text/0000-repr-transparent.md b/text/0000-repr-transparent.md new file mode 100644 index 00000000000..b34c9082796 --- /dev/null +++ b/text/0000-repr-transparent.md @@ -0,0 +1,191 @@ +- Feature Name: `repr_transparent` +- Start Date: 2016-09-26 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Extend the existing `#[repr]` attribute on newtypes with a `transparent` option +specifying that the type representation is the representation of its only field. +This matters in FFI context where `struct Foo(T)` might not behave the same +as `T`. + + +# Motivation +[motivation]: #motivation + +On some ABIs, structures with one field aren't handled the same way as values of +the same type as the single field. For example on ARM64, functions returning +a structure with a single `f64` field return nothing and take a pointer to be +filled with the return value, whereas functions returning a `f64` return the +floating-point number directly. + +This means that if someone wants to wrap a `f64` value in a struct tuple +wrapper and use that wrapper as the return type of a FFI function that actually +returns a bare `f64`, the calls to this function will be compiled incorrectly +by Rust and the execution of the program will segfault. + +This also means that `UnsafeCell` cannot be soundly used in place of a +bare `T` in FFI context, which might be necessary to signal to the Rust side +of things that this `T` value may unexpectedly be mutated. + +```c +// The value is returned directly in a floating-point register on ARM64. +double do_something_and_return_a_double(void); +``` + +```rust +mod bogus { + #[repr(C)] + struct FancyWrapper(f64); + + extern { + // Incorrect: the wrapped value on ARM64 is indirectly returned and the + // function takes a pointer to where the return value must be stored. + fn do_something_and_return_a_double() -> FancyWrapper; + } +} + +mod correct { + #[repr(transparent)] + struct FancyWrapper(f64); + + extern { + // Correct: FancyWrapper is handled exactly the same as f64 on all + // platforms. + fn do_something_and_return_a_double() -> FancyWrapper; + } +} +``` + +Given this attribute delegates all representation concerns, no other `repr` +attribute should be present on the type. This means the following definitions +are illegal: + +```rust +#[repr(transparent, align = "128")] +struct BogusAlign(f64); + +#[repr(transparent, packed)] +struct BogusPacked(f64); +``` + +# Detailed design +[design]: #detailed-design + +The `#[repr]` attribute on newtypes will be extended to include a form such as: + +```rust +#[repr(transparent)] +struct TransparentNewtype(f64); +``` + +This structure will still have the same representation as a raw `f64` value. + +Syntactically, the `repr` meta list will be extended to accept a meta item +with the name "transparent". This attribute can be placed on newtypes, +i.e. structures (and structure tuples) with a single field, and on structures +that are logically equivalent to a newtype, i.e. structures with multiple fields +where only a single one of them has a non-zero size. + +Some examples of `#[repr(transparent)]` are: + +```rust +// Transparent struct tuple. +#[repr(transparent)] +struct TransparentStructTuple(i32); + +// Transparent structure. +#[repr(transparent)] +struct TransparentStructure { only_field: f64 } + +// Transparent struct wrapper with a marker. +#[repr(transparent)] +struct TransparentWrapper { + only_non_zero_sized_field: f64, + marker: PhantomData, +} +``` + +This new representation is mostly useful when the structure it is put on must be +used in FFI context as a wrapper to the underlying type without actually being +affected by any ABI semantics. + +It is also useful for `AtomicUsize`-like types, which [RFC 1649] states should +have the same representation as their underlying types. + +[RFC 1649]: https://github.com/rust-lang/rfcs/pull/1649 + +This new representation cannot be used with any other representation attribute +but alignment, to be able to specify a transparent wrapper with additional +alignment constraints: + +```rust +#[repr(transparent, align = "128")] +struct OverAligned(f64); // Behaves as a bare f64 with 128 bits alignment. + +#[repr(C, transparent)] +struct BogusRepr(f64); // Nonsensical, repr cannot be C and transparent. +``` + +As a matter of optimisation, eligible `#[repr(Rust)]` structs behave as if +they were `#[repr(transparent)]` but as an implementation detail that can't be +relied upon by users. + +```rust +struct ImplicitlyTransparentWrapper(f64); + +#[repr(C)] +struct BogusRepr { + // While ImplicitlyTransparentWrapper implicitly has the same representation + // as f64, this will fail to compile because ImplicitlyTransparentWrapper + // has no explicit transparent or C representation. + wrapper: ImplicitlyTransparentWrapper, +} +``` + +The representation of a transparent wrapper is the representation of its +only non-zero-sized field, transitively: + +```rust +#[repr(transparent)] +struct Transparent(T); + +#[repr(transparent)] +struct F64(f64); + +#[repr(C)] +struct C(usize); + +type TransparentF64 = Transparent; // Behaves as f64. + +type TransparentString = Transparent; // Representation is Rust. + +type TransparentC = Transparent; // Representation is C. + +type TransparentTransparentC = Transparent>; // Transitively C. +``` + +Coercions and casting between the transparent wrapper and its non-zero-sized +types are forbidden. + +# Drawbacks +[drawbacks]: #drawbacks + +None. + +# Alternatives +[alternatives]: #alternatives + +The only alternative to such a construct for FFI purposes is to use the exact +same types as specified in the C header (or wherever the FFI types come from) +and to make additional wrappers for them in Rust. This does not help if a +field using interior mutability (i.e. uses `UnsafeCell`) has to be passed +to the FFI side, so this alternative does not actually cover all the uses cases +allowed by `#[repr(transparent)]`. + +# Unresolved questions +[unresolved]: #unresolved-questions + +* None From c86cfd3710687e375d6fba68a0322976865e3700 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 3 Jul 2017 12:05:32 -0700 Subject: [PATCH 2/2] RFC 1758 is Specify repr(transparent) --- text/{0000-repr-transparent.md => 1758-repr-transparent.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename text/{0000-repr-transparent.md => 1758-repr-transparent.md} (98%) diff --git a/text/0000-repr-transparent.md b/text/1758-repr-transparent.md similarity index 98% rename from text/0000-repr-transparent.md rename to text/1758-repr-transparent.md index b34c9082796..f9b312dafca 100644 --- a/text/0000-repr-transparent.md +++ b/text/1758-repr-transparent.md @@ -1,7 +1,7 @@ - Feature Name: `repr_transparent` - Start Date: 2016-09-26 -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) +- RFC PR: https://github.com/rust-lang/rfcs/pull/1758 +- Rust Issue:https://github.com/rust-lang/rust/issues/43036 # Summary [summary]: #summary