Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix suggestion to borrow when casting from pointer to reference #89528

Merged
merged 1 commit into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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!(
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/cast/issue-89497.fixed
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions src/test/ui/cast/issue-89497.rs
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions src/test/ui/cast/issue-89497.stderr
Original file line number Diff line number Diff line change
@@ -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`.
5 changes: 3 additions & 2 deletions src/test/ui/error-codes/E0605.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/issues/issue-2995.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/mismatched_types/cast-rfc0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down