about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs31
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs25
2 files changed, 45 insertions, 11 deletions
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 2f851cd1eb5..70812761e88 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -525,6 +525,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     }
 
     let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
+    // Only suggest wrapping the entire function body in an unsafe block once
+    let mut suggest_unsafe_block = true;
 
     for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
         let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
@@ -559,12 +561,29 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     op_in_unsafe_fn_allowed,
                 });
             }
-            UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
-                UNSAFE_OP_IN_UNSAFE_FN,
-                lint_root,
-                source_info.span,
-                errors::UnsafeOpInUnsafeFn { details },
-            ),
+            UnsafetyViolationKind::UnsafeFn => {
+                tcx.emit_spanned_lint(
+                    UNSAFE_OP_IN_UNSAFE_FN,
+                    lint_root,
+                    source_info.span,
+                    errors::UnsafeOpInUnsafeFn {
+                        details,
+                        suggest_unsafe_block: suggest_unsafe_block.then(|| {
+                            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+                            let fn_sig = tcx
+                                .hir()
+                                .fn_sig_by_hir_id(hir_id)
+                                .expect("this violation only occurs in fn");
+                            let body = tcx.hir().body_owned_by(def_id);
+                            let body_span = tcx.hir().body(body).value.span;
+                            let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi();
+                            let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo();
+                            (start, end, fn_sig.span)
+                        }),
+                    },
+                );
+                suggest_unsafe_block = false;
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 22f71bb0851..4b796d79ef6 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -1,5 +1,6 @@
 use rustc_errors::{
-    DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, IntoDiagnostic,
+    Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
+    IntoDiagnostic,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
@@ -130,6 +131,12 @@ impl RequiresUnsafeDetail {
 
 pub(crate) struct UnsafeOpInUnsafeFn {
     pub details: RequiresUnsafeDetail,
+
+    /// These spans point to:
+    ///  1. the start of the function body
+    ///  2. the end of the function body
+    ///  3. the function signature
+    pub suggest_unsafe_block: Option<(Span, Span, Span)>,
 }
 
 impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
@@ -138,13 +145,21 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
         self,
         diag: &'b mut DiagnosticBuilder<'a, ()>,
     ) -> &'b mut DiagnosticBuilder<'a, ()> {
-        let desc = diag
-            .handler()
-            .expect("lint should not yet be emitted")
-            .eagerly_translate_to_string(self.details.label(), [].into_iter());
+        let handler = diag.handler().expect("lint should not yet be emitted");
+        let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
         diag.set_arg("details", desc);
         diag.span_label(self.details.span, self.details.label());
         diag.note(self.details.note());
+
+        if let Some((start, end, fn_sig)) = self.suggest_unsafe_block {
+            diag.span_note(fn_sig, crate::fluent_generated::mir_transform_note);
+            diag.tool_only_multipart_suggestion(
+                crate::fluent_generated::mir_transform_suggestion,
+                vec![(start, " unsafe {".into()), (end, "}".into())],
+                Applicability::MaybeIncorrect,
+            );
+        }
+
         diag
     }