mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +00:00
Support unions in borrow checker
Add some more tests
This commit is contained in:
parent
59ccb7b6db
commit
5f975e969b
@ -461,6 +461,10 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
(&ty::TyUnion(..), None) => {
|
||||
// Do nothing, all union fields are moved/assigned together.
|
||||
}
|
||||
|
||||
(&ty::TyEnum(def, _), ref enum_variant_info) => {
|
||||
let variant = match *enum_variant_info {
|
||||
Some((vid, ref _lp2)) => def.variant_with_id(vid),
|
||||
|
@ -89,7 +89,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||
self.restrict(cmt_base)
|
||||
}
|
||||
|
||||
Categorization::Interior(cmt_base, i) => {
|
||||
Categorization::Interior(cmt_base, interior) => {
|
||||
// R-Field
|
||||
//
|
||||
// Overwriting the base would not change the type of
|
||||
@ -99,8 +99,34 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||
Categorization::Downcast(_, variant_id) => Some(variant_id),
|
||||
_ => None
|
||||
};
|
||||
let interior = interior.cleaned();
|
||||
let base_ty = cmt_base.ty;
|
||||
let result = self.restrict(cmt_base);
|
||||
self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
|
||||
if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
|
||||
match result {
|
||||
RestrictionResult::Safe => RestrictionResult::Safe,
|
||||
RestrictionResult::SafeIf(base_lp, mut base_vec) => {
|
||||
for field in &adt_def.struct_variant().fields {
|
||||
let field = InteriorKind::InteriorField(mc::NamedField(field.name));
|
||||
let field_ty = if field == interior {
|
||||
cmt.ty
|
||||
} else {
|
||||
self.bccx.tcx.types.err // Doesn't matter
|
||||
};
|
||||
let sibling_lp_kind = LpExtend(base_lp.clone(), cmt.mutbl,
|
||||
LpInterior(opt_variant_id, field));
|
||||
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
|
||||
base_vec.push(sibling_lp);
|
||||
}
|
||||
|
||||
let lp = new_lp(LpExtend(base_lp, cmt.mutbl,
|
||||
LpInterior(opt_variant_id, interior)));
|
||||
RestrictionResult::SafeIf(lp, base_vec)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.extend(result, &cmt, LpInterior(opt_variant_id, interior))
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::StaticItem => {
|
||||
|
@ -477,8 +477,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
|
||||
base.common(&base2).map(|x| {
|
||||
let xd = x.depth();
|
||||
if base.depth() == xd && base2.depth() == xd {
|
||||
assert_eq!(base.ty, base2.ty);
|
||||
assert_eq!(self.ty, other.ty);
|
||||
LoanPath {
|
||||
kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
|
||||
ty: self.ty,
|
||||
@ -495,7 +493,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
|
||||
(_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
|
||||
(&LpVar(id), &LpVar(id2)) => {
|
||||
if id == id2 {
|
||||
assert_eq!(self.ty, other.ty);
|
||||
Some(LoanPath { kind: LpVar(id), ty: self.ty })
|
||||
} else {
|
||||
None
|
||||
@ -503,7 +500,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
|
||||
}
|
||||
(&LpUpvar(id), &LpUpvar(id2)) => {
|
||||
if id == id2 {
|
||||
assert_eq!(self.ty, other.ty);
|
||||
Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
|
||||
} else {
|
||||
None
|
||||
@ -1136,7 +1132,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
out.push(')');
|
||||
}
|
||||
|
||||
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
|
||||
self.append_autoderefd_loan_path_to_string(&lp_base, out);
|
||||
match fname {
|
||||
|
@ -21,7 +21,8 @@ use rustc::middle::dataflow::DataFlowOperator;
|
||||
use rustc::middle::dataflow::KillFrom;
|
||||
use rustc::middle::expr_use_visitor as euv;
|
||||
use rustc::middle::expr_use_visitor::MutateMode;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::middle::mem_categorization as mc;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::util::nodemap::{FnvHashMap, NodeSet};
|
||||
|
||||
use std::cell::RefCell;
|
||||
@ -364,6 +365,32 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
lp: Rc<LoanPath<'tcx>>,
|
||||
id: ast::NodeId,
|
||||
kind: MoveKind) {
|
||||
// Moving one union field automatically moves all its fields.
|
||||
if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
|
||||
if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
|
||||
for field in &adt_def.struct_variant().fields {
|
||||
let field = InteriorKind::InteriorField(mc::NamedField(field.name));
|
||||
let field_ty = if field == interior {
|
||||
lp.ty
|
||||
} else {
|
||||
tcx.types.err // Doesn't matter
|
||||
};
|
||||
let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
|
||||
LpInterior(opt_variant_id, field));
|
||||
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
|
||||
self.add_move_helper(tcx, sibling_lp, id, kind);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.add_move_helper(tcx, lp.clone(), id, kind);
|
||||
}
|
||||
|
||||
fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
lp: Rc<LoanPath<'tcx>>,
|
||||
id: ast::NodeId,
|
||||
kind: MoveKind) {
|
||||
debug!("add_move(lp={:?}, id={}, kind={:?})",
|
||||
lp,
|
||||
id,
|
||||
@ -393,6 +420,34 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
span: Span,
|
||||
assignee_id: ast::NodeId,
|
||||
mode: euv::MutateMode) {
|
||||
// Assigning to one union field automatically assigns to all its fields.
|
||||
if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
|
||||
if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
|
||||
for field in &adt_def.struct_variant().fields {
|
||||
let field = InteriorKind::InteriorField(mc::NamedField(field.name));
|
||||
let field_ty = if field == interior {
|
||||
lp.ty
|
||||
} else {
|
||||
tcx.types.err // Doesn't matter
|
||||
};
|
||||
let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
|
||||
LpInterior(opt_variant_id, field));
|
||||
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
|
||||
self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
|
||||
}
|
||||
|
||||
pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
lp: Rc<LoanPath<'tcx>>,
|
||||
assign_id: ast::NodeId,
|
||||
span: Span,
|
||||
assignee_id: ast::NodeId,
|
||||
mode: euv::MutateMode) {
|
||||
debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
|
||||
lp, assign_id, assignee_id);
|
||||
|
||||
|
44
src/test/compile-fail/union-borrow-nested.rs
Normal file
44
src/test/compile-fail/union-borrow-nested.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct S {
|
||||
a: u8,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
union U {
|
||||
s: S,
|
||||
c: u32,
|
||||
}
|
||||
|
||||
impl Clone for U {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
impl Copy for U {}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
{
|
||||
let mut u = U { s: S { a: 0, b: 1 } };
|
||||
let ra = &mut u.s.a;
|
||||
let b = u.s.b; // OK
|
||||
}
|
||||
{
|
||||
let mut u = U { s: S { a: 0, b: 1 } };
|
||||
let ra = &mut u.s.a;
|
||||
let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed
|
||||
}
|
||||
}
|
||||
}
|
97
src/test/compile-fail/union-borrow.rs
Normal file
97
src/test/compile-fail/union-borrow.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
union U {
|
||||
a: u8,
|
||||
b: u64,
|
||||
}
|
||||
|
||||
impl Clone for U {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
impl Copy for U {}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut u = U { b: 0 };
|
||||
// Imm borrow, same field
|
||||
{
|
||||
let ra = &u.a;
|
||||
let ra2 = &u.a; // OK
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
let a = u.a; // OK
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||
}
|
||||
// Imm borrow, other field
|
||||
{
|
||||
let ra = &u.a;
|
||||
let rb = &u.b; // OK
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
let b = u.b; // OK
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
||||
}
|
||||
{
|
||||
let ra = &u.a;
|
||||
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||
}
|
||||
// Mut borrow, same field
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||
}
|
||||
{
|
||||
let ra = &mut u.a;
|
||||
let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
|
||||
}
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
||||
}
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||
}
|
||||
// Mut borrow, other field
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
||||
}
|
||||
{
|
||||
let ra = &mut u.a;
|
||||
let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
|
||||
}
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||
}
|
||||
{
|
||||
let rma = &mut u.a;
|
||||
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||
}
|
||||
}
|
||||
}
|
42
src/test/compile-fail/union-move-assign.rs
Normal file
42
src/test/compile-fail/union-move-assign.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
// Non-copy
|
||||
struct A;
|
||||
struct B;
|
||||
|
||||
union U {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
{
|
||||
let mut u = U { a: A };
|
||||
let a = u.a;
|
||||
let a = u.a; //~ ERROR use of moved value: `u.a`
|
||||
}
|
||||
{
|
||||
let mut u = U { a: A };
|
||||
let a = u.a;
|
||||
u.a = A;
|
||||
let a = u.a; // OK
|
||||
}
|
||||
{
|
||||
let mut u = U { a: A };
|
||||
let a = u.a;
|
||||
u.b = B;
|
||||
let a = u.a; // OK
|
||||
}
|
||||
}
|
||||
}
|
96
src/test/compile-fail/union-move.rs
Normal file
96
src/test/compile-fail/union-move.rs
Normal file
@ -0,0 +1,96 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Copy;
|
||||
struct NonCopy;
|
||||
|
||||
union Unn {
|
||||
n1: NonCopy,
|
||||
n2: NonCopy,
|
||||
}
|
||||
union Ucc {
|
||||
c1: Copy,
|
||||
c2: Copy,
|
||||
}
|
||||
union Ucn {
|
||||
c: Copy,
|
||||
n: NonCopy,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
// 2 NonCopy
|
||||
{
|
||||
let mut u = Unn { n1: NonCopy };
|
||||
let a = u.n1;
|
||||
let a = u.n1; //~ ERROR use of moved value: `u.n1`
|
||||
}
|
||||
{
|
||||
let mut u = Unn { n1: NonCopy };
|
||||
let a = u.n1;
|
||||
let a = u; //~ ERROR use of partially moved value: `u`
|
||||
}
|
||||
{
|
||||
let mut u = Unn { n1: NonCopy };
|
||||
let a = u.n1;
|
||||
let a = u.n2; //~ ERROR use of moved value: `u.n2`
|
||||
}
|
||||
// 2 Copy
|
||||
{
|
||||
let mut u = Ucc { c1: Copy };
|
||||
let a = u.c1;
|
||||
let a = u.c1; // OK
|
||||
}
|
||||
{
|
||||
let mut u = Ucc { c1: Copy };
|
||||
let a = u.c1;
|
||||
let a = u; // OK
|
||||
}
|
||||
{
|
||||
let mut u = Ucc { c1: Copy };
|
||||
let a = u.c1;
|
||||
let a = u.c2; // OK
|
||||
}
|
||||
// 1 Copy, 1 NonCopy
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.c;
|
||||
let a = u.c; // OK
|
||||
}
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.n;
|
||||
let a = u.n; //~ ERROR use of moved value: `u.n`
|
||||
}
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.n;
|
||||
let a = u.c; //~ ERROR use of moved value: `u.c`
|
||||
}
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.c;
|
||||
let a = u.n; // OK
|
||||
}
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.c;
|
||||
let a = u; // OK
|
||||
}
|
||||
{
|
||||
let mut u = Ucn { c: Copy };
|
||||
let a = u.n;
|
||||
let a = u; //~ ERROR use of partially moved value: `u`
|
||||
}
|
||||
}
|
||||
}
|
30
src/test/compile-fail/union-uninitialized.rs
Normal file
30
src/test/compile-fail/union-uninitialized.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
struct S {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
union U {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut s: S;
|
||||
let mut u: U;
|
||||
s.a = 0;
|
||||
u.a = 0;
|
||||
let sa = s.a; //~ ERROR use of possibly uninitialized variable: `s.a`
|
||||
let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a`
|
||||
}
|
||||
}
|
@ -52,8 +52,8 @@ fn main() {
|
||||
unsafe {
|
||||
assert_eq!(w.a, 0);
|
||||
assert_eq!(w.b, 0);
|
||||
// w.a = 1;
|
||||
assert_eq!(w.a, 0);
|
||||
assert_eq!(w.b, 0);
|
||||
w.a = 1;
|
||||
assert_eq!(w.a, 1);
|
||||
assert_eq!(w.b, 1);
|
||||
}
|
||||
}
|
||||
|
44
src/test/run-pass/union-drop-assign.rs
Normal file
44
src/test/run-pass/union-drop-assign.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Drop works for union itself.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
struct S;
|
||||
|
||||
union U {
|
||||
a: S
|
||||
}
|
||||
|
||||
impl Drop for S {
|
||||
fn drop(&mut self) {
|
||||
unsafe { CHECK += 10; }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for U {
|
||||
fn drop(&mut self) {
|
||||
unsafe { CHECK += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
static mut CHECK: u8 = 0;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut u = U { a: S };
|
||||
assert_eq!(CHECK, 0);
|
||||
u = U { a: S };
|
||||
assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
|
||||
u.a = S;
|
||||
assert_eq!(CHECK, 11); // union field is assigned, field is dropped
|
||||
}
|
||||
}
|
40
src/test/run-pass/union-transmute.rs
Normal file
40
src/test/run-pass/union-transmute.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core_float)]
|
||||
#![feature(float_extras)]
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
extern crate core;
|
||||
use core::num::Float;
|
||||
|
||||
union U {
|
||||
a: (u8, u8),
|
||||
b: u16,
|
||||
}
|
||||
|
||||
union W {
|
||||
a: u32,
|
||||
b: f32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut u = U { a: (1, 1) };
|
||||
assert_eq!(u.b, (1 << 8) + 1);
|
||||
u.b = (2 << 8) + 2;
|
||||
assert_eq!(u.a, (2, 2));
|
||||
|
||||
let mut w = W { a: 0b0_11111111_00000000000000000000000 };
|
||||
assert_eq!(w.b, f32::infinity());
|
||||
w.b = f32::neg_infinity();
|
||||
assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user