diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 4728edd837a..c1c58db5764 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -89,6 +89,8 @@ hir_typeck_suggest_boxing_note = for more on the distinction between the stack a hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new` +hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead + hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 5161a366ae7..6b4168d8944 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -298,6 +298,17 @@ pub enum SuggestBoxing { }, } +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_suggest_ptr_null_mut, + applicability = "maybe-incorrect", + code = "core::ptr::null_mut()" +)] +pub struct SuggestPtrNullMut { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = "E0599")] pub struct NoAssociatedItem { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 48c3d6f08de..4a3e28ffce9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,4 +1,5 @@ use crate::coercion::CoerceMany; +use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::gather_locals::Declaration; use crate::method::MethodCallee; @@ -814,6 +815,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + self.suggest_ptr_null_mut( + expected_ty, + provided_ty, + provided_args[*provided_idx], + &mut err, + ); + // Call out where the function is defined self.label_fn_like( &mut err, @@ -1271,6 +1279,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } + fn suggest_ptr_null_mut( + &self, + expected_ty: Ty<'tcx>, + provided_ty: Ty<'tcx>, + arg: &hir::Expr<'tcx>, + err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>, + ) { + if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind() + && let ty::RawPtr(ty::TypeAndMut { mutbl: 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) + { + // The user provided `ptr::null()`, but the function expects + // `ptr::null_mut()`. + err.subdiagnostic(SuggestPtrNullMut { + span: arg.span + }); + } + } + // AST fragment checking pub(in super::super) fn check_lit( &self, diff --git a/tests/ui/typeck/ptr-null-mutability-suggestions.fixed b/tests/ui/typeck/ptr-null-mutability-suggestions.fixed new file mode 100644 index 00000000000..d00536b29cf --- /dev/null +++ b/tests/ui/typeck/ptr-null-mutability-suggestions.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused_imports)] +use std::ptr; + +fn expecting_null_mut(_: *mut u8) {} + +fn main() { + expecting_null_mut(core::ptr::null_mut()); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/ptr-null-mutability-suggestions.rs b/tests/ui/typeck/ptr-null-mutability-suggestions.rs new file mode 100644 index 00000000000..ea3066d2289 --- /dev/null +++ b/tests/ui/typeck/ptr-null-mutability-suggestions.rs @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused_imports)] +use std::ptr; + +fn expecting_null_mut(_: *mut u8) {} + +fn main() { + expecting_null_mut(ptr::null()); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/ptr-null-mutability-suggestions.stderr b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr new file mode 100644 index 00000000000..705b029bdea --- /dev/null +++ b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/ptr-null-mutability-suggestions.rs:9:24 + | +LL | expecting_null_mut(ptr::null()); + | ------------------ ^^^^^^^^^^^ + | | | + | | types differ in mutability + | | help: consider using `core::ptr::null_mut` instead: `core::ptr::null_mut()` + | arguments to this function are incorrect + | + = note: expected raw pointer `*mut u8` + found raw pointer `*const _` +note: function defined here + --> $DIR/ptr-null-mutability-suggestions.rs:6:4 + | +LL | fn expecting_null_mut(_: *mut u8) {} + | ^^^^^^^^^^^^^^^^^^ ---------- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.