Rollup merge of #129032 - jswrenn:transmute-method, r=compiler-errors
Document & implement 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 Tracking Issue: https://github.com/rust-lang/rust/issues/99571 r? `@compiler-errors` cc `@scottmcm,` `@Lokathor`
This commit is contained in:
commit
29923b6801
@ -363,6 +363,11 @@ fn resolve_associated_item<'tcx>(
|
|||||||
tcx.item_name(trait_item_id)
|
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 {
|
} else {
|
||||||
Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
|
Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,88 @@
|
|||||||
use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
|
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
|
/// # Implementation
|
||||||
/// 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.
|
/// 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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
#[lang = "transmute_trait"]
|
#[lang = "transmute_trait"]
|
||||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||||
@ -13,28 +91,207 @@ pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOT
|
|||||||
where
|
where
|
||||||
Src: ?Sized,
|
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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
#[lang = "transmute_opts"]
|
#[lang = "transmute_opts"]
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
pub struct Assume {
|
pub struct Assume {
|
||||||
/// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
|
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
|
||||||
/// destination referents do not have stricter alignment requirements than source referents.
|
/// 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,
|
pub alignment: bool,
|
||||||
|
|
||||||
/// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
|
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
|
||||||
/// that violates Rust's memory model.
|
/// 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,
|
pub lifetimes: bool,
|
||||||
|
|
||||||
/// When `true`, the compiler assumes that *you* have ensured that no
|
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
|
||||||
/// unsoundness will arise from violating the safety invariants of the
|
/// transmutations that might violate the library safety invariants of the
|
||||||
/// destination type (and sometimes of the source type, too).
|
/// 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,
|
pub safety: bool,
|
||||||
|
|
||||||
/// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
|
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
|
||||||
/// instance of the destination type.
|
/// 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,
|
pub validity: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,29 +301,87 @@ impl ConstParamTy_ for Assume {}
|
|||||||
impl UnsizedConstParamTy for Assume {}
|
impl UnsizedConstParamTy for Assume {}
|
||||||
|
|
||||||
impl 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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const NOTHING: Self =
|
pub const NOTHING: Self =
|
||||||
Self { alignment: false, lifetimes: false, safety: false, validity: false };
|
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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING };
|
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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING };
|
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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING };
|
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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING };
|
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")]
|
#[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 {
|
pub const fn and(self, other_assumptions: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
alignment: self.alignment || other_assumptions.alignment,
|
alignment: self.alignment || other_assumptions.alignment,
|
||||||
@ -76,7 +391,21 @@ pub const fn and(self, other_assumptions: Self) -> Self {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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")]
|
#[unstable(feature = "transmutability", issue = "99571")]
|
||||||
pub const fn but_not(self, other_assumptions: Self) -> Self {
|
pub const fn but_not(self, other_assumptions: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -19,7 +19,7 @@ fn main() -> () {
|
|||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = ();
|
_3 = ();
|
||||||
_2 = transmute::<(), Void>(move _3) -> bb4;
|
_2 = std::intrinsics::transmute::<(), Void>(move _3) -> bb4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as i8 (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as i8 (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as *const T (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as *const T (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as &mut Never (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as &mut Never (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as &Never (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
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);
|
+ _1 = const 1_usize as &Never (Transmute);
|
||||||
+ goto -> bb1;
|
+ goto -> bb1;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as Never (Transmute);
|
||||||
+ unreachable;
|
+ unreachable;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = copy _1;
|
_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);
|
+ _0 = move _2 as Never (Transmute);
|
||||||
+ unreachable;
|
+ unreachable;
|
||||||
}
|
}
|
||||||
|
@ -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
|
--> $DIR/coerce-unsafe-to-closure.rs:2:44
|
||||||
|
|
|
|
||||||
LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
|
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
|
| 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: unsafe function cannot be called generically without an unsafe block
|
||||||
note: required by a bound in `Option::<T>::map`
|
note: required by a bound in `Option::<T>::map`
|
||||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||||
|
@ -7,9 +7,9 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
|
|||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
|
= 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
|
--> $DIR/reify-intrinsic.rs:11:13
|
||||||
|
|
|
|
||||||
LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;
|
LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;
|
||||||
|
Loading…
Reference in New Issue
Block a user