Skip to content
Open
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
24 changes: 24 additions & 0 deletions compiler/rustc_hir_typeck/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,30 @@ pub(crate) struct SuggestPtrNullMut {
pub span: Span,
}

#[derive(Subdiagnostic)]
#[suggestion(
"consider using `&mut` instead",
applicability = "maybe-incorrect",
style = "verbose",
code = "&mut "
)]
pub(crate) struct SuggestRefMut {
#[primary_span]
pub span: Span,
}

#[derive(Subdiagnostic)]
#[suggestion(
"consider using `&raw mut` instead",
applicability = "maybe-incorrect",
style = "verbose",
code = "&raw mut "
)]
pub(crate) struct SuggestRawMut {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(
"trivial {$numeric ->
Expand Down
61 changes: 50 additions & 11 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::Expectation::*;
use crate::TupleArgumentsFlag::*;
use crate::callee::SplatLoweringInfo;
use crate::coercion::CoerceMany;
use crate::diagnostics::{ExprParenthesesNeeded, SuggestPtrNullMut};
use crate::diagnostics::{ExprParenthesesNeeded, SuggestPtrNullMut, SuggestRawMut, SuggestRefMut};
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::gather_locals::Declaration;
use crate::inline_asm::InlineAsmCtxt;
Expand Down Expand Up @@ -982,23 +982,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit()
}

fn suggest_ptr_null_mut(
fn suggest_mut_addr(
&self,
expected_ty: Ty<'tcx>,
provided_ty: Ty<'tcx>,
arg: &hir::Expr<'tcx>,
err: &mut Diag<'_>,
) {
if let ty::RawPtr(_, hir::Mutability::Mut) = expected_ty.kind()
&& let ty::RawPtr(_, hir::Mutability::Not) = provided_ty.kind()
&& let hir::ExprKind::Call(callee, _) = arg.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
&& let Res::Def(_, def_id) = path.res
&& self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id)
{
match (expected_ty.kind(), provided_ty.kind(), arg.kind) {
// The user provided `ptr::null()`, but the function expects
// `ptr::null_mut()`.
err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
(
ty::RawPtr(_, hir::Mutability::Mut),
ty::RawPtr(_, hir::Mutability::Not),
hir::ExprKind::Call(callee, _),
) if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
&& let Res::Def(_, def_id) = path.res
&& self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id) =>
{
err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
}
// &mut T expected, &T or *const/mut T found
// suggestion: replace `&` or `&raw const/mut` with `&mut`
(
ty::Ref(_, expected_ty, hir::Mutability::Mut),
ty::Ref(_, provided_ty, hir::Mutability::Not),
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr),
)
| (
ty::Ref(_, expected_ty, hir::Mutability::Mut),
ty::RawPtr(provided_ty, _),
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, _, expr),
) if expected_ty == provided_ty => {
let span = arg.span.until(expr.span);
err.subdiagnostic(SuggestRefMut { span });
}
// *mut T expected, *const T found
// suggestion: replace `&raw const` with `&raw mut`
(
ty::RawPtr(expected_ty, hir::Mutability::Mut),
ty::RawPtr(provided_ty, hir::Mutability::Not),
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, hir::Mutability::Not, expr),
) if expected_ty == provided_ty => {
let span = arg.span.until(expr.span);
err.subdiagnostic(SuggestRawMut { span });
}
// *mut T expected, &T found
// suggestion: replace `&` `&mut`
(
ty::RawPtr(expected_ty, hir::Mutability::Mut),
ty::Ref(_, provided_ty, hir::Mutability::Not),
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr),
) if expected_ty == provided_ty => {
let span = arg.span.until(expr.span);
err.subdiagnostic(SuggestRefMut { span });
}
_ => {}
}
}

Expand Down Expand Up @@ -2491,7 +2530,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
);
}

self.suggest_ptr_null_mut(
self.suggest_mut_addr(
expected_ty,
provided_ty,
self.provided_args[provided_idx],
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/span/coerce-suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ fn test(_x: &mut String) {}

fn test2(_x: &mut i32) {}

fn test3(_x: *mut String) {}

fn main() {
let x: usize = String::new();
Expand All @@ -11,9 +12,18 @@ fn main() {
let y = String::new();
test(&y);
//~^ ERROR E0308
test(&raw const y);
//~^ ERROR E0308
test(&raw mut y);
//~^ ERROR E0308
test2(&y);
//~^ ERROR E0308
let s = &mut String::new();
s = format!("foo");
//~^ ERROR E0308
let s = String::new();
test3(&raw const s);
//~^ ERROR E0308
test3(&s);
//~^ ERROR E0308
}
99 changes: 93 additions & 6 deletions tests/ui/span/coerce-suggestions.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:7:20
--> $DIR/coerce-suggestions.rs:8:20
|
LL | let x: usize = String::new();
| ----- ^^^^^^^^^^^^^ expected `usize`, found `String`
| |
| expected due to this

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:9:19
--> $DIR/coerce-suggestions.rs:10:19
|
LL | let x: &str = String::new();
| ---- ^^^^^^^^^^^^^ expected `&str`, found `String`
Expand All @@ -20,7 +20,7 @@ LL | let x: &str = &String::new();
| +

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:12:10
--> $DIR/coerce-suggestions.rs:13:10
|
LL | test(&y);
| ---- ^^ types differ in mutability
Expand All @@ -34,9 +34,55 @@ note: function defined here
|
LL | fn test(_x: &mut String) {}
| ^^^^ ---------------
help: consider using `&mut` instead
|
LL | test(&mut y);
| +++

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:14:11
--> $DIR/coerce-suggestions.rs:15:10
|
LL | test(&raw const y);
| ---- ^^^^^^^^^^^^ expected `&mut String`, found `*const String`
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut String`
found raw pointer `*const String`
note: function defined here
--> $DIR/coerce-suggestions.rs:1:4
|
LL | fn test(_x: &mut String) {}
| ^^^^ ---------------
help: consider using `&mut` instead
|
LL - test(&raw const y);
LL + test(&mut y);
|

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:17:10
|
LL | test(&raw mut y);
| ---- ^^^^^^^^^^ expected `&mut String`, found `*mut String`
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut String`
found raw pointer `*mut String`
note: function defined here
--> $DIR/coerce-suggestions.rs:1:4
|
LL | fn test(_x: &mut String) {}
| ^^^^ ---------------
help: consider using `&mut` instead
|
LL - test(&raw mut y);
LL + test(&mut y);
|

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:19:11
|
LL | test2(&y);
| ----- ^^ types differ in mutability
Expand All @@ -52,11 +98,52 @@ LL | fn test2(_x: &mut i32) {}
| ^^^^^ ------------

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:17:9
--> $DIR/coerce-suggestions.rs:22:9
|
LL | s = format!("foo");
| ^^^^^^^^^^^^^^ expected `&mut String`, found `String`

error: aborting due to 5 previous errors
error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:25:11
|
LL | test3(&raw const s);
| ----- ^^^^^^^^^^^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*mut String`
found raw pointer `*const String`
note: function defined here
--> $DIR/coerce-suggestions.rs:5:4
|
LL | fn test3(_x: *mut String) {}
| ^^^^^ ---------------
help: consider using `&raw mut` instead
|
LL - test3(&raw const s);
LL + test3(&raw mut s);
|

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:27:11
|
LL | test3(&s);
| ----- ^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*mut String`
found reference `&String`
note: function defined here
--> $DIR/coerce-suggestions.rs:5:4
|
LL | fn test3(_x: *mut String) {}
| ^^^^^ ---------------
help: consider using `&mut` instead
|
LL | test3(&mut s);
| +++

error: aborting due to 9 previous errors

For more information about this error, try `rustc --explain E0308`.
Loading