Rollup merge of #107553 - edward-shen:edward-shen/suggest-null-ptr, r=WaffleLapkin

Suggest std::ptr::null if literal 0 is given to a raw pointer function argument

Implementation feels a little sus (we're parsing the span for a `0`) but it seems to fall in line the string-expected-found-char condition right above this check, so I think it's fine.

Feedback appreciated on help text? I think it's consistent but it does sound a little awkward maybe?

Fixes #107517
This commit is contained in:
Dylan DPC 2023-02-06 19:54:13 +05:30 committed by GitHub
commit 496adf81de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 190 additions and 0 deletions

View File

@ -60,6 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_clone_for_ref(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected)
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
|| self.note_result_coercion(err, expr, expected, expr_ty);
if !suggested {
self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span);

View File

@ -13,6 +13,7 @@ use rustc_hir::{
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
TypeVisitable,
@ -1244,6 +1245,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
/// Suggest providing `std::ptr::null()` or `std::ptr::null_mut()` if they
/// pass in a literal 0 to an raw pointer.
#[instrument(skip(self, err))]
pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
expected_ty: Ty<'tcx>,
) -> bool {
// Expected type needs to be a raw pointer.
let ty::RawPtr(ty::TypeAndMut { mutbl, .. }) = expected_ty.kind() else {
return false;
};
// Provided expression needs to be a literal `0`.
let ExprKind::Lit(Spanned {
node: rustc_ast::LitKind::Int(0, _),
span,
}) = expr.kind else {
return false;
};
// We need to find a null pointer symbol to suggest
let null_sym = match mutbl {
hir::Mutability::Not => sym::ptr_null,
hir::Mutability::Mut => sym::ptr_null_mut,
};
let Some(null_did) = self.tcx.get_diagnostic_item(null_sym) else {
return false;
};
let null_path_str = with_no_trimmed_paths!(self.tcx.def_path_str(null_did));
// We have satisfied all requirements to provide a suggestion. Emit it.
err.span_suggestion(
span,
format!("if you meant to create a null pointer, use `{null_path_str}()`"),
null_path_str + "()",
Applicability::MachineApplicable,
);
true
}
pub(crate) fn suggest_associated_const(
&self,
err: &mut Diagnostic,

View File

@ -0,0 +1,31 @@
// run-rustfix
// Suggest providing a std::ptr::null{,_mut}() to a function that takes in a raw
// pointer if a literal 0 was provided by the user.
extern "C" {
fn foo(ptr: *const u8);
fn foo_mut(ptr: *mut u8);
fn usize(ptr: *const usize);
fn usize_mut(ptr: *mut usize);
}
fn main() {
unsafe {
foo(std::ptr::null());
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null()`
foo_mut(std::ptr::null_mut());
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null_mut()`
usize(std::ptr::null());
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null()`
usize_mut(std::ptr::null_mut());
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null_mut()`
}
}

View File

@ -0,0 +1,31 @@
// run-rustfix
// Suggest providing a std::ptr::null{,_mut}() to a function that takes in a raw
// pointer if a literal 0 was provided by the user.
extern "C" {
fn foo(ptr: *const u8);
fn foo_mut(ptr: *mut u8);
fn usize(ptr: *const usize);
fn usize_mut(ptr: *mut usize);
}
fn main() {
unsafe {
foo(0);
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null()`
foo_mut(0);
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null_mut()`
usize(0);
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null()`
usize_mut(0);
//~^ mismatched types [E0308]
//~| if you meant to create a null pointer, use `std::ptr::null_mut()`
}
}

View File

@ -0,0 +1,83 @@
error[E0308]: mismatched types
--> $DIR/suggest-null-ptr.rs:18:13
|
LL | foo(0);
| --- ^ expected `*const u8`, found `usize`
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*const u8`
found type `usize`
note: function defined here
--> $DIR/suggest-null-ptr.rs:7:8
|
LL | fn foo(ptr: *const u8);
| ^^^
help: if you meant to create a null pointer, use `std::ptr::null()`
|
LL | foo(std::ptr::null());
| ~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/suggest-null-ptr.rs:21:17
|
LL | foo_mut(0);
| ------- ^ expected `*mut u8`, found `usize`
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*mut u8`
found type `usize`
note: function defined here
--> $DIR/suggest-null-ptr.rs:9:8
|
LL | fn foo_mut(ptr: *mut u8);
| ^^^^^^^
help: if you meant to create a null pointer, use `std::ptr::null_mut()`
|
LL | foo_mut(std::ptr::null_mut());
| ~~~~~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/suggest-null-ptr.rs:24:15
|
LL | usize(0);
| ----- ^ expected `*const usize`, found `usize`
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*const usize`
found type `usize`
note: function defined here
--> $DIR/suggest-null-ptr.rs:11:8
|
LL | fn usize(ptr: *const usize);
| ^^^^^
help: if you meant to create a null pointer, use `std::ptr::null()`
|
LL | usize(std::ptr::null());
| ~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/suggest-null-ptr.rs:27:19
|
LL | usize_mut(0);
| --------- ^ expected `*mut usize`, found `usize`
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*mut usize`
found type `usize`
note: function defined here
--> $DIR/suggest-null-ptr.rs:13:8
|
LL | fn usize_mut(ptr: *mut usize);
| ^^^^^^^^^
help: if you meant to create a null pointer, use `std::ptr::null_mut()`
|
LL | usize_mut(std::ptr::null_mut());
| ~~~~~~~~~~~~~~~~~~~~
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.