From 388bcc1cb086c567f17a4933bfb1d3f14eb19fb7 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Mon, 4 Oct 2021 21:15:02 +0200 Subject: [PATCH] Fix suggestion to borrow when casting from pointer to reference --- compiler/rustc_typeck/src/check/cast.rs | 44 +++++++++++++++---- src/test/ui/cast/issue-89497.fixed | 10 +++++ src/test/ui/cast/issue-89497.rs | 10 +++++ src/test/ui/cast/issue-89497.stderr | 15 +++++++ src/test/ui/error-codes/E0605.stderr | 5 ++- src/test/ui/issues/issue-2995.stderr | 5 ++- .../ui/mismatched_types/cast-rfc0401.stderr | 5 ++- 7 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/cast/issue-89497.fixed create mode 100644 src/test/ui/cast/issue-89497.rs create mode 100644 src/test/ui/cast/issue-89497.stderr diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 4ea7a8694c075..fe0de61ab89e2 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 0000000000000..04c10a5f79ed4 --- /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 0000000000000..76301b704c81c --- /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 0000000000000..3726f8a41015e --- /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 e5647ee6d0968..d082b6c10cc2a 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 455d32e233ab9..7616f987d7312 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 a47eb87cff06c..7f91d5ed42ce4 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