1
Fork 0

Auto merge of #114494 - est31:extend_useless_ptr_null_checks, r=jackh726

Make useless_ptr_null_checks smarter about some std functions

This teaches the `useless_ptr_null_checks` lint that some std functions can't ever return null pointers, because they need to point to valid data, get references as input, etc.

This is achieved by introducing an `#[rustc_never_returns_null_ptr]` attribute and adding it to these std functions (gated behind bootstrap `cfg_attr`).

Later on, the attribute could maybe be used to tell LLVM that the returned pointer is never null. I don't expect much impact of that though, as the functions are pretty shallow and usually the input data is already never null.

Follow-up of PR #113657

Fixes #114442
This commit is contained in:
bors 2023-09-16 03:40:20 +00:00
commit 635c4a5e61
18 changed files with 94 additions and 46 deletions

View file

@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> {
#[label]
label: Span,
},
#[diag(lint_ptr_null_checks_fn_ret)]
FnRet { fn_name: Ident },
}
// for_loops_over_fallibles.rs

View file

@ -31,12 +31,30 @@ declare_lint! {
declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
/// This function detects and returns the original expression from a series of consecutive casts,
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
/// This function checks if the expression is from a series of consecutive casts,
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either
/// a fn ptr, a reference, or a function call whose definition is
/// annotated with `#![rustc_never_returns_null_ptr]`.
/// If this situation is present, the function returns the appropriate diagnostic.
fn incorrect_check<'a, 'tcx: 'a>(
cx: &'a LateContext<'tcx>,
mut e: &'a Expr<'a>,
) -> Option<PtrNullChecksDiag<'tcx>> {
let mut had_at_least_one_cast = false;
loop {
e = e.peel_blocks();
if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
return Some(PtrNullChecksDiag::FnRet { fn_name });
} else if let ExprKind::Call(path, _args) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
return Some(PtrNullChecksDiag::FnRet { fn_name });
}
e = if let ExprKind::Cast(expr, t) = e.kind
&& let TyKind::Ptr(_) = t.kind {
had_at_least_one_cast = true;
@ -46,33 +64,21 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
had_at_least_one_cast = true;
expr
} else if let ExprKind::Call(path, [arg]) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
had_at_least_one_cast = true;
arg
} else if had_at_least_one_cast {
return Some(e);
let orig_ty = cx.typeck_results().expr_ty(e);
return if orig_ty.is_fn() {
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span })
} else if orig_ty.is_ref() {
Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span })
} else {
None
};
} else {
return None;
};
}
}
fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
let expr = ptr_cast_chain(cx, expr)?;
let orig_ty = cx.typeck_results().expr_ty(expr);
if orig_ty.is_fn() {
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span })
} else if orig_ty.is_ref() {
Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
} else {
None
}
}
impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match expr.kind {