Skip to content

Commit 02d12bc

Browse files
committed
Improve lossy_provenance_casts lint diagnostics
Use `multipart_suggestion` and don't suggested unnecessary parenthesis.
1 parent 080d545 commit 02d12bc

File tree

3 files changed

+61
-13
lines changed

3 files changed

+61
-13
lines changed

compiler/rustc_typeck/src/check/cast.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -993,20 +993,33 @@ impl<'a, 'tcx> CastCheck<'tcx> {
993993
));
994994

995995
let msg = "use `.addr()` to obtain the address of a pointer";
996-
if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
997-
let scalar_cast = match t_c {
998-
ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
999-
_ => format!(" as {}", self.cast_ty),
1000-
};
996+
997+
let expr_prec = self.expr.precedence().order();
998+
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
999+
1000+
let scalar_cast = match t_c {
1001+
ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
1002+
_ => format!(" as {}", self.cast_ty),
1003+
};
1004+
1005+
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
1006+
1007+
if needs_parens {
1008+
let suggestions = vec![
1009+
(self.expr_span.shrink_to_lo(), String::from("(")),
1010+
(cast_span, format!(").addr(){scalar_cast}")),
1011+
];
1012+
1013+
err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
1014+
} else {
10011015
err.span_suggestion(
1002-
self.span,
1016+
cast_span,
10031017
msg,
1004-
format!("({snippet}).addr(){scalar_cast}"),
1005-
Applicability::MaybeIncorrect
1018+
format!(".addr(){scalar_cast}"),
1019+
Applicability::MaybeIncorrect,
10061020
);
1007-
} else {
1008-
err.help(msg);
10091021
}
1022+
10101023
err.help(
10111024
"if you can't comply with strict provenance and need to expose the pointer \
10121025
provenance you can use `.expose_addr()` instead"

src/test/ui/lint/lint-strict-provenance-lossy-casts.rs

+7
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ fn main() {
88

99
let addr_32bit = &x as *const u8 as u32;
1010
//~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
11+
12+
// don't add unnecessary parens in the suggestion
13+
let ptr = &x as *const u8;
14+
let ptr_addr = ptr as usize;
15+
//~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
16+
let ptr_addr_32bit = ptr as u32;
17+
//~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
1118
}

src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr

+31-3
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,50 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
22
--> $DIR/lint-strict-provenance-lossy-casts.rs:6:23
33
|
44
LL | let addr: usize = &x as *const u8 as usize;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
note: the lint level is defined here
88
--> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
99
|
1010
LL | #![deny(lossy_provenance_casts)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^
1212
= help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
13+
help: use `.addr()` to obtain the address of a pointer
14+
|
15+
LL | let addr: usize = (&x as *const u8).addr();
16+
| + ~~~~~~~~
1317

1418
error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
1519
--> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
1620
|
1721
LL | let addr_32bit = &x as *const u8 as u32;
18-
| ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
22+
| ^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
25+
help: use `.addr()` to obtain the address of a pointer
26+
|
27+
LL | let addr_32bit = (&x as *const u8).addr() as u32;
28+
| + ~~~~~~~~~~~~~~~
29+
30+
error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
31+
--> $DIR/lint-strict-provenance-lossy-casts.rs:14:20
32+
|
33+
LL | let ptr_addr = ptr as usize;
34+
| ^^^---------
35+
| |
36+
| help: use `.addr()` to obtain the address of a pointer: `.addr()`
37+
|
38+
= help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
39+
40+
error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
41+
--> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
42+
|
43+
LL | let ptr_addr_32bit = ptr as u32;
44+
| ^^^-------
45+
| |
46+
| help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
1947
|
2048
= help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
2149

22-
error: aborting due to 2 previous errors
50+
error: aborting due to 4 previous errors
2351

0 commit comments

Comments
 (0)