about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-08-03 17:29:06 +0200
committerGitHub <noreply@github.com>2023-08-03 17:29:06 +0200
commit7518ae566ef8f0f36f07683e6bbebbd2fa4402d1 (patch)
tree70dfa91e6011b93af9466e122fc6f36c973890b1
parentfcf3006e0133365ecd26894689c086387edcbecb (diff)
parentee519532f69610e208fc61a68537aa662c3e8d16 (diff)
downloadrust-7518ae566ef8f0f36f07683e6bbebbd2fa4402d1.tar.gz
rust-7518ae566ef8f0f36f07683e6bbebbd2fa4402d1.zip
Rollup merge of #113657 - Urgau:expand-incorrect_fn_null_check-lint, r=cjgillot
Expand, rename and improve `incorrect_fn_null_checks` lint

This PR,

 - firstly, expand the lint by now linting on references
 - secondly, it renames the lint `incorrect_fn_null_checks` -> `useless_ptr_null_checks`
 - and thirdly it improves the lint by catching `ptr::from_mut`, `ptr::from_ref`, as well as `<*mut _>::cast` and `<*const _>::cast_mut`

Fixes https://github.com/rust-lang/rust/issues/113601
cc ```@est31```
-rw-r--r--compiler/rustc_lint/messages.ftl10
-rw-r--r--compiler/rustc_lint/src/fn_null_check.rs112
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs20
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs146
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--library/core/src/ptr/mod.rs1
-rw-r--r--library/core/src/ptr/mut_ptr.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr4
-rw-r--r--tests/ui/consts/ptr_is_null.rs1
-rw-r--r--tests/ui/lint/fn_null_check.rs30
-rw-r--r--tests/ui/lint/fn_null_check.stderr67
-rw-r--r--tests/ui/lint/ptr_null_checks.rs76
-rw-r--r--tests/ui/lint/ptr_null_checks.stderr225
17 files changed, 484 insertions, 225 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index f482e3d7c12..0eacb4a000b 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -213,9 +213,6 @@ lint_expectation = this lint expectation is unfulfilled
     .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
     .rationale = {$rationale}
 
-lint_fn_null_check = function pointers are not nullable, so checking them for null will always return false
-    .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
 lint_for_loops_over_fallibles =
     for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
     .suggestion = consider using `if let` to clear intent
@@ -454,6 +451,13 @@ lint_path_statement_drop = path statement drops value
 
 lint_path_statement_no_effect = path statement with no effect
 
+lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false
+    .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_ref = references are not nullable, so checking them for null will always return false
+    .label = expression has type `{$orig_ty}`
+
 lint_query_instability = using `{$query}` can result in unstable query results
     .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
diff --git a/compiler/rustc_lint/src/fn_null_check.rs b/compiler/rustc_lint/src/fn_null_check.rs
deleted file mode 100644
index e3b33463ccf..00000000000
--- a/compiler/rustc_lint/src/fn_null_check.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use crate::{lints::FnNullCheckDiag, LateContext, LateLintPass, LintContext};
-use rustc_ast::LitKind;
-use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::sym;
-
-declare_lint! {
-    /// The `incorrect_fn_null_checks` lint checks for expression that checks if a
-    /// function pointer is null.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// # fn test() {}
-    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
-    /// #   test;
-    ///
-    /// if (fn_ptr as *const ()).is_null() { /* ... */ }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Function pointers are assumed to be non-null, checking them for null will always
-    /// return false.
-    INCORRECT_FN_NULL_CHECKS,
-    Warn,
-    "incorrect checking of null function pointer"
-}
-
-declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]);
-
-fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let mut expr = expr.peel_blocks();
-    let mut had_at_least_one_cast = false;
-    while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
-            && let TyKind::Ptr(_) = cast_ty.kind {
-        expr = cast_expr.peel_blocks();
-        had_at_least_one_cast = true;
-    }
-    had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn()
-}
-
-impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        match expr.kind {
-            // Catching:
-            // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
-            ExprKind::Call(path, [arg])
-                if 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_const_is_null | sym::ptr_is_null)
-                    )
-                    && is_fn_ptr_cast(cx, arg) =>
-            {
-                cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-            }
-
-            // Catching:
-            // (fn_ptr as *<const/mut> <ty>).is_null()
-            ExprKind::MethodCall(_, receiver, _, _)
-                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-                    && matches!(
-                        cx.tcx.get_diagnostic_name(def_id),
-                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
-                    )
-                    && is_fn_ptr_cast(cx, receiver) =>
-            {
-                cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-            }
-
-            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
-                let to_check: &Expr<'_>;
-                if is_fn_ptr_cast(cx, left) {
-                    to_check = right;
-                } else if is_fn_ptr_cast(cx, right) {
-                    to_check = left;
-                } else {
-                    return;
-                }
-
-                match to_check.kind {
-                    // Catching:
-                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
-                    ExprKind::Cast(cast_expr, _)
-                        if let ExprKind::Lit(spanned) = cast_expr.kind
-                            && let LitKind::Int(v, _) = spanned.node && v == 0 =>
-                    {
-                        cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-                    },
-
-                    // Catching:
-                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
-                    ExprKind::Call(path, [])
-                        if let ExprKind::Path(ref qpath) = path.kind
-                            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-                            && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
-                            && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
-                    {
-                        cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-                    },
-
-                    _ => {},
-                }
-            }
-            _ => {}
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 96fd3ccf774..a07b772d35a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -57,7 +57,6 @@ mod early;
 mod enum_intrinsics_non_enums;
 mod errors;
 mod expect;
-mod fn_null_check;
 mod for_loops_over_fallibles;
 pub mod hidden_unicode_codepoints;
 mod internal;
@@ -76,6 +75,7 @@ mod noop_method_call;
 mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
+mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
 mod traits;
@@ -102,7 +102,6 @@ use builtin::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
-use fn_null_check::*;
 use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
 use internal::*;
@@ -117,6 +116,7 @@ use nonstandard_style::*;
 use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
+use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
 use traits::*;
@@ -227,7 +227,7 @@ late_lint_methods!(
             // Depends on types used in type definitions
             MissingCopyImplementations: MissingCopyImplementations,
             // Depends on referenced function signatures in expressions
-            IncorrectFnNullChecks: IncorrectFnNullChecks,
+            PtrNullChecks: PtrNullChecks,
             MutableTransmutes: MutableTransmutes,
             TypeAliasBounds: TypeAliasBounds,
             TrivialConstraints: TrivialConstraints,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index a6a48bf4ffa..3d65ac26bd5 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -613,11 +613,23 @@ pub struct ExpectationNote {
     pub rationale: Symbol,
 }
 
-// fn_null_check.rs
+// ptr_nulls.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_fn_null_check)]
-#[help]
-pub struct FnNullCheckDiag;
+pub enum PtrNullChecksDiag<'a> {
+    #[diag(lint_ptr_null_checks_fn_ptr)]
+    #[help(lint_help)]
+    FnPtr {
+        orig_ty: Ty<'a>,
+        #[label]
+        label: Span,
+    },
+    #[diag(lint_ptr_null_checks_ref)]
+    Ref {
+        orig_ty: Ty<'a>,
+        #[label]
+        label: Span,
+    },
+}
 
 // for_loops_over_fallibles.rs
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
new file mode 100644
index 00000000000..02aff91032f
--- /dev/null
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -0,0 +1,146 @@
+use crate::{lints::PtrNullChecksDiag, LateContext, LateLintPass, LintContext};
+use rustc_ast::LitKind;
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+declare_lint! {
+    /// The `useless_ptr_null_checks` lint checks for useless null checks against pointers
+    /// obtained from non-null types.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn test() {}
+    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+    /// #   test;
+    ///
+    /// if (fn_ptr as *const ()).is_null() { /* ... */ }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Function pointers and references are assumed to be non-null, checking them for null
+    /// will always return false.
+    USELESS_PTR_NULL_CHECKS,
+    Warn,
+    "useless checking of non-null-typed pointer"
+}
+
+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>> {
+    let mut had_at_least_one_cast = false;
+    loop {
+        e = e.peel_blocks();
+        e = if let ExprKind::Cast(expr, t) = e.kind
+            && let TyKind::Ptr(_) = t.kind {
+            had_at_least_one_cast = true;
+            expr
+        } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
+            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+            && 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);
+        } 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 {
+            // Catching:
+            // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
+            ExprKind::Call(path, [arg])
+                if 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_const_is_null | sym::ptr_is_null)
+                    )
+                    && let Some(diag) = incorrect_check(cx, arg) =>
+            {
+                cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+            }
+
+            // Catching:
+            // (fn_ptr as *<const/mut> <ty>).is_null()
+            ExprKind::MethodCall(_, receiver, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && matches!(
+                        cx.tcx.get_diagnostic_name(def_id),
+                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
+                    )
+                    && let Some(diag) = incorrect_check(cx, receiver) =>
+            {
+                cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+            }
+
+            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+                let to_check: &Expr<'_>;
+                let diag: PtrNullChecksDiag<'_>;
+                if let Some(ddiag) = incorrect_check(cx, left) {
+                    to_check = right;
+                    diag = ddiag;
+                } else if let Some(ddiag) = incorrect_check(cx, right) {
+                    to_check = left;
+                    diag = ddiag;
+                } else {
+                    return;
+                }
+
+                match to_check.kind {
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+                    ExprKind::Cast(cast_expr, _)
+                        if let ExprKind::Lit(spanned) = cast_expr.kind
+                            && let LitKind::Int(v, _) = spanned.node && v == 0 =>
+                    {
+                        cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+                    ExprKind::Call(path, [])
+                        if let ExprKind::Path(ref qpath) = path.kind
+                            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                            && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
+                            && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
+                    {
+                        cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+                    },
+
+                    _ => {},
+                }
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d3739733c1d..9cff8a688ff 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1155,8 +1155,10 @@ symbols! {
         profiler_builtins,
         profiler_runtime,
         ptr,
+        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 acc9ca29d41..5f094ac4e7e 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -710,6 +710,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[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/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index e7f27439540..e3a3f69afd9 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -54,6 +54,7 @@ impl<T: ?Sized> *mut T {
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
+    #[rustc_diagnostic_item = "ptr_cast"]
     #[inline(always)]
     pub const fn cast<U>(self) -> *mut U {
         self as _
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 49bdc679604..fc1fabcc0ae 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -43,7 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
     ("clippy::forget_copy", "forgetting_copy_types"),
     ("clippy::forget_ref", "forgetting_references"),
-    ("clippy::fn_null_check", "incorrect_fn_null_checks"),
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
     ("clippy::invalid_ref", "invalid_value"),
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 8ec19b120d1..8257bf2947a 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -38,7 +38,7 @@
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(incorrect_fn_null_checks)]
+#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -92,7 +92,7 @@
 #![warn(for_loops_over_fallibles)]
 #![warn(forgetting_copy_types)]
 #![warn(forgetting_references)]
-#![warn(incorrect_fn_null_checks)]
+#![warn(useless_ptr_null_checks)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
 #![warn(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 51a5976eb61..6569dad18d4 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -38,7 +38,7 @@
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(incorrect_fn_null_checks)]
+#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index e420ea1d2ad..57e991e5695 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -246,11 +246,11 @@ error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
-error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks`
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
   --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
-   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks`
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
   --> $DIR/rename.rs:96:9
diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs
index 8babb68585d..43b9767db16 100644
--- a/tests/ui/consts/ptr_is_null.rs
+++ b/tests/ui/consts/ptr_is_null.rs
@@ -2,6 +2,7 @@
 // check-pass
 
 #![feature(const_ptr_is_null)]
+#![allow(useless_ptr_null_checks)]
 
 const FOO: &usize = &42;
 
diff --git a/tests/ui/lint/fn_null_check.rs b/tests/ui/lint/fn_null_check.rs
deleted file mode 100644
index 7f01f2c4283..00000000000
--- a/tests/ui/lint/fn_null_check.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// check-pass
-
-fn main() {
-    let fn_ptr = main;
-
-    if (fn_ptr as *mut ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const u8).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const ()) == std::ptr::null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const ()) == (0 as *const ()) {}
-    //~^ WARN function pointers are not nullable
-    if <*const _>::is_null(fn_ptr as *const ()) {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as fn() as *const ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-
-    const ZPTR: *const () = 0 as *const _;
-    const NOT_ZPTR: *const () = 1 as *const _;
-
-    // unlike the uplifted clippy::fn_null_check lint we do
-    // not lint on them
-    if (fn_ptr as *const ()) == ZPTR {}
-    if (fn_ptr as *const ()) == NOT_ZPTR {}
-}
diff --git a/tests/ui/lint/fn_null_check.stderr b/tests/ui/lint/fn_null_check.stderr
deleted file mode 100644
index 0398c0da50f..00000000000
--- a/tests/ui/lint/fn_null_check.stderr
+++ /dev/null
@@ -1,67 +0,0 @@
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:6:8
-   |
-LL |     if (fn_ptr as *mut ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-   = note: `#[warn(incorrect_fn_null_checks)]` on by default
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:8:8
-   |
-LL |     if (fn_ptr as *const u8).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:10:8
-   |
-LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:12:8
-   |
-LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:14:8
-   |
-LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:16:8
-   |
-LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:18:8
-   |
-LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:20:8
-   |
-LL |     if (fn_ptr as fn() as *const ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: 8 warnings emitted
-
diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs
new file mode 100644
index 00000000000..e677ea3094d
--- /dev/null
+++ b/tests/ui/lint/ptr_null_checks.rs
@@ -0,0 +1,76 @@
+// check-pass
+
+#![feature(ptr_from_ref)]
+
+use std::ptr;
+
+extern "C" fn c_fn() {}
+fn static_i32() -> &'static i32 { &1 }
+
+fn main() {
+    let fn_ptr = main;
+
+    // ------------- Function pointers ---------------
+    if (fn_ptr as *mut ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const u8).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const ()) == std::ptr::null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const ()) == (0 as *const ()) {}
+    //~^ WARN function pointers are not nullable
+    if <*const _>::is_null(fn_ptr as *const ()) {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
+    if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as fn() as *const ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (c_fn as *const fn()).is_null() {}
+    //~^ WARN function pointers are not nullable
+
+    // ---------------- References ------------------
+    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
+    if (&8 as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_ref(&8).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_ref(&8).cast_mut().is_null() {}
+    //~^ WARN references are not nullable
+    if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&8 as *const i32) == std::ptr::null() {}
+    //~^ WARN references are not nullable
+    let ref_num = &8;
+    if (ref_num as *const i32) == std::ptr::null() {}
+    //~^ WARN references are not nullable
+    if (b"\0" as *const u8).is_null() {}
+    //~^ WARN references are not nullable
+    if ("aa" as *const str).is_null() {}
+    //~^ WARN references are not nullable
+    if (&[1, 2] as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
+    //~^ WARN references are not nullable
+    if (static_i32() as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&*{ static_i32() } as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+
+    // ----------------------------------------------
+    const ZPTR: *const () = 0 as *const _;
+    const NOT_ZPTR: *const () = 1 as *const _;
+
+    // unlike the uplifted clippy::fn_null_check lint we do
+    // not lint on them
+    if (fn_ptr as *const ()) == ZPTR {}
+    if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr
new file mode 100644
index 00000000000..3cee1804b62
--- /dev/null
+++ b/tests/ui/lint/ptr_null_checks.stderr
@@ -0,0 +1,225 @@
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:14:8
+   |
+LL |     if (fn_ptr as *mut ()).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+   = note: `#[warn(useless_ptr_null_checks)]` on by default
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:16:8
+   |
+LL |     if (fn_ptr as *const u8).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:18:8
+   |
+LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:20:8
+   |
+LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:22:8
+   |
+LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:24:8
+   |
+LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
+   |        ^^^^^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^
+   |                            |
+   |                            expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:26:8
+   |
+LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:28:8
+   |
+LL |     if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:30:8
+   |
+LL |     if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+   |        ^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:32:8
+   |
+LL |     if (fn_ptr as fn() as *const ()).is_null() {}
+   |        ^--------------^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn()`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:34:8
+   |
+LL |     if (c_fn as *const fn()).is_null() {}
+   |        ^----^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `extern "C" fn() {c_fn}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:38:8
+   |
+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
+  --> $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
+   |
+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
+  --> $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
+  --> $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
+  --> $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
+   |
+LL |     if (&8 as *const i32) == std::ptr::null() {}
+   |        ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:53:8
+   |
+LL |     if (ref_num as *const i32) == std::ptr::null() {}
+   |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:55:8
+   |
+LL |     if (b"\0" as *const u8).is_null() {}
+   |        ^-----^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&[u8; 1]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:57:8
+   |
+LL |     if ("aa" as *const str).is_null() {}
+   |        ^----^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&str`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:59:8
+   |
+LL |     if (&[1, 2] as *const i32).is_null() {}
+   |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&[i32; 2]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:61:8
+   |
+LL |     if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
+   |        ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&mut [i32; 2]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:63:8
+   |
+LL |     if (static_i32() as *const 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:65:8
+   |
+LL |     if (&*{ static_i32() } as *const i32).is_null() {}
+   |        ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: 25 warnings emitted
+