Skip to content

Commit 5fe0ad1

Browse files
committed
Implement unsafe trait semantics.
1 parent 22f777b commit 5fe0ad1

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed

src/librustc_typeck/coherence/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use util::ppaux::Repr;
5050

5151
mod orphan;
5252
mod overlap;
53+
mod unsafety;
5354

5455
fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
5556
span: Span,
@@ -620,6 +621,7 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
620621
inference_context: new_infer_ctxt(crate_context.tcx),
621622
inherent_impls: RefCell::new(FnvHashMap::new()),
622623
}.check(crate_context.tcx.map.krate());
624+
unsafety::check(crate_context.tcx);
623625
orphan::check(crate_context.tcx);
624626
overlap::check(crate_context.tcx);
625627
}
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Unsafety checker: every impl either implements a trait defined in this
12+
//! crate or pertains to a type defined in this crate.
13+
14+
use middle::ty;
15+
use syntax::ast::{Item, ItemImpl};
16+
use syntax::ast;
17+
use syntax::ast_util;
18+
use syntax::visit;
19+
use util::ppaux::UserString;
20+
21+
pub fn check(tcx: &ty::ctxt) {
22+
let mut orphan = UnsafetyChecker { tcx: tcx };
23+
visit::walk_crate(&mut orphan, tcx.map.krate());
24+
}
25+
26+
struct UnsafetyChecker<'cx, 'tcx:'cx> {
27+
tcx: &'cx ty::ctxt<'tcx>
28+
}
29+
30+
impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
31+
fn visit_item(&mut self, item: &'v ast::Item) {
32+
match item.node {
33+
ast::ItemImpl(unsafety, _, _, _, _) => {
34+
match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
35+
None => {
36+
// Inherent impl.
37+
match unsafety {
38+
ast::Unsafety::Normal => { /* OK */ }
39+
ast::Unsafety::Unsafe => {
40+
self.tcx.sess.span_err(
41+
item.span,
42+
"inherent impls cannot be declared as unsafe");
43+
}
44+
}
45+
}
46+
47+
Some(trait_ref) => {
48+
let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
49+
match (trait_def.unsafety, unsafety) {
50+
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
51+
self.tcx.sess.span_err(
52+
item.span,
53+
format!("implementing the trait `{}` is not unsafe",
54+
trait_ref.user_string(self.tcx)).as_slice());
55+
}
56+
57+
(ast::Unsafety::Unsafe, ast::Unsafety::Normal) => {
58+
self.tcx.sess.span_err(
59+
item.span,
60+
format!("the trait `{}` requires an `unsafe impl` declaration",
61+
trait_ref.user_string(self.tcx)).as_slice());
62+
}
63+
64+
(ast::Unsafety::Unsafe, ast::Unsafety::Unsafe) |
65+
(ast::Unsafety::Normal, ast::Unsafety::Normal) => {
66+
/* OK */
67+
}
68+
}
69+
}
70+
}
71+
}
72+
_ => { }
73+
}
74+
75+
visit::walk_item(self, item);
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that an unsafe impl does not imply that unsafe actions are
12+
// legal in the methods.
13+
14+
unsafe trait UnsafeTrait {
15+
fn foo(self) { }
16+
}
17+
18+
unsafe impl UnsafeTrait for *mut int {
19+
fn foo(self) {
20+
// Unsafe actions are not made legal by taking place in an unsafe trait:
21+
*self += 1; //~ ERROR E0133
22+
}
23+
}
24+
25+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that inherent impls cannot be unsafe.
12+
13+
struct SomeStruct;
14+
15+
unsafe impl SomeStruct { //~ ERROR inherent impls cannot be declared as unsafe
16+
fn foo(self) { }
17+
}
18+
19+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that unsafe traits require unsafe impls and that inherent
12+
// impls cannot be unsafe.
13+
14+
trait SafeTrait {
15+
fn foo(self) { }
16+
}
17+
18+
unsafe trait UnsafeTrait {
19+
fn foo(self) { }
20+
}
21+
22+
unsafe impl UnsafeTrait for u8 { } // OK
23+
24+
impl UnsafeTrait for u16 { } //~ ERROR requires an `unsafe impl` declaration
25+
26+
unsafe impl SafeTrait for u32 { } //~ ERROR the trait `SafeTrait` is not unsafe
27+
28+
fn main() { }

0 commit comments

Comments
 (0)