Skip to content

Commit

Permalink
Suggest null ptr if 0 is given as a raw ptr arg
Browse files Browse the repository at this point in the history
  • Loading branch information
edward-shen committed Feb 5, 2023
1 parent 50d3ba5 commit 3296729
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 0 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
31 changes: 31 additions & 0 deletions tests/ui/suggest-null-ptr.fixed
Original file line number Diff line number Diff line change
@@ -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()`
}
}
31 changes: 31 additions & 0 deletions tests/ui/suggest-null-ptr.rs
Original file line number Diff line number Diff line change
@@ -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()`
}
}
83 changes: 83 additions & 0 deletions tests/ui/suggest-null-ptr.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 3296729

Please sign in to comment.