diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 959fcf8d89e86..269d9f3b102c1 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; +use rustc_hir::{BlockCheckMode, ExprKind, Node}; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; @@ -517,24 +518,48 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() { let (description, note) = details.description_and_note(); - // Report an error. - let unsafe_fn_msg = - if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; - match kind { UnsafetyViolationKind::General => { // once - struct_span_err!( + let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { + " function or" + } else { + "" + }; + + let mut err = struct_span_err!( tcx.sess, source_info.span, E0133, "{} is unsafe and requires unsafe{} block", description, unsafe_fn_msg, - ) - .span_label(source_info.span, description) - .note(note) - .emit(); + ); + err.span_label(source_info.span, description).note(note); + let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| { + if let Node::Expr(block) = node + && let ExprKind::Block(block, _) = block.kind + && let BlockCheckMode::UnsafeBlock(_) = block.rules + { + true + } + else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) + && sig.header.is_unsafe() + { + true + } else { + false + } + }); + if let Some((id, _)) = note_non_inherited { + let span = tcx.hir().span(id); + err.span_label( + tcx.sess.source_map().guess_head_span(span), + "items do not inherit unsafety from separate enclosing items", + ); + } + + err.emit(); } UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( UNSAFE_OP_IN_UNSAFE_FN, diff --git a/src/test/ui/unsafe/unsafe-not-inherited.rs b/src/test/ui/unsafe/unsafe-not-inherited.rs new file mode 100644 index 0000000000000..6d797caa0f94d --- /dev/null +++ b/src/test/ui/unsafe/unsafe-not-inherited.rs @@ -0,0 +1,26 @@ +#![allow(unused, dead_code)] + +static mut FOO: u64 = 0; + +fn static_mod() { + unsafe {static BAR: u64 = FOO;} + //~^ ERROR: use of mutable static is unsafe + //~| NOTE: use of mutable static + //~| NOTE: mutable statics can be mutated by multiple threads + //~| NOTE: items do not inherit unsafety +} + +unsafe fn unsafe_call() {} +fn foo() { + unsafe { + //~^ NOTE: items do not inherit unsafety + fn bar() { + unsafe_call(); + //~^ ERROR: call to unsafe function + //~| NOTE: call to unsafe function + //~| NOTE: consult the function's documentation + } + } +} + +fn main() {} diff --git a/src/test/ui/unsafe/unsafe-not-inherited.stderr b/src/test/ui/unsafe/unsafe-not-inherited.stderr new file mode 100644 index 0000000000000..3bc5ca5c9d151 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-not-inherited.stderr @@ -0,0 +1,24 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/unsafe-not-inherited.rs:6:31 + | +LL | unsafe {static BAR: u64 = FOO;} + | ------ ^^^ use of mutable static + | | + | items do not inherit unsafety from separate enclosing items + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unsafe-not-inherited.rs:18:13 + | +LL | unsafe { + | ------ items do not inherit unsafety from separate enclosing items +... +LL | unsafe_call(); + | ^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`.