diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 8ae26d81442..d9244c32dc4 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -33,9 +33,28 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { }); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); -impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, lint_node_id }); +impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); +impl<'gcx> HashStable> +for mir::UnsafetyViolationKind { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::UnsafetyViolationKind::General => {} + mir::UnsafetyViolationKind::ExternStatic(lint_node_id) | + mir::UnsafetyViolationKind::BorrowPacked(lint_node_id) => { + lint_node_id.hash_stable(hcx, hasher); + } + + } + } +} impl<'gcx> HashStable> for mir::Terminator<'gcx> { #[inline] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 75446586365..ef4a1c8c399 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -155,6 +155,12 @@ declare_lint! { "safe access to extern statics was erroneously allowed" } +declare_lint! { + pub SAFE_PACKED_BORROWS, + Warn, + "safe borrows of fields of packed structs were was erroneously allowed" +} + declare_lint! { pub PATTERNS_IN_FNS_WITHOUT_BODY, Warn, @@ -247,6 +253,7 @@ impl LintPass for HardwiredLints { RENAMED_AND_REMOVED_LINTS, RESOLVE_TRAIT_ON_DEFAULTED_UNIT, SAFE_EXTERN_STATICS, + SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, LEGACY_DIRECTORY_OWNERSHIP, LEGACY_IMPORTS, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d093ab45b55..266f60094c3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1722,11 +1722,18 @@ impl Location { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum UnsafetyViolationKind { + General, + ExternStatic(ast::NodeId), + BorrowPacked(ast::NodeId), +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct UnsafetyViolation { pub source_info: SourceInfo, pub description: &'static str, - pub lint_node_id: Option, + pub kind: UnsafetyViolationKind, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 97c34a1c302..b4d439f0ba8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -243,6 +243,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS), reference: "issue #42868 ", }, + FutureIncompatibleInfo { + id: LintId::of(SAFE_PACKED_BORROWS), + reference: "issue #46043 ", + }, + ]); // Register renamed and removed lints diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 9cadc04dc0a..5fe3ad86d4f 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -15,7 +15,7 @@ use rustc::ty::maps::Providers; use rustc::ty::{self, TyCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::lint::builtin::{SAFE_EXTERN_STATICS, UNUSED_UNSAFE}; +use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSAFE}; use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; @@ -140,7 +140,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { location: Location) { if let LvalueContext::Borrow { .. } = context { if util::is_disaligned(self.tcx, self.mir, self.param_env, lvalue) { - self.require_unsafe("borrow of packed field") + let source_info = self.source_info; + let lint_root = + self.visibility_scope_info[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: "borrow of packed field", + kind: UnsafetyViolationKind::BorrowPacked(lint_root) + }], &[]); } } @@ -203,7 +210,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.register_violations(&[UnsafetyViolation { source_info, description: "use of extern static", - lint_node_id: Some(lint_root) + kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]); } } @@ -218,7 +225,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { - source_info, description, lint_node_id: None + source_info, description, kind: UnsafetyViolationKind::General }], &[]); } @@ -380,21 +387,31 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } = tcx.unsafety_check_result(def_id); for &UnsafetyViolation { - source_info, description, lint_node_id + source_info, description, kind } in violations.iter() { // Report an error. - if let Some(lint_node_id) = lint_node_id { - tcx.lint_node(SAFE_EXTERN_STATICS, - lint_node_id, - source_info.span, - &format!("{} requires unsafe function or \ - block (error E0133)", description)); - } else { - struct_span_err!( - tcx.sess, source_info.span, E0133, - "{} requires unsafe function or block", description) - .span_label(source_info.span, description) - .emit(); + match kind { + UnsafetyViolationKind::General => { + struct_span_err!( + tcx.sess, source_info.span, E0133, + "{} requires unsafe function or block", description) + .span_label(source_info.span, description) + .emit(); + } + UnsafetyViolationKind::ExternStatic(lint_node_id) => { + tcx.lint_node(SAFE_EXTERN_STATICS, + lint_node_id, + source_info.span, + &format!("{} requires unsafe function or \ + block (error E0133)", description)); + } + UnsafetyViolationKind::BorrowPacked(lint_node_id) => { + tcx.lint_node(SAFE_PACKED_BORROWS, + lint_node_id, + source_info.span, + &format!("{} requires unsafe function or \ + block (error E0133)", description)); + } } } diff --git a/src/test/compile-fail/issue-27060.rs b/src/test/compile-fail/issue-27060.rs index 895d3b3fc84..37369d551fc 100644 --- a/src/test/compile-fail/issue-27060.rs +++ b/src/test/compile-fail/issue-27060.rs @@ -20,6 +20,7 @@ pub struct JustArray { array: [u32] } +#[deny(safe_packed_borrows)] fn main() { let good = Good { data: &0, @@ -33,7 +34,9 @@ fn main() { } let _ = &good.data; //~ ERROR borrow of packed field requires unsafe + //~| hard error let _ = &good.data2[0]; //~ ERROR borrow of packed field requires unsafe + //~| hard error let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 let _ = &good.aligned[2]; // ok, has align 1 diff --git a/src/test/run-pass/issue-27060.rs b/src/test/run-pass/issue-27060.rs new file mode 100644 index 00000000000..809c45466f0 --- /dev/null +++ b/src/test/run-pass/issue-27060.rs @@ -0,0 +1,42 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(packed)] +pub struct Good { + data: &'static u32, + data2: [&'static u32; 2], + aligned: [u8; 32], +} + +#[repr(packed)] +pub struct JustArray { + array: [u32] +} + +// kill this test when that turns to a hard error +#[allow(safe_packed_borrows)] +fn main() { + let good = Good { + data: &0, + data2: [&0, &0], + aligned: [0; 32] + }; + + unsafe { + let _ = &good.data; // ok + let _ = &good.data2[0]; // ok + } + + let _ = &good.data; + let _ = &good.data2[0]; + let _ = &*good.data; // ok, behind a pointer + let _ = &good.aligned; // ok, has align 1 + let _ = &good.aligned[2]; // ok, has align 1 +}