about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-18 20:12:28 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:39:34 +0300
commite88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc (patch)
tree31c42de603fd42f5737f49013166c2cf066c18fc
parentf3b41c18a8dfbcfec4b2a9e8d9e6a921189e3eea (diff)
downloadrust-e88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc.tar.gz
rust-e88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc.zip
Make accesses to union fields unsafe
-rw-r--r--src/librustc/middle/effect.rs24
-rw-r--r--src/test/compile-fail/union-unsafe.rs23
-rw-r--r--src/test/run-pass/union-basic.rs20
-rw-r--r--src/test/run-pass/union-pat-refutability.rs14
4 files changed, 63 insertions, 18 deletions
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 <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
+}
+
+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::<Y>(), 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);
+            }
         }
     }
 }