about summary refs log tree commit diff
diff options
context:
space:
mode:
authorniluxv <niluxv.opensource.C-h2ty6xl@yandex.com>2022-04-16 10:05:33 +0200
committerniluxv <niluxv.opensource.C-h2ty6xl@yandex.com>2022-04-16 10:32:37 +0200
commit02d12bc30c173fd0cbf55d67c42d6cbae231203a (patch)
treec3433d6a54133e83b84456e8c9fffcfda6c55797
parent080d5452e1bb6e18e12a073d4d0283fd9b6dac0b (diff)
downloadrust-02d12bc30c173fd0cbf55d67c42d6cbae231203a.tar.gz
rust-02d12bc30c173fd0cbf55d67c42d6cbae231203a.zip
Improve `lossy_provenance_casts` lint diagnostics
Use `multipart_suggestion` and don't suggested unnecessary parenthesis.
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs33
-rw-r--r--src/test/ui/lint/lint-strict-provenance-lossy-casts.rs7
-rw-r--r--src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr34
3 files changed, 61 insertions, 13 deletions
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 049940d19a6..da054077376 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -993,20 +993,33 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 ));
 
                 let msg = "use `.addr()` to obtain the address of a pointer";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
-                    let scalar_cast = match t_c {
-                        ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
-                        _ => format!(" as {}", self.cast_ty),
-                    };
+
+                let expr_prec = self.expr.precedence().order();
+                let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
+
+                let scalar_cast = match t_c {
+                    ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
+                    _ => format!(" as {}", self.cast_ty),
+                };
+
+                let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
+
+                if needs_parens {
+                    let suggestions = vec![
+                        (self.expr_span.shrink_to_lo(), String::from("(")),
+                        (cast_span, format!(").addr(){scalar_cast}")),
+                    ];
+
+                    err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                } else {
                     err.span_suggestion(
-                        self.span,
+                        cast_span,
                         msg,
-                        format!("({snippet}).addr(){scalar_cast}"),
-                        Applicability::MaybeIncorrect
+                        format!(".addr(){scalar_cast}"),
+                        Applicability::MaybeIncorrect,
                     );
-                } else {
-                    err.help(msg);
                 }
+
                 err.help(
                     "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
index 3690fbc904d..9799a053756 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
@@ -8,4 +8,11 @@ fn main() {
 
     let addr_32bit = &x as *const u8 as u32;
     //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+
+    // don't add unnecessary parens in the suggestion
+    let ptr = &x as *const u8;
+    let ptr_addr = ptr as usize;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+    let ptr_addr_32bit = ptr as u32;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
 }
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
index e7a6c1837bd..05178b34b11 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -2,7 +2,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
   --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23
    |
 LL |     let addr: usize = &x as *const u8 as usize;
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
@@ -10,14 +10,42 @@ note: the lint level is defined here
 LL | #![deny(lossy_provenance_casts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
    = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+help: use `.addr()` to obtain the address of a pointer
+   |
+LL |     let addr: usize = (&x as *const u8).addr();
+   |                       +               ~~~~~~~~
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
    |
 LL |     let addr_32bit = &x as *const u8 as u32;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+help: use `.addr()` to obtain the address of a pointer
+   |
+LL |     let addr_32bit = (&x as *const u8).addr() as u32;
+   |                      +               ~~~~~~~~~~~~~~~
+
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:14:20
+   |
+LL |     let ptr_addr = ptr as usize;
+   |                    ^^^---------
+   |                       |
+   |                       help: use `.addr()` to obtain the address of a pointer: `.addr()`
+   |
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
+   |
+LL |     let ptr_addr_32bit = ptr as u32;
+   |                          ^^^-------
+   |                             |
+   |                             help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
    |
    = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors