Skip to content

Commit 1f75da0

Browse files
Add MVP suggestion for unsafe_op_in_unsafe_fn
1 parent e5a7d8f commit 1f75da0

File tree

5 files changed

+100
-6
lines changed

5 files changed

+100
-6
lines changed

compiler/rustc_mir_transform/src/check_unsafety.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_data_structures::fx::FxHashMap;
2-
use rustc_errors::struct_span_err;
2+
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
33
use rustc_hir as hir;
44
use rustc_hir::def_id::{DefId, LocalDefId};
55
use rustc_hir::hir_id::HirId;
@@ -569,6 +569,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
569569
}
570570

571571
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
572+
// Only suggest wrapping the entire function body in an unsafe block once
573+
let mut suggest_unsafe_block = true;
572574

573575
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
574576
let (description, note) = details.description_and_note();
@@ -597,13 +599,16 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
597599
lint_root,
598600
source_info.span,
599601
|lint| {
600-
lint.build(&format!(
602+
let mut err = lint.build(&format!(
601603
"{} is unsafe and requires unsafe block (error E0133)",
602604
description,
603-
))
604-
.span_label(source_info.span, description)
605-
.note(note)
606-
.emit();
605+
));
606+
err.span_label(source_info.span, description).note(note);
607+
if suggest_unsafe_block {
608+
suggest_wrapping_unsafe_block(tcx, def_id, &mut err);
609+
suggest_unsafe_block = false;
610+
}
611+
err.emit();
607612
},
608613
),
609614
}
@@ -614,6 +619,25 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
614619
}
615620
}
616621

622+
fn suggest_wrapping_unsafe_block(
623+
tcx: TyCtxt<'_>,
624+
def_id: LocalDefId,
625+
err: &mut DiagnosticBuilder<'_, ()>,
626+
) {
627+
let body_span = tcx.hir().body(tcx.hir().body_owned_by(def_id)).value.span;
628+
629+
let suggestion = vec![
630+
(tcx.sess.source_map().start_point(body_span).shrink_to_hi(), " unsafe {".into()),
631+
(tcx.sess.source_map().end_point(body_span).shrink_to_lo(), "}".into()),
632+
];
633+
634+
err.multipart_suggestion_verbose(
635+
"consider wrapping the function in an unsafe block",
636+
suggestion,
637+
Applicability::MaybeIncorrect,
638+
);
639+
}
640+
617641
fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
618642
tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
619643
}

src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ note: the lint level is defined here
1010
LL | #![deny(unsafe_op_in_unsafe_fn)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^
1212
= note: consult the function's documentation for information on how to avoid undefined behavior
13+
help: consider wrapping the function in an unsafe block
14+
|
15+
LL ~ unsafe fn deny_level() { unsafe {
16+
LL | unsf();
17+
...
18+
LL |
19+
LL ~ }}
20+
|
1321

1422
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
1523
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:15:5
@@ -52,6 +60,14 @@ LL | #[deny(warnings)]
5260
| ^^^^^^^^
5361
= note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
5462
= note: consult the function's documentation for information on how to avoid undefined behavior
63+
help: consider wrapping the function in an unsafe block
64+
|
65+
LL ~ unsafe fn warning_level() { unsafe {
66+
LL | unsf();
67+
...
68+
LL |
69+
LL ~ }}
70+
|
5571

5672
error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
5773
--> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// run-rustfix
2+
3+
#![deny(unsafe_op_in_unsafe_fn)]
4+
5+
unsafe fn unsf() {}
6+
7+
pub unsafe fn foo() { unsafe {
8+
unsf(); //~ ERROR call to unsafe function is unsafe
9+
unsf(); //~ ERROR call to unsafe function is unsafe
10+
}}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// run-rustfix
2+
3+
#![deny(unsafe_op_in_unsafe_fn)]
4+
5+
unsafe fn unsf() {}
6+
7+
pub unsafe fn foo() {
8+
unsf(); //~ ERROR call to unsafe function is unsafe
9+
unsf(); //~ ERROR call to unsafe function is unsafe
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
2+
--> $DIR/wrapping-unsafe-block-sugg.rs:8:5
3+
|
4+
LL | unsf();
5+
| ^^^^^^ call to unsafe function
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/wrapping-unsafe-block-sugg.rs:3:9
9+
|
10+
LL | #![deny(unsafe_op_in_unsafe_fn)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
= note: consult the function's documentation for information on how to avoid undefined behavior
13+
help: consider wrapping the function in an unsafe block
14+
|
15+
LL ~ pub unsafe fn foo() { unsafe {
16+
LL | unsf();
17+
LL | unsf();
18+
LL ~ }}
19+
|
20+
21+
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
22+
--> $DIR/wrapping-unsafe-block-sugg.rs:9:5
23+
|
24+
LL | unsf();
25+
| ^^^^^^ call to unsafe function
26+
|
27+
= note: consult the function's documentation for information on how to avoid undefined behavior
28+
29+
error: aborting due to 2 previous errors
30+

0 commit comments

Comments
 (0)