diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 50a3df21a3bc9..d43c661dda6fa 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2548,7 +2548,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
         /// Return `Some` only if we are sure this type does *not*
         /// allow zero initialization.
         fn ty_find_init_error<'tcx>(
-            tcx: TyCtxt<'tcx>,
+            cx: &LateContext<'tcx>,
             ty: Ty<'tcx>,
             init: InitKind,
         ) -> Option<InitError> {
@@ -2575,7 +2575,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 Adt(adt_def, substs) if !adt_def.is_union() => {
                     // First check if this ADT has a layout attribute (like `NonNull` and friends).
                     use std::ops::Bound;
-                    match tcx.layout_scalar_valid_range(adt_def.did()) {
+                    match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
                         // We exploit here that `layout_scalar_valid_range` will never
                         // return `Bound::Excluded`.  (And we have tests checking that we
                         // handle the attribute correctly.)
@@ -2603,12 +2603,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                             // Proceed recursively, check all fields.
                             let variant = &adt_def.variant(VariantIdx::from_u32(0));
                             variant.fields.iter().find_map(|field| {
-                                ty_find_init_error(tcx, field.ty(tcx, substs), init).map(
+                                ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
                                     |(mut msg, span)| {
                                         if span.is_none() {
                                             // Point to this field, should be helpful for figuring
                                             // out where the source of the error is.
-                                            let span = tcx.def_span(field.did);
+                                            let span = cx.tcx.def_span(field.did);
                                             write!(
                                                 &mut msg,
                                                 " (in this {} field)",
@@ -2627,7 +2627,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         // Multi-variant enum.
                         _ => {
                             if init == InitKind::Uninit && is_multi_variant(*adt_def) {
-                                let span = tcx.def_span(adt_def.did());
+                                let span = cx.tcx.def_span(adt_def.did());
                                 Some((
                                     "enums have to be initialized to a variant".to_string(),
                                     Some(span),
@@ -2642,7 +2642,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 }
                 Tuple(..) => {
                     // Proceed recursively, check all fields.
-                    ty.tuple_fields().iter().find_map(|field| ty_find_init_error(tcx, field, init))
+                    ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
+                }
+                Array(ty, len) => {
+                    if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
+                        // Array length known at array non-empty -- recurse.
+                        ty_find_init_error(cx, *ty, init)
+                    } else {
+                        // Empty array or size unknown.
+                        None
+                    }
                 }
                 // Conservative fallback.
                 _ => None,
@@ -2655,7 +2664,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             // We are extremely conservative with what we warn about.
             let conjured_ty = cx.typeck_results().expr_ty(expr);
             if let Some((msg, span)) =
-                with_no_trimmed_paths!(ty_find_init_error(cx.tcx, conjured_ty, init))
+                with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
             {
                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
                     let mut err = lint.build(&format!(
diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/uninitialized-zeroed.rs
index 122933c3c4e46..5cd323c01db8c 100644
--- a/src/test/ui/lint/uninitialized-zeroed.rs
+++ b/src/test/ui/lint/uninitialized-zeroed.rs
@@ -81,6 +81,9 @@ fn main() {
         let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization
         let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: [fn(); 2] = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: [fn(); 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Things that can be zero, but not uninit.
         let _val: bool = mem::zeroed();
         let _val: bool = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
@@ -94,6 +97,9 @@ fn main() {
         let _val: Fruit = mem::zeroed();
         let _val: Fruit = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: [bool; 2] = mem::zeroed();
+        let _val: [bool; 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Transmute-from-0
         let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization
         let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
@@ -110,6 +116,8 @@ fn main() {
         let _val: MaybeUninit<&'static i32> = mem::zeroed();
         let _val: i32 = mem::zeroed();
         let _val: bool = MaybeUninit::zeroed().assume_init();
+        let _val: [bool; 0] = MaybeUninit::uninit().assume_init();
+        let _val: [!; 0] = MaybeUninit::zeroed().assume_init();
         // Some things that happen to work due to rustc implementation details,
         // but are not guaranteed to keep working.
         let _val: i32 = mem::uninitialized();
diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr
index 0af185ef61b5e..b6a66f0a95ad1 100644
--- a/src/test/ui/lint/uninitialized-zeroed.stderr
+++ b/src/test/ui/lint/uninitialized-zeroed.stderr
@@ -329,8 +329,30 @@ LL |         let _val: *const dyn Send = mem::uninitialized();
    |
    = note: the vtable of a wide raw pointer must be non-null
 
+error: the type `[fn(); 2]` does not permit zero-initialization
+  --> $DIR/uninitialized-zeroed.rs:84:31
+   |
+LL |         let _val: [fn(); 2] = mem::zeroed();
+   |                               ^^^^^^^^^^^^^
+   |                               |
+   |                               this code causes undefined behavior when executed
+   |                               help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: function pointers must be non-null
+
+error: the type `[fn(); 2]` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:85:31
+   |
+LL |         let _val: [fn(); 2] = mem::uninitialized();
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               this code causes undefined behavior when executed
+   |                               help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: function pointers must be non-null
+
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:86:26
+  --> $DIR/uninitialized-zeroed.rs:89:26
    |
 LL |         let _val: bool = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -341,7 +363,7 @@ LL |         let _val: bool = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `Wrap<char>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:89:32
+  --> $DIR/uninitialized-zeroed.rs:92:32
    |
 LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -356,7 +378,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `NonBig` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:92:28
+  --> $DIR/uninitialized-zeroed.rs:95:28
    |
 LL |         let _val: NonBig = mem::uninitialized();
    |                            ^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +389,7 @@ LL |         let _val: NonBig = mem::uninitialized();
    = note: `NonBig` must be initialized inside its custom valid range
 
 error: the type `Fruit` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:95:27
+  --> $DIR/uninitialized-zeroed.rs:98:27
    |
 LL |         let _val: Fruit = mem::uninitialized();
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -384,8 +406,19 @@ LL | |     Banana,
 LL | | }
    | |_^
 
+error: the type `[bool; 2]` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:101:31
+   |
+LL |         let _val: [bool; 2] = mem::uninitialized();
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               this code causes undefined behavior when executed
+   |                               help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: booleans must be either `true` or `false`
+
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:98:34
+  --> $DIR/uninitialized-zeroed.rs:104:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -396,7 +429,7 @@ LL |         let _val: &'static i32 = mem::transmute(0usize);
    = note: references must be non-null
 
 error: the type `&[i32]` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:99:36
+  --> $DIR/uninitialized-zeroed.rs:105:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -407,7 +440,7 @@ LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    = note: references must be non-null
 
 error: the type `NonZeroU32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:100:32
+  --> $DIR/uninitialized-zeroed.rs:106:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -418,7 +451,7 @@ LL |         let _val: NonZeroU32 = mem::transmute(0);
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:103:34
+  --> $DIR/uninitialized-zeroed.rs:109:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -429,7 +462,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:104:34
+  --> $DIR/uninitialized-zeroed.rs:110:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -440,7 +473,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:105:26
+  --> $DIR/uninitialized-zeroed.rs:111:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -450,5 +483,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 36 previous errors
+error: aborting due to 39 previous errors