Skip to content

Commit 975152c

Browse files
LeSeulArtichautNemo157
authored andcommitted
Add MVP suggestion for unsafe_op_in_unsafe_fn
Nemo157 rebase notes: Migrated the changes to the lint into fluent
1 parent a525c7d commit 975152c

File tree

7 files changed

+105
-11
lines changed

7 files changed

+105
-11
lines changed

compiler/rustc_mir_transform/messages.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned
5555
mir_transform_union_access_label = access to union field
5656
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
5757
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
58+
.suggestion = consider wrapping the function body in an unsafe block
5859
5960
mir_transform_unused_unsafe = unnecessary `unsafe` block
6061
.label = because it's nested under this `unsafe` block

compiler/rustc_mir_transform/src/check_unsafety.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
527527
}
528528

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

531533
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
532534
let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
@@ -561,12 +563,24 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
561563
op_in_unsafe_fn_allowed,
562564
});
563565
}
564-
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
565-
UNSAFE_OP_IN_UNSAFE_FN,
566-
lint_root,
567-
source_info.span,
568-
errors::UnsafeOpInUnsafeFn { details },
569-
),
566+
UnsafetyViolationKind::UnsafeFn => {
567+
tcx.emit_spanned_lint(
568+
UNSAFE_OP_IN_UNSAFE_FN,
569+
lint_root,
570+
source_info.span,
571+
errors::UnsafeOpInUnsafeFn {
572+
details,
573+
suggest_unsafe_block: suggest_unsafe_block.then(|| {
574+
let body = tcx.hir().body_owned_by(def_id);
575+
let body_span = tcx.hir().body(body).value.span;
576+
let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi();
577+
let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo();
578+
(start, end)
579+
}),
580+
},
581+
);
582+
suggest_unsafe_block = false;
583+
}
570584
}
571585
}
572586

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_errors::{
2-
DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, IntoDiagnostic,
2+
Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
3+
IntoDiagnostic,
34
};
45
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
56
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
@@ -130,6 +131,7 @@ impl RequiresUnsafeDetail {
130131

131132
pub(crate) struct UnsafeOpInUnsafeFn {
132133
pub details: RequiresUnsafeDetail,
134+
pub suggest_unsafe_block: Option<(Span, Span)>,
133135
}
134136

135137
impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
@@ -138,13 +140,20 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
138140
self,
139141
diag: &'b mut DiagnosticBuilder<'a, ()>,
140142
) -> &'b mut DiagnosticBuilder<'a, ()> {
141-
let desc = diag
142-
.handler()
143-
.expect("lint should not yet be emitted")
144-
.eagerly_translate_to_string(self.details.label(), [].into_iter());
143+
let handler = diag.handler().expect("lint should not yet be emitted");
144+
let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
145145
diag.set_arg("details", desc);
146146
diag.span_label(self.details.span, self.details.label());
147147
diag.note(self.details.note());
148+
149+
if let Some((start, end)) = self.suggest_unsafe_block {
150+
diag.multipart_suggestion_verbose(
151+
crate::fluent_generated::mir_transform_suggestion,
152+
vec![(start, " unsafe {".into()), (end, "}".into())],
153+
Applicability::MaybeIncorrect,
154+
);
155+
}
156+
148157
diag
149158
}
150159

tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ note: the lint level is defined here
1010
|
1111
LL | #![deny(unsafe_op_in_unsafe_fn)]
1212
| ^^^^^^^^^^^^^^^^^^^^^^
13+
help: consider wrapping the function body 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 @@ note: the lint level is defined here
5260
LL | #[deny(warnings)]
5361
| ^^^^^^^^
5462
= note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
63+
help: consider wrapping the function body 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
Lines changed: 12 additions & 0 deletions
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() {}
Lines changed: 12 additions & 0 deletions
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() {}
Lines changed: 30 additions & 0 deletions
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: consult the function's documentation for information on how to avoid undefined behavior
8+
note: the lint level is defined here
9+
--> $DIR/wrapping-unsafe-block-sugg.rs:3:9
10+
|
11+
LL | #![deny(unsafe_op_in_unsafe_fn)]
12+
| ^^^^^^^^^^^^^^^^^^^^^^
13+
help: consider wrapping the function body 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)