Implement unsafe trait semantics.

This commit is contained in:
Niko Matsakis 2014-12-10 10:59:20 -05:00
parent 22f777ba2e
commit 5fe0ad1c0f
5 changed files with 151 additions and 0 deletions

View file

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

View file

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

View file

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

View file

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

View file

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