diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a2692fb8f5a..68aa553c529 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1352,22 +1352,19 @@ impl<'a, 'tcx> LayoutDetails { }).collect::, _>>() }).collect::, _>>()?; - let (inh_first, inh_second) = { - let mut inh_variants = (0..variants.len()).filter(|&v| { - variants[v].iter().all(|f| f.abi != Abi::Uninhabited) - }); - (inh_variants.next(), inh_variants.next()) - }; - if inh_first.is_none() { - // Uninhabited because it has no variants, or only uninhabited ones. - return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0))); - } - if def.is_union() { let packed = def.repr.packed(); if packed && def.repr.align > 0 { bug!("Union cannot be packed and aligned"); } + if variants.len() != 1 { + bug!("Union must be represented as a single variant"); + } + + if variants[0].iter().all(|f| f.abi == Abi::Uninhabited) { + // Uninhabited because it has only uninhabited variants/fields. + return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0))); + } let mut align = if def.repr.packed() { dl.i8_align @@ -1400,6 +1397,17 @@ impl<'a, 'tcx> LayoutDetails { })); } + let (inh_first, inh_second) = { + let mut inh_variants = (0..variants.len()).filter(|&v| { + variants[v].iter().all(|f| f.abi != Abi::Uninhabited) + }); + (inh_variants.next(), inh_variants.next()) + }; + if inh_first.is_none() { + // Uninhabited because it has no variants, or only uninhabited ones. + return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0))); + } + let is_struct = !def.is_enum() || // Only one variant is inhabited. (inh_second.is_none() && diff --git a/src/test/run-pass/issue-46845.rs b/src/test/run-pass/issue-46845.rs new file mode 100644 index 00000000000..235d3982a9c --- /dev/null +++ b/src/test/run-pass/issue-46845.rs @@ -0,0 +1,39 @@ +// 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. + +// To work around #46855 +// compile-flags: -Z mir-opt-level=0 +// Regression test for the inhabitedness of unions with uninhabited variants, issue #46845 + +use std::mem; + +#[derive(Copy, Clone)] +enum Never { } + +// A single uninhabited variant shouldn't make the whole union uninhabited. +union Foo { + a: u64, + _b: Never +} + +// If all the variants are uninhabited, however, the union should be uninhabited. +union Bar { + _a: (Never, u64), + _b: (u64, Never) +} + +fn main() { + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::size_of::(), 0); + + let f = [Foo { a: 42 }, Foo { a: 10 }]; + println!("{}", unsafe { f[0].a }); + assert_eq!(unsafe { f[1].a }, 10); +}