From 4d74572cb622657cab3f7f8d7b513d89e61c36fa Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sat, 20 Jan 2018 03:29:10 -0500 Subject: [PATCH 01/13] allow the last field of a union to be ?Sized - theoretically any single field of the union could be ?Sized, but it's easier to implement this way - still have to allow/implement the unsize cast for unions --- src/librustc/traits/error_reporting.rs | 3 ++- src/librustc_typeck/check/wfcheck.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index dba23c22647f8..2bd61027d31ea 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1342,7 +1342,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sized type"); } AdtKind::Union => { - err.note("no field of a union may have a dynamically sized type"); + err.note("only the last field of a union may have a dynamically \ + sized type"); } AdtKind::Enum => { err.note("no field of an enum variant may have a dynamically sized type"); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 39e757c52ff29..c8ad43da60d00 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -141,7 +141,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } hir::ItemUnion(ref struct_def, ref ast_generics) => { - self.check_type_defn(item, true, |fcx| { + self.check_type_defn(item, false, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); From 74ce9fb53c7f3665b61341bab4328f62a1e0b828 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 21 Jan 2018 16:57:19 -0500 Subject: [PATCH 02/13] Get unsized unions working this supports unsized unions, where the last field may be unsized. Theoretically, any number of fields of a union could be unsized, as long as the unsized type is the same for all of them, but this is the simplest way to get ManuallyDrop working. --- src/librustc/traits/select.rs | 3 ++- src/librustc/ty/layout.rs | 21 ++++++++++++++++++--- src/librustc/ty/util.rs | 6 ++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9e24a4e6afacf..c0d302a4f8703 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1957,7 +1957,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyArray(..), &ty::TySlice(_)) => true, // Struct -> Struct. - (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) if def_id_a.is_struct() => { + (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) + if def_id_a.is_struct() || def_id_a.is_union() => { def_id_a == def_id_b } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index c3cd65230bd86..3b3268e2cdb6d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -897,6 +897,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.layout_depth.set(depth+1); let cx = LayoutCx { tcx, param_env }; let layout = cx.layout_raw_uncached(ty); + debug!("computed layout, ty = {:?}, layout = {:?}", ty, layout); tcx.layout_depth.set(depth); layout @@ -1208,6 +1209,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let unsized_part = tcx.struct_tail(pointee); + debug!("compute_uncached: unsized_part = {:?}", unsized_part.sty); let metadata = match unsized_part.sty { ty::TyForeign(..) => { return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); @@ -1220,7 +1222,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { vtable.valid_range.start = 1; vtable } - _ => return Err(LayoutError::Unknown(unsized_part)) + _ => { + debug!("compute_uncached: unsized type with unknown \ + pointer layout: {:?}", unsized_part.sty); + return Err(LayoutError::Unknown(ty)) + } }; // Effectively a (ptr, meta) tuple. @@ -1361,6 +1367,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }).collect::, _>>()?; if def.is_union() { + debug!("compute_uncached: calculating layout for union: {:?}", ty.sty); let packed = def.repr.packed(); if packed && def.repr.align > 0 { bug!("Union cannot be packed and aligned"); @@ -1379,8 +1386,16 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let mut size = Size::from_bytes(0); + let mut sized = true; for field in &variants[0] { - assert!(!field.is_unsized()); + if field.is_unsized() { + if !sized { + bug!("compute_uncached: field {:?} of union {:?} \ + comes after unsized field", field, ty); + } + sized = false; + break; + } if !packed { align = align.max(field.align); @@ -1391,7 +1406,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index: 0 }, fields: FieldPlacement::Union(variants[0].len()), - abi: Abi::Aggregate { sized: true }, + abi: Abi::Aggregate { sized }, align, size: size.abi_align(align) })); diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 44771444c8aa8..61e33c93234ac 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -290,7 +290,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { loop { match ty.sty { ty::TyAdt(def, substs) => { - if !def.is_struct() { + if !def.is_struct() && !def.is_union() { break; } match def.non_enum_variant().fields.last() { @@ -328,7 +328,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { loop { match (&a.sty, &b.sty) { (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) - if a_def == b_def && a_def.is_struct() => { + if a_def == b_def && ( + a_def.is_struct() || a_def.is_union() + ) => { if let Some(f) = a_def.non_enum_variant().fields.last() { a = f.ty(self, a_substs); b = f.ty(self, b_substs); From 06cc03c108c44cb551bf073443c59ef42e85a7a6 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 21 Jan 2018 22:22:03 -0500 Subject: [PATCH 03/13] update union-unsized compile-fail test this now only fails if the unsized field is not the last field --- src/test/compile-fail/union/union-unsized.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs index a238eaf052508..13437672d6396 100644 --- a/src/test/compile-fail/union/union-unsized.rs +++ b/src/test/compile-fail/union/union-unsized.rs @@ -17,7 +17,7 @@ union U { union W { a: u8, - b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + b: str, } fn main() {} From 43fa32747957b1d22160838f4f7640d0caa9aae7 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 21 Jan 2018 22:34:45 -0500 Subject: [PATCH 04/13] start adding an unsized-union run-pass test --- src/test/run-pass/union/union-unsized.rs | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/run-pass/union/union-unsized.rs diff --git a/src/test/run-pass/union/union-unsized.rs b/src/test/run-pass/union/union-unsized.rs new file mode 100644 index 0000000000000..a1b786e985b8f --- /dev/null +++ b/src/test/run-pass/union/union-unsized.rs @@ -0,0 +1,64 @@ +// Copyright 2016 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. + +#![feature(untagged_unions)] +#![feature(nll)] + +use std::ptr; + +trait Trait {} +impl Trait for T {} + +#[allow(unions_with_drop_fields)] +union NoDrop { + value: T, +} + +struct ShouldDrop<'a> { + dropped: &'a mut bool +} + +impl<'a> Drop for ShouldDrop<'a> { + fn drop(&mut self) { + *self.dropped = true; + } +} + +struct ShouldntDrop; + +impl Drop for ShouldntDrop { + fn drop(&mut self) { + unsafe { + panic!("This should not be dropped!"); + } + } +} + +fn main() { + let mut dropped = false; + { + let mut should_drop = &mut NoDrop { + value: ShouldDrop { + dropped: &mut dropped + } + } as &mut NoDrop; + + unsafe { + ptr::drop_in_place(&mut should_drop.value); + } + } + + assert!(dropped); + + // NoDrop will be dropped, but the ShouldntDrop won't be + Box::new(NoDrop { value: ShouldntDrop }) as Box>; + + // FIXME: do something with Bar +} From 76454900bd80b7b1731143c4bc7273bf89346b03 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 26 Feb 2018 16:33:44 -0500 Subject: [PATCH 05/13] WIP: only allow single field unions to be unsized --- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/select.rs | 1 + src/librustc/ty/layout.rs | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2bd61027d31ea..cb4edaced569d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1342,7 +1342,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sized type"); } AdtKind::Union => { - err.note("only the last field of a union may have a dynamically \ + err.note("only single-field unions may have a dynamically \ sized type"); } AdtKind::Enum => { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c0d302a4f8703..5b3b04e30a8d5 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1957,6 +1957,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyArray(..), &ty::TySlice(_)) => true, // Struct -> Struct. + // Union -> Union. (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) if def_id_a.is_struct() || def_id_a.is_union() => { def_id_a == def_id_b diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3b3268e2cdb6d..f32c8d10bd592 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1389,12 +1389,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut sized = true; for field in &variants[0] { if field.is_unsized() { - if !sized { + if variants[0].len() > 1 { bug!("compute_uncached: field {:?} of union {:?} \ - comes after unsized field", field, ty); + is unsized, but is not the only field", + field, ty); + } else { + sized = false; } - sized = false; - break; } if !packed { From 6d474ae4406f89376fabec831d4d1970045e671c Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sat, 10 Mar 2018 17:12:28 -0500 Subject: [PATCH 06/13] Add feature gate test for unsized unions --- src/test/ui/feature-gate-untagged_unions.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/ui/feature-gate-untagged_unions.rs b/src/test/ui/feature-gate-untagged_unions.rs index 6533fddd94714..b39ecba316a13 100644 --- a/src/test/ui/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gate-untagged_unions.rs @@ -32,4 +32,15 @@ impl Drop for U5 { fn drop(&mut self) {} } +// the non-`Copy` error message has priority +// replace this with unsized error message if +// non-`Copy` unions are stabilized before unsized unions +union U6 { //~ ERROR unions with non-`Copy` fields are unstable + a: T +} + +union U6 { // ERROR unsized unions are unstable + a: T +} + fn main() {} From cedec2bc31088f2abdfe3cae7107326b92d6c5fd Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sat, 10 Mar 2018 17:23:25 -0500 Subject: [PATCH 07/13] Update union-sized-field ui test Adds an extra field to the unsized union, so that there will be an error about the union needing to only have a single field --- src/test/ui/union/union-sized-field.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index 8999f1e0930be..2dbb5fdc13edb 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -11,6 +11,7 @@ #![feature(untagged_unions)] union Foo { + t: u32, value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied } From 6cb99d1b146fddc194f9fb1f051f75eb325be805 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 12 Mar 2018 23:14:19 -0400 Subject: [PATCH 08/13] fix typo in feature-gate test --- src/test/ui/feature-gate-untagged_unions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/feature-gate-untagged_unions.rs b/src/test/ui/feature-gate-untagged_unions.rs index b39ecba316a13..32b9aaf05880e 100644 --- a/src/test/ui/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gate-untagged_unions.rs @@ -39,7 +39,7 @@ union U6 { //~ ERROR unions with non-`Copy` fields are unstable a: T } -union U6 { // ERROR unsized unions are unstable +union U7 { // ERROR unsized unions are unstable a: T } From e2bb12676eb58270f78356119d1219a35b3fd260 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 13 Mar 2018 00:32:35 -0400 Subject: [PATCH 09/13] refactor FnCtxt::check_type_defn to handle unsized unions - the old implementation had an `all_sized: bool` parameter which was true iff the type was a struct, and allowed the last field to be unsized in that case. - Because of unsized unions, things are more complicated, and will become more complicated in the future if we get multiple unsized union fields or enum variants - this implementation gets rid of the `all_sized` parameter, and just checks directly in the function whether the type is a struct, enum or union, handling each case independently --- src/librustc_typeck/check/wfcheck.rs | 44 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index c8ad43da60d00..0a65f7f781e84 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -134,21 +134,21 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { self.check_item_type(item); } hir::ItemStruct(ref struct_def, ref ast_generics) => { - self.check_type_defn(item, false, |fcx| { + self.check_type_defn(item, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); } hir::ItemUnion(ref struct_def, ref ast_generics) => { - self.check_type_defn(item, false, |fcx| { + self.check_type_defn(item, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); } hir::ItemEnum(ref enum_def, ref ast_generics) => { - self.check_type_defn(item, true, |fcx| { + self.check_type_defn(item, |fcx| { fcx.enum_variants(enum_def) }); @@ -221,7 +221,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } /// In a type definition, we check that to ensure that the types of the fields are well-formed. - fn check_type_defn(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F) + fn check_type_defn(&mut self, item: &hir::Item, mut lookup_fields: F) where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec> { self.for_item(item).with_fcx(|fcx, this| { @@ -242,16 +242,36 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ty.needs_drop(this.tcx, this.tcx.param_env(def_id)) } }; - let unsized_len = if - all_sized || - variant.fields.is_empty() || - needs_drop_copy() - { - 0 + + let fields_that_must_be_sized = if needs_drop_copy() { + // all fields must be sized + // see definition of needs_drop_copy above^ + &variant.fields[..] } else { - 1 + match item.node { + hir::ItemStruct(..) => { + // last field in a struct may be unsized + &variant.fields[..variant.fields.len()-1] + } + hir::ItemUnion(..) => { + if variant.fields.len() == 1 { + // if there is only one field, it may be unsized + &[] + } else { + // otherwise all fields must be sized + &variant.fields[..] + } + } + hir::ItemEnum(..) => { + // all fields in an enum variant must be sized + &variant.fields[..] + } + + _ => unreachable!() + } }; - for field in &variant.fields[..variant.fields.len() - unsized_len] { + + for field in fields_that_must_be_sized { fcx.register_bound( field.ty, fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), From 55f0967e57658079235068bcf4689861cc0171b9 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 13 Mar 2018 02:10:23 -0400 Subject: [PATCH 10/13] Fix underflow bug The expression `slice.len()-1` underflows when the slice is empty, which caused an out-of-bounds array access. At least Rust panics in that case! I wish there was a more idiomatic way to get a sub-slice with everything but the last element. This way is evidently pretty bug-prone --- src/librustc_typeck/check/wfcheck.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 0a65f7f781e84..b606f7f3c15e6 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -251,7 +251,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { match item.node { hir::ItemStruct(..) => { // last field in a struct may be unsized - &variant.fields[..variant.fields.len()-1] + &variant.fields[..variant.fields.len().max(1)-1] } hir::ItemUnion(..) => { if variant.fields.len() == 1 { From 42b84f97ef3d874272032e8dfbe0c5abba23d431 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 13 Mar 2018 02:12:31 -0400 Subject: [PATCH 11/13] upgrade `unreachable!()` to a `span_bug!()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should output a better error message if check_type_defn ever gets called with something that’s not a struct, enum or union --- src/librustc_typeck/check/wfcheck.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b606f7f3c15e6..2bcc4baf07e13 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -267,7 +267,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { &variant.fields[..] } - _ => unreachable!() + _ => span_bug!(item.span, + "unexpected item {:?}", item.node) } }; From de2ff7fcacc69425c40df5ffa4aed20edbc00a54 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 13 Mar 2018 02:16:05 -0400 Subject: [PATCH 12/13] Update union-specific tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - update the comments on the `U6` test case, to make it more clear what to do when non-`Copy` unions are stabilized - add a crucial `~` that caused a test to pass that wasn’t supposed to - update stderr of some tests to reflect changes in the actual tests and compiler error messages --- src/test/ui/feature-gate-untagged_unions.rs | 6 +++--- src/test/ui/feature-gate-untagged_unions.stderr | 12 +++++++++++- src/test/ui/union/union-sized-field.stderr | 8 ++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/test/ui/feature-gate-untagged_unions.rs b/src/test/ui/feature-gate-untagged_unions.rs index 32b9aaf05880e..e22d563680a74 100644 --- a/src/test/ui/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gate-untagged_unions.rs @@ -33,13 +33,13 @@ impl Drop for U5 { } // the non-`Copy` error message has priority -// replace this with unsized error message if -// non-`Copy` unions are stabilized before unsized unions +// replace this with an "unsized unions are unstable" error message +// if non-`Copy` unions are stabilized before unsized unions union U6 { //~ ERROR unions with non-`Copy` fields are unstable a: T } -union U7 { // ERROR unsized unions are unstable +union U7 { //~ ERROR unsized unions are unstable a: T } diff --git a/src/test/ui/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gate-untagged_unions.stderr index eef42e8b6fd60..00af921879d39 100644 --- a/src/test/ui/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gate-untagged_unions.stderr @@ -28,6 +28,16 @@ LL | | } | = help: add #![feature(untagged_unions)] to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) + --> $DIR/feature-gate-untagged_unions.rs:38:1 + | +LL | / union U6 { //~ ERROR unions with non-`Copy` fields are unstable +LL | | a: T +LL | | } + | |_^ + | + = help: add #![feature(untagged_unions)] to the crate attributes to enable + +error: aborting due to 4 previous errors If you want more information on this error, try using "rustc --explain E0658" diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 4f2d00aaa3e20..9576380f6c637 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,15 +1,15 @@ error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:14:5 + --> $DIR/union-sized-field.rs:15:5 | LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = help: consider adding a `where T: std::marker::Sized` bound - = note: no field of a union may have a dynamically sized type + = note: only single-field unions may have a dynamically sized type error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:18:5 + --> $DIR/union-sized-field.rs:19:5 | LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied | ^^^^^^^^ `T` does not have a constant size known at compile-time @@ -19,7 +19,7 @@ LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not sati = note: only the last field of a struct may have a dynamically sized type error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:23:11 + --> $DIR/union-sized-field.rs:24:11 | LL | Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied | ^^ `T` does not have a constant size known at compile-time From d27141c9923b18313fe5b3ac7167b8ea64cb3e42 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sat, 17 Mar 2018 20:20:58 -0400 Subject: [PATCH 13/13] eemit a feature-gate error for unsized unions - unsized unions require the untagged_unions feature - prececedence is given to other error messages for the untagged_unions feature gate. For example, if there is already going to be an error about non-`Copy` unions being unstable, we do not also emit an error about unsized unions being unstable --- src/librustc/middle/stability.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e80ea16f565ab..8896d57ade5d8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -675,7 +675,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } - // There's no good place to insert stability check for non-Copy unions, + // There's no good place to insert stability check for non-Copy or unsized unions, // so semi-randomly perform it here in stability.rs hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); @@ -692,6 +692,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { emit_feature_err(&self.tcx.sess.parse_sess, "untagged_unions", item.span, GateIssue::Language, "unions with non-`Copy` fields are unstable"); + } else if !ty.is_sized(self.tcx, param_env, item.span) { + emit_feature_err(&self.tcx.sess.parse_sess, + "untagged_unions", item.span, GateIssue::Language, + "unsized unions are unstable"); } } }