From a6734cd89030b352f7cfcd765e451af5f1961985 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 19 Jun 2017 16:54:31 +0200 Subject: [PATCH] Fix unions --- src/lvalue.rs | 10 ++-- tests/run-pass/union-overwrite.rs | 81 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/union-overwrite.rs diff --git a/src/lvalue.rs b/src/lvalue.rs index 0205472254c..f344a4e3b2d 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -182,7 +182,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { field_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Lvalue<'tcx>> { let base_layout = self.type_layout(base_ty)?; - use rustc::ty::layout::Layout::*; let (offset, packed) = match *base_layout { Univariant { ref variant, .. } => { @@ -255,8 +254,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } }, Value::ByVal(_) => { - assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0"); - return Ok(base); + if self.get_field_count(base_ty)? == 1 { + assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0"); + return Ok(base); + } + // this branch is taken when a union creates a large ByVal which is then + // accessed as a struct with multiple small fields + (PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None) }, Value::ByValPair(_, _) => { let field_count = self.get_field_count(base_ty)?; diff --git a/tests/run-pass/union-overwrite.rs b/tests/run-pass/union-overwrite.rs new file mode 100644 index 00000000000..df2ff6e51a5 --- /dev/null +++ b/tests/run-pass/union-overwrite.rs @@ -0,0 +1,81 @@ +// 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)] +#![allow(unions_with_drop_fields)] + +#[repr(C)] +struct Pair(T, U); +#[repr(C)] +struct Triple(T, T, T); + +#[repr(C)] +union U { + a: Pair, + b: B, +} + +#[repr(C)] +union W { + a: A, + b: B, +} + +#[cfg(target_endian = "little")] +unsafe fn check() { + let mut u = U:: { b: 0xDE_DE }; + u.a.0 = 0xBE; + assert_eq!(u.b, 0xDE_BE); + + let mut u = U:: { b: 0xDEAD_DEAD }; + u.a.0 = 0xBEEF; + assert_eq!(u.b, 0xDEAD_BEEF); + + let mut u = U:: { b: 0xDEADBEEF_DEADBEEF }; + u.a.0 = 0xBAADF00D; + assert_eq!(u.b, 0xDEADBEEF_BAADF00D); + + let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD }; + w.a.0 = Triple(0, 0, 0); + assert_eq!(w.b, 0xDE00_0000); + + let mut w = W::>, u32> { b: 0xDEAD_DEAD }; + w.a.1 = Triple(0, 0, 0); + assert_eq!(w.b, 0x0000_00AD); +} + +#[cfg(target_endian = "big")] +unsafe fn check() { + let mut u = U:: { b: 0xDE_DE }; + u.a.0 = 0xBE; + assert_eq!(u.b, 0xBE_DE); + + let mut u = U:: { b: 0xDEAD_DEAD }; + u.a.0 = 0xBEEF; + assert_eq!(u.b, 0xBEEF_DEAD); + + let mut u = U:: { b: 0xDEADBEEF_DEADBEEF }; + u.a.0 = 0xBAADF00D; + assert_eq!(u.b, 0xBAADF00D_DEADBEEF); + + let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD }; + w.a.0 = Triple(0, 0, 0); + assert_eq!(w.b, 0x0000_00AD); + + let mut w = W::>, u32> { b: 0xDEAD_DEAD }; + w.a.1 = Triple(0, 0, 0); + assert_eq!(w.b, 0xDE00_0000); +} + +fn main() { + unsafe { + check(); + } +}