Skip to content

Commit 37b9ee2

Browse files
committed
Make assignments to Copy union fields safe
1 parent 6af8c6c commit 37b9ee2

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

src/librustc/middle/effect.rs

+18
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,24 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
218218
}
219219
}
220220
}
221+
hir::ExprAssign(ref lhs, ref rhs) => {
222+
if let hir::ExprField(ref base_expr, field) = lhs.node {
223+
if let ty::TyAdt(adt, ..) = self.tables.expr_ty_adjusted(base_expr).sty {
224+
if adt.is_union() {
225+
let field_ty = self.tables.expr_ty_adjusted(lhs);
226+
let param_env = self.tcx.parameter_environment(adt.did);
227+
if field_ty.moves_by_default(self.tcx, &param_env, field.span) {
228+
self.require_unsafe(field.span,
229+
"assignment to non-`Copy` union field");
230+
}
231+
// Do not walk the field expr again.
232+
intravisit::walk_expr(self, base_expr);
233+
intravisit::walk_expr(self, rhs);
234+
return
235+
}
236+
}
237+
}
238+
}
221239
_ => {}
222240
}
223241

src/test/compile-fail/union/union-unsafe.rs

+39-7
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,47 @@
1010

1111
#![feature(untagged_unions)]
1212

13-
union U {
13+
union U1 {
1414
a: u8
1515
}
1616

17+
union U2 {
18+
a: String
19+
}
20+
21+
union U3<T> {
22+
a: T
23+
}
24+
25+
union U4<T: Copy> {
26+
a: T
27+
}
28+
29+
fn generic_noncopy<T: Default>() {
30+
let mut u3 = U3 { a: T::default() };
31+
u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field requires unsafe
32+
}
33+
34+
fn generic_copy<T: Copy + Default>() {
35+
let mut u3 = U3 { a: T::default() };
36+
// FIXME: it should be known here that `T: Copy`, need to use correct "parameter environment"
37+
u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field requires unsafe
38+
let mut u4 = U4 { a: T::default() };
39+
u4.a = T::default(); // OK
40+
}
41+
1742
fn main() {
18-
let mut u = U { a: 10 }; // OK
19-
let a = u.a; //~ ERROR access to union field requires unsafe function or block
20-
u.a = 11; //~ ERROR access to union field requires unsafe function or block
21-
let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
22-
if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block
23-
// let U { .. } = u; // OK
43+
let mut u1 = U1 { a: 10 }; // OK
44+
let a = u1.a; //~ ERROR access to union field requires unsafe
45+
u1.a = 11; // OK
46+
let U1 { a } = u1; //~ ERROR matching on union field requires unsafe
47+
if let U1 { a: 12 } = u1 {} //~ ERROR matching on union field requires unsafe
48+
// let U1 { .. } = u1; // OK
49+
50+
let mut u2 = U2 { a: String::from("old") }; // OK
51+
u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field requires unsafe
52+
let mut u3 = U3 { a: 0 }; // OK
53+
u3.a = 1; // OK
54+
let mut u3 = U3 { a: String::from("old") }; // OK
55+
u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field requires unsafe
2456
}

0 commit comments

Comments
 (0)