}
}
+ (&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),
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
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 => {
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,
(_, &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
}
(&LpUpvar(id), &LpUpvar(id2)) => {
if id == id2 {
- assert_eq!(self.ty, other.ty);
Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
} else {
None
out.push(')');
}
-
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
self.append_autoderefd_loan_path_to_string(&lp_base, out);
match fname {
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;
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,
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);
--- /dev/null
+// 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
+ }
+ }
+}
--- /dev/null
+// 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
+ }
+ }
+}
--- /dev/null
+// 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
+ }
+ }
+}
--- /dev/null
+// 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`
+ }
+ }
+}
--- /dev/null
+// 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`
+ }
+}
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);
}
}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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);
+ }
+}