From 5f9ef3c8b28c9a25be74bc2e41399a4c684f07b1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2016 16:10:58 +0300 Subject: Implement encoding/decoding unions in metadata Add well-formedness check Implement some more missing code --- src/test/compile-fail/attr-usage-repr.rs | 2 +- src/test/compile-fail/issue-31769.rs | 2 +- src/test/compile-fail/union-nonrepresentable.rs | 18 ++++++++++++++++++ src/test/compile-fail/union-unsized.rs | 17 +++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/union-nonrepresentable.rs create mode 100644 src/test/compile-fail/union-unsized.rs (limited to 'src/test/compile-fail') diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs index 9bad6a8389a..b07d3e2f906 100644 --- a/src/test/compile-fail/attr-usage-repr.rs +++ b/src/test/compile-fail/attr-usage-repr.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] #![feature(repr_simd)] -#[repr(C)] //~ ERROR: attribute should be applied to struct or enum +#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union fn f() {} #[repr(C)] diff --git a/src/test/compile-fail/issue-31769.rs b/src/test/compile-fail/issue-31769.rs index 4b5df7ea53c..7f73d9076ec 100644 --- a/src/test/compile-fail/issue-31769.rs +++ b/src/test/compile-fail/issue-31769.rs @@ -10,5 +10,5 @@ fn main() { #[inline] struct Foo; //~ ERROR attribute should be applied to function - #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct or enum + #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union } diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union-nonrepresentable.rs new file mode 100644 index 00000000000..cb4683c2a0e --- /dev/null +++ b/src/test/compile-fail/union-nonrepresentable.rs @@ -0,0 +1,18 @@ +// 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)] + +union U { //~ ERROR recursive type `U` has infinite size + a: u8, + b: U, +} + +fn main() {} diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union-unsized.rs new file mode 100644 index 00000000000..381122406d7 --- /dev/null +++ b/src/test/compile-fail/union-unsized.rs @@ -0,0 +1,17 @@ +// 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)] + +union U { + a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From f3b41c18a8dfbcfec4b2a9e8d9e6a921189e3eea Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Aug 2016 18:31:47 +0300 Subject: Check fields in union patters/expressions Make parsing of union items backward compatible Add some tests --- src/librustc_typeck/check/_match.rs | 49 +++++++++-------- src/librustc_typeck/check/mod.rs | 31 ++++++----- src/libsyntax/parse/parser.rs | 4 +- src/test/compile-fail/issue-17800.rs | 2 +- src/test/compile-fail/issue-19922.rs | 2 +- src/test/compile-fail/issue-4736.rs | 2 +- src/test/compile-fail/numeric-fields.rs | 2 +- .../compile-fail/struct-fields-hints-no-dupe.rs | 2 +- src/test/compile-fail/struct-fields-hints.rs | 2 +- src/test/compile-fail/struct-fields-too-many.rs | 2 +- src/test/compile-fail/suggest-private-fields.rs | 8 +-- src/test/compile-fail/union-empty.rs | 15 ++++++ src/test/compile-fail/union-fields.rs | 34 ++++++++++++ src/test/run-pass/union-backcomp.rs | 23 ++++++++ src/test/run-pass/union-basic.rs | 8 +++ src/test/run-pass/union-drop.rs | 26 +++++++++ src/test/run-pass/union-pat-refutability.rs | 62 ++++++++++++++++++++++ 17 files changed, 227 insertions(+), 47 deletions(-) create mode 100644 src/test/compile-fail/union-empty.rs create mode 100644 src/test/compile-fail/union-fields.rs create mode 100644 src/test/run-pass/union-backcomp.rs create mode 100644 src/test/run-pass/union-drop.rs create mode 100644 src/test/run-pass/union-pat-refutability.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5fdfa19190b..5c19fa2a66c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,6 @@ use hir::def::Def; use rustc::infer::{self, InferOk, TypeOrigin}; use hir::pat_util::EnumerateAndAdjustIterator; -use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind}; use check::{FnCtxt, Expectation}; use lint; @@ -509,11 +508,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. - let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, - _ => span_bug!(pat.span, "struct variant is not an ADT") - }; - self.check_struct_pat_fields(pat.span, fields, variant, substs, etc); + self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc); } fn check_pat_path(&self, @@ -658,19 +653,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// `path` is the AST path item naming the type of this struct. - /// `fields` is the field patterns of the struct pattern. - /// `struct_fields` describes the type of each field of the struct. - /// `struct_id` is the ID of the struct. - /// `etc` is true if the pattern said '...' and false otherwise. - pub fn check_struct_pat_fields(&self, - span: Span, - fields: &'gcx [Spanned], - variant: ty::VariantDef<'tcx>, - substs: &Substs<'tcx>, - etc: bool) { + fn check_struct_pat_fields(&self, + adt_ty: Ty<'tcx>, + span: Span, + variant: ty::VariantDef<'tcx>, + fields: &'gcx [Spanned], + etc: bool) { let tcx = self.tcx; + let (substs, kind_name) = match adt_ty.sty { + ty::TyEnum(_, substs) => (substs, "variant"), + ty::TyStruct(_, substs) => (substs, "struct"), + ty::TyUnion(_, substs) => (substs, "union"), + _ => span_bug!(span, "struct pattern is not an ADT") + }; + // Index the struct fields' types. let field_map = variant.fields .iter() @@ -700,11 +697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .map(|f| self.field_ty(span, f, substs)) .unwrap_or_else(|| { struct_span_err!(tcx.sess, span, E0026, - "struct `{}` does not have a field named `{}`", + "{} `{}` does not have a field named `{}`", + kind_name, tcx.item_path_str(variant.did), field.name) .span_label(span, - &format!("struct `{}` does not have field `{}`", + &format!("{} `{}` does not have field `{}`", + kind_name, tcx.item_path_str(variant.did), field.name)) .emit(); @@ -717,8 +716,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&field.pat, field_ty); } - // Report an error if not all the fields were specified. - if !etc { + // Report an error if incorrect number of the fields were specified. + if kind_name == "union" { + if fields.len() > 1 { + tcx.sess.span_err(span, "union patterns can have at most one field"); + } + if fields.is_empty() && !etc { + tcx.sess.span_err(span, "union patterns without `..` \ + should have at least one field"); + } + } else if !etc { for field in variant.fields .iter() .filter(|field| !used_fields.contains_key(&field.name)) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e2954cecc9c..f8ee9efee7a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3109,17 +3109,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, variant: ty::VariantDef<'tcx>, field: &hir::Field, - skip_fields: &[hir::Field]) { + skip_fields: &[hir::Field], + kind_name: &str) { let mut err = self.type_error_struct_with_diag( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { struct_span_err!(self.tcx.sess, field.name.span, E0559, - "struct variant `{}::{}` has no field named `{}`", - actual, variant.name.as_str(), field.name.node) + "{} `{}::{}` has no field named `{}`", + kind_name, actual, variant.name.as_str(), field.name.node) } else { struct_span_err!(self.tcx.sess, field.name.span, E0560, - "structure `{}` has no field named `{}`", - actual, field.name.node) + "{} `{}` has no field named `{}`", + kind_name, actual, field.name.node) }, ty); // prevent all specified fields from being suggested @@ -3135,8 +3136,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ast_fields: &'gcx [hir::Field], check_completeness: bool) { let tcx = self.tcx; - let substs = match adt_ty.sty { - ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, + let (substs, kind_name) = match adt_ty.sty { + ty::TyEnum(_, substs) => (substs, "variant"), + ty::TyStruct(_, substs) => (substs, "struct"), + ty::TyUnion(_, substs) => (substs, "union"), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3175,7 +3178,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.emit(); } else { - self.report_unknown_field(adt_ty, variant, field, ast_fields); + self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name); } } @@ -3184,11 +3187,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_coercable_to_type(&field.expr, expected_field_type); } - // Make sure the programmer specified all the fields. - if check_completeness && - !error_happened && - !remaining_fields.is_empty() - { + // Make sure the programmer specified correct number of fields. + if kind_name == "union" { + if ast_fields.len() != 1 { + tcx.sess.span_err(span, "union expressions should have exactly one field"); + } + } else if check_completeness && !error_happened && !remaining_fields.is_empty() { span_err!(tcx.sess, span, E0063, "missing field{} {} in initializer of `{}`", if remaining_fields.len() == 1 {""} else {"s"}, @@ -3198,7 +3202,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .join(", "), adt_ty); } - } fn check_struct_fields_on_error(&self, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 290a59cf1e5..ec9dc1bae5a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5957,8 +5957,10 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Union) { + if self.check_keyword(keywords::Union) && + self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) { // UNION ITEM + self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; let last_span = self.last_span; let item = self.mk_item(lo, diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs index 58d580a5c1a..d5f1614c14d 100644 --- a/src/test/compile-fail/issue-17800.rs +++ b/src/test/compile-fail/issue-17800.rs @@ -18,7 +18,7 @@ enum MyOption { fn main() { match MyOption::MySome(42) { MyOption::MySome { x: 42 } => (), - //~^ ERROR struct `MyOption::MySome` does not have a field named `x` + //~^ ERROR variant `MyOption::MySome` does not have a field named `x` //~| ERROR pattern does not mention field `0` _ => (), } diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs index e3ced302809..a8350fe0986 100644 --- a/src/test/compile-fail/issue-19922.rs +++ b/src/test/compile-fail/issue-19922.rs @@ -14,5 +14,5 @@ enum Homura { fn main() { let homura = Homura::Akemi { kaname: () }; - //~^ ERROR struct variant `Homura::Akemi` has no field named `kaname` + //~^ ERROR variant `Homura::Akemi` has no field named `kaname` } diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs index a8a1b1482fc..c93e75042dd 100644 --- a/src/test/compile-fail/issue-4736.rs +++ b/src/test/compile-fail/issue-4736.rs @@ -13,5 +13,5 @@ struct NonCopyable(()); fn main() { - let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p` + let z = NonCopyable{ p: () }; //~ ERROR struct `NonCopyable` has no field named `p` } diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs index 480d2dcdddd..c4aff9471b8 100644 --- a/src/test/compile-fail/numeric-fields.rs +++ b/src/test/compile-fail/numeric-fields.rs @@ -13,7 +13,7 @@ struct S(u8, u16); fn main() { - let s = S{0b1: 10, 0: 11}; //~ ERROR structure `S` has no field named `0b1` + let s = S{0b1: 10, 0: 11}; //~ ERROR struct `S` has no field named `0b1` match s { S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1` } diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs index 8df9ffd6cc7..5f1f8ca856f 100644 --- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs +++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs @@ -17,7 +17,7 @@ struct A { fn main() { let a = A { foo : 5, - bar : 42,//~ ERROR structure `A` has no field named `bar` + bar : 42,//~ ERROR struct `A` has no field named `bar` //~^ HELP did you mean `barr`? car : 9, }; diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs index 37001f1e60a..4ba1fd2f7bb 100644 --- a/src/test/compile-fail/struct-fields-hints.rs +++ b/src/test/compile-fail/struct-fields-hints.rs @@ -17,7 +17,7 @@ struct A { fn main() { let a = A { foo : 5, - bar : 42,//~ ERROR structure `A` has no field named `bar` + bar : 42,//~ ERROR struct `A` has no field named `bar` //~^ HELP did you mean `car`? }; } diff --git a/src/test/compile-fail/struct-fields-too-many.rs b/src/test/compile-fail/struct-fields-too-many.rs index 9244a9d4f9d..5d16573f2f1 100644 --- a/src/test/compile-fail/struct-fields-too-many.rs +++ b/src/test/compile-fail/struct-fields-too-many.rs @@ -15,6 +15,6 @@ struct BuildData { fn main() { let foo = BuildData { foo: 0, - bar: 0 //~ ERROR structure `BuildData` has no field named `bar` + bar: 0 //~ ERROR struct `BuildData` has no field named `bar` }; } diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs index 9c61f618e69..41bd00a518c 100644 --- a/src/test/compile-fail/suggest-private-fields.rs +++ b/src/test/compile-fail/suggest-private-fields.rs @@ -22,16 +22,16 @@ struct A { fn main () { // external crate struct let k = B { - aa: 20, //~ ERROR structure `xc::B` has no field named `aa` + aa: 20, //~ ERROR struct `xc::B` has no field named `aa` //~^ HELP did you mean `a`? - bb: 20, //~ ERROR structure `xc::B` has no field named `bb` + bb: 20, //~ ERROR struct `xc::B` has no field named `bb` //~^ HELP did you mean `a`? }; // local crate struct let l = A { - aa: 20, //~ ERROR structure `A` has no field named `aa` + aa: 20, //~ ERROR struct `A` has no field named `aa` //~^ HELP did you mean `a`? - bb: 20, //~ ERROR structure `A` has no field named `bb` + bb: 20, //~ ERROR struct `A` has no field named `bb` //~^ HELP did you mean `b`? }; } diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union-empty.rs new file mode 100644 index 00000000000..ce5bbf60fee --- /dev/null +++ b/src/test/compile-fail/union-empty.rs @@ -0,0 +1,15 @@ +// 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)] + +union U {} //~ ERROR unions cannot have zero fields + +fn main() {} diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union-fields.rs new file mode 100644 index 00000000000..2bd1b8a7b32 --- /dev/null +++ b/src/test/compile-fail/union-fields.rs @@ -0,0 +1,34 @@ +// 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)] + +union U { + a: u8, + b: u16, +} + +fn main() { + let u = U {}; //~ ERROR union expressions should have exactly one field + let u = U { a: 0 }; // OK + let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field + let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field + //~^ ERROR union `U` has no field named `c` + let u = U { ..u }; //~ ERROR union expressions should have exactly one field + //~^ ERROR functional record update syntax requires a struct + + let U {} = u; //~ ERROR union patterns without `..` should have at least one field + let U { a } = u; // OK + let U { a, b } = u; //~ ERROR union patterns can have at most one field + let U { a, b, c } = u; //~ ERROR union patterns can have at most one field + //~^ ERROR union `U` does not have a field named `c` + let U { .. } = u; // OK + let U { a, .. } = u; // OK +} diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union-backcomp.rs new file mode 100644 index 00000000000..c1210dd6212 --- /dev/null +++ b/src/test/run-pass/union-backcomp.rs @@ -0,0 +1,23 @@ +// 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)] + +fn main() { + let union = 10; + + union; + + union as u8; + + union U { + a: u8, + } +} diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs index 474c8b4b181..dee86b232b4 100644 --- a/src/test/run-pass/union-basic.rs +++ b/src/test/run-pass/union-basic.rs @@ -25,6 +25,12 @@ union W { b: u64, } +#[repr(C)] +union Y { + f1: u16, + f2: [u8; 4], +} + fn main() { assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 8); @@ -32,6 +38,8 @@ fn main() { assert_eq!(align_of::(), 1); assert_eq!(align_of::(), align_of::()); assert_eq!(align_of::(), align_of::()); + assert_eq!(size_of::(), 4); + assert_eq!(align_of::(), 2); let u = U { a: 10 }; assert_eq!(u.a, 10); diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs new file mode 100644 index 00000000000..467403ff2e1 --- /dev/null +++ b/src/test/run-pass/union-drop.rs @@ -0,0 +1,26 @@ +// 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. + +// Drop works for union itself. + +#![feature(untagged_unions)] + +union U { + a: u8 +} + +impl Drop for U { + fn drop(&mut self) {} +} + +fn main() { + // 'unions are not fully implemented', src/librustc_trans/glue.rs:567 + // let u = U { a: 1 }; +} diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs new file mode 100644 index 00000000000..6b39eed7ac9 --- /dev/null +++ b/src/test/run-pass/union-pat-refutability.rs @@ -0,0 +1,62 @@ +// 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)] + +#[repr(u32)] +enum Tag { I, F } + +#[repr(C)] +union U { + i: i32, + f: f32, +} + +#[repr(C)] +struct Value { + tag: Tag, + u: U, +} + +fn is_zero(v: Value) -> bool { + unsafe { + match v { + Value { tag: Tag::I, u: U { i: 0 } } => true, + Value { tag: Tag::F, u: U { f: 0.0 } } => true, + _ => false, + } + } +} + +union W { + a: u8, + b: u8, +} + +fn refut(w: W) { + match w { + W { a: 10 } => { + panic!(); + } + W { b } => { + assert_eq!(b, 11); + } + } +} + +fn main() { + // ICE + // let v = Value { tag: Tag::I, u: U { i: 1 } }; + // assert_eq!(is_zero(v), false); + + // ICE + // let w = W { a: 11 }; + // refut(w); +} -- cgit 1.4.1-3-g733a5 From e88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Aug 2016 20:12:28 +0300 Subject: Make accesses to union fields unsafe --- src/librustc/middle/effect.rs | 24 ++++++++++++++++++++---- src/test/compile-fail/union-unsafe.rs | 23 +++++++++++++++++++++++ src/test/run-pass/union-basic.rs | 20 ++++++++++++-------- src/test/run-pass/union-pat-refutability.rs | 14 ++++++++------ 4 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/union-unsafe.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 250ad80f5af..e52eba68da1 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -13,15 +13,14 @@ use self::RootUnsafeContext::*; use dep_graph::DepNode; -use hir::def::Def; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use syntax::ast; use syntax_pos::Span; -use hir; -use hir::intravisit; -use hir::intravisit::{FnKind, Visitor}; +use hir::{self, PatKind}; +use hir::def::Def; +use hir::intravisit::{self, FnKind, Visitor}; #[derive(Copy, Clone)] struct UnsafeContext { @@ -178,11 +177,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.require_unsafe(expr.span, "use of mutable static"); } } + hir::ExprField(ref base_expr, field) => { + if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty { + self.require_unsafe(field.span, "access to union field"); + } + } _ => {} } intravisit::walk_expr(self, expr); } + + fn visit_pat(&mut self, pat: &hir::Pat) { + if let PatKind::Struct(_, ref fields, _) = pat.node { + if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty { + for field in fields { + self.require_unsafe(field.span, "matching on union field"); + } + } + } + + intravisit::walk_pat(self, pat); + } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union-unsafe.rs new file mode 100644 index 00000000000..762ac5d8751 --- /dev/null +++ b/src/test/compile-fail/union-unsafe.rs @@ -0,0 +1,23 @@ +// 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)] + +union U { + a: u8 +} + +fn main() { + let u = U { a: 10 }; // OK + let a = u.a; //~ ERROR access to union field requires unsafe function or block + let U { a } = u; //~ ERROR matching on union field requires unsafe function or block + if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block + let U { .. } = u; // OK +} diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs index dee86b232b4..afbfe5bf92b 100644 --- a/src/test/run-pass/union-basic.rs +++ b/src/test/run-pass/union-basic.rs @@ -42,14 +42,18 @@ fn main() { assert_eq!(align_of::(), 2); let u = U { a: 10 }; - assert_eq!(u.a, 10); - let U { a } = u; - assert_eq!(a, 10); + unsafe { + assert_eq!(u.a, 10); + let U { a } = u; + assert_eq!(a, 10); + } let mut w: W = unsafe { zeroed() }; - assert_eq!(w.a, 0); - assert_eq!(w.b, 0); - // w.a = 1; - // assert_eq!(w.a, 0); - // assert_eq!(w.b, 0); + unsafe { + assert_eq!(w.a, 0); + assert_eq!(w.b, 0); + // w.a = 1; + // assert_eq!(w.a, 0); + // assert_eq!(w.b, 0); + } } diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs index 6b39eed7ac9..a57c1103a9b 100644 --- a/src/test/run-pass/union-pat-refutability.rs +++ b/src/test/run-pass/union-pat-refutability.rs @@ -41,12 +41,14 @@ union W { } fn refut(w: W) { - match w { - W { a: 10 } => { - panic!(); - } - W { b } => { - assert_eq!(b, 11); + unsafe { + match w { + W { a: 10 } => { + panic!(); + } + W { b } => { + assert_eq!(b, 11); + } } } } -- cgit 1.4.1-3-g733a5 From bea0b15935a8cb5811eb80e3220e9ab786feb782 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 19 Aug 2016 19:20:30 +0300 Subject: Implement drop translation and add lint for unions with drop fields Fix some typeck bugs blocking drop tests --- src/librustc_lint/builtin.rs | 33 ++++++++++++++++ src/librustc_lint/lib.rs | 1 + src/librustc_trans/glue.rs | 17 +++++--- src/librustc_typeck/check/mod.rs | 9 ++--- src/librustc_typeck/collect.rs | 3 +- .../compile-fail/union-with-drop-fields-lint.rs | 40 +++++++++++++++++++ src/test/run-pass/union-drop.rs | 45 ++++++++++++++++++++-- 7 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/union-with-drop-fields-lint.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b55cad58e2f..1702c1c0edc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1164,3 +1164,36 @@ impl LateLintPass for UnstableFeatures { } } } + +/// Lint for unions that contain fields with possibly non-trivial destructors. +pub struct UnionsWithDropFields; + +declare_lint! { + UNIONS_WITH_DROP_FIELDS, + Warn, + "use of unions that contain fields with possibly non-trivial drop code" +} + +impl LintPass for UnionsWithDropFields { + fn get_lints(&self) -> LintArray { + lint_array!(UNIONS_WITH_DROP_FIELDS) + } +} + +impl LateLintPass for UnionsWithDropFields { + fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { + if let hir::ItemUnion(ref vdata, _) = item.node { + let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); + for field in vdata.fields() { + let field_ty = ctx.tcx.node_id_to_type(field.id); + if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { + ctx.span_lint(UNIONS_WITH_DROP_FIELDS, + field.span, + "union contains a field with possibly non-trivial drop code, \ + drop code of union fields is ignored when dropping the union"); + return; + } + } + } + } +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 0f0e9cfb357..c3b752d605f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -128,6 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { InvalidNoMangleItems, PluginAsLibrary, MutableTransmutes, + UnionsWithDropFields, ); add_builtin_with_new!(sess, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 5da9ef3646e..0d62a63b89f 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -267,7 +267,8 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, - v0: ValueRef) + v0: ValueRef, + shallow_drop: bool) -> Block<'blk, 'tcx> { debug!("trans_struct_drop t: {}", t); @@ -286,7 +287,9 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Issue #23611: schedule cleanup of contents, re-inspecting the // discriminant (if any) in case of variant swap in drop code. - bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t); + if !shallow_drop { + bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t); + } let (sized_args, unsized_args); let args: &[ValueRef] = if type_is_sized(tcx, t) { @@ -470,9 +473,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) } } - ty::TyUnion(..) => { - unimplemented_unions!(); - } ty::TyTrait(..) => { // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is @@ -491,6 +491,13 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK if def.dtor_kind().is_present() && !skip_dtor => { trans_struct_drop(bcx, t, v0) } + ty::TyUnion(def, _) => { + if def.dtor_kind().is_present() && !skip_dtor { + trans_struct_drop(bcx, t, v0, true) + } else { + bcx + } + } _ => { if bcx.fcx.type_needs_drop(t) { drop_structural_ty(bcx, v0, t) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f8ee9efee7a..f4fea5542b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3235,11 +3235,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some((type_did, self.tcx.expect_variant_def(def))) } Def::TyAlias(did) => { - if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did) - .map(|scheme| &scheme.ty.sty) { - Some((did, adt.struct_variant())) - } else { - None + match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) { + Some(&ty::TyStruct(adt, _)) | + Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())), + _ => None, } } _ => None diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a100c919d6f..31f28b3803d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1450,7 +1450,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ItemTy(_, ref generics) | ItemEnum(_, ref generics) | - ItemStruct(_, ref generics) => { + ItemStruct(_, ref generics) | + ItemUnion(_, ref generics) => { allow_defaults = true; generics } diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union-with-drop-fields-lint.rs new file mode 100644 index 00000000000..87a72efbe08 --- /dev/null +++ b/src/test/compile-fail/union-with-drop-fields-lint.rs @@ -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 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(dead_code)] +#![deny(unions_with_drop_fields)] + +union U { + a: u8, // OK +} + +union W { + a: String, //~ ERROR union contains a field with possibly non-trivial drop code + b: String, // OK, only one field is reported +} + +struct S(String); + +// `S` doesn't implement `Drop` trait, but still has non-trivial destructor +union Y { + a: S, //~ ERROR union contains a field with possibly non-trivial drop code +} + +// We don't know if `T` is trivially-destructable or not until trans +union J { + a: T, //~ ERROR union contains a field with possibly non-trivial drop code +} + +union H { + a: T, // OK, `T` is `Copy`, no destructor +} + +fn main() {} diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs index 467403ff2e1..2ca68dc3b6e 100644 --- a/src/test/run-pass/union-drop.rs +++ b/src/test/run-pass/union-drop.rs @@ -12,15 +12,54 @@ #![feature(untagged_unions)] +struct S; + union U { a: u8 } +union W { + a: S, +} + +union Y { + a: S, +} + +impl Drop for S { + fn drop(&mut self) { + unsafe { CHECK += 10; } + } +} + impl Drop for U { - fn drop(&mut self) {} + fn drop(&mut self) { + unsafe { CHECK += 1; } + } } +impl Drop for W { + fn drop(&mut self) { + unsafe { CHECK += 1; } + } +} + +static mut CHECK: u8 = 0; + fn main() { - // 'unions are not fully implemented', src/librustc_trans/glue.rs:567 - // let u = U { a: 1 }; + unsafe { + assert_eq!(CHECK, 0); + { + let u = U { a: 1 }; + } + assert_eq!(CHECK, 1); // 1, dtor of U is called + { + let w = W { a: S }; + } + assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called + { + let y = Y { a: S }; + } + assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called + } } -- cgit 1.4.1-3-g733a5 From d9b332bd69770cb716233b6998b11d345f6f184b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 22 Aug 2016 19:56:14 +0300 Subject: Translate union constants Fix alignment for packed unions Add some missing privacy test Get rid of `unimplemented_unions` macro --- src/librustc_const_eval/eval.rs | 7 ++- src/librustc_privacy/lib.rs | 5 +- src/librustc_trans/adt.rs | 23 +++++++-- src/librustc_trans/debuginfo/metadata.rs | 9 ++-- src/libsyntax/diagnostics/macros.rs | 7 --- src/libsyntax/feature_gate.rs | 2 +- src/test/compile-fail/union-const-eval.rs | 26 ++++++++++ src/test/compile-fail/union-const-pat.rs | 25 ++++++++++ src/test/compile-fail/union-field-privacy.rs | 21 ++++++++ src/test/run-pass/union-const-trans.rs | 27 ++++++++++ src/test/run-pass/union-packed.rs | 74 ++++++++++++++++++++++++++++ 11 files changed, 206 insertions(+), 20 deletions(-) create mode 100644 src/test/compile-fail/union-const-eval.rs create mode 100644 src/test/compile-fail/union-const-pat.rs create mode 100644 src/test/compile-fail/union-field-privacy.rs create mode 100644 src/test/run-pass/union-const-trans.rs create mode 100644 src/test/run-pass/union-packed.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 81fe19812ca..114b5e1331d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -258,8 +258,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, format!("floating point constants cannot be used in patterns")); } ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) => { + ty::TyStruct(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, @@ -272,6 +271,10 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(adt_def.did))); } } + ty::TyUnion(..) => { + // Matching on union fields is unsafe, we can't hide it in constants + tcx.sess.span_err(span, "cannot use unions in constant patterns"); + } _ => { } } let pat = match expr.node { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 25601b6bfec..6b291c69307 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -385,8 +385,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { if def.adt_kind() != ty::AdtKind::Enum && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { - struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private", - field.name, self.tcx.item_path_str(def.did)) + let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" }; + struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", + field.name, kind_descr, self.tcx.item_path_str(def.did)) .span_label(span, &format!("field `{}` is private", field.name)) .emit(); } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index abbb9a5d4db..7fd02ab82a3 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -516,7 +516,7 @@ fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Union { min_size: min_size, - align: align, + align: if packed { 1 } else { align }, packed: packed, fields: tys.to_vec(), } @@ -1176,8 +1176,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]); C_struct(ccx, &contents[..], false) } - UntaggedUnion(..) => { - unimplemented_unions!(); + UntaggedUnion(ref un) => { + assert_eq!(discr, Disr(0)); + let contents = build_const_union(ccx, un, vals[0]); + C_struct(ccx, &contents, un.packed) } Univariant(ref st) => { assert_eq!(discr, Disr(0)); @@ -1272,6 +1274,21 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, cfields } +fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + un: &Union<'tcx>, + field_val: ValueRef) + -> Vec { + let mut cfields = vec![field_val]; + + let offset = machine::llsize_of_alloc(ccx, val_ty(field_val)); + let size = roundup(un.min_size, un.align); + if offset != size { + cfields.push(padding(ccx, size - offset)); + } + + cfields +} + fn padding(ccx: &CrateContext, size: u64) -> ValueRef { C_undef(Type::array(&Type::i8(ccx), size)) } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index bd67a215d65..00493b018c1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -786,7 +786,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, usage_site_span).finalize(cx) } ty::TyUnion(..) => { - unimplemented_unions!(); + unimplemented!(); } ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, @@ -1302,9 +1302,6 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { ] } } - adt::UntaggedUnion(..) => { - unimplemented_unions!(); - } adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => { // As far as debuginfo is concerned, the pointer this enum // represents is still wrapped in a struct. This is to make the @@ -1421,7 +1418,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { } ] }, - adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.") + adt::CEnum(..) | adt::UntaggedUnion(..) => { + span_bug!(self.span, "This should be unreachable.") + } } } } diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index e2a7ec0a33d..25e0428248d 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -107,13 +107,6 @@ macro_rules! help { }) } -#[macro_export] -macro_rules! unimplemented_unions { - () => ({ - panic!("unions are not fully implemented"); - }) -} - #[macro_export] macro_rules! register_diagnostics { ($($code:tt),*) => ( diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b40124bd774..287d33cc3e5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -959,7 +959,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ast::ItemKind::Union(..) => { gate_feature_post!(&self, untagged_unions, i.span, - "unions are unstable and not fully implemented"); + "unions are unstable and possibly buggy"); } ast::ItemKind::DefaultImpl(..) => { diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union-const-eval.rs new file mode 100644 index 00000000000..b2bf173c59c --- /dev/null +++ b/src/test/compile-fail/union-const-eval.rs @@ -0,0 +1,26 @@ +// 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)] + +union U { + a: usize, + b: usize, +} + +const C: U = U { a: 10 }; + +fn main() { + unsafe { + let a: [u8; C.a]; // OK + let b: [u8; C.b]; //~ ERROR constant evaluation error + //~^ NOTE nonexistent struct field + } +} diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union-const-pat.rs new file mode 100644 index 00000000000..3d168980ed2 --- /dev/null +++ b/src/test/compile-fail/union-const-pat.rs @@ -0,0 +1,25 @@ +// 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)] + +union U { + a: usize, + b: usize, +} + +const C: U = U { a: 10 }; + +fn main() { + match C { + C => {} //~ ERROR cannot use unions in constant patterns + _ => {} + } +} diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/compile-fail/union-field-privacy.rs new file mode 100644 index 00000000000..d1f2bbbc3d0 --- /dev/null +++ b/src/test/compile-fail/union-field-privacy.rs @@ -0,0 +1,21 @@ +// 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)] + +mod m { + pub union U { + a: u8 + } +} + +fn main() { + let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private +} diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union-const-trans.rs new file mode 100644 index 00000000000..bdae1a0eaf8 --- /dev/null +++ b/src/test/run-pass/union-const-trans.rs @@ -0,0 +1,27 @@ +// 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)] + +union U { + a: u64, + b: u64, +} + +const C: U = U { b: 10 }; + +fn main() { + unsafe { + let a = C.a; + let b = C.b; + assert_eq!(a, 10); + assert_eq!(b, 10); + } +} diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union-packed.rs new file mode 100644 index 00000000000..b1650ae3a7c --- /dev/null +++ b/src/test/run-pass/union-packed.rs @@ -0,0 +1,74 @@ +// 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)] + +use std::mem::{size_of, size_of_val, align_of, align_of_val}; + +struct S { + a: u16, + b: [u8; 3], +} + +#[repr(packed)] +struct Sp { + a: u16, + b: [u8; 3], +} + +union U { + a: u16, + b: [u8; 3], +} + +#[repr(packed)] +union Up { + a: u16, + b: [u8; 3], +} + +const CS: S = S { a: 0, b: [0, 0, 0] }; +const CSP: Sp = Sp { a: 0, b: [0, 0, 0] }; +const CU: U = U { b: [0, 0, 0] }; +const CUP: Up = Up { b: [0, 0, 0] }; + +fn main() { + let s = S { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 6); + assert_eq!(size_of_val(&s), 6); + assert_eq!(size_of_val(&CS), 6); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&s), 2); + assert_eq!(align_of_val(&CS), 2); + + let sp = Sp { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 5); + assert_eq!(size_of_val(&sp), 5); + assert_eq!(size_of_val(&CSP), 5); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&sp), 1); + assert_eq!(align_of_val(&CSP), 1); + + let u = U { b: [0, 0, 0] }; + assert_eq!(size_of::(), 4); + assert_eq!(size_of_val(&u), 4); + assert_eq!(size_of_val(&CU), 4); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&u), 2); + assert_eq!(align_of_val(&CU), 2); + + let up = Up { b: [0, 0, 0] }; + assert_eq!(size_of::(), 3); + assert_eq!(size_of_val(&up), 3); + assert_eq!(size_of_val(&CUP), 3); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&up), 1); + assert_eq!(align_of_val(&CUP), 1); +} -- cgit 1.4.1-3-g733a5 From 59ccb7b6dbaf3a590cf3a234661aa7dcc2188aed Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Aug 2016 21:10:19 +0300 Subject: Support deriving some traits for unions --- src/libsyntax_ext/deriving/generic/mod.rs | 11 ++++++++++- src/test/compile-fail/union-derive.rs | 30 ++++++++++++++++++++++++++++++ src/test/run-pass/union-derive.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/union-derive.rs create mode 100644 src/test/run-pass/union-derive.rs (limited to 'src/test/compile-fail') diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 5c636d43a71..b37d5332983 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -410,9 +410,18 @@ impl<'a> TraitDef<'a> { ast::ItemKind::Enum(ref enum_def, ref generics) => { self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics) } + ast::ItemKind::Union(ref struct_def, ref generics) => { + if self.supports_unions { + self.expand_struct_def(cx, &struct_def, item.ident, generics) + } else { + cx.span_err(mitem.span, + "this trait cannot be derived for unions"); + return; + } + } _ => { cx.span_err(mitem.span, - "`derive` may only be applied to structs and enums"); + "`derive` may only be applied to structs, enums and unions"); return; } }; diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union-derive.rs new file mode 100644 index 00000000000..0f78e96f640 --- /dev/null +++ b/src/test/compile-fail/union-derive.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Most traits cannot be derived for unions. + +#![feature(untagged_unions)] + +#[derive( + Clone, //~ ERROR this trait cannot be derived for unions + PartialEq, //~ ERROR this trait cannot be derived for unions + Eq, //~ ERROR this trait cannot be derived for unions + PartialOrd, //~ ERROR this trait cannot be derived for unions + Ord, //~ ERROR this trait cannot be derived for unions + Hash, //~ ERROR this trait cannot be derived for unions + Default, //~ ERROR this trait cannot be derived for unions + Debug, //~ ERROR this trait cannot be derived for unions +)] +union U { + a: u8, + b: u16, +} + +fn main() {} diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union-derive.rs new file mode 100644 index 00000000000..b71c23990a4 --- /dev/null +++ b/src/test/run-pass/union-derive.rs @@ -0,0 +1,31 @@ +// 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. + +// Some traits can be derived for unions. + +#![feature(untagged_unions)] + +#[derive( + Copy, +)] +union U { + a: u8, + b: u16, +} + +impl Clone for U { + fn clone(&self) -> Self { *self } +} + +fn main() { + let u = U { b: 0 }; + let u1 = u; + let u2 = u.clone(); +} -- cgit 1.4.1-3-g733a5 From 5f975e969b46278669940aa60e5aea50ba588531 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 16:54:58 +0300 Subject: Support unions in borrow checker Add some more tests --- src/librustc_borrowck/borrowck/fragments.rs | 4 + .../borrowck/gather_loans/restrictions.rs | 30 ++++++- src/librustc_borrowck/borrowck/mod.rs | 5 -- src/librustc_borrowck/borrowck/move_data.rs | 57 ++++++++++++- src/test/compile-fail/union-borrow-nested.rs | 44 ++++++++++ src/test/compile-fail/union-borrow.rs | 97 ++++++++++++++++++++++ src/test/compile-fail/union-move-assign.rs | 42 ++++++++++ src/test/compile-fail/union-move.rs | 96 +++++++++++++++++++++ src/test/compile-fail/union-uninitialized.rs | 30 +++++++ src/test/run-pass/union-basic.rs | 6 +- src/test/run-pass/union-drop-assign.rs | 44 ++++++++++ src/test/run-pass/union-transmute.rs | 40 +++++++++ 12 files changed, 484 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/union-borrow-nested.rs create mode 100644 src/test/compile-fail/union-borrow.rs create mode 100644 src/test/compile-fail/union-move-assign.rs create mode 100644 src/test/compile-fail/union-move.rs create mode 100644 src/test/compile-fail/union-uninitialized.rs create mode 100644 src/test/run-pass/union-drop-assign.rs create mode 100644 src/test/run-pass/union-transmute.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index a8993724e67..86f396d8982 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -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), diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index d08f792b30c..6193157fa7b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -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 => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 67152ed04ec..f5e20285e0c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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 { diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index c9822a4fee7..b13291b8419 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -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>, 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>, + 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>, + 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); diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/union-borrow-nested.rs new file mode 100644 index 00000000000..19975d79b60 --- /dev/null +++ b/src/test/compile-fail/union-borrow-nested.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/union-borrow.rs new file mode 100644 index 00000000000..e8989a3c2d4 --- /dev/null +++ b/src/test/compile-fail/union-borrow.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/union-move-assign.rs new file mode 100644 index 00000000000..d4d7bc6b0f7 --- /dev/null +++ b/src/test/compile-fail/union-move-assign.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/union-move.rs new file mode 100644 index 00000000000..5320244cf43 --- /dev/null +++ b/src/test/compile-fail/union-move.rs @@ -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 or the MIT license +// , 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` + } + } +} diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/union-uninitialized.rs new file mode 100644 index 00000000000..36e062f8464 --- /dev/null +++ b/src/test/compile-fail/union-uninitialized.rs @@ -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 or the MIT license +// , 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` + } +} diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs index a00bd73115a..1651aa901b9 100644 --- a/src/test/run-pass/union-basic.rs +++ b/src/test/run-pass/union-basic.rs @@ -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); } } diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union-drop-assign.rs new file mode 100644 index 00000000000..0da68e43f32 --- /dev/null +++ b/src/test/run-pass/union-drop-assign.rs @@ -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 or the MIT license +// , 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 + } +} diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union-transmute.rs new file mode 100644 index 00000000000..4eb66268ab8 --- /dev/null +++ b/src/test/run-pass/union-transmute.rs @@ -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 or the MIT license +// , 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); + } +} -- cgit 1.4.1-3-g733a5 From e67c2282afa3c527da49618b928280564e92868f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: Fix rebase, fix some tests --- src/librustc_trans/adt.rs | 4 ++-- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/test/compile-fail/deriving-non-type.rs | 18 +++++++++--------- src/test/debuginfo/union-smoke.rs | 17 +++++++++-------- src/test/incremental/struct_change_field_name.rs | 2 +- 6 files changed, 23 insertions(+), 22 deletions(-) (limited to 'src/test/compile-fail') diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 7fd02ab82a3..15a9d58c9b5 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -749,12 +749,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; match name { None => { - TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed)) + Type::struct_(cx, &[fill_ty], un.packed) } Some(name) => { let mut llty = Type::named_struct(cx, name); llty.set_struct_body(&[fill_ty], un.packed); - TypeContext::direct(llty) + llty } } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index a3a7a79fb58..20a33498475 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyStruct(..) | ty::TyEnum(..) => { + ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 0d62a63b89f..bb77db8fd69 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -489,7 +489,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK } ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.dtor_kind().is_present() && !skip_dtor => { - trans_struct_drop(bcx, t, v0) + trans_struct_drop(bcx, t, v0, false) } ty::TyUnion(def, _) => { if def.dtor_kind().is_present() && !skip_dtor { diff --git a/src/test/compile-fail/deriving-non-type.rs b/src/test/compile-fail/deriving-non-type.rs index 5b215f3ccd9..84dd22435b8 100644 --- a/src/test/compile-fail/deriving-non-type.rs +++ b/src/test/compile-fail/deriving-non-type.rs @@ -12,29 +12,29 @@ struct S; -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions trait T { } -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions impl S { } -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions impl T for S { } -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions static s: usize = 0; -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions const c: usize = 0; -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions mod m { } -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions extern "C" { } -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions type A = usize; -#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums +#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions fn main() { } diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs index 11ee5031ca7..17dea300ff9 100644 --- a/src/test/debuginfo/union-smoke.rs +++ b/src/test/debuginfo/union-smoke.rs @@ -16,17 +16,17 @@ // gdb-command:run // gdb-command:print u -// gdb-check:$1 = {a = 11 '\v', b = 11} +// gdb-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} // gdb-command:print union_smoke::SU -// gdb-check:$2 = {a = 10 '\n', b = 10} +// gdb-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print a -// lldb-check:[...]$0 = {a = 11 '\v', b = 11} +// lldb-check:[...]$0 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} // lldb-command:print union_smoke::SU -// lldb-check:[...]$1 = {a = 10 '\n', b = 10} +// lldb-check:[...]$1 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} #![allow(unused)] #![feature(omit_gdb_pretty_printer_section)] @@ -34,14 +34,15 @@ #![feature(untagged_unions)] union U { - a: u8, - b: u64, + a: (u8, u8), + b: u16, } -static SU: U = U { a: 10 }; +static mut SU: U = U { a: (1, 1) }; fn main() { - let u = U { b: 11 }; + let u = U { b: (2 << 8) + 2 }; + unsafe { SU = U { a: (1, 1) } } zzz(); // #break } diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index ba469c62002..c27294442e7 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -37,7 +37,7 @@ pub struct Y { #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; - //[cfail2]~^ ERROR structure `X` has no field named `x` + //[cfail2]~^ ERROR struct `X` has no field named `x` x.x as u32 //[cfail2]~^ ERROR attempted access of field `x` } -- cgit 1.4.1-3-g733a5 From 93067ca089ea570e4e2bdfc456958c81a4d1e092 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: Address comments and add requested tests --- src/librustc/middle/expr_use_visitor.rs | 43 ++++----- src/librustc/ty/mod.rs | 2 +- .../borrowck/gather_loans/restrictions.rs | 1 + src/librustc_borrowck/borrowck/move_data.rs | 12 +-- src/librustc_privacy/lib.rs | 23 +++-- src/librustc_trans/glue.rs | 8 +- src/librustc_typeck/check/_match.rs | 9 +- src/rt/rust_test_helpers.c | 21 +++++ .../borrowck/borrowck-union-borrow-nested.rs | 44 +++++++++ .../compile-fail/borrowck/borrowck-union-borrow.rs | 97 +++++++++++++++++++ .../borrowck/borrowck-union-move-assign.rs | 42 +++++++++ .../compile-fail/borrowck/borrowck-union-move.rs | 96 +++++++++++++++++++ .../borrowck/borrowck-union-uninitialized.rs | 30 ++++++ .../compile-fail/privacy/union-field-privacy-1.rs | 30 ++++++ .../compile-fail/privacy/union-field-privacy-2.rs | 28 ++++++ src/test/compile-fail/union-borrow-nested.rs | 44 --------- src/test/compile-fail/union-borrow.rs | 97 ------------------- src/test/compile-fail/union-const-eval.rs | 26 ------ src/test/compile-fail/union-const-pat.rs | 25 ----- src/test/compile-fail/union-derive.rs | 30 ------ src/test/compile-fail/union-empty.rs | 15 --- src/test/compile-fail/union-field-privacy.rs | 21 ----- src/test/compile-fail/union-fields.rs | 34 ------- src/test/compile-fail/union-move-assign.rs | 42 --------- src/test/compile-fail/union-move.rs | 96 ------------------- src/test/compile-fail/union-nonrepresentable.rs | 18 ---- src/test/compile-fail/union-uninitialized.rs | 30 ------ src/test/compile-fail/union-unsafe.rs | 23 ----- src/test/compile-fail/union-unsized.rs | 17 ---- .../compile-fail/union-with-drop-fields-lint.rs | 40 -------- src/test/compile-fail/union/union-const-eval.rs | 26 ++++++ src/test/compile-fail/union/union-const-pat.rs | 25 +++++ src/test/compile-fail/union/union-copy.rs | 26 ++++++ src/test/compile-fail/union/union-derive.rs | 30 ++++++ src/test/compile-fail/union/union-empty.rs | 15 +++ src/test/compile-fail/union/union-feature-gate.rs | 15 +++ src/test/compile-fail/union/union-fields.rs | 35 +++++++ src/test/compile-fail/union/union-generic.rs | 24 +++++ .../compile-fail/union/union-nonrepresentable.rs | 18 ++++ src/test/compile-fail/union/union-repr-c.rs | 29 ++++++ src/test/compile-fail/union/union-suggest-field.rs | 29 ++++++ src/test/compile-fail/union/union-unsafe.rs | 24 +++++ src/test/compile-fail/union/union-unsized.rs | 23 +++++ .../union/union-with-drop-fields-lint.rs | 40 ++++++++ src/test/run-pass/auxiliary/union.rs | 16 ---- src/test/run-pass/union-backcomp.rs | 23 ----- src/test/run-pass/union-basic.rs | 59 ------------ src/test/run-pass/union-const-trans.rs | 27 ------ src/test/run-pass/union-derive.rs | 31 ------ src/test/run-pass/union-drop-assign.rs | 44 --------- src/test/run-pass/union-drop.rs | 65 ------------- src/test/run-pass/union-packed.rs | 74 --------------- src/test/run-pass/union-pat-refutability.rs | 62 ------------ src/test/run-pass/union-transmute.rs | 40 -------- src/test/run-pass/union-xcrate.rs | 21 ----- src/test/run-pass/union/auxiliary/union.rs | 16 ++++ src/test/run-pass/union/union-backcomp.rs | 27 ++++++ src/test/run-pass/union/union-basic.rs | 59 ++++++++++++ src/test/run-pass/union/union-c-interop.rs | 47 ++++++++++ src/test/run-pass/union/union-const-trans.rs | 27 ++++++ src/test/run-pass/union/union-derive.rs | 31 ++++++ src/test/run-pass/union/union-drop-assign.rs | 44 +++++++++ src/test/run-pass/union/union-drop.rs | 65 +++++++++++++ src/test/run-pass/union/union-generic.rs | 43 +++++++++ src/test/run-pass/union/union-inherent-method.rs | 24 +++++ src/test/run-pass/union/union-macro.rs | 33 +++++++ src/test/run-pass/union/union-overwrite.rs | 80 ++++++++++++++++ src/test/run-pass/union/union-packed.rs | 104 +++++++++++++++++++++ src/test/run-pass/union/union-pat-refutability.rs | 62 ++++++++++++ src/test/run-pass/union/union-trait-impl.rs | 27 ++++++ src/test/run-pass/union/union-transmute.rs | 40 ++++++++ .../run-pass/union/union-with-drop-fields-lint.rs | 42 +++++++++ src/test/run-pass/union/union-xcrate.rs | 21 +++++ 73 files changed, 1589 insertions(+), 1068 deletions(-) create mode 100644 src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs create mode 100644 src/test/compile-fail/borrowck/borrowck-union-borrow.rs create mode 100644 src/test/compile-fail/borrowck/borrowck-union-move-assign.rs create mode 100644 src/test/compile-fail/borrowck/borrowck-union-move.rs create mode 100644 src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs create mode 100644 src/test/compile-fail/privacy/union-field-privacy-1.rs create mode 100644 src/test/compile-fail/privacy/union-field-privacy-2.rs delete mode 100644 src/test/compile-fail/union-borrow-nested.rs delete mode 100644 src/test/compile-fail/union-borrow.rs delete mode 100644 src/test/compile-fail/union-const-eval.rs delete mode 100644 src/test/compile-fail/union-const-pat.rs delete mode 100644 src/test/compile-fail/union-derive.rs delete mode 100644 src/test/compile-fail/union-empty.rs delete mode 100644 src/test/compile-fail/union-field-privacy.rs delete mode 100644 src/test/compile-fail/union-fields.rs delete mode 100644 src/test/compile-fail/union-move-assign.rs delete mode 100644 src/test/compile-fail/union-move.rs delete mode 100644 src/test/compile-fail/union-nonrepresentable.rs delete mode 100644 src/test/compile-fail/union-uninitialized.rs delete mode 100644 src/test/compile-fail/union-unsafe.rs delete mode 100644 src/test/compile-fail/union-unsized.rs delete mode 100644 src/test/compile-fail/union-with-drop-fields-lint.rs create mode 100644 src/test/compile-fail/union/union-const-eval.rs create mode 100644 src/test/compile-fail/union/union-const-pat.rs create mode 100644 src/test/compile-fail/union/union-copy.rs create mode 100644 src/test/compile-fail/union/union-derive.rs create mode 100644 src/test/compile-fail/union/union-empty.rs create mode 100644 src/test/compile-fail/union/union-feature-gate.rs create mode 100644 src/test/compile-fail/union/union-fields.rs create mode 100644 src/test/compile-fail/union/union-generic.rs create mode 100644 src/test/compile-fail/union/union-nonrepresentable.rs create mode 100644 src/test/compile-fail/union/union-repr-c.rs create mode 100644 src/test/compile-fail/union/union-suggest-field.rs create mode 100644 src/test/compile-fail/union/union-unsafe.rs create mode 100644 src/test/compile-fail/union/union-unsized.rs create mode 100644 src/test/compile-fail/union/union-with-drop-fields-lint.rs delete mode 100644 src/test/run-pass/auxiliary/union.rs delete mode 100644 src/test/run-pass/union-backcomp.rs delete mode 100644 src/test/run-pass/union-basic.rs delete mode 100644 src/test/run-pass/union-const-trans.rs delete mode 100644 src/test/run-pass/union-derive.rs delete mode 100644 src/test/run-pass/union-drop-assign.rs delete mode 100644 src/test/run-pass/union-drop.rs delete mode 100644 src/test/run-pass/union-packed.rs delete mode 100644 src/test/run-pass/union-pat-refutability.rs delete mode 100644 src/test/run-pass/union-transmute.rs delete mode 100644 src/test/run-pass/union-xcrate.rs create mode 100644 src/test/run-pass/union/auxiliary/union.rs create mode 100644 src/test/run-pass/union/union-backcomp.rs create mode 100644 src/test/run-pass/union/union-basic.rs create mode 100644 src/test/run-pass/union/union-c-interop.rs create mode 100644 src/test/run-pass/union/union-const-trans.rs create mode 100644 src/test/run-pass/union/union-derive.rs create mode 100644 src/test/run-pass/union/union-drop-assign.rs create mode 100644 src/test/run-pass/union/union-drop.rs create mode 100644 src/test/run-pass/union/union-generic.rs create mode 100644 src/test/run-pass/union/union-inherent-method.rs create mode 100644 src/test/run-pass/union/union-macro.rs create mode 100644 src/test/run-pass/union/union-overwrite.rs create mode 100644 src/test/run-pass/union/union-packed.rs create mode 100644 src/test/run-pass/union/union-pat-refutability.rs create mode 100644 src/test/run-pass/union/union-trait-impl.rs create mode 100644 src/test/run-pass/union/union-transmute.rs create mode 100644 src/test/run-pass/union/union-with-drop-fields-lint.rs create mode 100644 src/test/run-pass/union/union-xcrate.rs (limited to 'src/test/compile-fail') diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a6835802f1c..541aeeb7d8d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -671,31 +671,28 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_cmt.ty.sty { - ty::TyStruct(def, substs) => { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); - } + if let ty::TyStruct(def, substs) = with_cmt.ty.sty { + // Consume those fields of the with expression that are needed. + for with_field in &def.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); } } - _ => { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); - } + } else { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ee2188e8e11..e88f72f2d84 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1423,7 +1423,7 @@ bitflags! { const IS_PHANTOM_DATA = 1 << 3, const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, - const IS_UNION = 1 << 7, + const IS_UNION = 1 << 6, } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 6193157fa7b..c08dc9330b8 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -102,6 +102,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let interior = interior.cleaned(); let base_ty = cmt_base.ty; let result = self.restrict(cmt_base); + // Borrowing one union field automatically borrows all its fields. if let ty::TyUnion(ref adt_def, _) = base_ty.sty { match result { RestrictionResult::Safe => RestrictionResult::Safe, diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index b13291b8419..236a1a2835c 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -442,12 +442,12 @@ impl<'a, 'tcx> MoveData<'tcx> { 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>, - assign_id: ast::NodeId, - span: Span, - assignee_id: ast::NodeId, - mode: euv::MutateMode) { + fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + lp: Rc>, + 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); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6b291c69307..179863c16ff 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -429,19 +429,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { let method = self.tcx.tables.borrow().method_map[&method_call]; self.check_method(expr.span, method.def_id); } - hir::ExprStruct(_, ref fields, _) => { + hir::ExprStruct(_, ref expr_fields, _) => { let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(expr.id)); // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields - // (i.e. `all_fields - fields`), just check them all. - for field in variant.fields.iter() { - let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) { - f.span - } else { - expr.span - }; - self.check_field(span, adt, field); + // (i.e. `all_fields - fields`), just check them all, + // unless the ADT is a union, then unmentioned fields + // are not checked. + if adt.adt_kind() == ty::AdtKind::Union { + for expr_field in expr_fields { + self.check_field(expr.span, adt, variant.field_named(expr_field.name.node)); + } + } else { + for field in &variant.fields { + let expr_field = expr_fields.iter().find(|f| f.name.node == field.name); + let span = if let Some(f) = expr_field { f.span } else { expr.span }; + self.check_field(span, adt, field); + } } } hir::ExprPath(..) => { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index bb77db8fd69..34c92f334d0 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -265,13 +265,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fcx.finish(bcx, DebugLoc::None); } -fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, shallow_drop: bool) -> Block<'blk, 'tcx> { - debug!("trans_struct_drop t: {}", t); + debug!("trans_custom_dtor t: {}", t); let tcx = bcx.tcx(); let mut bcx = bcx; @@ -489,11 +489,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK } ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.dtor_kind().is_present() && !skip_dtor => { - trans_struct_drop(bcx, t, v0, false) + trans_custom_dtor(bcx, t, v0, false) } ty::TyUnion(def, _) => { if def.dtor_kind().is_present() && !skip_dtor { - trans_struct_drop(bcx, t, v0, true) + trans_custom_dtor(bcx, t, v0, true) } else { bcx } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5c19fa2a66c..12fce4b928e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -718,12 +718,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Report an error if incorrect number of the fields were specified. if kind_name == "union" { - if fields.len() > 1 { - tcx.sess.span_err(span, "union patterns can have at most one field"); + if fields.len() != 1 { + tcx.sess.span_err(span, "union patterns should have exactly one field"); } - if fields.is_empty() && !etc { - tcx.sess.span_err(span, "union patterns without `..` \ - should have at least one field"); + if etc { + tcx.sess.span_err(span, "`..` cannot be used in union patterns"); } } else if !etc { for field in variant.fields diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index d2ebdcca80c..7a04d377608 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -247,3 +247,24 @@ double rust_interesting_average(uint64_t n, ...) { int32_t rust_int8_to_int32(int8_t x) { return (int32_t)x; } + +typedef union LARGE_INTEGER { + struct { + uint32_t LowPart; + uint32_t HighPart; + }; + struct { + uint32_t LowPart; + uint32_t HighPart; + } u; + uint64_t QuadPart; +} LARGE_INTEGER; + +LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) { + li.LowPart += 1; + li.HighPart += 1; + li.u.LowPart += 1; + li.u.HighPart += 1; + li.QuadPart += 1; + return li; +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs new file mode 100644 index 00000000000..19975d79b60 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs new file mode 100644 index 00000000000..e8989a3c2d4 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs new file mode 100644 index 00000000000..d4d7bc6b0f7 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs @@ -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 or the MIT license +// , 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 + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-move.rs b/src/test/compile-fail/borrowck/borrowck-union-move.rs new file mode 100644 index 00000000000..5320244cf43 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-union-move.rs @@ -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 or the MIT license +// , 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` + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs new file mode 100644 index 00000000000..36e062f8464 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs @@ -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 or the MIT license +// , 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` + } +} diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs new file mode 100644 index 00000000000..4924fabafb0 --- /dev/null +++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(pub_restricted)] +#![feature(untagged_unions)] + +mod m { + pub union U { + pub a: u8, + pub(super) b: u8, + c: u8, + } +} + +fn main() { + let u = m::U { a: 0 }; // OK + let u = m::U { b: 0 }; // OK + let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private + + let m::U { a } = u; // OK + let m::U { b } = u; // OK + let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private +} diff --git a/src/test/compile-fail/privacy/union-field-privacy-2.rs b/src/test/compile-fail/privacy/union-field-privacy-2.rs new file mode 100644 index 00000000000..7151538f412 --- /dev/null +++ b/src/test/compile-fail/privacy/union-field-privacy-2.rs @@ -0,0 +1,28 @@ +// 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(pub_restricted)] +#![feature(untagged_unions)] + +mod m { + pub union U { + pub a: u8, + pub(super) b: u8, + c: u8, + } +} + +fn main() { + let u = m::U { a: 10 }; + + let a = u.a; // OK + let b = u.b; // OK + let c = u.c; //~ ERROR field `c` of struct `m::U` is private +} diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/union-borrow-nested.rs deleted file mode 100644 index 19975d79b60..00000000000 --- a/src/test/compile-fail/union-borrow-nested.rs +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -// 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 - } - } -} diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/union-borrow.rs deleted file mode 100644 index e8989a3c2d4..00000000000 --- a/src/test/compile-fail/union-borrow.rs +++ /dev/null @@ -1,97 +0,0 @@ -// 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. - -// 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 - } - } -} diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union-const-eval.rs deleted file mode 100644 index b2bf173c59c..00000000000 --- a/src/test/compile-fail/union-const-eval.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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)] - -union U { - a: usize, - b: usize, -} - -const C: U = U { a: 10 }; - -fn main() { - unsafe { - let a: [u8; C.a]; // OK - let b: [u8; C.b]; //~ ERROR constant evaluation error - //~^ NOTE nonexistent struct field - } -} diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union-const-pat.rs deleted file mode 100644 index 3d168980ed2..00000000000 --- a/src/test/compile-fail/union-const-pat.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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)] - -union U { - a: usize, - b: usize, -} - -const C: U = U { a: 10 }; - -fn main() { - match C { - C => {} //~ ERROR cannot use unions in constant patterns - _ => {} - } -} diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union-derive.rs deleted file mode 100644 index 0f78e96f640..00000000000 --- a/src/test/compile-fail/union-derive.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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. - -// Most traits cannot be derived for unions. - -#![feature(untagged_unions)] - -#[derive( - Clone, //~ ERROR this trait cannot be derived for unions - PartialEq, //~ ERROR this trait cannot be derived for unions - Eq, //~ ERROR this trait cannot be derived for unions - PartialOrd, //~ ERROR this trait cannot be derived for unions - Ord, //~ ERROR this trait cannot be derived for unions - Hash, //~ ERROR this trait cannot be derived for unions - Default, //~ ERROR this trait cannot be derived for unions - Debug, //~ ERROR this trait cannot be derived for unions -)] -union U { - a: u8, - b: u16, -} - -fn main() {} diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union-empty.rs deleted file mode 100644 index ce5bbf60fee..00000000000 --- a/src/test/compile-fail/union-empty.rs +++ /dev/null @@ -1,15 +0,0 @@ -// 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)] - -union U {} //~ ERROR unions cannot have zero fields - -fn main() {} diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/compile-fail/union-field-privacy.rs deleted file mode 100644 index d1f2bbbc3d0..00000000000 --- a/src/test/compile-fail/union-field-privacy.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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)] - -mod m { - pub union U { - a: u8 - } -} - -fn main() { - let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private -} diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union-fields.rs deleted file mode 100644 index 2bd1b8a7b32..00000000000 --- a/src/test/compile-fail/union-fields.rs +++ /dev/null @@ -1,34 +0,0 @@ -// 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)] - -union U { - a: u8, - b: u16, -} - -fn main() { - let u = U {}; //~ ERROR union expressions should have exactly one field - let u = U { a: 0 }; // OK - let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field - let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field - //~^ ERROR union `U` has no field named `c` - let u = U { ..u }; //~ ERROR union expressions should have exactly one field - //~^ ERROR functional record update syntax requires a struct - - let U {} = u; //~ ERROR union patterns without `..` should have at least one field - let U { a } = u; // OK - let U { a, b } = u; //~ ERROR union patterns can have at most one field - let U { a, b, c } = u; //~ ERROR union patterns can have at most one field - //~^ ERROR union `U` does not have a field named `c` - let U { .. } = u; // OK - let U { a, .. } = u; // OK -} diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/union-move-assign.rs deleted file mode 100644 index d4d7bc6b0f7..00000000000 --- a/src/test/compile-fail/union-move-assign.rs +++ /dev/null @@ -1,42 +0,0 @@ -// 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)] - -// 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 - } - } -} diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/union-move.rs deleted file mode 100644 index 5320244cf43..00000000000 --- a/src/test/compile-fail/union-move.rs +++ /dev/null @@ -1,96 +0,0 @@ -// 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)] - -#[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` - } - } -} diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union-nonrepresentable.rs deleted file mode 100644 index cb4683c2a0e..00000000000 --- a/src/test/compile-fail/union-nonrepresentable.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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)] - -union U { //~ ERROR recursive type `U` has infinite size - a: u8, - b: U, -} - -fn main() {} diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/union-uninitialized.rs deleted file mode 100644 index 36e062f8464..00000000000 --- a/src/test/compile-fail/union-uninitialized.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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)] - -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` - } -} diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union-unsafe.rs deleted file mode 100644 index 762ac5d8751..00000000000 --- a/src/test/compile-fail/union-unsafe.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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)] - -union U { - a: u8 -} - -fn main() { - let u = U { a: 10 }; // OK - let a = u.a; //~ ERROR access to union field requires unsafe function or block - let U { a } = u; //~ ERROR matching on union field requires unsafe function or block - if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block - let U { .. } = u; // OK -} diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union-unsized.rs deleted file mode 100644 index 381122406d7..00000000000 --- a/src/test/compile-fail/union-unsized.rs +++ /dev/null @@ -1,17 +0,0 @@ -// 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)] - -union U { - a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied -} - -fn main() {} diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union-with-drop-fields-lint.rs deleted file mode 100644 index 87a72efbe08..00000000000 --- a/src/test/compile-fail/union-with-drop-fields-lint.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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(dead_code)] -#![deny(unions_with_drop_fields)] - -union U { - a: u8, // OK -} - -union W { - a: String, //~ ERROR union contains a field with possibly non-trivial drop code - b: String, // OK, only one field is reported -} - -struct S(String); - -// `S` doesn't implement `Drop` trait, but still has non-trivial destructor -union Y { - a: S, //~ ERROR union contains a field with possibly non-trivial drop code -} - -// We don't know if `T` is trivially-destructable or not until trans -union J { - a: T, //~ ERROR union contains a field with possibly non-trivial drop code -} - -union H { - a: T, // OK, `T` is `Copy`, no destructor -} - -fn main() {} diff --git a/src/test/compile-fail/union/union-const-eval.rs b/src/test/compile-fail/union/union-const-eval.rs new file mode 100644 index 00000000000..b2bf173c59c --- /dev/null +++ b/src/test/compile-fail/union/union-const-eval.rs @@ -0,0 +1,26 @@ +// 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)] + +union U { + a: usize, + b: usize, +} + +const C: U = U { a: 10 }; + +fn main() { + unsafe { + let a: [u8; C.a]; // OK + let b: [u8; C.b]; //~ ERROR constant evaluation error + //~^ NOTE nonexistent struct field + } +} diff --git a/src/test/compile-fail/union/union-const-pat.rs b/src/test/compile-fail/union/union-const-pat.rs new file mode 100644 index 00000000000..3d168980ed2 --- /dev/null +++ b/src/test/compile-fail/union/union-const-pat.rs @@ -0,0 +1,25 @@ +// 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)] + +union U { + a: usize, + b: usize, +} + +const C: U = U { a: 10 }; + +fn main() { + match C { + C => {} //~ ERROR cannot use unions in constant patterns + _ => {} + } +} diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs new file mode 100644 index 00000000000..6e08ae0074d --- /dev/null +++ b/src/test/compile-fail/union/union-copy.rs @@ -0,0 +1,26 @@ +// 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)] + +union U { + a: u8 +} + +union W { + a: String +} + +impl Clone for U { fn clone(&self) { panic!(); } } +impl Clone for W { fn clone(&self) { panic!(); } } +impl Copy for U {} // OK +impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type + +fn main() {} diff --git a/src/test/compile-fail/union/union-derive.rs b/src/test/compile-fail/union/union-derive.rs new file mode 100644 index 00000000000..0f78e96f640 --- /dev/null +++ b/src/test/compile-fail/union/union-derive.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Most traits cannot be derived for unions. + +#![feature(untagged_unions)] + +#[derive( + Clone, //~ ERROR this trait cannot be derived for unions + PartialEq, //~ ERROR this trait cannot be derived for unions + Eq, //~ ERROR this trait cannot be derived for unions + PartialOrd, //~ ERROR this trait cannot be derived for unions + Ord, //~ ERROR this trait cannot be derived for unions + Hash, //~ ERROR this trait cannot be derived for unions + Default, //~ ERROR this trait cannot be derived for unions + Debug, //~ ERROR this trait cannot be derived for unions +)] +union U { + a: u8, + b: u16, +} + +fn main() {} diff --git a/src/test/compile-fail/union/union-empty.rs b/src/test/compile-fail/union/union-empty.rs new file mode 100644 index 00000000000..ce5bbf60fee --- /dev/null +++ b/src/test/compile-fail/union/union-empty.rs @@ -0,0 +1,15 @@ +// 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)] + +union U {} //~ ERROR unions cannot have zero fields + +fn main() {} diff --git a/src/test/compile-fail/union/union-feature-gate.rs b/src/test/compile-fail/union/union-feature-gate.rs new file mode 100644 index 00000000000..abfc4d90921 --- /dev/null +++ b/src/test/compile-fail/union/union-feature-gate.rs @@ -0,0 +1,15 @@ +// 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. + +union U { //~ ERROR unions are unstable and possibly buggy + a: u8, +} + +fn main() {} diff --git a/src/test/compile-fail/union/union-fields.rs b/src/test/compile-fail/union/union-fields.rs new file mode 100644 index 00000000000..a1721dda7de --- /dev/null +++ b/src/test/compile-fail/union/union-fields.rs @@ -0,0 +1,35 @@ +// 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)] + +union U { + a: u8, + b: u16, +} + +fn main() { + let u = U {}; //~ ERROR union expressions should have exactly one field + let u = U { a: 0 }; // OK + let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field + let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field + //~^ ERROR union `U` has no field named `c` + let u = U { ..u }; //~ ERROR union expressions should have exactly one field + //~^ ERROR functional record update syntax requires a struct + + let U {} = u; //~ ERROR union patterns should have exactly one field + let U { a } = u; // OK + let U { a, b } = u; //~ ERROR union patterns should have exactly one field + let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field + //~^ ERROR union `U` does not have a field named `c` + let U { .. } = u; //~ ERROR union patterns should have exactly one field + //~^ ERROR `..` cannot be used in union patterns + let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns +} diff --git a/src/test/compile-fail/union/union-generic.rs b/src/test/compile-fail/union/union-generic.rs new file mode 100644 index 00000000000..e6586b0fb7f --- /dev/null +++ b/src/test/compile-fail/union/union-generic.rs @@ -0,0 +1,24 @@ +// 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)] + +use std::rc::Rc; + +union U { + a: T +} + +fn main() { + let u = U { a: Rc::new(0u32) }; + //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied + let u = U::> { a: Default::default() }; + //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +} diff --git a/src/test/compile-fail/union/union-nonrepresentable.rs b/src/test/compile-fail/union/union-nonrepresentable.rs new file mode 100644 index 00000000000..cb4683c2a0e --- /dev/null +++ b/src/test/compile-fail/union/union-nonrepresentable.rs @@ -0,0 +1,18 @@ +// 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)] + +union U { //~ ERROR recursive type `U` has infinite size + a: u8, + b: U, +} + +fn main() {} diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs new file mode 100644 index 00000000000..d7dfb126c93 --- /dev/null +++ b/src/test/compile-fail/union/union-repr-c.rs @@ -0,0 +1,29 @@ +// 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(unused)] +#![deny(improper_ctypes)] + +#[repr(C)] +union U { + a: u8, +} + +union W { + a: u8, +} + +extern "C" { + static FOREIGN1: U; // OK + static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation +} + +fn main() {} diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs new file mode 100644 index 00000000000..b05e9b6e273 --- /dev/null +++ b/src/test/compile-fail/union/union-suggest-field.rs @@ -0,0 +1,29 @@ +// 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)] + +union U { + principal: u8, +} + +impl U { + fn calculate(&self) {} +} + +fn main() { + let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle` + //~^ HELP did you mean `principal`? + let w = u.principial; //~ ERROR attempted access of field `principial` on type `U` + //~^ HELP did you mean `principal`? + + let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U` + //~^ HELP maybe a `()` to call it is missing? +} diff --git a/src/test/compile-fail/union/union-unsafe.rs b/src/test/compile-fail/union/union-unsafe.rs new file mode 100644 index 00000000000..97e1ec2cba8 --- /dev/null +++ b/src/test/compile-fail/union/union-unsafe.rs @@ -0,0 +1,24 @@ +// 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)] + +union U { + a: u8 +} + +fn main() { + let mut u = U { a: 10 }; // OK + let a = u.a; //~ ERROR access to union field requires unsafe function or block + u.a = 11; //~ ERROR access to union field requires unsafe function or block + let U { a } = u; //~ ERROR matching on union field requires unsafe function or block + if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block + // let U { .. } = u; // OK +} diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs new file mode 100644 index 00000000000..a238eaf0525 --- /dev/null +++ b/src/test/compile-fail/union/union-unsized.rs @@ -0,0 +1,23 @@ +// 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)] + +union U { + a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + b: u8, +} + +union W { + a: u8, + b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +} + +fn main() {} diff --git a/src/test/compile-fail/union/union-with-drop-fields-lint.rs b/src/test/compile-fail/union/union-with-drop-fields-lint.rs new file mode 100644 index 00000000000..87a72efbe08 --- /dev/null +++ b/src/test/compile-fail/union/union-with-drop-fields-lint.rs @@ -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 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(dead_code)] +#![deny(unions_with_drop_fields)] + +union U { + a: u8, // OK +} + +union W { + a: String, //~ ERROR union contains a field with possibly non-trivial drop code + b: String, // OK, only one field is reported +} + +struct S(String); + +// `S` doesn't implement `Drop` trait, but still has non-trivial destructor +union Y { + a: S, //~ ERROR union contains a field with possibly non-trivial drop code +} + +// We don't know if `T` is trivially-destructable or not until trans +union J { + a: T, //~ ERROR union contains a field with possibly non-trivial drop code +} + +union H { + a: T, // OK, `T` is `Copy`, no destructor +} + +fn main() {} diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/auxiliary/union.rs deleted file mode 100644 index dc0ca7c81c0..00000000000 --- a/src/test/run-pass/auxiliary/union.rs +++ /dev/null @@ -1,16 +0,0 @@ -// 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)] - -pub union U { - pub a: u8, - b: u16, -} diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union-backcomp.rs deleted file mode 100644 index c1210dd6212..00000000000 --- a/src/test/run-pass/union-backcomp.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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)] - -fn main() { - let union = 10; - - union; - - union as u8; - - union U { - a: u8, - } -} diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs deleted file mode 100644 index 1651aa901b9..00000000000 --- a/src/test/run-pass/union-basic.rs +++ /dev/null @@ -1,59 +0,0 @@ -// 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)] - -use std::mem::{size_of, align_of, zeroed}; - -union U { - a: u8, -} - -union U64 { - a: u64, -} - -union W { - a: u8, - b: u64, -} - -#[repr(C)] -union Y { - f1: u16, - f2: [u8; 4], -} - -fn main() { - assert_eq!(size_of::(), 1); - assert_eq!(size_of::(), 8); - assert_eq!(size_of::(), 8); - assert_eq!(align_of::(), 1); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(size_of::(), 4); - assert_eq!(align_of::(), 2); - - let u = U { a: 10 }; - unsafe { - assert_eq!(u.a, 10); - let U { a } = u; - assert_eq!(a, 10); - } - - let mut w = W { b: 0 }; - unsafe { - assert_eq!(w.a, 0); - assert_eq!(w.b, 0); - w.a = 1; - assert_eq!(w.a, 1); - assert_eq!(w.b, 1); - } -} diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union-const-trans.rs deleted file mode 100644 index bdae1a0eaf8..00000000000 --- a/src/test/run-pass/union-const-trans.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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)] - -union U { - a: u64, - b: u64, -} - -const C: U = U { b: 10 }; - -fn main() { - unsafe { - let a = C.a; - let b = C.b; - assert_eq!(a, 10); - assert_eq!(b, 10); - } -} diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union-derive.rs deleted file mode 100644 index b71c23990a4..00000000000 --- a/src/test/run-pass/union-derive.rs +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -// Some traits can be derived for unions. - -#![feature(untagged_unions)] - -#[derive( - Copy, -)] -union U { - a: u8, - b: u16, -} - -impl Clone for U { - fn clone(&self) -> Self { *self } -} - -fn main() { - let u = U { b: 0 }; - let u1 = u; - let u2 = u.clone(); -} diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union-drop-assign.rs deleted file mode 100644 index 0da68e43f32..00000000000 --- a/src/test/run-pass/union-drop-assign.rs +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -// 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 - } -} diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs deleted file mode 100644 index 2ca68dc3b6e..00000000000 --- a/src/test/run-pass/union-drop.rs +++ /dev/null @@ -1,65 +0,0 @@ -// 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. - -// Drop works for union itself. - -#![feature(untagged_unions)] - -struct S; - -union U { - a: u8 -} - -union W { - a: S, -} - -union Y { - a: S, -} - -impl Drop for S { - fn drop(&mut self) { - unsafe { CHECK += 10; } - } -} - -impl Drop for U { - fn drop(&mut self) { - unsafe { CHECK += 1; } - } -} - -impl Drop for W { - fn drop(&mut self) { - unsafe { CHECK += 1; } - } -} - -static mut CHECK: u8 = 0; - -fn main() { - unsafe { - assert_eq!(CHECK, 0); - { - let u = U { a: 1 }; - } - assert_eq!(CHECK, 1); // 1, dtor of U is called - { - let w = W { a: S }; - } - assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called - { - let y = Y { a: S }; - } - assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called - } -} diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union-packed.rs deleted file mode 100644 index b1650ae3a7c..00000000000 --- a/src/test/run-pass/union-packed.rs +++ /dev/null @@ -1,74 +0,0 @@ -// 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)] - -use std::mem::{size_of, size_of_val, align_of, align_of_val}; - -struct S { - a: u16, - b: [u8; 3], -} - -#[repr(packed)] -struct Sp { - a: u16, - b: [u8; 3], -} - -union U { - a: u16, - b: [u8; 3], -} - -#[repr(packed)] -union Up { - a: u16, - b: [u8; 3], -} - -const CS: S = S { a: 0, b: [0, 0, 0] }; -const CSP: Sp = Sp { a: 0, b: [0, 0, 0] }; -const CU: U = U { b: [0, 0, 0] }; -const CUP: Up = Up { b: [0, 0, 0] }; - -fn main() { - let s = S { a: 0, b: [0, 0, 0] }; - assert_eq!(size_of::(), 6); - assert_eq!(size_of_val(&s), 6); - assert_eq!(size_of_val(&CS), 6); - assert_eq!(align_of::(), 2); - assert_eq!(align_of_val(&s), 2); - assert_eq!(align_of_val(&CS), 2); - - let sp = Sp { a: 0, b: [0, 0, 0] }; - assert_eq!(size_of::(), 5); - assert_eq!(size_of_val(&sp), 5); - assert_eq!(size_of_val(&CSP), 5); - assert_eq!(align_of::(), 1); - assert_eq!(align_of_val(&sp), 1); - assert_eq!(align_of_val(&CSP), 1); - - let u = U { b: [0, 0, 0] }; - assert_eq!(size_of::(), 4); - assert_eq!(size_of_val(&u), 4); - assert_eq!(size_of_val(&CU), 4); - assert_eq!(align_of::(), 2); - assert_eq!(align_of_val(&u), 2); - assert_eq!(align_of_val(&CU), 2); - - let up = Up { b: [0, 0, 0] }; - assert_eq!(size_of::(), 3); - assert_eq!(size_of_val(&up), 3); - assert_eq!(size_of_val(&CUP), 3); - assert_eq!(align_of::(), 1); - assert_eq!(align_of_val(&up), 1); - assert_eq!(align_of_val(&CUP), 1); -} diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs deleted file mode 100644 index e6144f35f1d..00000000000 --- a/src/test/run-pass/union-pat-refutability.rs +++ /dev/null @@ -1,62 +0,0 @@ -// 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)] - -#[repr(u32)] -enum Tag { I, F } - -#[repr(C)] -union U { - i: i32, - f: f32, -} - -#[repr(C)] -struct Value { - tag: Tag, - u: U, -} - -fn is_zero(v: Value) -> bool { - unsafe { - match v { - Value { tag: Tag::I, u: U { i: 0 } } => true, - Value { tag: Tag::F, u: U { f: 0.0 } } => true, - _ => false, - } - } -} - -union W { - a: u8, - b: u8, -} - -fn refut(w: W) { - unsafe { - match w { - W { a: 10 } => { - panic!(); - } - W { b } => { - assert_eq!(b, 11); - } - } - } -} - -fn main() { - let v = Value { tag: Tag::I, u: U { i: 1 } }; - assert_eq!(is_zero(v), false); - - let w = W { a: 11 }; - refut(w); -} diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union-transmute.rs deleted file mode 100644 index 4eb66268ab8..00000000000 --- a/src/test/run-pass/union-transmute.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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(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); - } -} diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union-xcrate.rs deleted file mode 100644 index 2a76c96ef25..00000000000 --- a/src/test/run-pass/union-xcrate.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -// aux-build:union.rs - -// #![feature(untagged_unions)] - -extern crate union; - -type A = union::U; - -fn main() { - assert_eq!(std::mem::size_of::(), 8); -} diff --git a/src/test/run-pass/union/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs new file mode 100644 index 00000000000..dc0ca7c81c0 --- /dev/null +++ b/src/test/run-pass/union/auxiliary/union.rs @@ -0,0 +1,16 @@ +// 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)] + +pub union U { + pub a: u8, + b: u16, +} diff --git a/src/test/run-pass/union/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs new file mode 100644 index 00000000000..9394b618ddf --- /dev/null +++ b/src/test/run-pass/union/union-backcomp.rs @@ -0,0 +1,27 @@ +// 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)] + +fn union() {} + +fn main() { + union(); + + let union = 10; + + union; + + union as u8; + + union U { + a: u8, + } +} diff --git a/src/test/run-pass/union/union-basic.rs b/src/test/run-pass/union/union-basic.rs new file mode 100644 index 00000000000..1651aa901b9 --- /dev/null +++ b/src/test/run-pass/union/union-basic.rs @@ -0,0 +1,59 @@ +// 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)] + +use std::mem::{size_of, align_of, zeroed}; + +union U { + a: u8, +} + +union U64 { + a: u64, +} + +union W { + a: u8, + b: u64, +} + +#[repr(C)] +union Y { + f1: u16, + f2: [u8; 4], +} + +fn main() { + assert_eq!(size_of::(), 1); + assert_eq!(size_of::(), 8); + assert_eq!(size_of::(), 8); + assert_eq!(align_of::(), 1); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(size_of::(), 4); + assert_eq!(align_of::(), 2); + + let u = U { a: 10 }; + unsafe { + assert_eq!(u.a, 10); + let U { a } = u; + assert_eq!(a, 10); + } + + let mut w = W { b: 0 }; + unsafe { + assert_eq!(w.a, 0); + assert_eq!(w.b, 0); + w.a = 1; + assert_eq!(w.a, 1); + assert_eq!(w.b, 1); + } +} diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs new file mode 100644 index 00000000000..a9f97620ebd --- /dev/null +++ b/src/test/run-pass/union/union-c-interop.rs @@ -0,0 +1,47 @@ +// 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)] + +#[derive(Copy)] +#[repr(C)] +struct LARGE_INTEGER_U { + LowPart: u32, + HighPart: u32, +} + +#[derive(Copy)] +#[repr(C)] +union LARGE_INTEGER { + __unnamed__: LARGE_INTEGER_U, + u: LARGE_INTEGER_U, + QuadPart: u64, +} + +impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } } +impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } } + +#[link(name = "rust_test_helpers")] +extern "C" { + fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER; +} + +fn main() { + unsafe { + let mut li = LARGE_INTEGER { QuadPart: 0 }; + let li_c = increment_all_parts(li); + li.__unnamed__.LowPart += 1; + li.__unnamed__.HighPart += 1; + li.u.LowPart += 1; + li.u.HighPart += 1; + li.QuadPart += 1; + assert_eq!(li.QuadPart, li_c.QuadPart); + } +} diff --git a/src/test/run-pass/union/union-const-trans.rs b/src/test/run-pass/union/union-const-trans.rs new file mode 100644 index 00000000000..bdae1a0eaf8 --- /dev/null +++ b/src/test/run-pass/union/union-const-trans.rs @@ -0,0 +1,27 @@ +// 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)] + +union U { + a: u64, + b: u64, +} + +const C: U = U { b: 10 }; + +fn main() { + unsafe { + let a = C.a; + let b = C.b; + assert_eq!(a, 10); + assert_eq!(b, 10); + } +} diff --git a/src/test/run-pass/union/union-derive.rs b/src/test/run-pass/union/union-derive.rs new file mode 100644 index 00000000000..b71c23990a4 --- /dev/null +++ b/src/test/run-pass/union/union-derive.rs @@ -0,0 +1,31 @@ +// 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. + +// Some traits can be derived for unions. + +#![feature(untagged_unions)] + +#[derive( + Copy, +)] +union U { + a: u8, + b: u16, +} + +impl Clone for U { + fn clone(&self) -> Self { *self } +} + +fn main() { + let u = U { b: 0 }; + let u1 = u; + let u2 = u.clone(); +} diff --git a/src/test/run-pass/union/union-drop-assign.rs b/src/test/run-pass/union/union-drop-assign.rs new file mode 100644 index 00000000000..0da68e43f32 --- /dev/null +++ b/src/test/run-pass/union/union-drop-assign.rs @@ -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 or the MIT license +// , 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 + } +} diff --git a/src/test/run-pass/union/union-drop.rs b/src/test/run-pass/union/union-drop.rs new file mode 100644 index 00000000000..2ca68dc3b6e --- /dev/null +++ b/src/test/run-pass/union/union-drop.rs @@ -0,0 +1,65 @@ +// 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. + +// Drop works for union itself. + +#![feature(untagged_unions)] + +struct S; + +union U { + a: u8 +} + +union W { + a: S, +} + +union Y { + a: S, +} + +impl Drop for S { + fn drop(&mut self) { + unsafe { CHECK += 10; } + } +} + +impl Drop for U { + fn drop(&mut self) { + unsafe { CHECK += 1; } + } +} + +impl Drop for W { + fn drop(&mut self) { + unsafe { CHECK += 1; } + } +} + +static mut CHECK: u8 = 0; + +fn main() { + unsafe { + assert_eq!(CHECK, 0); + { + let u = U { a: 1 }; + } + assert_eq!(CHECK, 1); // 1, dtor of U is called + { + let w = W { a: S }; + } + assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called + { + let y = Y { a: S }; + } + assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called + } +} diff --git a/src/test/run-pass/union/union-generic.rs b/src/test/run-pass/union/union-generic.rs new file mode 100644 index 00000000000..9293805edbf --- /dev/null +++ b/src/test/run-pass/union/union-generic.rs @@ -0,0 +1,43 @@ +// 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)] + +union MaybeItem { + elem: T::Item, + none: (), +} + +union U { + a: A, + b: B, +} + +unsafe fn union_transmute(a: A) -> B { + U { a: a }.b +} + +fn main() { + unsafe { + let u = U::> { a: String::from("abcd") }; + + assert_eq!(u.b.len(), 4); + assert_eq!(u.b[0], b'a'); + + let b = union_transmute::<(u8, u8), u16>((1, 1)); + assert_eq!(b, (1 << 8) + 1); + + let v: Vec = vec![1, 2, 3]; + let mut i = v.iter(); + i.next(); + let mi = MaybeItem::> { elem: i.next().unwrap() }; + assert_eq!(*mi.elem, 2); + } +} diff --git a/src/test/run-pass/union/union-inherent-method.rs b/src/test/run-pass/union/union-inherent-method.rs new file mode 100644 index 00000000000..adea27bd254 --- /dev/null +++ b/src/test/run-pass/union/union-inherent-method.rs @@ -0,0 +1,24 @@ +// 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)] + +union U { + a: u8, +} + +impl U { + fn method(&self) -> u8 { unsafe { self.a } } +} + +fn main() { + let u = U { a: 10 }; + assert_eq!(u.method(), 10); +} diff --git a/src/test/run-pass/union/union-macro.rs b/src/test/run-pass/union/union-macro.rs new file mode 100644 index 00000000000..a23fbc3be9e --- /dev/null +++ b/src/test/run-pass/union/union-macro.rs @@ -0,0 +1,33 @@ +// 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)] + +macro_rules! duplicate { + ($i: item) => { + mod m1 { + $i + } + mod m2 { + $i + } + } +} + +duplicate! { + pub union U { + pub a: u8 + } +} + +fn main() { + let u1 = m1::U { a: 0 }; + let u2 = m2::U { a: 0 }; +} diff --git a/src/test/run-pass/union/union-overwrite.rs b/src/test/run-pass/union/union-overwrite.rs new file mode 100644 index 00000000000..9389a6237bc --- /dev/null +++ b/src/test/run-pass/union/union-overwrite.rs @@ -0,0 +1,80 @@ +// 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)] + +#[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(); + } +} diff --git a/src/test/run-pass/union/union-packed.rs b/src/test/run-pass/union/union-packed.rs new file mode 100644 index 00000000000..6a61280823e --- /dev/null +++ b/src/test/run-pass/union/union-packed.rs @@ -0,0 +1,104 @@ +// 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)] + +use std::mem::{size_of, size_of_val, align_of, align_of_val}; + +struct S { + a: u16, + b: [u8; 3], +} + +#[repr(packed)] +struct Sp { + a: u16, + b: [u8; 3], +} + +union U { + a: u16, + b: [u8; 3], +} + +#[repr(packed)] +union Up { + a: u16, + b: [u8; 3], +} + +const CS: S = S { a: 0, b: [0, 0, 0] }; +const CSP: Sp = Sp { a: 0, b: [0, 0, 0] }; +const CU: U = U { b: [0, 0, 0] }; +const CUP: Up = Up { b: [0, 0, 0] }; + +fn main() { + let s = S { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 6); + assert_eq!(size_of_val(&s), 6); + assert_eq!(size_of_val(&CS), 6); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&s), 2); + assert_eq!(align_of_val(&CS), 2); + + let sp = Sp { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::(), 5); + assert_eq!(size_of_val(&sp), 5); + assert_eq!(size_of_val(&CSP), 5); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&sp), 1); + assert_eq!(align_of_val(&CSP), 1); + + let u = U { b: [0, 0, 0] }; + assert_eq!(size_of::(), 4); + assert_eq!(size_of_val(&u), 4); + assert_eq!(size_of_val(&CU), 4); + assert_eq!(align_of::(), 2); + assert_eq!(align_of_val(&u), 2); + assert_eq!(align_of_val(&CU), 2); + + let up = Up { b: [0, 0, 0] }; + assert_eq!(size_of::(), 3); + assert_eq!(size_of_val(&up), 3); + assert_eq!(size_of_val(&CUP), 3); + assert_eq!(align_of::(), 1); + assert_eq!(align_of_val(&up), 1); + assert_eq!(align_of_val(&CUP), 1); + + hybrid::check_hybrid(); +} + +mod hybrid { + use std::mem::size_of; + + #[repr(packed)] + struct S1 { + a: u16, + b: u8, + } + + #[repr(packed)] + union U { + s: S1, + c: u16, + } + + #[repr(packed)] + struct S2 { + d: u8, + u: U, + } + + pub fn check_hybrid() { + assert_eq!(size_of::(), 3); + assert_eq!(size_of::(), 3); + assert_eq!(size_of::(), 4); + } +} diff --git a/src/test/run-pass/union/union-pat-refutability.rs b/src/test/run-pass/union/union-pat-refutability.rs new file mode 100644 index 00000000000..e6144f35f1d --- /dev/null +++ b/src/test/run-pass/union/union-pat-refutability.rs @@ -0,0 +1,62 @@ +// 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)] + +#[repr(u32)] +enum Tag { I, F } + +#[repr(C)] +union U { + i: i32, + f: f32, +} + +#[repr(C)] +struct Value { + tag: Tag, + u: U, +} + +fn is_zero(v: Value) -> bool { + unsafe { + match v { + Value { tag: Tag::I, u: U { i: 0 } } => true, + Value { tag: Tag::F, u: U { f: 0.0 } } => true, + _ => false, + } + } +} + +union W { + a: u8, + b: u8, +} + +fn refut(w: W) { + unsafe { + match w { + W { a: 10 } => { + panic!(); + } + W { b } => { + assert_eq!(b, 11); + } + } + } +} + +fn main() { + let v = Value { tag: Tag::I, u: U { i: 1 } }; + assert_eq!(is_zero(v), false); + + let w = W { a: 11 }; + refut(w); +} diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs new file mode 100644 index 00000000000..a5a2be0133a --- /dev/null +++ b/src/test/run-pass/union/union-trait-impl.rs @@ -0,0 +1,27 @@ +// 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)] + +use std::fmt; + +union U { + a: u8 +} + +impl fmt::Display for U { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + unsafe { write!(f, "Oh hai {}", self.a) } + } +} + +fn main() { + assert_eq!(U { a: 2 }.to_string(), "Oh hai 2"); +} diff --git a/src/test/run-pass/union/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs new file mode 100644 index 00000000000..4eb66268ab8 --- /dev/null +++ b/src/test/run-pass/union/union-transmute.rs @@ -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 or the MIT license +// , 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); + } +} diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs new file mode 100644 index 00000000000..5a1424830d0 --- /dev/null +++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty + +#![feature(untagged_unions)] +#![allow(dead_code)] +#![allow(unions_with_drop_fields)] + +union U { + a: u8, // OK +} + +union W { + a: String, // OK + b: String, // OK +} + +struct S(String); + +// `S` doesn't implement `Drop` trait, but still has non-trivial destructor +union Y { + a: S, // OK +} + +// We don't know if `T` is trivially-destructable or not until trans +union J { + a: T, // OK +} + +union H { + a: T, // OK +} + +fn main() {} diff --git a/src/test/run-pass/union/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs new file mode 100644 index 00000000000..2a76c96ef25 --- /dev/null +++ b/src/test/run-pass/union/union-xcrate.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:union.rs + +// #![feature(untagged_unions)] + +extern crate union; + +type A = union::U; + +fn main() { + assert_eq!(std::mem::size_of::(), 8); +} -- cgit 1.4.1-3-g733a5