about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2021-10-06 12:33:21 -0700
committerGitHub <noreply@github.com>2021-10-06 12:33:21 -0700
commitf5bfa3450a4f115bcddb1296b2e3ec13dbaac945 (patch)
treef6691a0540df1868b0cc3152e5b623bf09a1e2ef
parent7d6feb421ed159ee8f110741d4fb8a43b4ba7ff5 (diff)
parent388bcc1cb086c567f17a4933bfb1d3f14eb19fb7 (diff)
downloadrust-f5bfa3450a4f115bcddb1296b2e3ec13dbaac945.tar.gz
rust-f5bfa3450a4f115bcddb1296b2e3ec13dbaac945.zip
Rollup merge of #89528 - FabianWolff:issue-89497, r=jackh726
Fix suggestion to borrow when casting from pointer to reference

Fixes #89497.
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs44
-rw-r--r--src/test/ui/cast/issue-89497.fixed10
-rw-r--r--src/test/ui/cast/issue-89497.rs10
-rw-r--r--src/test/ui/cast/issue-89497.stderr15
-rw-r--r--src/test/ui/error-codes/E0605.stderr5
-rw-r--r--src/test/ui/issues/issue-2995.stderr5
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr5
7 files changed, 80 insertions, 14 deletions
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 9736a7b2e28..51c766fe57c 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -351,7 +351,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 );
                 let mut sugg = None;
                 let mut sugg_mutref = false;
-                if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
+                if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
                     if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
                         if fcx
                             .try_coerce(
@@ -366,7 +366,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             )
                             .is_ok()
                         {
-                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                            sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
                         }
                     } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
                         if expr_mutbl == Mutability::Not
@@ -400,7 +400,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             )
                             .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() {
                     if fcx
@@ -416,19 +416,47 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         )
                         .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
                     err.span_note(self.expr.span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
-                } else if let Some(sugg) = sugg {
+                } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
-                    err.span_suggestion_verbose(
-                        self.expr.span.shrink_to_lo(),
+
+                    let has_parens = fcx
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(self.expr.span)
+                        .map_or(false, |snip| snip.starts_with("("));
+
+                    // Very crude check to see whether the expression must be wrapped
+                    // in parentheses for the suggestion to work (issue #89497).
+                    // Can/should be extended in the future.
+                    let needs_parens = !has_parens
+                        && match self.expr.kind {
+                            hir::ExprKind::Cast(..) => true,
+                            _ => false,
+                        };
+
+                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    if needs_parens {
+                        suggestion[0].1 += "(";
+                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                    }
+                    if remove_cast {
+                        suggestion.push((
+                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            String::new(),
+                        ));
+                    }
+
+                    err.multipart_suggestion_verbose(
                         "consider borrowing the value",
-                        sugg,
+                        suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if !matches!(
diff --git a/src/test/ui/cast/issue-89497.fixed b/src/test/ui/cast/issue-89497.fixed
new file mode 100644
index 00000000000..04c10a5f79e
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.fixed
@@ -0,0 +1,10 @@
+// Regression test for issue #89497.
+
+// run-rustfix
+
+fn main() {
+    let pointer: usize = &1_i32 as *const i32 as usize;
+    let _reference: &'static i32 = unsafe { &*(pointer as *const i32) };
+    //~^ ERROR: non-primitive cast
+    //~| HELP: consider borrowing the value
+}
diff --git a/src/test/ui/cast/issue-89497.rs b/src/test/ui/cast/issue-89497.rs
new file mode 100644
index 00000000000..76301b704c8
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #89497.
+
+// run-rustfix
+
+fn main() {
+    let pointer: usize = &1_i32 as *const i32 as usize;
+    let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+    //~^ ERROR: non-primitive cast
+    //~| HELP: consider borrowing the value
+}
diff --git a/src/test/ui/cast/issue-89497.stderr b/src/test/ui/cast/issue-89497.stderr
new file mode 100644
index 00000000000..3726f8a4101
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.stderr
@@ -0,0 +1,15 @@
+error[E0605]: non-primitive cast: `*const i32` as `&'static i32`
+  --> $DIR/issue-89497.rs:7:45
+   |
+LL |     let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL -     let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+LL +     let _reference: &'static i32 = unsafe { &*(pointer as *const i32) };
+   | 
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr
index e5647ee6d09..d082b6c10cc 100644
--- a/src/test/ui/error-codes/E0605.stderr
+++ b/src/test/ui/error-codes/E0605.stderr
@@ -12,8 +12,9 @@ LL |     v as &u8;
    |
 help: consider borrowing the value
    |
-LL |     &*v as &u8;
-   |     ++
+LL -     v as &u8;
+LL +     &*v;
+   | 
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr
index 455d32e233a..7616f987d73 100644
--- a/src/test/ui/issues/issue-2995.stderr
+++ b/src/test/ui/issues/issue-2995.stderr
@@ -6,8 +6,9 @@ LL |     let _q: &isize = p as &isize;
    |
 help: consider borrowing the value
    |
-LL |     let _q: &isize = &*p as &isize;
-   |                      ++
+LL -     let _q: &isize = p as &isize;
+LL +     let _q: &isize = &*p;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index a47eb87cff0..7f91d5ed42c 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -28,8 +28,9 @@ LL |     let _ = v as &u8;
    |
 help: consider borrowing the value
    |
-LL |     let _ = &*v as &u8;
-   |             ++
+LL -     let _ = v as &u8;
+LL +     let _ = &*v;
+   | 
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13