summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint/src/ptr_nulls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src/ptr_nulls.rs')
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs52
1 files changed, 29 insertions, 23 deletions
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 02aff9103..0de72d8d3 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -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 {