about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-10-05 17:27:32 +0530
committerGitHub <noreply@github.com>2022-10-05 17:27:32 +0530
commitab88c19f15fe12625524a6474e0d63ead0333be0 (patch)
treeeb5946f2c631f32f38b3fb2abee05eef4a84d37c
parentf8f501997a4b293db86d6358c21a5de5642a5d66 (diff)
parenta0131f0a369dcb44c855d0ce483744e6efaa3df8 (diff)
downloadrust-ab88c19f15fe12625524a6474e0d63ead0333be0.tar.gz
rust-ab88c19f15fe12625524a6474e0d63ead0333be0.zip
Rollup merge of #101061 - RalfJung:panic-on-uninit, r=oli-obk
panic-on-uninit: adjust checks to 0x01-filling

Now that `mem::uninitiailized` actually fills memory with `0x01` (https://github.com/rust-lang/rust/pull/99182), we can make it panic in a few less cases without risking a lot more UB -- which hopefully slightly improves compatibility with some old code, and which might increase the chance that we can check inside arrays in the future.

We detect almost all of these with our lint, so authors of such code should still be warned -- but if this happens deep inside a dependency, the panic can be quite interruptive, so it might be better not to do it when there is no risk of LLVM UB.  Therefore, adjust the `might_permit_raw_init` logic to care primarily about LLVM UB. To my knowledge, it actually covers all cases of LLVM UB now.

Fixes https://github.com/rust-lang/rust/issues/66151

Cc ``@5225225``
-rw-r--r--compiler/rustc_const_eval/src/lib.rs6
-rw-r--r--compiler/rustc_const_eval/src/might_permit_raw_init.rs44
-rw-r--r--compiler/rustc_const_eval/src/util/might_permit_raw_init.rs151
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs2
-rw-r--r--compiler/rustc_target/src/abi/mod.rs70
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.rs9
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.stderr24
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs250
-rw-r--r--src/test/ui/lint/invalid_value.rs5
-rw-r--r--src/test/ui/lint/invalid_value.stderr72
10 files changed, 393 insertions, 240 deletions
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index ebdaf61e439..230f841cf4d 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -32,7 +32,6 @@ extern crate rustc_middle;
 pub mod const_eval;
 mod errors;
 pub mod interpret;
-mod might_permit_raw_init;
 pub mod transform;
 pub mod util;
 
@@ -61,7 +60,6 @@ pub fn provide(providers: &mut Providers) {
         const_eval::deref_mir_constant(tcx, param_env, value)
     };
     providers.permits_uninit_init =
-        |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit);
-    providers.permits_zero_init =
-        |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero);
+        |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
+    providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
 }
diff --git a/compiler/rustc_const_eval/src/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/might_permit_raw_init.rs
deleted file mode 100644
index 37ffa19ccd6..00000000000
--- a/compiler/rustc_const_eval/src/might_permit_raw_init.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use crate::const_eval::CompileTimeInterpreter;
-use crate::interpret::{InterpCx, MemoryKind, OpTy};
-use rustc_middle::ty::layout::LayoutCx;
-use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt};
-use rustc_session::Limit;
-use rustc_target::abi::InitKind;
-
-pub fn might_permit_raw_init<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: TyAndLayout<'tcx>,
-    kind: InitKind,
-) -> bool {
-    let strict = tcx.sess.opts.unstable_opts.strict_init_checks;
-
-    if strict {
-        let machine = CompileTimeInterpreter::new(
-            Limit::new(0),
-            /*can_access_statics:*/ false,
-            /*check_alignment:*/ true,
-        );
-
-        let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
-
-        let allocated = cx
-            .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
-            .expect("OOM: failed to allocate for uninit check");
-
-        if kind == InitKind::Zero {
-            cx.write_bytes_ptr(
-                allocated.ptr,
-                std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
-            )
-            .expect("failed to write bytes for zero valid check");
-        }
-
-        let ot: OpTy<'_, _> = allocated.into();
-
-        // Assume that if it failed, it's a validation failure.
-        cx.validate_operand(&ot).is_ok()
-    } else {
-        let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
-        ty.might_permit_raw_init(&layout_cx, kind)
-    }
-}
diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
new file mode 100644
index 00000000000..6ca71223391
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
@@ -0,0 +1,151 @@
+use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_session::Limit;
+use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
+
+use crate::const_eval::CompileTimeInterpreter;
+use crate::interpret::{InterpCx, MemoryKind, OpTy};
+
+/// Determines if this type permits "raw" initialization by just transmuting some memory into an
+/// instance of `T`.
+///
+/// `init_kind` indicates if the memory is zero-initialized or left uninitialized. We assume
+/// uninitialized memory is mitigated by filling it with 0x01, which reduces the chance of causing
+/// LLVM UB.
+///
+/// By default we check whether that operation would cause *LLVM UB*, i.e., whether the LLVM IR we
+/// generate has UB or not. This is a mitigation strategy, which is why we are okay with accepting
+/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
+/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
+/// to the full uninit check).
+pub fn might_permit_raw_init<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: TyAndLayout<'tcx>,
+    kind: InitKind,
+) -> bool {
+    if tcx.sess.opts.unstable_opts.strict_init_checks {
+        might_permit_raw_init_strict(ty, tcx, kind)
+    } else {
+        let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
+        might_permit_raw_init_lax(ty, &layout_cx, kind)
+    }
+}
+
+/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for
+/// details.
+fn might_permit_raw_init_strict<'tcx>(
+    ty: TyAndLayout<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    kind: InitKind,
+) -> bool {
+    let machine = CompileTimeInterpreter::new(
+        Limit::new(0),
+        /*can_access_statics:*/ false,
+        /*check_alignment:*/ true,
+    );
+
+    let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
+
+    let allocated = cx
+        .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
+        .expect("OOM: failed to allocate for uninit check");
+
+    if kind == InitKind::Zero {
+        cx.write_bytes_ptr(
+            allocated.ptr,
+            std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
+        )
+        .expect("failed to write bytes for zero valid check");
+    }
+
+    let ot: OpTy<'_, _> = allocated.into();
+
+    // Assume that if it failed, it's a validation failure.
+    // This does *not* actually check that references are dereferenceable, but since all types that
+    // require dereferenceability also require non-null, we don't actually get any false negatives
+    // due to this.
+    cx.validate_operand(&ot).is_ok()
+}
+
+/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
+/// details.
+fn might_permit_raw_init_lax<'tcx>(
+    this: TyAndLayout<'tcx>,
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    init_kind: InitKind,
+) -> bool {
+    let scalar_allows_raw_init = move |s: Scalar| -> bool {
+        match init_kind {
+            InitKind::Zero => {
+                // The range must contain 0.
+                s.valid_range(cx).contains(0)
+            }
+            InitKind::UninitMitigated0x01Fill => {
+                // The range must include an 0x01-filled buffer.
+                let mut val: u128 = 0x01;
+                for _ in 1..s.size(cx).bytes() {
+                    // For sizes >1, repeat the 0x01.
+                    val = (val << 8) | 0x01;
+                }
+                s.valid_range(cx).contains(val)
+            }
+        }
+    };
+
+    // Check the ABI.
+    let valid = match this.abi {
+        Abi::Uninhabited => false, // definitely UB
+        Abi::Scalar(s) => scalar_allows_raw_init(s),
+        Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
+        Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
+        Abi::Aggregate { .. } => true, // Fields are checked below.
+    };
+    if !valid {
+        // This is definitely not okay.
+        return false;
+    }
+
+    // Special magic check for references and boxes (i.e., special pointer types).
+    if let Some(pointee) = this.ty.builtin_deref(false) {
+        let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
+        // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
+        if pointee.align.abi.bytes() > 1 {
+            // 0x01-filling is not aligned.
+            return false;
+        }
+        if pointee.size.bytes() > 0 {
+            // A 'fake' integer pointer is not sufficiently dereferenceable.
+            return false;
+        }
+    }
+
+    // If we have not found an error yet, we need to recursively descend into fields.
+    match &this.fields {
+        FieldsShape::Primitive | FieldsShape::Union { .. } => {}
+        FieldsShape::Array { .. } => {
+            // Arrays never have scalar layout in LLVM, so if the array is not actually
+            // accessed, there is no LLVM UB -- therefore we can skip this.
+        }
+        FieldsShape::Arbitrary { offsets, .. } => {
+            for idx in 0..offsets.len() {
+                if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
+                    // We found a field that is unhappy with this kind of initialization.
+                    return false;
+                }
+            }
+        }
+    }
+
+    match &this.variants {
+        Variants::Single { .. } => {
+            // All fields of this single variant have already been checked above, there is nothing
+            // else to do.
+        }
+        Variants::Multiple { .. } => {
+            // We cannot tell LLVM anything about the details of this multi-variant layout, so
+            // invalid values "hidden" inside the variant cannot cause LLVM trouble.
+        }
+    }
+
+    true
+}
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index a1876bed83e..7a05cfd235f 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -3,8 +3,10 @@ mod alignment;
 mod call_kind;
 pub mod collect_writes;
 mod find_self_call;
+mod might_permit_raw_init;
 
 pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
 pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
 pub use self::find_self_call::find_self_call;
+pub use self::might_permit_raw_init::might_permit_raw_init;
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index ec334e5887a..7171ca7bf89 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1392,7 +1392,7 @@ pub struct PointeeInfo {
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum InitKind {
     Zero,
-    Uninit,
+    UninitMitigated0x01Fill,
 }
 
 /// Trait that needs to be implemented by the higher-level type representation
@@ -1498,72 +1498,4 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
         }
     }
-
-    /// Determines if this type permits "raw" initialization by just transmuting some
-    /// memory into an instance of `T`.
-    ///
-    /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
-    ///
-    /// This code is intentionally conservative, and will not detect
-    /// * zero init of an enum whose 0 variant does not allow zero initialization
-    /// * making uninitialized types who have a full valid range (ints, floats, raw pointers)
-    /// * Any form of invalid value being made inside an array (unless the value is uninhabited)
-    ///
-    /// A strict form of these checks that uses const evaluation exists in
-    /// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
-    /// stricter is <https://github.com/rust-lang/rust/issues/66151>.
-    ///
-    /// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
-    /// we can use the const evaluation checks always instead.
-    pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind) -> bool
-    where
-        Self: Copy,
-        Ty: TyAbiInterface<'a, C>,
-        C: HasDataLayout,
-    {
-        let scalar_allows_raw_init = move |s: Scalar| -> bool {
-            match init_kind {
-                InitKind::Zero => {
-                    // The range must contain 0.
-                    s.valid_range(cx).contains(0)
-                }
-                InitKind::Uninit => {
-                    // The range must include all values.
-                    s.is_always_valid(cx)
-                }
-            }
-        };
-
-        // Check the ABI.
-        let valid = match self.abi {
-            Abi::Uninhabited => false, // definitely UB
-            Abi::Scalar(s) => scalar_allows_raw_init(s),
-            Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
-            Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
-            Abi::Aggregate { .. } => true, // Fields are checked below.
-        };
-        if !valid {
-            // This is definitely not okay.
-            return false;
-        }
-
-        // If we have not found an error yet, we need to recursively descend into fields.
-        match &self.fields {
-            FieldsShape::Primitive | FieldsShape::Union { .. } => {}
-            FieldsShape::Array { .. } => {
-                // FIXME(#66151): For now, we are conservative and do not check arrays by default.
-            }
-            FieldsShape::Arbitrary { offsets, .. } => {
-                for idx in 0..offsets.len() {
-                    if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) {
-                        // We found a field that is unhappy with this kind of initialization.
-                        return false;
-                    }
-                }
-            }
-        }
-
-        // FIXME(#66151): For now, we are conservative and do not check `self.variants`.
-        true
-    }
 }
diff --git a/src/test/ui/consts/assert-type-intrinsics.rs b/src/test/ui/consts/assert-type-intrinsics.rs
index 3ce3e1bdbac..6b5612dda90 100644
--- a/src/test/ui/consts/assert-type-intrinsics.rs
+++ b/src/test/ui/consts/assert-type-intrinsics.rs
@@ -11,12 +11,15 @@ fn main() {
     use std::mem::MaybeUninit;
 
     const _BAD1: () = unsafe {
-        MaybeUninit::<!>::uninit().assume_init();
+        intrinsics::assert_inhabited::<!>(); //~ERROR: any use of this value will cause an error
+        //~^WARN: previously accepted
     };
     const _BAD2: () = {
-        intrinsics::assert_uninit_valid::<bool>();
+        intrinsics::assert_uninit_valid::<!>(); //~ERROR: any use of this value will cause an error
+        //~^WARN: previously accepted
     };
     const _BAD3: () = {
-        intrinsics::assert_zero_valid::<&'static i32>();
+        intrinsics::assert_zero_valid::<&'static i32>(); //~ERROR: any use of this value will cause an error
+        //~^WARN: previously accepted
     };
 }
diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr
index a183856dff8..9f97d836705 100644
--- a/src/test/ui/consts/assert-type-intrinsics.stderr
+++ b/src/test/ui/consts/assert-type-intrinsics.stderr
@@ -3,26 +3,26 @@ error: any use of this value will cause an error
    |
 LL |     const _BAD1: () = unsafe {
    |     ---------------
-LL |         MaybeUninit::<!>::uninit().assume_init();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL |         intrinsics::assert_inhabited::<!>();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: `#[deny(const_err)]` on by default
 
 error: any use of this value will cause an error
-  --> $DIR/assert-type-intrinsics.rs:17:9
+  --> $DIR/assert-type-intrinsics.rs:18:9
    |
 LL |     const _BAD2: () = {
    |     ---------------
-LL |         intrinsics::assert_uninit_valid::<bool>();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL |         intrinsics::assert_uninit_valid::<!>();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error: any use of this value will cause an error
-  --> $DIR/assert-type-intrinsics.rs:20:9
+  --> $DIR/assert-type-intrinsics.rs:22:9
    |
 LL |     const _BAD3: () = {
    |     ---------------
@@ -40,8 +40,8 @@ error: any use of this value will cause an error
    |
 LL |     const _BAD1: () = unsafe {
    |     ---------------
-LL |         MaybeUninit::<!>::uninit().assume_init();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL |         intrinsics::assert_inhabited::<!>();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
@@ -49,12 +49,12 @@ LL |         MaybeUninit::<!>::uninit().assume_init();
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/assert-type-intrinsics.rs:17:9
+  --> $DIR/assert-type-intrinsics.rs:18:9
    |
 LL |     const _BAD2: () = {
    |     ---------------
-LL |         intrinsics::assert_uninit_valid::<bool>();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL |         intrinsics::assert_uninit_valid::<!>();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
@@ -62,7 +62,7 @@ LL |         intrinsics::assert_uninit_valid::<bool>();
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/assert-type-intrinsics.rs:20:9
+  --> $DIR/assert-type-intrinsics.rs:22:9
    |
 LL |     const _BAD3: () = {
    |     ---------------
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 4aa869cca35..ae44ffd29bd 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -34,6 +34,12 @@ enum OneVariant_NonZero {
     DeadVariant(Bar),
 }
 
+#[allow(dead_code, non_camel_case_types)]
+enum OneVariant_Ref {
+    Variant(&'static i32),
+    DeadVariant(Bar),
+}
+
 // An `Aggregate` abi enum where 0 is not a valid discriminant.
 #[allow(dead_code)]
 #[repr(i32)]
@@ -63,6 +69,7 @@ enum ZeroIsValid {
     One(NonNull<()>) = 1,
 }
 
+#[track_caller]
 fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     let err = panic::catch_unwind(op).err();
     assert_eq!(
@@ -71,6 +78,15 @@ fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     );
 }
 
+#[track_caller]
+fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
+    let err = panic::catch_unwind(op).err();
+    assert_eq!(
+        err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
+        if cfg!(strict) { Some(&msg) } else { None },
+    );
+}
+
 fn main() {
     unsafe {
         // Uninhabited types
@@ -139,92 +155,216 @@ fn main() {
             "attempted to instantiate uninhabited type `[Bar; 2]`"
         );
 
-        // Types that do not like zero-initialziation
+        // Types that don't allow either.
         test_panic_msg(
-            || mem::uninitialized::<fn()>(),
-            "attempted to leave type `fn()` uninitialized, which is invalid"
+            || mem::zeroed::<&i32>(),
+            "attempted to zero-initialize type `&i32`, which is invalid"
         );
         test_panic_msg(
-            || mem::zeroed::<fn()>(),
-            "attempted to zero-initialize type `fn()`, which is invalid"
+            || mem::uninitialized::<&i32>(),
+            "attempted to leave type `&i32` uninitialized, which is invalid"
         );
 
         test_panic_msg(
-            || mem::uninitialized::<*const dyn Send>(),
-            "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
+            || mem::zeroed::<Box<[i32; 0]>>(),
+            "attempted to zero-initialize type `alloc::boxed::Box<[i32; 0]>`, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<Box<[i32; 0]>>(),
+            "attempted to leave type `alloc::boxed::Box<[i32; 0]>` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<Box<u8>>(),
+            "attempted to zero-initialize type `alloc::boxed::Box<u8>`, which is invalid"
         );
         test_panic_msg(
+            || mem::uninitialized::<Box<u8>>(),
+            "attempted to leave type `alloc::boxed::Box<u8>` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&[i32]>(),
+            "attempted to zero-initialize type `&[i32]`, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<&[i32]>(),
+            "attempted to leave type `&[i32]` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&(u8, [u8])>(),
+            "attempted to zero-initialize type `&(u8, [u8])`, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<&(u8, [u8])>(),
+            "attempted to leave type `&(u8, [u8])` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&dyn Send>(),
+            "attempted to zero-initialize type `&dyn core::marker::Send`, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<&dyn Send>(),
+            "attempted to leave type `&dyn core::marker::Send` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
             || mem::zeroed::<*const dyn Send>(),
             "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid"
         );
+        test_panic_msg(
+            || mem::uninitialized::<*const dyn Send>(),
+            "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
+        );
 
         test_panic_msg(
-            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
-            "attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \
+            || mem::uninitialized::<NoNullVariant>(),
+            "attempted to leave type `NoNullVariant` uninitialized, \
+                which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<NoNullVariant>(),
+            "attempted to zero-initialize type `NoNullVariant`, \
                 which is invalid"
         );
 
         test_panic_msg(
-            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
-            "attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
+            || mem::zeroed::<OneVariant_Ref>(),
+            "attempted to zero-initialize type `OneVariant_Ref`, \
                 which is invalid"
         );
+        test_panic_msg(
+            || mem::uninitialized::<OneVariant_Ref>(),
+            "attempted to leave type `OneVariant_Ref` uninitialized, which is invalid"
+        );
 
+        // Types where both are invalid, but we allow uninit since the 0x01-filling is not LLVM UB.
         test_panic_msg(
-            || mem::uninitialized::<OneVariant_NonZero>(),
-            "attempted to leave type `OneVariant_NonZero` uninitialized, \
+            || mem::zeroed::<fn()>(),
+            "attempted to zero-initialize type `fn()`, which is invalid"
+        );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<fn()>(),
+            "attempted to leave type `fn()` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&()>(),
+            "attempted to zero-initialize type `&()`, which is invalid"
+        );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<&()>(),
+            "attempted to leave type `&()` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&[u8]>(),
+            "attempted to zero-initialize type `&[u8]`, which is invalid"
+        );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<&[u8]>(),
+            "attempted to leave type `&[u8]` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<&str>(),
+            "attempted to zero-initialize type `&str`, which is invalid"
+        );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<&str>(),
+            "attempted to leave type `&str` uninitialized, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
+            "attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
                 which is invalid"
         );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
+            "attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, which is invalid"
+        );
+
         test_panic_msg(
             || mem::zeroed::<OneVariant_NonZero>(),
             "attempted to zero-initialize type `OneVariant_NonZero`, \
                 which is invalid"
         );
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<OneVariant_NonZero>(),
+            "attempted to leave type `OneVariant_NonZero` uninitialized, which is invalid"
+        );
 
+        // Types where both are invalid but we allow the zeroed form since it is not LLVM UB.
+        test_panic_msg_only_if_strict(
+            || mem::zeroed::<LR_NonZero>(),
+            "attempted to zero-initialize type `LR_NonZero`, which is invalid"
+        );
         test_panic_msg(
             || mem::uninitialized::<LR_NonZero>(),
             "attempted to leave type `LR_NonZero` uninitialized, which is invalid"
         );
 
+        test_panic_msg_only_if_strict(
+            || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
+            "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
+             which is invalid"
+        );
         test_panic_msg(
             || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
             "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \
              which is invalid"
         );
 
-        test_panic_msg(
-            || mem::uninitialized::<NoNullVariant>(),
-            "attempted to leave type `NoNullVariant` uninitialized, \
-                which is invalid"
+        // Some strict-only things
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<i32>(),
+            "attempted to leave type `i32` uninitialized, which is invalid"
         );
 
-        test_panic_msg(
-            || mem::zeroed::<NoNullVariant>(),
-            "attempted to zero-initialize type `NoNullVariant`, \
-                which is invalid"
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<*const ()>(),
+            "attempted to leave type `*const ()` uninitialized, which is invalid"
         );
 
-        // Types that can be zero, but not uninit.
-        test_panic_msg(
-            || mem::uninitialized::<bool>(),
-            "attempted to leave type `bool` uninitialized, which is invalid"
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<[i32; 1]>(),
+            "attempted to leave type `[i32; 1]` uninitialized, which is invalid"
         );
 
+        test_panic_msg_only_if_strict(
+            || mem::zeroed::<[NonNull<()>; 1]>(),
+            "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
+        );
+
+        // Types that can be zero, but not uninit (though some are mitigated).
+        let _val = mem::zeroed::<LR>();
         test_panic_msg(
             || mem::uninitialized::<LR>(),
             "attempted to leave type `LR` uninitialized, which is invalid"
         );
 
+        let _val = mem::zeroed::<ManuallyDrop<LR>>();
         test_panic_msg(
             || mem::uninitialized::<ManuallyDrop<LR>>(),
             "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid"
         );
 
-        // Some things that should work.
         let _val = mem::zeroed::<bool>();
-        let _val = mem::zeroed::<LR>();
-        let _val = mem::zeroed::<ManuallyDrop<LR>>();
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<bool>(),
+            "attempted to leave type `bool` uninitialized, which is invalid"
+        );
+
         let _val = mem::zeroed::<OneVariant>();
+        test_panic_msg_only_if_strict(
+            || mem::uninitialized::<OneVariant>(),
+            "attempted to leave type `OneVariant` uninitialized, which is invalid"
+        );
+
+        // Some things that are actually allowed.
         let _val = mem::zeroed::<Option<&'static i32>>();
         let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
         let _val = mem::zeroed::<[!; 0]>();
@@ -233,59 +373,5 @@ fn main() {
         let _val = mem::uninitialized::<[!; 0]>();
         let _val = mem::uninitialized::<()>();
         let _val = mem::uninitialized::<ZeroSized>();
-
-        if cfg!(strict) {
-            test_panic_msg(
-                || mem::uninitialized::<i32>(),
-                "attempted to leave type `i32` uninitialized, which is invalid"
-            );
-
-            test_panic_msg(
-                || mem::uninitialized::<*const ()>(),
-                "attempted to leave type `*const ()` uninitialized, which is invalid"
-            );
-
-            test_panic_msg(
-                || mem::uninitialized::<[i32; 1]>(),
-                "attempted to leave type `[i32; 1]` uninitialized, which is invalid"
-            );
-
-            test_panic_msg(
-                || mem::zeroed::<NonNull<()>>(),
-                "attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid"
-            );
-
-            test_panic_msg(
-                || mem::zeroed::<[NonNull<()>; 1]>(),
-                "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
-            );
-
-            // FIXME(#66151) we conservatively do not error here yet (by default).
-            test_panic_msg(
-                || mem::zeroed::<LR_NonZero>(),
-                "attempted to zero-initialize type `LR_NonZero`, which is invalid"
-            );
-
-            test_panic_msg(
-                || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
-                "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
-                 which is invalid"
-            );
-        } else {
-            // These are UB because they have not been officially blessed, but we await the resolution
-            // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
-            // anything about that.
-            let _val = mem::uninitialized::<i32>();
-            let _val = mem::uninitialized::<*const ()>();
-
-            // These are UB, but best to test them to ensure we don't become unintentionally
-            // stricter.
-
-            // It's currently unchecked to create invalid enums and values inside arrays.
-            let _val = mem::zeroed::<LR_NonZero>();
-            let _val = mem::zeroed::<[LR_NonZero; 1]>();
-            let _val = mem::zeroed::<[NonNull<()>; 1]>();
-            let _val = mem::uninitialized::<[NonNull<()>; 1]>();
-        }
     }
 }
diff --git a/src/test/ui/lint/invalid_value.rs b/src/test/ui/lint/invalid_value.rs
index 51edb2b7baf..946a0e38861 100644
--- a/src/test/ui/lint/invalid_value.rs
+++ b/src/test/ui/lint/invalid_value.rs
@@ -88,6 +88,9 @@ fn main() {
         let _val: NonNull<i32> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
         let _val: NonNull<i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: (NonZeroU32, i32) = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: (NonZeroU32, i32) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         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
 
@@ -133,7 +136,7 @@ fn main() {
         let _val: Result<i32, i32> = mem::zeroed();
         let _val: Result<i32, i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
-        // Some things that happen to work due to rustc implementation details,
+        // Some things that happen to be UB-free due to rustc implementation details,
         // but are not guaranteed to keep working.
         let _val: OneFruit = mem::zeroed();
         let _val: OneFruit = mem::uninitialized();
diff --git a/src/test/ui/lint/invalid_value.stderr b/src/test/ui/lint/invalid_value.stderr
index f0dcf53dfee..3901692001a 100644
--- a/src/test/ui/lint/invalid_value.stderr
+++ b/src/test/ui/lint/invalid_value.stderr
@@ -315,8 +315,30 @@ LL |         let _val: NonNull<i32> = mem::uninitialized();
    |
    = note: `std::ptr::NonNull<i32>` must be non-null
 
+error: the type `(NonZeroU32, i32)` does not permit zero-initialization
+  --> $DIR/invalid_value.rs:91:39
+   |
+LL |         let _val: (NonZeroU32, i32) = mem::zeroed();
+   |                                       ^^^^^^^^^^^^^
+   |                                       |
+   |                                       this code causes undefined behavior when executed
+   |                                       help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: `std::num::NonZeroU32` must be non-null
+
+error: the type `(NonZeroU32, i32)` does not permit being left uninitialized
+  --> $DIR/invalid_value.rs:92:39
+   |
+LL |         let _val: (NonZeroU32, i32) = mem::uninitialized();
+   |                                       ^^^^^^^^^^^^^^^^^^^^
+   |                                       |
+   |                                       this code causes undefined behavior when executed
+   |                                       help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: `std::num::NonZeroU32` must be non-null
+
 error: the type `*const dyn Send` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:91:37
+  --> $DIR/invalid_value.rs:94:37
    |
 LL |         let _val: *const dyn Send = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -327,7 +349,7 @@ LL |         let _val: *const dyn Send = mem::zeroed();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `*const dyn Send` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:92:37
+  --> $DIR/invalid_value.rs:95:37
    |
 LL |         let _val: *const dyn Send = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -338,7 +360,7 @@ 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/invalid_value.rs:94:31
+  --> $DIR/invalid_value.rs:97:31
    |
 LL |         let _val: [fn(); 2] = mem::zeroed();
    |                               ^^^^^^^^^^^^^
@@ -349,7 +371,7 @@ LL |         let _val: [fn(); 2] = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `[fn(); 2]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:95:31
+  --> $DIR/invalid_value.rs:98:31
    |
 LL |         let _val: [fn(); 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +382,7 @@ LL |         let _val: [fn(); 2] = mem::uninitialized();
    = note: function pointers must be non-null
 
 error: the type `TwoUninhabited` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:97:36
+  --> $DIR/invalid_value.rs:100:36
    |
 LL |         let _val: TwoUninhabited = mem::zeroed();
    |                                    ^^^^^^^^^^^^^
@@ -375,7 +397,7 @@ LL | enum TwoUninhabited {
    | ^^^^^^^^^^^^^^^^^^^
 
 error: the type `TwoUninhabited` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:98:36
+  --> $DIR/invalid_value.rs:101:36
    |
 LL |         let _val: TwoUninhabited = mem::uninitialized();
    |                                    ^^^^^^^^^^^^^^^^^^^^
@@ -390,7 +412,7 @@ LL | enum TwoUninhabited {
    | ^^^^^^^^^^^^^^^^^^^
 
 error: the type `OneFruitNonZero` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:100:37
+  --> $DIR/invalid_value.rs:103:37
    |
 LL |         let _val: OneFruitNonZero = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -405,7 +427,7 @@ LL |     Banana(NonZeroU32),
    |            ^^^^^^^^^^
 
 error: the type `OneFruitNonZero` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:101:37
+  --> $DIR/invalid_value.rs:104:37
    |
 LL |         let _val: OneFruitNonZero = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -420,7 +442,7 @@ LL |     Banana(NonZeroU32),
    |            ^^^^^^^^^^
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:105:26
+  --> $DIR/invalid_value.rs:108:26
    |
 LL |         let _val: bool = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -431,7 +453,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/invalid_value.rs:108:32
+  --> $DIR/invalid_value.rs:111:32
    |
 LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -446,7 +468,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `NonBig` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:111:28
+  --> $DIR/invalid_value.rs:114:28
    |
 LL |         let _val: NonBig = mem::uninitialized();
    |                            ^^^^^^^^^^^^^^^^^^^^
@@ -457,7 +479,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/invalid_value.rs:114:27
+  --> $DIR/invalid_value.rs:117:27
    |
 LL |         let _val: Fruit = mem::uninitialized();
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -472,7 +494,7 @@ LL | enum Fruit {
    | ^^^^^^^^^^
 
 error: the type `[bool; 2]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:117:31
+  --> $DIR/invalid_value.rs:120:31
    |
 LL |         let _val: [bool; 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -483,7 +505,7 @@ LL |         let _val: [bool; 2] = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `i32` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:120:25
+  --> $DIR/invalid_value.rs:123:25
    |
 LL |         let _val: i32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -494,7 +516,7 @@ LL |         let _val: i32 = mem::uninitialized();
    = note: integers must not be uninitialized
 
 error: the type `f32` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:123:25
+  --> $DIR/invalid_value.rs:126:25
    |
 LL |         let _val: f32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -505,7 +527,7 @@ LL |         let _val: f32 = mem::uninitialized();
    = note: floats must not be uninitialized
 
 error: the type `*const ()` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:126:31
+  --> $DIR/invalid_value.rs:129:31
    |
 LL |         let _val: *const () = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -516,7 +538,7 @@ LL |         let _val: *const () = mem::uninitialized();
    = note: raw pointers must not be uninitialized
 
 error: the type `*const [()]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:129:33
+  --> $DIR/invalid_value.rs:132:33
    |
 LL |         let _val: *const [()] = mem::uninitialized();
    |                                 ^^^^^^^^^^^^^^^^^^^^
@@ -527,7 +549,7 @@ LL |         let _val: *const [()] = mem::uninitialized();
    = note: raw pointers must not be uninitialized
 
 error: the type `Result<i32, i32>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:134:38
+  --> $DIR/invalid_value.rs:137:38
    |
 LL |         let _val: Result<i32, i32> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
@@ -542,7 +564,7 @@ LL | pub enum Result<T, E> {
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:142:34
+  --> $DIR/invalid_value.rs:145:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -553,7 +575,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/invalid_value.rs:143:36
+  --> $DIR/invalid_value.rs:146:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +586,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/invalid_value.rs:144:32
+  --> $DIR/invalid_value.rs:147:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -575,7 +597,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/invalid_value.rs:147:34
+  --> $DIR/invalid_value.rs:150:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -586,7 +608,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/invalid_value.rs:148:34
+  --> $DIR/invalid_value.rs:151:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -597,7 +619,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/invalid_value.rs:149:26
+  --> $DIR/invalid_value.rs:152:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -607,5 +629,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 48 previous errors
+error: aborting due to 50 previous errors