about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-10 10:59:20 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-14 11:11:55 -0500
commit5fe0ad1c0fde4c93ec010e95457d5831d11f013d (patch)
tree5cf46e5b4e42399e4fc496e16afcdd262cc06e8e
parent22f777ba2ecfcd8d914d37db310a6feb4ad5219e (diff)
downloadrust-5fe0ad1c0fde4c93ec010e95457d5831d11f013d.tar.gz
rust-5fe0ad1c0fde4c93ec010e95457d5831d11f013d.zip
Implement `unsafe trait` semantics.
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs77
-rw-r--r--src/test/compile-fail/trait-safety-fn-body.rs25
-rw-r--r--src/test/compile-fail/trait-safety-inherent-impl.rs19
-rw-r--r--src/test/compile-fail/trait-safety-trait-impl.rs28
5 files changed, 151 insertions, 0 deletions
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 7bc79d6e4a4..a55f3c61919 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -50,6 +50,7 @@ use util::ppaux::Repr;
 
 mod orphan;
 mod overlap;
+mod unsafety;
 
 fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
                            span: Span,
@@ -620,6 +621,7 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
         inference_context: new_infer_ctxt(crate_context.tcx),
         inherent_impls: RefCell::new(FnvHashMap::new()),
     }.check(crate_context.tcx.map.krate());
+    unsafety::check(crate_context.tcx);
     orphan::check(crate_context.tcx);
     overlap::check(crate_context.tcx);
 }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
new file mode 100644
index 00000000000..07a84846c47
--- /dev/null
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -0,0 +1,77 @@
+// Copyright 2014 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.
+
+//! Unsafety checker: every impl either implements a trait defined in this
+//! crate or pertains to a type defined in this crate.
+
+use middle::ty;
+use syntax::ast::{Item, ItemImpl};
+use syntax::ast;
+use syntax::ast_util;
+use syntax::visit;
+use util::ppaux::UserString;
+
+pub fn check(tcx: &ty::ctxt) {
+    let mut orphan = UnsafetyChecker { tcx: tcx };
+    visit::walk_crate(&mut orphan, tcx.map.krate());
+}
+
+struct UnsafetyChecker<'cx, 'tcx:'cx> {
+    tcx: &'cx ty::ctxt<'tcx>
+}
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &'v ast::Item) {
+        match item.node {
+            ast::ItemImpl(unsafety, _, _, _, _) => {
+                match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
+                    None => {
+                        // Inherent impl.
+                        match unsafety {
+                            ast::Unsafety::Normal => { /* OK */ }
+                            ast::Unsafety::Unsafe => {
+                                self.tcx.sess.span_err(
+                                    item.span,
+                                    "inherent impls cannot be declared as unsafe");
+                            }
+                        }
+                    }
+
+                    Some(trait_ref) => {
+                        let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
+                        match (trait_def.unsafety, unsafety) {
+                            (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
+                                self.tcx.sess.span_err(
+                                    item.span,
+                                    format!("implementing the trait `{}` is not unsafe",
+                                            trait_ref.user_string(self.tcx)).as_slice());
+                            }
+
+                            (ast::Unsafety::Unsafe, ast::Unsafety::Normal) => {
+                                self.tcx.sess.span_err(
+                                    item.span,
+                                    format!("the trait `{}` requires an `unsafe impl` declaration",
+                                            trait_ref.user_string(self.tcx)).as_slice());
+                            }
+
+                            (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe) |
+                            (ast::Unsafety::Normal, ast::Unsafety::Normal) => {
+                                /* OK */
+                            }
+                        }
+                    }
+                }
+            }
+            _ => { }
+        }
+
+        visit::walk_item(self, item);
+    }
+}
diff --git a/src/test/compile-fail/trait-safety-fn-body.rs b/src/test/compile-fail/trait-safety-fn-body.rs
new file mode 100644
index 00000000000..d174092e4d0
--- /dev/null
+++ b/src/test/compile-fail/trait-safety-fn-body.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+// Check that an unsafe impl does not imply that unsafe actions are
+// legal in the methods.
+
+unsafe trait UnsafeTrait {
+    fn foo(self) { }
+}
+
+unsafe impl UnsafeTrait for *mut int {
+    fn foo(self) {
+        // Unsafe actions are not made legal by taking place in an unsafe trait:
+        *self += 1; //~ ERROR E0133
+    }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/trait-safety-inherent-impl.rs b/src/test/compile-fail/trait-safety-inherent-impl.rs
new file mode 100644
index 00000000000..285d4c1ba8d
--- /dev/null
+++ b/src/test/compile-fail/trait-safety-inherent-impl.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 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.
+
+// Check that inherent impls cannot be unsafe.
+
+struct SomeStruct;
+
+unsafe impl SomeStruct { //~ ERROR inherent impls cannot be declared as unsafe
+    fn foo(self) { }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/trait-safety-trait-impl.rs b/src/test/compile-fail/trait-safety-trait-impl.rs
new file mode 100644
index 00000000000..1bd6d763607
--- /dev/null
+++ b/src/test/compile-fail/trait-safety-trait-impl.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+// Check that unsafe traits require unsafe impls and that inherent
+// impls cannot be unsafe.
+
+trait SafeTrait {
+    fn foo(self) { }
+}
+
+unsafe trait UnsafeTrait {
+    fn foo(self) { }
+}
+
+unsafe impl UnsafeTrait for u8 { } // OK
+
+impl UnsafeTrait for u16 { } //~ ERROR requires an `unsafe impl` declaration
+
+unsafe impl SafeTrait for u32 { } //~ ERROR the trait `SafeTrait` is not unsafe
+
+fn main() { }