From e2aef92c19a95d6a0b8e75b473023f77de6150f0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 13:24:16 +0200 Subject: [PATCH] Stabilize #[repr(transparent)] Tracking issue FCP: https://github.com/rust-lang/rust/issues/43036#issuecomment-394094318 Reference PR: https://github.com/rust-lang-nursery/reference/pull/353 --- .../src/language-features/repr-transparent.md | 176 ------------------ src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/librustc/diagnostics.rs | 8 - src/librustc_typeck/diagnostics.rs | 10 +- src/libsyntax/feature_gate.rs | 10 +- .../codegen/repr-transparent-aggregates-1.rs | 1 - .../codegen/repr-transparent-aggregates-2.rs | 1 - .../codegen/repr-transparent-aggregates-3.rs | 1 - src/test/codegen/repr-transparent-sysv64.rs | 1 - src/test/codegen/repr-transparent.rs | 2 +- .../repr-transparent-other-items.rs | 2 - .../repr-transparent-other-reprs.rs | 2 +- src/test/compile-fail/repr-transparent.rs | 1 - src/test/ui/feature-gate-repr_transparent.rs | 14 -- .../ui/feature-gate-repr_transparent.stderr | 11 -- src/test/ui/lint-ctypes.rs | 2 +- 17 files changed, 9 insertions(+), 237 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/repr-transparent.md delete mode 100644 src/test/ui/feature-gate-repr_transparent.rs delete mode 100644 src/test/ui/feature-gate-repr_transparent.stderr diff --git a/src/doc/unstable-book/src/language-features/repr-transparent.md b/src/doc/unstable-book/src/language-features/repr-transparent.md deleted file mode 100644 index 62202dc96fd..00000000000 --- a/src/doc/unstable-book/src/language-features/repr-transparent.md +++ /dev/null @@ -1,176 +0,0 @@ -# `repr_transparent` - -The tracking issue for this feature is: [#43036] - -[#43036]: https://github.com/rust-lang/rust/issues/43036 - ------------------------- - -This feature enables the `repr(transparent)` attribute on structs, which enables -the use of newtypes without the usual ABI implications of wrapping the value in -a struct. - -## Background - -It's sometimes useful to add additional type safety by introducing *newtypes*. -For example, code that handles numeric quantities in different units such as -millimeters, centimeters, grams, kilograms, etc. may want to use the type system -to rule out mistakes such as adding millimeters to grams: - -```rust -use std::ops::Add; - -struct Millimeters(f64); -struct Grams(f64); - -impl Add for Millimeters { - type Output = Millimeters; - - fn add(self, other: Millimeters) -> Millimeters { - Millimeters(self.0 + other.0) - } -} - -// Likewise: impl Add for Grams {} -``` - -Other uses of newtypes include using `PhantomData` to add lifetimes to raw -pointers or to implement the "phantom types" pattern. See the [PhantomData] -documentation and [the Nomicon][nomicon-phantom] for more details. - -The added type safety is especially useful when interacting with C or other -languages. However, in those cases we need to ensure the newtypes we add do not -introduce incompatibilities with the C ABI. - -## Newtypes in FFI - -Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all -platforms which Rust currently supports, and likely on many more. For example, -consider this C declaration: - -```C -struct Object { - double weight; //< in grams - double height; //< in millimeters - // ... -} - -void frobnicate(struct Object *); -``` - -While using this C code from Rust, we could add `repr(C)` to the `Grams` and -`Millimeters` newtypes introduced above and use them to add some type safety -while staying compatible with the memory layout of `Object`: - -```rust,no_run -#[repr(C)] -struct Grams(f64); - -#[repr(C)] -struct Millimeters(f64); - -#[repr(C)] -struct Object { - weight: Grams, - height: Millimeters, - // ... -} - -extern { - fn frobnicate(_: *mut Object); -} -``` - -This works even when adding some `PhantomData` fields, because they are -zero-sized and therefore don't have to affect the memory layout. - -However, there's more to the ABI than just memory layout: there's also the -question of how function call arguments and return values are passed. Many -common ABI treat a struct containing a single field differently from that field -itself, at least when the field is a scalar (e.g., integer or float or pointer). - -To continue the above example, suppose the C library also exposes a function -like this: - -```C -double calculate_weight(double height); -``` - -Using our newtypes on the Rust side like this will cause an ABI mismatch on many -platforms: - -```rust,ignore -extern { - fn calculate_weight(height: Millimeters) -> Grams; -} -``` - -For example, on x86_64 Linux, Rust will pass the argument in an integer -register, while the C function expects the argument to be in a floating-point -register. Likewise, the C function will return the result in a floating-point -register while Rust will expect it in an integer register. - -Note that this problem is not specific to floats: To give another example, -32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while -`i32` is placed in registers. - -## Enter `repr(transparent)` - -So while `repr(C)` happens to do the right thing with respect to memory layout, -it's not quite the right tool for newtypes in FFI. Instead of declaring a C -struct, we need to communicate to the Rust compiler that our newtype is just for -type safety on the Rust side. This is what `repr(transparent)` does. - -The attribute can be applied to a newtype-like structs that contains a single -field. It indicates that the newtype should be represented exactly like that -field's type, i.e., the newtype should be ignored for ABI purpopses: not only is -it laid out the same in memory, it is also passed identically in function calls. - -In the above example, the ABI mismatches can be prevented by making the newtypes -`Grams` and `Millimeters` transparent like this: - -```rust -#![feature(repr_transparent)] - -#[repr(transparent)] -struct Grams(f64); - -#[repr(transparent)] -struct Millimeters(f64); -``` - -In addition to that single field, any number of zero-sized fields are permitted, -including but not limited to `PhantomData`: - -```rust -#![feature(repr_transparent)] - -use std::marker::PhantomData; - -struct Foo { /* ... */ } - -#[repr(transparent)] -struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>); - -#[repr(transparent)] -struct NumberWithUnit(T, PhantomData); - -struct CustomZst; - -#[repr(transparent)] -struct PtrWithCustomZst<'a> { - ptr: FooPtrWithLifetime<'a>, - some_marker: CustomZst, -} -``` - -Transparent structs can be nested: `PtrWithCustomZst` is also represented -exactly like `*const Foo`. - -Because `repr(transparent)` delegates all representation concerns to another -type, it is incompatible with all other `repr(..)` attributes. It also cannot be -applied to enums, unions, empty structs, structs whose fields are all -zero-sized, or structs with *multiple* non-zero-sized fields. - -[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html -[nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 74bbd659246..e25742a4a61 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -105,7 +105,7 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(staged_api)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ba77edee6e..40caee85541 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,7 +100,7 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 7415ddd455d..1435957a5c1 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1958,8 +1958,6 @@ representation hints. Erroneous code example: ```compile_fail,E0692 -#![feature(repr_transparent)] - #[repr(transparent, C)] // error: incompatible representation hints struct Grams(f32); ``` @@ -1969,8 +1967,6 @@ another type, so adding more representation hints is contradictory. Remove either the `transparent` hint or the other hints, like this: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); ``` @@ -1978,8 +1974,6 @@ struct Grams(f32); Alternatively, move the other attributes to the contained type: ``` -#![feature(repr_transparent)] - #[repr(C)] struct Foo { x: i32, @@ -1994,8 +1988,6 @@ Note that introducing another `struct` just to have a place for the other attributes may have unintended side effects on the representation: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e4c73218de5..da54eeabdb9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4581,8 +4581,6 @@ on fields that were not guaranteed to be zero-sized. Erroneous code example: ```compile_fail,E0690 -#![feature(repr_transparent)] - #[repr(transparent)] struct LengthWithUnit { // error: transparent struct needs exactly one value: f32, // non-zero-sized field, but has 2 @@ -4602,8 +4600,6 @@ To combine `repr(transparent)` with type parameters, `PhantomData` may be useful: ``` -#![feature(repr_transparent)] - use std::marker::PhantomData; #[repr(transparent)] @@ -4621,7 +4617,7 @@ field that requires non-trivial alignment. Erroneous code example: ```compile_fail,E0691 -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] #[repr(align(32))] struct ForceAlign32; @@ -4640,8 +4636,6 @@ requirement. Consider removing the over-aligned zero-sized field: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Wrapper(f32); ``` @@ -4650,7 +4644,7 @@ Alternatively, `PhantomData` has alignment 1 for all `T`, so you can use it if you need to keep the field for some reason: ``` -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] use std::marker::PhantomData; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1535e649506..9f370672cb2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -399,9 +399,6 @@ declare_features! ( // `extern` in paths (active, extern_in_paths, "1.23.0", Some(44660), None), - // Allows `#[repr(transparent)]` attribute on newtype structs - (active, repr_transparent, "1.25.0", Some(43036), None), - // Use `?` as the Kleene "at most one" operator (active, macro_at_most_once_rep, "1.25.0", Some(48075), None), @@ -615,6 +612,8 @@ declare_features! ( (accepted, termination_trait_test, "1.27.0", Some(48854), None), // The #[global_allocator] attribute (accepted, global_allocator, "1.28.0", Some(27389), None), + // Allows `#[repr(transparent)]` attribute on newtype structs + (accepted, repr_transparent, "1.28.0", Some(43036), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1595,11 +1594,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } - if item.check_name("transparent") { - gate_feature_post!(&self, repr_transparent, attr.span, - "the `#[repr(transparent)]` attribute \ - is experimental"); - } if let Some((name, _)) = item.name_value_literal() { if name == "packed" { gate_feature_post!(&self, repr_packed, attr.span, diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788c..a1185cc1e2e 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -18,7 +18,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 25750a6513f..bc000bd3165 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -22,7 +22,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs index 0c90239c9de..a292f1d70f3 100644 --- a/src/test/codegen/repr-transparent-aggregates-3.rs +++ b/src/test/codegen/repr-transparent-aggregates-3.rs @@ -14,7 +14,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-sysv64.rs b/src/test/codegen/repr-transparent-sysv64.rs index 7a30983fdd3..2e4665e22e3 100644 --- a/src/test/codegen/repr-transparent-sysv64.rs +++ b/src/test/codegen/repr-transparent-sysv64.rs @@ -13,7 +13,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] pub struct Rgb8 { r: u8, g: u8, b: u8 } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index 087fa9b16b4..64a62fd7e88 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -11,7 +11,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent, repr_simd)] +#![feature(repr_simd)] use std::marker::PhantomData; diff --git a/src/test/compile-fail/repr-transparent-other-items.rs b/src/test/compile-fail/repr-transparent-other-items.rs index cf0870866c7..685d62dc3a9 100644 --- a/src/test/compile-fail/repr-transparent-other-items.rs +++ b/src/test/compile-fail/repr-transparent-other-items.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent)] - // See also repr-transparent.rs #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum diff --git a/src/test/compile-fail/repr-transparent-other-reprs.rs b/src/test/compile-fail/repr-transparent-other-reprs.rs index 7b91a6f68e3..a391c0ae1f8 100644 --- a/src/test/compile-fail/repr-transparent-other-reprs.rs +++ b/src/test/compile-fail/repr-transparent-other-reprs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] // See also repr-transparent.rs diff --git a/src/test/compile-fail/repr-transparent.rs b/src/test/compile-fail/repr-transparent.rs index b5e6a0fa0b1..4d8ec4cdb40 100644 --- a/src/test/compile-fail/repr-transparent.rs +++ b/src/test/compile-fail/repr-transparent.rs @@ -14,7 +14,6 @@ // - repr-transparent-other-items.rs #![feature(repr_align, attr_literals)] -#![feature(repr_transparent)] use std::marker::PhantomData; diff --git a/src/test/ui/feature-gate-repr_transparent.rs b/src/test/ui/feature-gate-repr_transparent.rs deleted file mode 100644 index deadf2e535d..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental -struct Foo(u64); - -fn main() {} diff --git a/src/test/ui/feature-gate-repr_transparent.stderr b/src/test/ui/feature-gate-repr_transparent.stderr deleted file mode 100644 index a4ffaa26690..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036) - --> $DIR/feature-gate-repr_transparent.rs:11:1 - | -LL | #[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_transparent)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 85957831653..4b20001457f 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, repr_transparent)] +#![feature(libc)] extern crate libc;