Address comments and add requested tests

This commit is contained in:
Vadim Petrochenkov 2016-08-26 19:23:42 +03:00
parent e67c2282af
commit 93067ca089
47 changed files with 582 additions and 61 deletions

View File

@ -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");
}
}

View File

@ -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,
}
}

View File

@ -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,

View File

@ -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<LoanPath<'tcx>>,
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<LoanPath<'tcx>>,
assign_id: ast::NodeId,
span: Span,
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
lp, assign_id, assignee_id);

View File

@ -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(..) => {

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,30 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(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
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(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
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
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() {}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
union U { //~ ERROR unions are unstable and possibly buggy
a: u8,
}
fn main() {}

View File

@ -24,11 +24,12 @@ fn main() {
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 {} = u; //~ ERROR union patterns should have exactly 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
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; // OK
let U { a, .. } = u; // OK
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
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
use std::rc::Rc;
union U<T: Copy> {
a: T
}
fn main() {
let u = U { a: Rc::new(0u32) };
//~^ ERROR the trait bound `std::rc::Rc<u32>: std::marker::Copy` is not satisfied
let u = U::<Rc<u32>> { a: Default::default() };
//~^ ERROR the trait bound `std::rc::Rc<u32>: std::marker::Copy` is not satisfied
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
#![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() {}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
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?
}

View File

@ -15,9 +15,10 @@ union U {
}
fn main() {
let u = U { a: 10 }; // OK
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: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
let U { .. } = u; // OK
if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block
// let U { .. } = u; // OK
}

View File

@ -12,6 +12,12 @@
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() {}

View File

@ -10,7 +10,11 @@
#![feature(untagged_unions)]
fn union() {}
fn main() {
union();
let union = 10;
union;

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
#[derive(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);
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
union MaybeItem<T: Iterator> {
elem: T::Item,
none: (),
}
union U<A, B> {
a: A,
b: B,
}
unsafe fn union_transmute<A, B>(a: A) -> B {
U { a: a }.b
}
fn main() {
unsafe {
let u = U::<String, Vec<u8>> { 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<u8> = vec![1, 2, 3];
let mut i = v.iter();
i.next();
let mi = MaybeItem::<std::slice::Iter<_>> { elem: i.next().unwrap() };
assert_eq!(*mi.elem, 2);
}
}

View File

@ -10,12 +10,15 @@
#![feature(untagged_unions)]
mod m {
pub union U {
a: u8
}
union U {
a: u8,
}
impl U {
fn method(&self) -> u8 { unsafe { self.a } }
}
fn main() {
let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
let u = U { a: 10 };
assert_eq!(u.method(), 10);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
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 };
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
#[repr(C)]
struct Pair<T, U>(T, U);
#[repr(C)]
struct Triple<T>(T, T, T);
#[repr(C)]
union U<A, B> {
a: Pair<A, A>,
b: B,
}
#[repr(C)]
union W<A, B> {
a: A,
b: B,
}
#[cfg(target_endian = "little")]
unsafe fn check() {
let mut u = U::<u8, u16> { b: 0xDE_DE };
u.a.0 = 0xBE;
assert_eq!(u.b, 0xDE_BE);
let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
u.a.0 = 0xBEEF;
assert_eq!(u.b, 0xDEAD_BEEF);
let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
u.a.0 = 0xBAADF00D;
assert_eq!(u.b, 0xDEADBEEF_BAADF00D);
let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
w.a.0 = Triple(0, 0, 0);
assert_eq!(w.b, 0xDE00_0000);
let mut w = W::<Pair<u8, Triple<u8>>, 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::<u8, u16> { b: 0xDE_DE };
u.a.0 = 0xBE;
assert_eq!(u.b, 0xBE_DE);
let mut u = U::<u16, u32> { b: 0xDEAD_DEAD };
u.a.0 = 0xBEEF;
assert_eq!(u.b, 0xBEEF_DEAD);
let mut u = U::<u32, u64> { b: 0xDEADBEEF_DEADBEEF };
u.a.0 = 0xBAADF00D;
assert_eq!(u.b, 0xBAADF00D_DEADBEEF);
let mut w = W::<Pair<Triple<u8>, u8>, u32> { b: 0xDEAD_DEAD };
w.a.0 = Triple(0, 0, 0);
assert_eq!(w.b, 0x0000_00AD);
let mut w = W::<Pair<u8, Triple<u8>>, u32> { b: 0xDEAD_DEAD };
w.a.1 = Triple(0, 0, 0);
assert_eq!(w.b, 0xDE00_0000);
}
fn main() {
unsafe {
check();
}
}

View File

@ -71,4 +71,34 @@ fn main() {
assert_eq!(align_of::<Up>(), 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::<S1>(), 3);
assert_eq!(size_of::<U>(), 3);
assert_eq!(size_of::<S2>(), 4);
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(untagged_unions)]
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");
}

View File

@ -0,0 +1,42 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T> {
a: T, // OK
}
union H<T: Copy> {
a: T, // OK
}
fn main() {}