Change:
tcx: &'cx ty::ctxt<'tcx> } <del> 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, polarity, _, _, _, _) => { 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 => { span_err!(self.tcx.sess, item.span, E0197, "inherent impls cannot be declared as unsafe"); } } </del> <ins> impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { fn check_unsafety_coherence(&mut self, item: &'v ast::Item, unsafety: ast::Unsafety, polarity: ast::ImplPolarity) { 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 => { span_err!(self.tcx.sess, item.span, E0197, "inherent impls cannot be declared as unsafe"); </ins> } <ins> } } </ins> <del> Some(trait_ref) => { let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id); match (trait_def.unsafety, unsafety, polarity) { (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => { span_err!(self.tcx.sess, item.span, E0198, "negative implementations are not unsafe"); } </del> <ins> Some(trait_ref) => { let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id); match (trait_def.unsafety, unsafety, polarity) { (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => { span_err!(self.tcx.sess, item.span, E0198, "negative implementations are not unsafe"); } </ins> <del> (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => { span_err!(self.tcx.sess, item.span, E0199, "implementing the trait `{}` is not unsafe", trait_ref.user_string(self.tcx)); } </del> <ins> (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => { span_err!(self.tcx.sess, item.span, E0199, "implementing the trait `{}` is not unsafe", trait_ref.user_string(self.tcx)); } </ins> <del> (ast::Unsafety::Unsafe, ast::Unsafety::Normal, ast::ImplPolarity::Positive) => { span_err!(self.tcx.sess, item.span, E0200, "the trait `{}` requires an `unsafe impl` declaration", trait_ref.user_string(self.tcx)); } </del> <ins> (ast::Unsafety::Unsafe, ast::Unsafety::Normal, ast::ImplPolarity::Positive) => { span_err!(self.tcx.sess, item.span, E0200, "the trait `{}` requires an `unsafe impl` declaration", trait_ref.user_string(self.tcx)); } </ins> <del> (ast::Unsafety::Unsafe, ast::Unsafety::Normal, ast::ImplPolarity::Negative) | (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) | (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => { /* OK */ } } </del> <ins> (ast::Unsafety::Unsafe, ast::Unsafety::Normal, ast::ImplPolarity::Negative) | (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) | (ast::Unsafety::Normal, ast::Unsafety::Normal, _) => { /* OK */ </ins> } } } <ins> } } } impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v ast::Item) { match item.node { ast::ItemDefaultImpl(unsafety, _) => { self.check_unsafety_coherence(item, unsafety, ast::ImplPolarity::Positive); } ast::ItemImpl(unsafety, polarity, _, _, _, _) => { self.check_unsafety_coherence(item, unsafety, polarity); } </ins> _ => { } }

Discussion:
I suspect that we may want more experience with this syntax before freezing it, but I may also be misremembering! cc cc
triage: I-nominated
I believe you're right. I'll work on a fix for this. Here's a test case:
0 beta, P-backcompat-lang.