From 8cfa4fe6b2268385480dc4a88ce3e6fdb06a3596 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Sat, 5 Aug 2023 04:54:23 +0200
Subject: [PATCH 1/4] Add #[rustc_never_returns_null_ptr]

And look for it in the useless_ptr_null_checks lint
---
 compiler/rustc_feature/src/builtin_attrs.rs | 4 ++++
 compiler/rustc_lint/src/ptr_nulls.rs        | 2 +-
 compiler/rustc_passes/src/check_attr.rs     | 3 +++
 compiler/rustc_span/src/symbol.rs           | 1 +
 4 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index a183cfd8776..6596e47f615 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -698,6 +698,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
     ),
+    rustc_attr!(
+        rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
+        "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
+    ),
     rustc_attr!(
         rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
         "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 02aff91032f..52d8099091a 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -49,7 +49,7 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'
         } 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)) {
+            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) {
             had_at_least_one_cast = true;
             arg
         } else if had_at_least_one_cast {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index cbb030958c6..bec12ca185e 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -139,6 +139,9 @@ impl CheckAttrVisitor<'_> {
                     self.check_rustc_std_internal_symbol(&attr, span, target)
                 }
                 sym::naked => self.check_naked(hir_id, attr, span, target),
+                sym::rustc_never_returns_null_ptr => {
+                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                }
                 sym::rustc_legacy_const_generics => {
                     self.check_rustc_legacy_const_generics(hir_id, &attr, span, target, item)
                 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 44820ae6f72..07d48170add 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1311,6 +1311,7 @@ symbols! {
         rustc_main,
         rustc_mir,
         rustc_must_implement_one_of,
+        rustc_never_returns_null_ptr,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
         rustc_object_lifetime_default,

From 33970db8c6a50a4a8c0fbb3d7d94893de24b98b5 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Sat, 5 Aug 2023 14:01:56 +0200
Subject: [PATCH 2/4] Add #[rustc_never_returns_null_ptr] to std functions

Add the attribute to standard library functions that
are guaranteed to never return null pointers, as their
originating data wouldn't allow it.
---
 library/alloc/src/rc.rs          | 2 ++
 library/alloc/src/sync.rs        | 2 ++
 library/alloc/src/vec/mod.rs     | 2 ++
 library/core/src/cell.rs         | 4 ++++
 library/core/src/ffi/c_str.rs    | 1 +
 library/core/src/ptr/mod.rs      | 2 ++
 library/core/src/ptr/non_null.rs | 2 ++
 library/core/src/slice/mod.rs    | 2 ++
 library/core/src/str/mod.rs      | 2 ++
 library/core/src/sync/atomic.rs  | 3 +++
 10 files changed, 22 insertions(+)

diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 60b07485c3a..c6693626e0a 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1304,6 +1304,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
     /// ```
     #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = Self::as_ptr(&this);
         mem::forget(this);
@@ -1327,6 +1328,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
     /// ```
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(this: &Self) -> *const T {
         let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 6c701225a84..d085466d847 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1455,6 +1455,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = Self::as_ptr(&this);
         mem::forget(this);
@@ -1479,6 +1480,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rc_as_ptr", since = "1.45.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(this: &Self) -> *const T {
         let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index e45ddc7896b..a7bd8fdd424 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1233,6 +1233,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline]
     pub fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
@@ -1266,6 +1267,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert_eq!(&*x, &[0, 1, 2, 3]);
     /// ```
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index bf4c682d33e..82e24644414 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -543,6 +543,7 @@ impl<T: ?Sized> Cell<T> {
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
     #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -1076,6 +1077,7 @@ impl<T: ?Sized> RefCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -2071,6 +2073,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
         // #[repr(transparent)]. This exploits std's special status, there is
@@ -2213,6 +2216,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
     /// when casting to `&mut T`, and ensure that there are no mutations
     /// or mutable aliases going on when casting to `&T`
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn get(&self) -> *mut T {
         self.value.get()
     }
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index b59ec12790d..388a545d3d9 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -509,6 +509,7 @@ impl CStr {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
     }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 5f094ac4e7e..84cc2e474a1 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -698,6 +698,7 @@ where
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
 #[rustc_diagnostic_item = "ptr_from_ref"]
 pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
     r
@@ -710,6 +711,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
 #[rustc_diagnostic_item = "ptr_from_mut"]
 pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
     r
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 9582ca9e0be..77a2e0775a3 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -320,6 +320,7 @@ impl<T: ?Sized> NonNull<T> {
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(self) -> *mut T {
@@ -579,6 +580,7 @@ impl<T> NonNull<[T]> {
     #[must_use]
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
     #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_mut_ptr(self) -> *mut T {
         self.as_non_null_ptr().as_ptr()
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d95662afddd..0d635aced85 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -730,6 +730,7 @@ impl<T> [T] {
     /// [`as_mut_ptr`]: slice::as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_ptr(&self) -> *const T {
@@ -760,6 +761,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[rustc_allow_const_fn_unstable(const_mut_refs)]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 71c03f7bfc5..569707a40f3 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -387,6 +387,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const u8 {
@@ -402,6 +403,7 @@ impl str {
     /// It is your responsibility to make sure that the string slice only gets
     /// modified in a way that it remains valid UTF-8.
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub fn as_mut_ptr(&mut self) -> *mut u8 {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 22a1c09782c..cf1fbe2d389 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1018,6 +1018,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
     #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut bool {
         self.v.get().cast()
     }
@@ -1953,6 +1954,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
     #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut *mut T {
         self.p.get()
     }
@@ -2891,6 +2893,7 @@ macro_rules! atomic_int {
             #[inline]
             #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
             #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+            #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
             pub const fn as_ptr(&self) -> *mut $int_type {
                 self.v.get()
             }

From 8faac74e54e8a76cd4ff860c1b6da3836e4a1b1e Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Sat, 5 Aug 2023 05:14:32 +0200
Subject: [PATCH 3/4] Remove ptr_from_mut diagnostic item

It was added by #113657 for its purposes.
Now it is not used any more, remove it,
as we use the attr now.
---
 compiler/rustc_span/src/symbol.rs | 1 -
 library/core/src/ptr/mod.rs       | 1 -
 2 files changed, 2 deletions(-)

diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 07d48170add..46f3487475b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1159,7 +1159,6 @@ symbols! {
         ptr_cast,
         ptr_cast_mut,
         ptr_const_is_null,
-        ptr_from_mut,
         ptr_from_ref,
         ptr_guaranteed_cmp,
         ptr_is_null,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 84cc2e474a1..8d1a4de9de6 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -712,7 +712,6 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
 #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
-#[rustc_diagnostic_item = "ptr_from_mut"]
 pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
     r
 }

From 4b1bc2701067d7b340d102d40227091c00447f48 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Sun, 6 Aug 2023 01:25:24 +0200
Subject: [PATCH 4/4] Improve diagnostics and add tests for function calls

---
 compiler/rustc_lint/messages.ftl     |  2 ++
 compiler/rustc_lint/src/lints.rs     |  2 ++
 compiler/rustc_lint/src/ptr_nulls.rs | 52 ++++++++++++++++------------
 tests/ui/lint/ptr_null_checks.rs     | 14 +++++---
 tests/ui/lint/ptr_null_checks.stderr | 38 +++++++++++---------
 5 files changed, 64 insertions(+), 44 deletions(-)

diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c4a7f717840..61f68db2cc0 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -457,6 +457,8 @@ lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking th
     .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
     .label = expression has type `{$orig_ty}`
 
+lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false
+
 lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
     .label = expression has type `{$orig_ty}`
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 70311a5c576..049a7c3f7fa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -634,6 +634,8 @@ pub enum PtrNullChecksDiag<'a> {
         #[label]
         label: Span,
     },
+    #[diag(lint_ptr_null_checks_fn_ret)]
+    FnRet { fn_name: Ident },
 }
 
 // for_loops_over_fallibles.rs
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 52d8099091a..0de72d8d3db 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()
-            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) {
-            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 {
diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs
index e677ea3094d..3028084e962 100644
--- a/tests/ui/lint/ptr_null_checks.rs
+++ b/tests/ui/lint/ptr_null_checks.rs
@@ -38,15 +38,15 @@ fn main() {
     if (&mut 8 as *mut i32).is_null() {}
     //~^ WARN references are not nullable
     if ptr::from_mut(&mut 8).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (&8 as *const i32).is_null() {}
     //~^ WARN references are not nullable
     if ptr::from_ref(&8).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if ptr::from_ref(&8).cast_mut().is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (&8 as *const i32) == std::ptr::null() {}
     //~^ WARN references are not nullable
     let ref_num = &8;
@@ -65,6 +65,12 @@ fn main() {
     if (&*{ static_i32() } as *const i32).is_null() {}
     //~^ WARN references are not nullable
 
+    // ---------------- Functions -------------------
+    if ptr::NonNull::new(&mut 8).unwrap().as_ptr().is_null() {}
+    //~^ WARN call is never null
+    if ptr::NonNull::<u8>::dangling().as_ptr().is_null() {}
+    //~^ WARN call is never null
+
     // ----------------------------------------------
     const ZPTR: *const () = 0 as *const _;
     const NOT_ZPTR: *const () = 1 as *const _;
diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr
index 3cee1804b62..0edc1b86536 100644
--- a/tests/ui/lint/ptr_null_checks.stderr
+++ b/tests/ui/lint/ptr_null_checks.stderr
@@ -117,13 +117,11 @@ LL |     if (&mut 8 as *mut i32).is_null() {}
    |         |
    |         expression has type `&mut i32`
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_mut` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:40:8
    |
 LL |     if ptr::from_mut(&mut 8).is_null() {}
-   |        ^^^^^^^^^^^^^^------^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&mut i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: references are not nullable, so checking them for null will always return false
   --> $DIR/ptr_null_checks.rs:42:8
@@ -133,29 +131,23 @@ LL |     if (&8 as *const i32).is_null() {}
    |         |
    |         expression has type `&i32`
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:44:8
    |
 LL |     if ptr::from_ref(&8).is_null() {}
-   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:46:8
    |
 LL |     if ptr::from_ref(&8).cast_mut().is_null() {}
-   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:48:8
    |
 LL |     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
-   |        ^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                       |
-   |                       expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: references are not nullable, so checking them for null will always return false
   --> $DIR/ptr_null_checks.rs:50:8
@@ -221,5 +213,17 @@ LL |     if (&*{ static_i32() } as *const i32).is_null() {}
    |         |
    |         expression has type `&i32`
 
-warning: 25 warnings emitted
+warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false
+  --> $DIR/ptr_null_checks.rs:69:8
+   |
+LL |     if ptr::NonNull::new(&mut 8).unwrap().as_ptr().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false
+  --> $DIR/ptr_null_checks.rs:71:8
+   |
+LL |     if ptr::NonNull::<u8>::dangling().as_ptr().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 27 warnings emitted