diff --git a/src/doc/unstable-book/src/language-features/transparent-enums.md b/src/doc/unstable-book/src/language-features/transparent-enums.md new file mode 100644 index 0000000000000..862411ab39203 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/transparent-enums.md @@ -0,0 +1,93 @@ +# `transparent_enums` + +The tracking issue for this feature is [#60405] + +[60405]: https://github.com/rust-lang/rust/issues/60405 + +---- + +The `transparent_enums` feature allows you mark `enum`s as +`#[repr(transparent)]`. An `enum` may be `#[repr(transparent)]` if it has +exactly one variant, and that variant matches the same conditions which `struct` +requires for transparency. Some concrete illustrations follow. + +```rust +#![feature(transparent_enums)] + +// This enum has the same representation as `f32`. +#[repr(transparent)] +enum SingleFieldEnum { + Variant(f32) +} + +// This enum has the same representation as `usize`. +#[repr(transparent)] +enum MultiFieldEnum { + Variant { field: usize, nothing: () }, +} +``` + +For consistency with transparent `struct`s, `enum`s must have exactly one +non-zero-sized field. If all fields are zero-sized, the `enum` must not be +`#[repr(transparent)]`: + +```rust +#![feature(transparent_enums)] + +// This (non-transparent) enum is already valid in stable Rust: +pub enum GoodEnum { + Nothing, +} + +// Error: transparent enum needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub enum BadEnum { +// Nothing(()), +// } + +// Error: transparent enum needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub enum BadEmptyEnum { +// Nothing, +// } +``` + +The one exception is if the `enum` is generic over `T` and has a field of type +`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type: + +```rust +#![feature(transparent_enums)] + +// This enum has the same representation as `T`. +#[repr(transparent)] +pub enum GenericEnum { + Variant(T, ()), +} + +// This is okay even though `()` is a zero-sized type. +pub const THIS_IS_OKAY: GenericEnum<()> = GenericEnum::Variant((), ()); +``` + +Transparent `enum`s require exactly one variant: + +```rust +// Error: transparent enum needs exactly one variant, but has 0 +// #[repr(transparent)] +// pub enum TooFewVariants { +// } + +// Error: transparent enum needs exactly one variant, but has 2 +// #[repr(transparent)] +// pub enum TooManyVariants { +// First(usize), +// Second, +// } +``` + +Like transarent `struct`s, a transparent `enum` of type `E` has the same layout, +size, and ABI as its single non-ZST field. If it is generic over a type `T`, and +all its fields are ZSTs except for exactly one field of type `T`, then it has +the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). + +Like transparent `struct`s, transparent `enum`s are FFI-safe if and only if +their underlying representation type is also FFI-safe. diff --git a/src/doc/unstable-book/src/language-features/transparent-unions.md b/src/doc/unstable-book/src/language-features/transparent-unions.md new file mode 100644 index 0000000000000..b731c9ea6d012 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/transparent-unions.md @@ -0,0 +1,83 @@ +# `transparent_unions` + +The tracking issue for this feature is [#60405] + +[60405]: https://github.com/rust-lang/rust/issues/60405 + +---- + +The `transparent_unions` feature allows you mark `union`s as +`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the +same conditions in which a `struct` may be `#[repr(transparent)]` (generally, +this means the `union` must have exactly one non-zero-sized field). Some +concrete illustrations follow. + +```rust +#![feature(transparent_unions)] + +// This union has the same representation as `f32`. +#[repr(transparent)] +union SingleFieldUnion { + field: f32, +} + +// This union has the same representation as `usize`. +#[repr(transparent)] +union MultiFieldUnion { + field: usize, + nothing: (), +} +``` + +For consistency with transparent `struct`s, `union`s must have exactly one +non-zero-sized field. If all fields are zero-sized, the `union` must not be +`#[repr(transparent)]`: + +```rust +#![feature(transparent_unions)] + +// This (non-transparent) union is already valid in stable Rust: +pub union GoodUnion { + pub nothing: (), +} + +// Error: transparent union needs exactly one non-zero-sized field, but has 0 +// #[repr(transparent)] +// pub union BadUnion { +// pub nothing: (), +// } +``` + +The one exception is if the `union` is generic over `T` and has a field of type +`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type: + +```rust +#![feature(transparent_unions)] + +// This union has the same representation as `T`. +#[repr(transparent)] +pub union GenericUnion { // Unions with non-`Copy` fields are unstable. + pub field: T, + pub nothing: (), +} + +// This is okay even though `()` is a zero-sized type. +pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () }; +``` + +Like transarent `struct`s, a transparent `union` of type `U` has the same +layout, size, and ABI as its single non-ZST field. If it is generic over a type +`T`, and all its fields are ZSTs except for exactly one field of type `T`, then +it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). + +Like transparent `struct`s, transparent `union`s are FFI-safe if and only if +their underlying representation type is also FFI-safe. + +A `union` may not be eligible for the same nonnull-style optimizations that a +`struct` or `enum` (with the same fields) are eligible for. Adding +`#[repr(transparent)]` to `union` does not change this. To give a more concrete +example, it is unspecified whether `size_of::()` is equal to +`size_of::>()`, where `T` is a `union` (regardless of whether or not +it is transparent). The Rust compiler is free to perform this optimization if +possible, but is not required to, and different compiler versions may differ in +their application of these optimizations. diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index b199eee6dad87..f7d1094b3a2d1 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -181,12 +181,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { let (article, allowed_targets) = match hint.name_or_empty() { name @ sym::C | name @ sym::align => { is_c |= name == sym::C; - if target != Target::Struct && - target != Target::Union && - target != Target::Enum { - ("a", "struct, enum or union") - } else { - continue + match target { + Target::Struct | Target::Union | Target::Enum => continue, + _ => ("a", "struct, enum, or union"), } } sym::packed => { @@ -207,10 +204,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } sym::transparent => { is_transparent = true; - if target != Target::Struct { - ("a", "struct") - } else { - continue + match target { + Target::Struct | Target::Union | Target::Enum => continue, + _ => ("a", "struct, enum, or union"), } } sym::i8 | sym::u8 | sym::i16 | sym::u16 | @@ -241,7 +237,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { if is_transparent && hints.len() > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); span_err!(self.tcx.sess, hint_spans, E0692, - "transparent struct cannot have other repr hints"); + "transparent {} cannot have other repr hints", target); } // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) if (int_reprs > 1) @@ -277,7 +273,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { attr.span, stmt.span, "attribute should not be applied to a statement", - "not a struct, enum or union", + "not a struct, enum, or union", ); } } @@ -298,7 +294,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { attr.span, expr.span, "attribute should not be applied to an expression", - "not defining a struct, enum or union", + "not defining a struct, enum, or union", ); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 69bf05c66f394..80781dd9bc736 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2303,7 +2303,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Returns an iterator over all fields contained /// by this ADT. #[inline] - pub fn all_fields<'s>(&'s self) -> impl Iterator { + pub fn all_fields<'s>(&'s self) -> impl Iterator + Clone { self.variants.iter().flat_map(|v| v.fields.iter()) } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index ac18e131c4a3d..f89a772bef5da 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -531,8 +531,8 @@ fn ty_is_known_nonnull<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> b match ty.sty { ty::FnPtr(_) => true, ty::Ref(..) => true, - ty::Adt(field_def, substs) if field_def.repr.transparent() && field_def.is_struct() => { - for field in &field_def.non_enum_variant().fields { + ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { + for field in field_def.all_fields() { let field_ty = tcx.normalize_erasing_regions( ParamEnv::reveal_all(), field.ty(tcx, substs), @@ -627,8 +627,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty: ty, reason: "this struct has unspecified layout", - help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \ - attribute to this struct"), + help: Some("consider adding a `#[repr(C)]` or \ + `#[repr(transparent)]` attribute to this struct"), }; } @@ -668,11 +668,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if all_phantom { FfiPhantom(ty) } else { FfiSafe } } AdtKind::Union => { - if !def.repr.c() { + if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { ty: ty, reason: "this union has unspecified layout", - help: Some("consider adding a #[repr(C)] attribute to this union"), + help: Some("consider adding a `#[repr(C)]` or \ + `#[repr(transparent)]` attribute to this union"), }; } @@ -690,6 +691,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ParamEnv::reveal_all(), field.ty(cx, substs), ); + // repr(transparent) types are allowed to have arbitrary ZSTs, not just + // PhantomData -- skip checking all ZST fields. + if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + continue; + } let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => { @@ -712,14 +718,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. - if !def.repr.c() && def.repr.int.is_none() { + if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, ty, def, substs) { return FfiUnsafe { ty: ty, reason: "enum has no representation hint", - help: Some("consider adding a #[repr(...)] attribute \ - to this enum"), + help: Some("consider adding a `#[repr(C)]`, \ + `#[repr(transparent)]`, or integer `#[repr(...)]` \ + attribute to this enum"), }; } } @@ -727,11 +734,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check the contained variants. for variant in &def.variants { for field in &variant.fields { - let arg = cx.normalize_erasing_regions( + let field_ty = cx.normalize_erasing_regions( ParamEnv::reveal_all(), field.ty(cx, substs), ); - let r = self.check_type_for_ffi(cache, arg); + // repr(transparent) types are allowed to have arbitrary ZSTs, not + // just PhantomData -- skip checking all ZST fields. + if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + continue; + } + let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} FfiUnsafe { .. } => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0b558a20ed47e..2e53b380cb71a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1310,7 +1310,7 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); - + check_transparent(tcx, span, def_id); check_packed(tcx, span, def_id); } @@ -1807,8 +1807,43 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De return; } + if adt.is_enum() { + if !tcx.features().transparent_enums { + emit_feature_err(&tcx.sess.parse_sess, + sym::transparent_enums, + sp, + GateIssue::Language, + "transparent enums are unstable"); + } + if adt.variants.len() != 1 { + let variant_spans: Vec<_> = adt.variants.iter().map(|variant| { + tcx.hir().span_if_local(variant.def_id).unwrap() + }).collect(); + let mut err = struct_span_err!(tcx.sess, sp, E0731, + "transparent enum needs exactly one variant, but has {}", + adt.variants.len()); + if !variant_spans.is_empty() { + err.span_note(variant_spans, &format!("the following variants exist on `{}`", + tcx.def_path_str(def_id))); + } + err.emit(); + if adt.variants.is_empty() { + // Don't bother checking the fields. No variants (and thus no fields) exist. + return; + } + } + } + + if adt.is_union() && !tcx.features().transparent_unions { + emit_feature_err(&tcx.sess.parse_sess, + sym::transparent_unions, + sp, + GateIssue::Language, + "transparent unions are unstable"); + } + // For each field, figure out if it's known to be a ZST and align(1) - let field_infos = adt.non_enum_variant().fields.iter().map(|field| { + let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); let layout = tcx.layout_of(param_env.and(ty)); @@ -1823,16 +1858,24 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De let non_zst_count = non_zst_fields.clone().count(); if non_zst_count != 1 { let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect(); - struct_span_err!(tcx.sess, sp, E0690, - "transparent struct needs exactly one non-zero-sized field, but has {}", - non_zst_count) - .span_note(field_spans, "non-zero-sized field") - .emit(); + + let mut err = struct_span_err!(tcx.sess, sp, E0690, + "{}transparent {} needs exactly one non-zero-sized field, but has {}", + if adt.is_enum() { "the variant of a " } else { "" }, + adt.descr(), + non_zst_count); + if !field_spans.is_empty() { + err.span_note(field_spans, + &format!("the following non-zero-sized fields exist on `{}`:", + tcx.def_path_str(def_id))); + } + err.emit(); } for (span, zst, align1) in field_infos { if zst && !align1 { span_err!(tcx.sess, span, E0691, - "zero-sized field in transparent struct has alignment larger than 1"); + "zero-sized field in transparent {} has alignment larger than 1", + adt.descr()); } } } @@ -1899,6 +1942,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } check_representable(tcx, sp, def_id); + check_transparent(tcx, sp, def_id); } fn report_unexpected_variant_res<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 66e9a6e6b2a2e..0b618cdf1dbb7 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -4484,7 +4484,7 @@ let _ = (2.0 as f32).neg(); E0690: r##" A struct with the representation hint `repr(transparent)` had zero or more than -on fields that were not guaranteed to be zero-sized. +one fields that were not guaranteed to be zero-sized. Erroneous code example: @@ -4519,8 +4519,8 @@ struct LengthWithUnit { "##, E0691: r##" -A struct with the `repr(transparent)` representation hint contains a zero-sized -field that requires non-trivial alignment. +A struct, enum, or union with the `repr(transparent)` representation hint +contains a zero-sized field that requires non-trivial alignment. Erroneous code example: @@ -4535,11 +4535,11 @@ struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent // struct has alignment larger than 1 ``` -A transparent struct is supposed to be represented exactly like the piece of -data it contains. Zero-sized fields with different alignment requirements -potentially conflict with this property. In the example above, `Wrapper` would -have to be aligned to 32 bytes even though `f32` has a smaller alignment -requirement. +A transparent struct, enum, or union is supposed to be represented exactly like +the piece of data it contains. Zero-sized fields with different alignment +requirements potentially conflict with this property. In the example above, +`Wrapper` would have to be aligned to 32 bytes even though `f32` has a smaller +alignment requirement. Consider removing the over-aligned zero-sized field: @@ -4569,7 +4569,6 @@ the alignment of the zero-sized type is less than or equal to the data field's alignment. "##, - E0699: r##" A method was called on a raw pointer whose inner type wasn't completely known. @@ -4680,6 +4679,26 @@ match r { ``` "##, +E0731: r##" +An enum with the representation hint `repr(transparent)` had zero or more than +one variants. + +Erroneous code example: + +```compile_fail,E0731 +#[repr(transparent)] +enum Status { // error: transparent enum needs exactly one variant, but has 2 + Errno(u32), + Ok, +} +``` + +Because transparent enums are represented exactly like one of their variants at +run time, said variant must be uniquely determined. If there is no variant, or +if there are multiple variants, it is not clear how the enum should be +represented. +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bbb297e3c4fc7..044c4b18905ef 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -561,6 +561,12 @@ declare_features! ( // FIXME Create issue (active, const_constructor, "1.37.0", Some(61456), None), + // #[repr(transparent)] on enums. + (active, transparent_enums, "1.37.0", Some(60405), None), + + // #[repr(transparent)] on unions. + (active, transparent_unions, "1.37.0", Some(60405), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 302b3c75263cf..875c286bd8a90 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -623,6 +623,8 @@ symbols! { trait_alias, transmute, transparent, + transparent_enums, + transparent_unions, trivial_bounds, Try, try_blocks, diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index fb88f2a69ca15..e7c4b6193bc09 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -1,4 +1,5 @@ // compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength // ignore-arm // ignore-mips @@ -7,36 +8,76 @@ // ignore-powerpc64 // See repr-transparent.rs +#![feature(transparent_enums, transparent_unions)] + #![crate_type="lib"] +#[derive(Clone, Copy)] #[repr(C)] -pub struct Big([u32; 16]); +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} #[repr(transparent)] -pub struct BigW(Big); +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], %BigS* [[BIGS_ARG_ATTRS:.*]]) +#[no_mangle] +pub extern fn test_BigS(_: BigS) -> BigS { loop {} } + +// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], %TsBigS* [[BIGS_ARG_ATTRS]]) +#[no_mangle] +pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], %Big* [[BIG_ARG_ATTRS:.*]]) +// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], %TuBigS* [[BIGS_ARG_ATTRS]]) #[no_mangle] -pub extern fn test_Big(_: Big) -> Big { loop {} } +pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], %BigW* [[BIG_ARG_ATTRS]]) +// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], %"TeBigS::Variant"* [[BIGS_ARG_ATTRS]]) #[no_mangle] -pub extern fn test_BigW(_: BigW) -> BigW { loop {} } +pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } +#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], } #[repr(transparent)] -pub struct BigUw(BigU); +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS:.*]]) #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], %BigUw* [[BIGU_ARG_ATTRS]]) +// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], %TsBigU* [[BIGU_ARG_ATTRS]]) +#[no_mangle] +pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } + +// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], %TuBigU* [[BIGU_ARG_ATTRS]]) +#[no_mangle] +pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } + +// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], %"TeBigU::Variant"* [[BIGU_ARG_ATTRS]]) #[no_mangle] -pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } +pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 6c628ac035fd9..5521c3c849f53 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -14,36 +14,76 @@ // ignore-x86_64 // See repr-transparent.rs +#![feature(transparent_enums, transparent_unions)] + #![crate_type="lib"] +#[derive(Clone, Copy)] #[repr(C)] -pub struct Big([u32; 16]); +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} #[repr(transparent)] -pub struct BigW(Big); +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], [16 x i32] +#[no_mangle] +pub extern fn test_BigS(_: BigS) -> BigS { loop {} } + +// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], [16 x i32] +#[no_mangle] +pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [16 x i32] +// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], [16 x i32] #[no_mangle] -pub extern fn test_Big(_: Big) -> Big { loop {} } +pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [16 x i32] +// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], [16 x i32] #[no_mangle] -pub extern fn test_BigW(_: BigW) -> BigW { loop {} } +pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } +#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], } #[repr(transparent)] -pub struct BigUw(BigU); +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [16 x i32] #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [16 x i32] +// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], [16 x i32] +#[no_mangle] +pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } + +// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], [16 x i32] +#[no_mangle] +pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } + +// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], [16 x i32] #[no_mangle] -pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } +pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs index cd740dc9b8233..1a59c9b48b976 100644 --- a/src/test/codegen/repr-transparent-aggregates-3.rs +++ b/src/test/codegen/repr-transparent-aggregates-3.rs @@ -3,36 +3,76 @@ // only-mips64 // See repr-transparent.rs +#![feature(transparent_enums, transparent_unions)] + #![crate_type="lib"] +#[derive(Clone, Copy)] #[repr(C)] -pub struct Big([u32; 16]); +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} #[repr(transparent)] -pub struct BigW(Big); +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], [8 x i64] +#[no_mangle] +pub extern fn test_BigS(_: BigS) -> BigS { loop {} } + +// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], [8 x i64] +#[no_mangle] +pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [8 x i64] +// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], [8 x i64] #[no_mangle] -pub extern fn test_Big(_: Big) -> Big { loop {} } +pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [8 x i64] +// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], [8 x i64] #[no_mangle] -pub extern fn test_BigW(_: BigW) -> BigW { loop {} } +pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } +#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], } #[repr(transparent)] -pub struct BigUw(BigU); +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [8 x i64] #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [8 x i64] +// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], [8 x i64] +#[no_mangle] +pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } + +// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], [8 x i64] +#[no_mangle] +pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } + +// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], [8 x i64] #[no_mangle] -pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} } +pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index fd655261ab852..c9f3837565808 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -1,13 +1,16 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_simd)] +#![feature(repr_simd, transparent_enums, transparent_unions)] use std::marker::PhantomData; +#[derive(Copy, Clone)] pub struct Zst1; +#[derive(Copy, Clone)] pub struct Zst2(()); +#[derive(Copy, Clone)] #[repr(transparent)] pub struct F32(f32); @@ -112,6 +115,44 @@ pub struct StructWithProjection(::It); #[no_mangle] pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} } +#[repr(transparent)] +pub enum EnumF32 { + Variant(F32) +} + +// CHECK: define float @test_EnumF32(float %arg0) +#[no_mangle] +pub extern fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} } + +#[repr(transparent)] +pub enum EnumF32WithZsts { + Variant(Zst1, F32, Zst2) +} + +// CHECK: define float @test_EnumF32WithZsts(float %arg0) +#[no_mangle] +pub extern fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} } + +#[repr(transparent)] +pub union UnionF32 { + field: F32, +} + +// CHECK: define float @test_UnionF32(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } + +#[repr(transparent)] +pub union UnionF32WithZsts { + zst1: Zst1, + field: F32, + zst2: Zst2, +} + +// CHECK: define float @test_UnionF32WithZsts(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} } + // All that remains to be tested are aggregates. They are tested in separate files called repr- // transparent-*.rs with `only-*` or `ignore-*` directives, because the expected LLVM IR diff --git a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs index 87629665bc2bd..f871c21855860 100644 --- a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs +++ b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs @@ -1,4 +1,6 @@ // run-pass +#![feature(transparent_unions)] + use std::mem::size_of; use std::num::NonZeroUsize; use std::ptr::NonNull; @@ -10,6 +12,11 @@ trait Mirror { type Image; } impl Mirror for T { type Image = T; } struct ParamTypeStruct(T); struct AssocTypeStruct(::Image); +#[repr(transparent)] +union MaybeUninitUnion { + _value: T, + _uninit: (), +} fn main() { // Functions @@ -29,9 +36,12 @@ fn main() { // Pointers - Box assert_eq!(size_of::>(), size_of::>>()); - // The optimization can't apply to raw pointers + // The optimization can't apply to raw pointers or unions with a ZST field. assert!(size_of::>() != size_of::<*const isize>()); assert!(Some(0 as *const isize).is_some()); // Can't collapse None to null + assert_ne!(size_of::(), size_of::>>()); + assert_ne!(size_of::<&str>(), size_of::>>()); + assert_ne!(size_of::>(), size_of::>>>()); struct Foo { _a: Box diff --git a/src/test/ui/attr-usage-repr.rs b/src/test/ui/attr-usage-repr.rs index ef64dfe20bc9d..a0b82375e777d 100644 --- a/src/test/ui/attr-usage-repr.rs +++ b/src/test/ui/attr-usage-repr.rs @@ -1,6 +1,6 @@ #![feature(repr_simd)] -#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union +#[repr(C)] //~ ERROR: attribute should be applied to struct, enum, or union fn f() {} #[repr(C)] diff --git a/src/test/ui/attr-usage-repr.stderr b/src/test/ui/attr-usage-repr.stderr index d1f4f3bfeb2cb..82d80d8d0b173 100644 --- a/src/test/ui/attr-usage-repr.stderr +++ b/src/test/ui/attr-usage-repr.stderr @@ -1,10 +1,10 @@ -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/attr-usage-repr.rs:3:8 | LL | #[repr(C)] | ^ LL | fn f() {} - | --------- not a struct, enum or union + | --------- not a struct, enum, or union error[E0517]: attribute should be applied to enum --> $DIR/attr-usage-repr.rs:15:8 diff --git a/src/test/ui/error-codes/E0517.stderr b/src/test/ui/error-codes/E0517.stderr index e256c07de2672..2cfca1724c81b 100644 --- a/src/test/ui/error-codes/E0517.stderr +++ b/src/test/ui/error-codes/E0517.stderr @@ -1,10 +1,10 @@ -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/E0517.rs:1:8 | LL | #[repr(C)] | ^ LL | type Foo = u8; - | -------------- not a struct, enum or union + | -------------- not a struct, enum, or union error[E0517]: attribute should be applied to struct or union --> $DIR/E0517.rs:4:8 @@ -22,14 +22,14 @@ LL | #[repr(u8)] LL | struct Foo3 {bar: bool, baz: bool} | ---------------------------------- not an enum -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/E0517.rs:10:8 | LL | #[repr(C)] | ^ LL | / impl Foo3 { LL | | } - | |_- not a struct, enum or union + | |_- not a struct, enum, or union error: aborting due to 4 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.rs b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs new file mode 100644 index 0000000000000..0a7a73a168ed5 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs @@ -0,0 +1,6 @@ +#[repr(transparent)] +enum OkButUnstableEnum { //~ ERROR transparent enums are unstable + Foo((), String, ()), +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr new file mode 100644 index 0000000000000..4b22654e9e411 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr @@ -0,0 +1,14 @@ +error[E0658]: transparent enums are unstable + --> $DIR/feature-gate-transparent_enums.rs:2:1 + | +LL | / enum OkButUnstableEnum { +LL | | Foo((), String, ()), +LL | | } + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60405 + = help: add #![feature(transparent_enums)] 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/feature-gates/feature-gate-transparent_unions.rs b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs new file mode 100644 index 0000000000000..73cac0a49148b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs @@ -0,0 +1,7 @@ +#[repr(transparent)] +union OkButUnstableUnion { //~ ERROR transparent unions are unstable + field: u8, + zst: (), +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr new file mode 100644 index 0000000000000..933b227de63b9 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr @@ -0,0 +1,15 @@ +error[E0658]: transparent unions are unstable + --> $DIR/feature-gate-transparent_unions.rs:2:1 + | +LL | / union OkButUnstableUnion { +LL | | field: u8, +LL | | zst: (), +LL | | } + | |_^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/60405 + = help: add #![feature(transparent_unions)] 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/issues/issue-14309.stderr b/src/test/ui/issues/issue-14309.stderr index 4376876ecd694..e0491093a722a 100644 --- a/src/test/ui/issues/issue-14309.stderr +++ b/src/test/ui/issues/issue-14309.stderr @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -24,7 +24,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe LL | fn bar(x: B); | ^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -39,7 +39,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe LL | fn qux(x: A2); | ^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -54,7 +54,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe LL | fn quux(x: B2); | ^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -69,7 +69,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe LL | fn fred(x: D); | ^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-14309.rs:4:1 | diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr index a8ff2548b73dc..142d8e21532d8 100644 --- a/src/test/ui/issues/issue-16250.stderr +++ b/src/test/ui/issues/issue-16250.stderr @@ -10,7 +10,7 @@ note: lint level defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: #[deny(improper_ctypes)] implied by #[deny(warnings)] - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/issue-16250.rs:3:1 | diff --git a/src/test/ui/issues/issue-31769.rs b/src/test/ui/issues/issue-31769.rs index 794c1d1989388..45eb5e4008089 100644 --- a/src/test/ui/issues/issue-31769.rs +++ b/src/test/ui/issues/issue-31769.rs @@ -1,4 +1,4 @@ fn main() { #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure - #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union + #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum, or union } diff --git a/src/test/ui/issues/issue-31769.stderr b/src/test/ui/issues/issue-31769.stderr index 51d1f51d1c909..20534e1ae82c5 100644 --- a/src/test/ui/issues/issue-31769.stderr +++ b/src/test/ui/issues/issue-31769.stderr @@ -4,11 +4,11 @@ error[E0518]: attribute should be applied to function or closure LL | #[inline] struct Foo; | ^^^^^^^^^ ----------- not a function or closure -error[E0517]: attribute should be applied to struct, enum or union +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/issue-31769.rs:3:12 | LL | #[repr(C)] fn foo() {} - | ^ ----------- not a struct, enum or union + | ^ ----------- not a struct, enum, or union error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr index c2f0cc6f0ffed..339c1a3b8f617 100644 --- a/src/test/ui/issues/issue-43988.stderr +++ b/src/test/ui/issues/issue-43988.stderr @@ -32,7 +32,7 @@ error[E0517]: attribute should not be applied to a statement LL | #[repr(nothing)] | ^^^^^^^^^^^^^^^^ LL | let _x = 0; - | ----------- not a struct, enum or union + | ----------- not a struct, enum, or union error[E0517]: attribute should not be applied to an expression --> $DIR/issue-43988.rs:18:5 @@ -42,7 +42,7 @@ LL | #[repr(something_not_real)] LL | / loop { LL | | () LL | | }; - | |_____- not defining a struct, enum or union + | |_____- not defining a struct, enum, or union error[E0517]: attribute should not be applied to a statement --> $DIR/issue-43988.rs:24:5 @@ -50,7 +50,7 @@ error[E0517]: attribute should not be applied to a statement LL | #[repr] | ^^^^^^^ LL | let _y = "123"; - | --------------- not a struct, enum or union + | --------------- not a struct, enum, or union error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:31:5 @@ -64,7 +64,7 @@ error[E0517]: attribute should not be applied to an expression --> $DIR/issue-43988.rs:35:14 | LL | let _z = #[repr] 1; - | ^^^^^^^ - not defining a struct, enum or union + | ^^^^^^^ - not defining a struct, enum, or union error: aborting due to 9 previous errors diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index d3e11d2f7ed64..45eeffff7a6ac 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -1,3 +1,4 @@ +#![feature(transparent_enums, transparent_unions)] #![deny(improper_ctypes)] #![allow(dead_code)] @@ -18,7 +19,17 @@ enum U8 { A, B, C } enum Isize { A, B, C } #[repr(transparent)] -struct Transparent(T, std::marker::PhantomData); +struct TransparentStruct(T, std::marker::PhantomData); + +#[repr(transparent)] +enum TransparentEnum { + Variant(T, std::marker::PhantomData), +} + +#[repr(transparent)] +union TransparentUnion { + field: T, +} struct Rust(T); @@ -47,7 +58,10 @@ extern { fn nonzero_i128(x: Option); //~^ ERROR 128-bit integers don't currently have a known stable ABI fn nonzero_isize(x: Option); - fn repr_transparent(x: Option>); + fn transparent_struct(x: Option>); + fn transparent_enum(x: Option>); + fn transparent_union(x: Option>); + //~^ ERROR enum has no representation hint fn repr_rust(x: Option>); //~ ERROR enum has no representation hint fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint } diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 6b807f48aaa82..2a60cd12d9936 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -1,74 +1,82 @@ error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:27:13 + --> $DIR/lint-ctypes-enum.rs:38:13 | LL | fn uf(x: U); | ^ | note: lint level defined here - --> $DIR/lint-ctypes-enum.rs:1:9 + --> $DIR/lint-ctypes-enum.rs:2:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:7:1 + --> $DIR/lint-ctypes-enum.rs:8:1 | LL | enum U { A } | ^^^^^^^^^^^^ error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:28:13 + --> $DIR/lint-ctypes-enum.rs:39:13 | LL | fn bf(x: B); | ^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:8:1 + --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum B { C, D } | ^^^^^^^^^^^^^^^ error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:29:13 + --> $DIR/lint-ctypes-enum.rs:40:13 | LL | fn tf(x: T); | ^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:9:1 + --> $DIR/lint-ctypes-enum.rs:10:1 | LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI - --> $DIR/lint-ctypes-enum.rs:40:23 + --> $DIR/lint-ctypes-enum.rs:51:23 | LL | fn nonzero_u128(x: Option); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI - --> $DIR/lint-ctypes-enum.rs:47:23 + --> $DIR/lint-ctypes-enum.rs:58:23 | LL | fn nonzero_i128(x: Option); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint + --> $DIR/lint-ctypes-enum.rs:63:28 + | +LL | fn transparent_union(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:51:20 + --> $DIR/lint-ctypes-enum.rs:65:20 | LL | fn repr_rust(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:52:20 + --> $DIR/lint-ctypes-enum.rs:66:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(...)] attribute to this enum + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index 03c18e4530b82..c78463beb6559 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/lint-ctypes.rs:24:1 | @@ -22,7 +22,7 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has uns LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct note: type defined here --> $DIR/lint-ctypes.rs:24:1 | @@ -51,7 +51,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th LL | pub fn box_type(p: Box); | ^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent --> $DIR/lint-ctypes.rs:51:25 @@ -142,7 +142,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI --> $DIR/lint-ctypes.rs:64:32 @@ -164,7 +164,7 @@ error: `extern` block uses type `std::boxed::Box` which is not FFI-safe: th LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ | - = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct error: aborting due to 20 previous errors diff --git a/src/test/ui/repr/repr-transparent-other-items.rs b/src/test/ui/repr/repr-transparent-other-items.rs index 392e7c9de4d09..c3d772f6266c0 100644 --- a/src/test/ui/repr/repr-transparent-other-items.rs +++ b/src/test/ui/repr/repr-transparent-other-items.rs @@ -1,26 +1,5 @@ // See also repr-transparent.rs -#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum -enum Void {} //~| ERROR should be applied to struct - -#[repr(transparent)] //~ ERROR should be applied to struct -enum FieldlessEnum { - Foo, - Bar, -} - -#[repr(transparent)] //~ ERROR should be applied to struct -enum Enum { - Foo(String), - Bar(u32), -} - -#[repr(transparent)] //~ ERROR should be applied to struct -union Foo { - u: u32, - s: i32 -} - #[repr(transparent)] //~ ERROR should be applied to struct fn cant_repr_this() {} diff --git a/src/test/ui/repr/repr-transparent-other-items.stderr b/src/test/ui/repr/repr-transparent-other-items.stderr index 24fa309a2fb69..03df3569b42bc 100644 --- a/src/test/ui/repr/repr-transparent-other-items.stderr +++ b/src/test/ui/repr/repr-transparent-other-items.stderr @@ -1,69 +1,19 @@ -error[E0517]: attribute should be applied to struct +error[E0517]: attribute should be applied to struct, enum, or union --> $DIR/repr-transparent-other-items.rs:3:8 | LL | #[repr(transparent)] | ^^^^^^^^^^^ -LL | enum Void {} - | ------------ not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:6:8 - | -LL | #[repr(transparent)] - | ^^^^^^^^^^^ -LL | / enum FieldlessEnum { -LL | | Foo, -LL | | Bar, -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:12:8 - | -LL | #[repr(transparent)] - | ^^^^^^^^^^^ -LL | / enum Enum { -LL | | Foo(String), -LL | | Bar(u32), -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:18:8 - | -LL | #[repr(transparent)] - | ^^^^^^^^^^^ -LL | / union Foo { -LL | | u: u32, -LL | | s: i32 -LL | | } - | |_- not a struct - -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:24:8 - | -LL | #[repr(transparent)] - | ^^^^^^^^^^^ LL | fn cant_repr_this() {} - | ---------------------- not a struct + | ---------------------- not a struct, enum, or union -error[E0517]: attribute should be applied to struct - --> $DIR/repr-transparent-other-items.rs:27:8 +error[E0517]: attribute should be applied to struct, enum, or union + --> $DIR/repr-transparent-other-items.rs:6:8 | LL | #[repr(transparent)] | ^^^^^^^^^^^ LL | static CANT_REPR_THIS: u32 = 0; - | ------------------------------- not a struct - -error[E0084]: unsupported representation for zero-variant enum - --> $DIR/repr-transparent-other-items.rs:3:1 - | -LL | #[repr(transparent)] - | ^^^^^^^^^^^^^^^^^^^^ -LL | enum Void {} - | ------------ zero-variant enum + | ------------------------------- not a struct, enum, or union -error: aborting due to 7 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0084, E0517. -For more information about an error, try `rustc --explain E0084`. +For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-transparent.rs b/src/test/ui/repr/repr-transparent.rs index 66d39ff9bb593..730d428ff500b 100644 --- a/src/test/ui/repr/repr-transparent.rs +++ b/src/test/ui/repr/repr-transparent.rs @@ -3,7 +3,7 @@ // - repr-transparent-other-reprs.rs // - repr-transparent-other-items.rs -#![feature(repr_align)] +#![feature(repr_align, transparent_enums, transparent_unions)] use std::marker::PhantomData; @@ -39,4 +39,36 @@ struct ZstAlign32(PhantomData); #[repr(transparent)] struct GenericAlign(ZstAlign32, u32); //~ ERROR alignment larger than 1 +#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum +enum Void {} +//~^ ERROR transparent enum needs exactly one variant, but has 0 + +#[repr(transparent)] +enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0 + Foo, +} + +#[repr(transparent)] +enum TooManyFieldsEnum { + Foo(u32, String), +} +//~^^^ ERROR transparent enum needs exactly one non-zero-sized field, but has 2 + +#[repr(transparent)] +enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but has 2 + Foo(String), + Bar, +} + +#[repr(transparent)] +union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0 + u: (), +} + +#[repr(transparent)] +union TooManyFields { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 2 + u: u32, + s: i32 +} + fn main() {} diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr index 2542a842fe8a9..ea16bdf53783d 100644 --- a/src/test/ui/repr/repr-transparent.stderr +++ b/src/test/ui/repr/repr-transparent.stderr @@ -3,32 +3,24 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has | LL | struct NoFields; | ^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:14:1 | LL | struct ContainsOnlyZst(()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:17:1 | LL | struct ContainsOnlyZstArray([bool; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:20:1 | LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: non-zero-sized field error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:24:1 @@ -36,7 +28,7 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has LL | struct MultipleNonZst(u8, u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: non-zero-sized field +note: the following non-zero-sized fields exist on `MultipleNonZst`: --> $DIR/repr-transparent.rs:24:23 | LL | struct MultipleNonZst(u8, u8); @@ -48,7 +40,7 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has LL | pub struct StructWithProjection(f32, ::It); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: non-zero-sized field +note: the following non-zero-sized fields exist on `StructWithProjection`: --> $DIR/repr-transparent.rs:30:33 | LL | pub struct StructWithProjection(f32, ::It); @@ -66,7 +58,85 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1 LL | struct GenericAlign(ZstAlign32, u32); | ^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error[E0084]: unsupported representation for zero-variant enum + --> $DIR/repr-transparent.rs:42:1 + | +LL | #[repr(transparent)] + | ^^^^^^^^^^^^^^^^^^^^ +LL | enum Void {} + | ------------ zero-variant enum + +error[E0731]: transparent enum needs exactly one variant, but has 0 + --> $DIR/repr-transparent.rs:43:1 + | +LL | enum Void {} + | ^^^^^^^^^^^^ + +error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0 + --> $DIR/repr-transparent.rs:47:1 + | +LL | / enum FieldlessEnum { +LL | | Foo, +LL | | } + | |_^ + +error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2 + --> $DIR/repr-transparent.rs:52:1 + | +LL | / enum TooManyFieldsEnum { +LL | | Foo(u32, String), +LL | | } + | |_^ + | +note: the following non-zero-sized fields exist on `TooManyFieldsEnum`: + --> $DIR/repr-transparent.rs:53:9 + | +LL | Foo(u32, String), + | ^^^ ^^^^^^ + +error[E0731]: transparent enum needs exactly one variant, but has 2 + --> $DIR/repr-transparent.rs:58:1 + | +LL | / enum TooManyVariants { +LL | | Foo(String), +LL | | Bar, +LL | | } + | |_^ + | +note: the following variants exist on `TooManyVariants` + --> $DIR/repr-transparent.rs:59:5 + | +LL | Foo(String), + | ^^^^^^^^^^^ +LL | Bar, + | ^^^ + +error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0 + --> $DIR/repr-transparent.rs:64:1 + | +LL | / union UnitUnion { +LL | | u: (), +LL | | } + | |_^ + +error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2 + --> $DIR/repr-transparent.rs:69:1 + | +LL | / union TooManyFields { +LL | | u: u32, +LL | | s: i32 +LL | | } + | |_^ + | +note: the following non-zero-sized fields exist on `TooManyFields`: + --> $DIR/repr-transparent.rs:70:5 + | +LL | u: u32, + | ^^^^^^ +LL | s: i32 + | ^^^^^^ + +error: aborting due to 15 previous errors -Some errors have detailed explanations: E0690, E0691. -For more information about an error, try `rustc --explain E0690`. +Some errors have detailed explanations: E0084, E0690, E0691, E0731. +For more information about an error, try `rustc --explain E0084`. diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr index 40d9a50f1fa4f..c60817a849a3b 100644 --- a/src/test/ui/union/union-repr-c.stderr +++ b/src/test/ui/union/union-repr-c.stderr @@ -9,7 +9,7 @@ note: lint level defined here | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ - = help: consider adding a #[repr(C)] attribute to this union + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union note: type defined here --> $DIR/union-repr-c.rs:9:1 |