about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJack Wrenn <jack@wrenn.fyi>2024-08-12 22:52:59 +0000
committerJack Wrenn <jack@wrenn.fyi>2024-08-23 14:37:36 +0000
commit2540070fd45defe48d02aa7af974c8f295b326a4 (patch)
tree4803e07359dcc31cbe80749e3435a14536592432
parent4d5b3b196284aded6ae99d12bcf149ffdc8ef379 (diff)
downloadrust-2540070fd45defe48d02aa7af974c8f295b326a4.tar.gz
rust-2540070fd45defe48d02aa7af974c8f295b326a4.zip
document & impl the transmutation modeled by `BikeshedIntrinsicFrom`
Documents that `BikeshedIntrinsicFrom` models transmute-via-union,
which is slightly more expressive than the transmute-via-cast
implemented by `transmute_copy`. Additionally, we provide an
implementation of transmute-via-union as a method on the
`BikeshedIntrinsicFrom` trait with additional documentation on
the boundary between trait invariants and caller obligations.

Whether or not transmute-via-union is the right kind of transmute
to model remains up for discussion [1]. Regardless, it seems wise
to document the present behavior.

[1] https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/What.20'kind'.20of.20transmute.20to.20model.3F/near/426331967
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs5
-rw-r--r--library/core/src/mem/transmutability.rs371
-rw-r--r--tests/mir-opt/issue_72181_1.main.built.after.mir2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/ui/closures/coerce-unsafe-to-closure.stderr4
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.stderr4
17 files changed, 372 insertions, 38 deletions
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index c7ed6e6110f..d77c3a277bf 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -363,6 +363,11 @@ fn resolve_associated_item<'tcx>(
                         tcx.item_name(trait_item_id)
                     ),
                 }
+            } else if tcx.is_lang_item(trait_ref.def_id, LangItem::TransmuteTrait) {
+                let name = tcx.item_name(trait_item_id);
+                assert_eq!(name, sym::transmute);
+                let args = tcx.erase_regions(rcvr_args);
+                Some(ty::Instance::new(trait_item_id, args))
             } else {
                 Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
             }
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index ea73c5b80ba..62d454a5289 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -1,10 +1,88 @@
 use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
 
-/// Are values of a type transmutable into values of another type?
+/// Marks that `Src` is transmutable into `Self`.
 ///
-/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
-/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
-/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
+/// # Implementation
+///
+/// This trait cannot be implemented explicitly. It is implemented on-the-fly by
+/// the compiler for all types `Src` and `Self` such that, given a set of safety
+/// obligations on the programmer (see [`Assume`]), the compiler has proved that
+/// the bits of a value of type `Src` can be soundly reinterpreted as a `Self`.
+///
+/// # Safety
+///
+/// If `Dst: BikeshedIntrinsicFrom<Src, ASSUMPTIONS>`, the compiler guarantees
+/// that `Src` is soundly *union-transmutable* into a value of type `Dst`,
+/// provided that the programmer has guaranteed that the given
+/// [`ASSUMPTIONS`](Assume) are satisfied.
+///
+/// A union-transmute is any bit-reinterpretation conversion in the form of:
+///
+/// ```rust
+/// pub unsafe fn transmute_via_union<Src, Dst>(src: Src) -> Dst {
+///     use core::mem::ManuallyDrop;
+///
+///     #[repr(C)]
+///     union Transmute<Src, Dst> {
+///         src: ManuallyDrop<Src>,
+///         dst: ManuallyDrop<Dst>,
+///     }
+///
+///     let transmute = Transmute {
+///         src: ManuallyDrop::new(src),
+///     };
+///
+///     let dst = transmute.dst;
+///
+///     ManuallyDrop::into_inner(dst)
+/// }
+/// ```
+///
+/// Note that this construction is more permissive than
+/// [`mem::transmute_copy`](super::transmute_copy); union-transmutes permit
+/// conversions that extend the bits of `Src` with trailing padding to fill
+/// trailing uninitialized bytes of `Self`; e.g.:
+///
+#[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+#[cfg_attr(not(bootstrap), doc = "```rust")]
+/// #![feature(transmutability)]
+///
+/// use core::mem::{Assume, BikeshedIntrinsicFrom};
+///
+/// let src = 42u8; // size = 1
+///
+/// #[repr(C, align(2))]
+/// struct Dst(u8); // size = 2
+//
+/// let _ = unsafe {
+///     <Dst as BikeshedIntrinsicFrom<u8, { Assume::SAFETY }>>::transmute(src)
+/// };
+/// ```
+///
+/// # Caveats
+///
+/// ## Portability
+///
+/// Implementations of this trait do not provide any guarantee of portability
+/// across toolchains, targets or compilations. This trait may be implemented
+/// for certain combinations of `Src`, `Self` and `ASSUME` on some toolchains,
+/// targets or compilations, but not others. For example, if the layouts of
+/// `Src` or `Self` are non-deterministic, the presence or absence of an
+/// implementation of this trait may also be non-deterministic. Even if `Src`
+/// and `Self` have deterministic layouts (e.g., they are `repr(C)` structs),
+/// Rust does not specify the alignments of its primitive integer types, and
+/// layouts that involve these types may vary across toolchains, targets or
+/// compilations.
+///
+/// ## Stability
+///
+/// Implementations of this trait do not provide any guarantee of SemVer
+/// stability across the crate versions that define the `Src` and `Self` types.
+/// If SemVer stability is crucial to your application, you must consult the
+/// documentation of `Src` and `Self`s' defining crates. Note that the presence
+/// of `repr(C)`, alone, does not carry a safety invariant of SemVer stability.
+/// Furthermore, stability does not imply portability. For example, the size of
+/// `usize` is stable, but not portable.
 #[unstable(feature = "transmutability", issue = "99571")]
 #[lang = "transmute_trait"]
 #[rustc_deny_explicit_impl(implement_via_object = false)]
@@ -13,28 +91,207 @@ pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOT
 where
     Src: ?Sized,
 {
+    /// Transmutes a `Src` value into a `Self`.
+    ///
+    /// # Safety
+    ///
+    /// The safety obligations of the caller depend on the value of `ASSUME`:
+    /// - If [`ASSUME.alignment`](Assume::alignment), the caller must guarantee
+    ///   that the addresses of references in the returned `Self` satisfy the
+    ///   alignment requirements of their referent types.
+    /// - If [`ASSUME.lifetimes`](Assume::lifetimes), the caller must guarantee
+    ///   that references in the returned `Self` will not outlive their
+    ///   referents.
+    /// - If [`ASSUME.safety`](Assume::safety), the returned value might not
+    ///   satisfy the library safety invariants of `Self`, and the caller must
+    ///   guarantee that undefined behavior does not arise from uses of the
+    ///   returned value.
+    /// - If [`ASSUME.validity`](Assume::validity), the caller must guarantee
+    ///   that `src` is a bit-valid instance of `Self`.
+    ///
+    /// When satisfying the above obligations (if any), the caller must *not*
+    /// assume that this trait provides any inherent guarantee of layout
+    /// [portability](#portability) or [stability](#stability).
+    unsafe fn transmute(src: Src) -> Self
+    where
+        Src: Sized,
+        Self: Sized,
+    {
+        use super::ManuallyDrop;
+
+        #[repr(C)]
+        union Transmute<Src, Dst> {
+            src: ManuallyDrop<Src>,
+            dst: ManuallyDrop<Dst>,
+        }
+
+        let transmute = Transmute { src: ManuallyDrop::new(src) };
+
+        // SAFETY: It is safe to reinterpret the bits of `src` as a value of
+        // type `Self`, because, by combination of invariant on this trait and
+        // contract on the caller, `src` has been proven to satisfy both the
+        // language and library invariants of `Self`. For all invariants not
+        // `ASSUME`'d by the caller, the safety obligation is supplied by the
+        // compiler. Conversely, for all invariants `ASSUME`'d by the caller,
+        // the safety obligation is supplied by contract on the caller.
+        let dst = unsafe { transmute.dst };
+
+        ManuallyDrop::into_inner(dst)
+    }
 }
 
-/// What transmutation safety conditions shall the compiler assume that *you* are checking?
+/// Configurable proof assumptions of [`BikeshedIntrinsicFrom`].
+///
+/// When `false`, the respective proof obligation belongs to the compiler. When
+/// `true`, the onus of the safety proof belongs to the programmer.
+/// [`BikeshedIntrinsicFrom`].
 #[unstable(feature = "transmutability", issue = "99571")]
 #[lang = "transmute_opts"]
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct Assume {
-    /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
-    /// destination referents do not have stricter alignment requirements than source referents.
+    /// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
+    /// transmutations that might violate the the alignment requirements of
+    /// references; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")]
+    /// #![feature(transmutability)]
+    /// use core::mem::{align_of, BikeshedIntrinsicFrom};
+    ///
+    /// assert_eq!(align_of::<[u8; 2]>(), 1);
+    /// assert_eq!(align_of::<u16>(), 2);
+    ///
+    /// let src: &[u8; 2] = &[0xFF, 0xFF];
+    ///
+    /// // SAFETY: No safety obligations.
+    /// let dst: &u16 = unsafe {
+    ///     <_ as BikeshedIntrinsicFrom<_>>::transmute(src)
+    /// };
+    /// ```
+    ///
+    /// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
+    /// that references in the transmuted value satisfy the alignment
+    /// requirements of their referent types; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
+    /// #![feature(pointer_is_aligned_to, transmutability)]
+    /// use core::mem::{align_of, Assume, BikeshedIntrinsicFrom};
+    ///
+    /// let src: &[u8; 2] = &[0xFF, 0xFF];
+    ///
+    /// let maybe_dst: Option<&u16> = if <*const _>::is_aligned_to(src, align_of::<u16>()) {
+    ///     // SAFETY: We have checked above that the address of `src` satisfies the
+    ///     // alignment requirements of `u16`.
+    ///     Some(unsafe {
+    ///         <_ as BikeshedIntrinsicFrom<_, { Assume::ALIGNMENT }>>::transmute(src)
+    ///     })
+    /// } else {
+    ///     None
+    /// };
+    ///
+    /// assert!(matches!(maybe_dst, Some(&u16::MAX) | None));
+    /// ```
     pub alignment: bool,
 
-    /// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
-    /// that violates Rust's memory model.
+    /// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
+    /// transmutations that extend the lifetimes of references.
+    ///
+    /// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
+    /// that references in the transmuted value do not outlive their referents.
     pub lifetimes: bool,
 
-    /// When `true`, the compiler assumes that *you* have ensured that no
-    /// unsoundness will arise from violating the safety invariants of the
-    /// destination type (and sometimes of the source type, too).
+    /// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
+    /// transmutations that might violate the library safety invariants of the
+    /// destination type; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")]
+    /// #![feature(transmutability)]
+    /// use core::mem::BikeshedIntrinsicFrom;
+    ///
+    /// let src: u8 = 3;
+    ///
+    /// struct EvenU8 {
+    ///     // SAFETY: `val` must be an even number.
+    ///     val: u8,
+    /// }
+    ///
+    /// // SAFETY: No safety obligations.
+    /// let dst: EvenU8 = unsafe {
+    ///     <_ as BikeshedIntrinsicFrom<_>>::transmute(src)
+    /// };
+    /// ```
+    ///
+    /// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
+    /// that undefined behavior does not arise from using the transmuted value;
+    /// e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
+    /// #![feature(transmutability)]
+    /// use core::mem::{Assume, BikeshedIntrinsicFrom};
+    ///
+    /// let src: u8 = 42;
+    ///
+    /// struct EvenU8 {
+    ///     // SAFETY: `val` must be an even number.
+    ///     val: u8,
+    /// }
+    ///
+    /// let maybe_dst: Option<EvenU8> = if src % 2 == 0 {
+    ///     // SAFETY: We have checked above that the value of `src` is even.
+    ///     Some(unsafe {
+    ///         <_ as BikeshedIntrinsicFrom<_, { Assume::SAFETY }>>::transmute(src)
+    ///     })
+    /// } else {
+    ///     None
+    /// };
+    ///
+    /// assert!(matches!(maybe_dst, Some(EvenU8 { val: 42 })));
+    /// ```
     pub safety: bool,
 
-    /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
-    /// instance of the destination type.
+    /// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
+    /// transmutations that might violate the language-level bit-validity
+    /// invariant of the destination type; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```compile_fail,E0277")]
+    /// #![feature(transmutability)]
+    /// use core::mem::BikeshedIntrinsicFrom;
+    ///
+    /// let src: u8 = 3;
+    ///
+    /// // SAFETY: No safety obligations.
+    /// let dst: bool = unsafe {
+    ///     <_ as BikeshedIntrinsicFrom<_>>::transmute(src)
+    /// };
+    /// ```
+    ///
+    /// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
+    /// that the value being transmuted is a bit-valid instance of the
+    /// transmuted value; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
+    /// #![feature(transmutability)]
+    /// use core::mem::{Assume, BikeshedIntrinsicFrom};
+    ///
+    /// let src: u8 = 1;
+    ///
+    /// let maybe_dst: Option<bool> = if src == 0 || src == 1 {
+    ///     // SAFETY: We have checked above that the value of `src` is a bit-valid
+    ///     // instance of `bool`.
+    ///     Some(unsafe {
+    ///         <_ as BikeshedIntrinsicFrom<_, { Assume::VALIDITY }>>::transmute(src)
+    ///     })
+    /// } else {
+    ///     None
+    /// };
+    ///
+    /// assert_eq!(maybe_dst, Some(true));
+    /// ```
     pub validity: bool,
 }
 
@@ -44,29 +301,87 @@ impl ConstParamTy_ for Assume {}
 impl UnsizedConstParamTy for Assume {}
 
 impl Assume {
-    /// Do not assume that *you* have ensured any safety properties are met.
+    /// With this, [`BikeshedIntrinsicFrom`] does not assume you have ensured
+    /// any safety obligations are met, and relies only upon its own analysis to
+    /// (dis)prove transmutability.
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const NOTHING: Self =
         Self { alignment: false, lifetimes: false, safety: false, validity: false };
 
-    /// Assume only that alignment conditions are met.
+    /// With this, [`BikeshedIntrinsicFrom`] assumes only that you have ensured
+    /// that references in the transmuted value satisfy the alignment
+    /// requirements of their referent types. See [`Assume::alignment`] for
+    /// examples.
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING };
 
-    /// Assume only that lifetime conditions are met.
+    /// With this, [`BikeshedIntrinsicFrom`] assumes only that you have ensured
+    /// that references in the transmuted value do not outlive their referents.
+    /// See [`Assume::lifetimes`] for examples.
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING };
 
-    /// Assume only that safety conditions are met.
+    /// With this, [`BikeshedIntrinsicFrom`] assumes only that you have ensured
+    /// that undefined behavior does not arise from using the transmuted value.
+    /// See [`Assume::safety`] for examples.
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING };
 
-    /// Assume only that dynamically-satisfiable validity conditions are met.
+    /// With this, [`BikeshedIntrinsicFrom`] assumes only that you have ensured
+    /// that the value being transmuted is a bit-valid instance of the
+    /// transmuted value. See [`Assume::validity`] for examples.
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING };
 
-    /// Assume both `self` and `other_assumptions`.
+    /// Combine the assumptions of `self` and `other_assumptions`.
+    ///
+    /// This is especially useful for extending [`Assume`] in generic contexts;
+    /// e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
     #[unstable(feature = "transmutability", issue = "99571")]
+    /// #![feature(
+    ///     adt_const_params,
+    ///     generic_const_exprs,
+    ///     pointer_is_aligned_to,
+    ///     transmutability,
+    /// )]
+    /// #![allow(incomplete_features)]
+    /// use core::mem::{align_of, Assume, BikeshedIntrinsicFrom};
+    ///
+    /// /// Attempts to transmute `src` to `&Dst`.
+    /// ///
+    /// /// Returns `None` if `src` violates the alignment requirements of `&Dst`.
+    /// ///
+    /// /// # Safety
+    /// ///
+    /// /// The caller guarantees that the obligations required by `ASSUME`, except
+    /// /// alignment, are satisfied.
+    /// unsafe fn try_transmute_ref<'a, Src, Dst, const ASSUME: Assume>(src: &'a Src) -> Option<&'a Dst>
+    /// where
+    ///     &'a Dst: BikeshedIntrinsicFrom<&'a Src, { ASSUME.and(Assume::ALIGNMENT) }>,
+    /// {
+    ///     if <*const _>::is_aligned_to(src, align_of::<Dst>()) {
+    ///         // SAFETY: By the above dynamic check, we have ensured that the address
+    ///         // of `src` satisfies the alignment requirements of `&Dst`. By contract
+    ///         // on the caller, the safety obligations required by `ASSUME` have also
+    ///         // been satisfied.
+    ///         Some(unsafe {
+    ///             <_ as BikeshedIntrinsicFrom<_, { ASSUME.and(Assume::ALIGNMENT) }>>::transmute(src)
+    ///         })
+    ///     } else {
+    ///         None
+    ///     }
+    /// }
+    ///
+    /// let src: &[u8; 2] = &[0xFF, 0xFF];
+    ///
+    /// // SAFETY: No safety obligations.
+    /// let maybe_dst: Option<&u16> = unsafe {
+    ///     try_transmute_ref::<_, _, { Assume::NOTHING }>(src)
+    /// };
+    ///```
     pub const fn and(self, other_assumptions: Self) -> Self {
         Self {
             alignment: self.alignment || other_assumptions.alignment,
@@ -76,7 +391,21 @@ impl Assume {
         }
     }
 
-    /// Assume `self`, excepting `other_assumptions`.
+    /// Remove `other_assumptions` the obligations of `self`; e.g.:
+    ///
+    #[cfg_attr(bootstrap, doc = "```rust,ignore not runnable on bootstrap")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
+    /// #![feature(transmutability)]
+    /// use core::mem::Assume;
+    ///
+    /// let assumptions = Assume::ALIGNMENT.and(Assume::SAFETY);
+    /// let to_be_removed = Assume::SAFETY.and(Assume::VALIDITY);
+    ///
+    /// assert_eq!(
+    ///     assumptions.but_not(to_be_removed),
+    ///     Assume::ALIGNMENT,
+    /// );
+    /// ```
     #[unstable(feature = "transmutability", issue = "99571")]
     pub const fn but_not(self, other_assumptions: Self) -> Self {
         Self {
diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir
index e8ad5cd8d16..293aa37944d 100644
--- a/tests/mir-opt/issue_72181_1.main.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.main.built.after.mir
@@ -19,7 +19,7 @@ fn main() -> () {
         StorageLive(_2);
         StorageLive(_3);
         _3 = ();
-        _2 = transmute::<(), Void>(move _3) -> bb4;
+        _2 = std::intrinsics::transmute::<(), Void>(move _3) -> bb4;
     }
 
     bb1: {
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
index 71e84fdd881..b1104c70e46 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-abort.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::transmute::<std::cmp::Ordering, i8>(move _2) -> [return: bb1, unwind unreachable];
 +         _0 = move _2 as i8 (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
index 71e84fdd881..b1104c70e46 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::transmute::<std::cmp::Ordering, i8>(move _2) -> [return: bb1, unwind unreachable];
 +         _0 = move _2 as i8 (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
index 37232b826c1..169e48a31dd 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-abort.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable];
 +         _0 = move _2 as *const T (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
index 37232b826c1..169e48a31dd 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable];
 +         _0 = move _2 as *const T (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
index 8ac70f99ad2..7098b4d3168 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
index 8ac70f99ad2..7098b4d3168 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff
index c2c4ec0003c..06225fffd7c 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as &mut Never (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff
index c2c4ec0003c..06225fffd7c 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as &mut Never (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff
index 1b516a1f53b..dd6ab3a9c97 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as &Never (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff
index 1b516a1f53b..dd6ab3a9c97 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable];
+-         _1 = std::intrinsics::transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable];
 +         _1 = const 1_usize as &Never (Transmute);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
index eab969e9fe5..6571f3d9db8 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<(), Never>(move _2) -> unwind unreachable;
+-         _0 = std::intrinsics::transmute::<(), Never>(move _2) -> unwind unreachable;
 +         _0 = move _2 as Never (Transmute);
 +         unreachable;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
index eab969e9fe5..6571f3d9db8 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = copy _1;
--         _0 = transmute::<(), Never>(move _2) -> unwind unreachable;
+-         _0 = std::intrinsics::transmute::<(), Never>(move _2) -> unwind unreachable;
 +         _0 = move _2 as Never (Transmute);
 +         unreachable;
       }
diff --git a/tests/ui/closures/coerce-unsafe-to-closure.stderr b/tests/ui/closures/coerce-unsafe-to-closure.stderr
index cb718ca160f..2538fc0361c 100644
--- a/tests/ui/closures/coerce-unsafe-to-closure.stderr
+++ b/tests/ui/closures/coerce-unsafe-to-closure.stderr
@@ -1,4 +1,4 @@
-error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
   --> $DIR/coerce-unsafe-to-closure.rs:2:44
    |
 LL |     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
@@ -6,7 +6,7 @@ LL |     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
    |                                        |
    |                                        required by a bound introduced by this call
    |
-   = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+   = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
index 0119a1a6650..21b7bf4e1cb 100644
--- a/tests/ui/intrinsics/reify-intrinsic.stderr
+++ b/tests/ui/intrinsics/reify-intrinsic.stderr
@@ -7,9 +7,9 @@ LL |     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
    |            expected due to this
    |
    = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
-                 found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+                 found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
 
-error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
+error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
   --> $DIR/reify-intrinsic.rs:11:13
    |
 LL |     let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;