Skip to content

Commit 20a6b57

Browse files
committed
Improve diagnostics of the invalid_reference_casting lint
1 parent 50a4671 commit 20a6b57

File tree

5 files changed

+152
-77
lines changed

5 files changed

+152
-77
lines changed

compiler/rustc_lint/messages.ftl

+4-1
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,10 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
318318
319319
lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
320320
321-
lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
321+
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
322+
.label = casting happend here
323+
324+
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
322325
.label = casting happend here
323326
324327
lint_lintpass_by_hand = implementing `LintPass` by hand

compiler/rustc_lint/src/lints.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -745,10 +745,17 @@ pub enum InvalidFromUtf8Diag {
745745

746746
// reference_casting.rs
747747
#[derive(LintDiagnostic)]
748-
#[diag(lint_invalid_reference_casting)]
749-
pub struct InvalidReferenceCastingDiag {
750-
#[label]
751-
pub orig_cast: Option<Span>,
748+
pub enum InvalidReferenceCastingDiag {
749+
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
750+
BorrowAsMut {
751+
#[label]
752+
orig_cast: Option<Span>,
753+
},
754+
#[diag(lint_invalid_reference_casting_assign_to_ref)]
755+
AssignToRef {
756+
#[label]
757+
orig_cast: Option<Span>,
758+
},
752759
}
753760

754761
// hidden_unicode_codepoints.rs

compiler/rustc_lint/src/reference_casting.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,25 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
7373
return;
7474
};
7575

76-
if is_cast_from_const_to_mut(cx, e) {
77-
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag { orig_cast: None });
76+
let orig_cast = if is_cast_from_const_to_mut(cx, e) {
77+
None
7878
} else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
7979
&& let Res::Local(hir_id) = &path.res
8080
&& let Some(orig_cast) = self.casted.get(hir_id) {
81-
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag { orig_cast: Some(*orig_cast) });
82-
}
81+
Some(*orig_cast)
82+
} else {
83+
return;
84+
};
85+
86+
cx.emit_spanned_lint(
87+
INVALID_REFERENCE_CASTING,
88+
expr.span,
89+
if matches!(expr.kind, ExprKind::AddrOf(..)) {
90+
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
91+
} else {
92+
InvalidReferenceCastingDiag::AssignToRef { orig_cast }
93+
},
94+
);
8395
}
8496
}
8597

tests/ui/lint/reference_casting.rs

+57-36
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,63 @@ extern "C" {
99
fn int_ffi(c: *mut i32);
1010
}
1111

12-
fn main() {
12+
unsafe fn ref_to_mut() {
13+
let num = &3i32;
14+
15+
let _num = &mut *(num as *const i32 as *mut i32);
16+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
17+
let _num = &mut *(num as *const i32).cast_mut();
18+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
19+
let _num = &mut *std::ptr::from_ref(num).cast_mut();
20+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
21+
let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
22+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
23+
let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
24+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
25+
let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
26+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
27+
28+
let deferred = num as *const i32 as *mut i32;
29+
let _num = &mut *deferred;
30+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
31+
}
32+
33+
unsafe fn assign_to_ref() {
1334
let s = String::from("Hello");
1435
let a = &s;
15-
unsafe {
16-
let num = &3i32;
17-
let mut_num = &mut 3i32;
18-
19-
*(a as *const _ as *mut _) = String::from("Replaced");
20-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
21-
*(a as *const _ as *mut String) += " world";
22-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
23-
let _num = &mut *(num as *const i32 as *mut i32);
24-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
25-
let _num = &mut *(num as *const i32).cast_mut();
26-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
27-
*std::ptr::from_ref(num).cast_mut() += 1;
28-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
29-
*std::ptr::from_ref({ num }).cast_mut() += 1;
30-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
31-
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
32-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
33-
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
34-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
35-
let value = num as *const i32 as *mut i32;
36-
*value = 1;
37-
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
38-
39-
// Shouldn't be warned against
40-
*(num as *const i32 as *mut i32);
41-
println!("{}", *(num as *const _ as *const i16));
42-
println!("{}", *(mut_num as *mut _ as *mut i16));
43-
ffi(a.as_ptr() as *mut _);
44-
int_ffi(num as *const _ as *mut _);
45-
int_ffi(&3 as *const _ as *mut _);
46-
let mut value = 3;
47-
let value: *const i32 = &mut value;
48-
*(value as *const i16 as *mut i16) = 42;
49-
}
36+
let num = &3i32;
37+
38+
*(a as *const _ as *mut _) = String::from("Replaced");
39+
//~^ ERROR assigning to `&T` is undefined behavior
40+
*(a as *const _ as *mut String) += " world";
41+
//~^ ERROR assigning to `&T` is undefined behavior
42+
*std::ptr::from_ref(num).cast_mut() += 1;
43+
//~^ ERROR assigning to `&T` is undefined behavior
44+
*std::ptr::from_ref({ num }).cast_mut() += 1;
45+
//~^ ERROR assigning to `&T` is undefined behavior
46+
*{ std::ptr::from_ref(num) }.cast_mut() += 1;
47+
//~^ ERROR assigning to `&T` is undefined behavior
48+
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
49+
//~^ ERROR assigning to `&T` is undefined behavior
50+
let value = num as *const i32 as *mut i32;
51+
*value = 1;
52+
//~^ ERROR assigning to `&T` is undefined behavior
5053
}
54+
55+
unsafe fn no_warn() {
56+
let num = &3i32;
57+
let mut_num = &mut 3i32;
58+
let a = &String::from("ffi");
59+
60+
*(num as *const i32 as *mut i32);
61+
println!("{}", *(num as *const _ as *const i16));
62+
println!("{}", *(mut_num as *mut _ as *mut i16));
63+
ffi(a.as_ptr() as *mut _);
64+
int_ffi(num as *const _ as *mut _);
65+
int_ffi(&3 as *const _ as *mut _);
66+
let mut value = 3;
67+
let value: *const i32 = &mut value;
68+
*(value as *const i16 as *mut i16) = 42;
69+
}
70+
71+
fn main() {}
+64-32
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,92 @@
11
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
2-
--> $DIR/reference_casting.rs:19:9
2+
--> $DIR/reference_casting.rs:15:16
33
|
4-
LL | *(a as *const _ as *mut _) = String::from("Replaced");
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | let _num = &mut *(num as *const i32 as *mut i32);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `#[deny(invalid_reference_casting)]` on by default
88

99
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
10-
--> $DIR/reference_casting.rs:21:9
10+
--> $DIR/reference_casting.rs:17:16
1111
|
12-
LL | *(a as *const _ as *mut String) += " world";
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | let _num = &mut *(num as *const i32).cast_mut();
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
16-
--> $DIR/reference_casting.rs:23:20
16+
--> $DIR/reference_casting.rs:19:16
1717
|
18-
LL | let _num = &mut *(num as *const i32 as *mut i32);
19-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
LL | let _num = &mut *std::ptr::from_ref(num).cast_mut();
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
22-
--> $DIR/reference_casting.rs:25:20
22+
--> $DIR/reference_casting.rs:21:16
2323
|
24-
LL | let _num = &mut *(num as *const i32).cast_mut();
25-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
LL | let _num = &mut *std::ptr::from_ref({ num }).cast_mut();
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
28-
--> $DIR/reference_casting.rs:27:9
28+
--> $DIR/reference_casting.rs:23:16
2929
|
30-
LL | *std::ptr::from_ref(num).cast_mut() += 1;
31-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
LL | let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut();
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232

3333
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
34-
--> $DIR/reference_casting.rs:29:9
34+
--> $DIR/reference_casting.rs:25:16
3535
|
36-
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
37-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
40-
--> $DIR/reference_casting.rs:31:9
40+
--> $DIR/reference_casting.rs:29:16
4141
|
42-
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
43-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
LL | let deferred = num as *const i32 as *mut i32;
43+
| ----------------------------- casting happend here
44+
LL | let _num = &mut *deferred;
45+
| ^^^^^^^^^^^^^^
4446

45-
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
46-
--> $DIR/reference_casting.rs:33:9
47+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
48+
--> $DIR/reference_casting.rs:38:5
4749
|
48-
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
49-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
LL | *(a as *const _ as *mut _) = String::from("Replaced");
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5052

51-
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
52-
--> $DIR/reference_casting.rs:36:9
53+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
54+
--> $DIR/reference_casting.rs:40:5
55+
|
56+
LL | *(a as *const _ as *mut String) += " world";
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
58+
59+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
60+
--> $DIR/reference_casting.rs:42:5
61+
|
62+
LL | *std::ptr::from_ref(num).cast_mut() += 1;
63+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64+
65+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
66+
--> $DIR/reference_casting.rs:44:5
67+
|
68+
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70+
71+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
72+
--> $DIR/reference_casting.rs:46:5
73+
|
74+
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76+
77+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
78+
--> $DIR/reference_casting.rs:48:5
79+
|
80+
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82+
83+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
84+
--> $DIR/reference_casting.rs:51:5
5385
|
54-
LL | let value = num as *const i32 as *mut i32;
55-
| ----------------------------- casting happend here
56-
LL | *value = 1;
57-
| ^^^^^^^^^^
86+
LL | let value = num as *const i32 as *mut i32;
87+
| ----------------------------- casting happend here
88+
LL | *value = 1;
89+
| ^^^^^^^^^^
5890

59-
error: aborting due to 9 previous errors
91+
error: aborting due to 14 previous errors
6092

0 commit comments

Comments
 (0)