3 The tracking issue for this feature is: [#43036]
5 [#43036]: https://github.com/rust-lang/rust/issues/43036
7 ------------------------
9 This feature enables the `repr(transparent)` attribute on structs, which enables
10 the use of newtypes without the usual ABI implications of wrapping the value in
15 It's sometimes useful to add additional type safety by introducing *newtypes*.
16 For example, code that handles numeric quantities in different units such as
17 millimeters, centimeters, grams, kilograms, etc. may want to use the type system
18 to rule out mistakes such as adding millimeters to grams:
23 struct Millimeters(f64);
26 impl Add<Millimeters> for Millimeters {
27 type Output = Millimeters;
29 fn add(self, other: Millimeters) -> Millimeters {
30 Millimeters(self.0 + other.0)
34 // Likewise: impl Add<Grams> for Grams {}
37 Other uses of newtypes include using `PhantomData` to add lifetimes to raw
38 pointers or to implement the "phantom types" pattern. See the [PhantomData]
39 documentation and [the Nomicon][nomicon-phantom] for more details.
41 The added type safety is especially useful when interacting with C or other
42 languages. However, in those cases we need to ensure the newtypes we add do not
43 introduce incompatibilities with the C ABI.
47 Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all
48 platforms which Rust currently supports, and likely on many more. For example,
49 consider this C declaration:
53 double weight; //< in grams
54 double height; //< in millimeters
58 void frobnicate(struct Object *);
61 While using this C code from Rust, we could add `repr(C)` to the `Grams` and
62 `Millimeters` newtypes introduced above and use them to add some type safety
63 while staying compatible with the memory layout of `Object`:
70 struct Millimeters(f64);
80 fn frobnicate(_: *mut Object);
84 This works even when adding some `PhantomData` fields, because they are
85 zero-sized and therefore don't have to affect the memory layout.
87 However, there's more to the ABI than just memory layout: there's also the
88 question of how function call arguments and return values are passed. Many
89 common ABI treat a struct containing a single field differently from that field
90 itself, at least when the field is a scalar (e.g., integer or float or pointer).
92 To continue the above example, suppose the C library also exposes a function
96 double calculate_weight(double height);
99 Using our newtypes on the Rust side like this will cause an ABI mismatch on many
104 fn calculate_weight(height: Millimeters) -> Grams;
108 For example, on x86_64 Linux, Rust will pass the argument in an integer
109 register, while the C function expects the argument to be in a floating-point
110 register. Likewise, the C function will return the result in a floating-point
111 register while Rust will expect it in an integer register.
113 Note that this problem is not specific to floats: To give another example,
114 32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while
115 `i32` is placed in registers.
117 ## Enter `repr(transparent)`
119 So while `repr(C)` happens to do the right thing with respect to memory layout,
120 it's not quite the right tool for newtypes in FFI. Instead of declaring a C
121 struct, we need to communicate to the Rust compiler that our newtype is just for
122 type safety on the Rust side. This is what `repr(transparent)` does.
124 The attribute can be applied to a newtype-like structs that contains a single
125 field. It indicates that the newtype should be represented exactly like that
126 field's type, i.e., the newtype should be ignored for ABI purpopses: not only is
127 it laid out the same in memory, it is also passed identically in function calls.
129 In the above example, the ABI mismatches can be prevented by making the newtypes
130 `Grams` and `Millimeters` transparent like this:
133 #![feature(repr_transparent)]
139 struct Millimeters(f64);
142 In addition to that single field, any number of zero-sized fields are permitted,
143 including but not limited to `PhantomData`:
146 #![feature(repr_transparent)]
148 use std::marker::PhantomData;
150 struct Foo { /* ... */ }
153 struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>);
156 struct NumberWithUnit<T, U>(T, PhantomData<U>);
161 struct PtrWithCustomZst<'a> {
162 ptr: FooPtrWithLifetime<'a>,
163 some_marker: CustomZst,
167 Transparent structs can be nested: `PtrWithCustomZst` is also represented
168 exactly like `*const Foo`.
170 Because `repr(transparent)` delegates all representation concerns to another
171 type, it is incompatible with all other `repr(..)` attributes. It also cannot be
172 applied to enums, unions, empty structs, structs whose fields are all
173 zero-sized, or structs with *multiple* non-zero-sized fields.
175 [PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html
176 [nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html