From 5b8f281df26dd3e1236df9bedb14930f5460098e Mon Sep 17 00:00:00 2001 From: Jed McKenna Date: Tue, 1 Sep 2026 17:23:20 +1000 Subject: [PATCH] new branch, fresh git history. --- compiler/rustc_hir_typeck/src/diagnostics.rs | 24 +++++ .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 61 +++++++++--- tests/ui/span/coerce-suggestions.rs | 10 ++ tests/ui/span/coerce-suggestions.stderr | 99 +++++++++++++++++-- 4 files changed, 177 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 2d4cf3d9b400d..04f0fd19b1482 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -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 -> diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ba44d1966d971..a6792408e34d2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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; @@ -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 }); + } + _ => {} } } @@ -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], diff --git a/tests/ui/span/coerce-suggestions.rs b/tests/ui/span/coerce-suggestions.rs index 13331a016fcfe..3395013e9910d 100644 --- a/tests/ui/span/coerce-suggestions.rs +++ b/tests/ui/span/coerce-suggestions.rs @@ -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(); @@ -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 } diff --git a/tests/ui/span/coerce-suggestions.stderr b/tests/ui/span/coerce-suggestions.stderr index d0f76a23edc45..5b9049ab6f214 100644 --- a/tests/ui/span/coerce-suggestions.stderr +++ b/tests/ui/span/coerce-suggestions.stderr @@ -1,5 +1,5 @@ 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` @@ -7,7 +7,7 @@ LL | let x: usize = String::new(); | 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` @@ -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 @@ -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 @@ -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`.