Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UnalignUnsized #1828

Open
wants to merge 2 commits into
base: v0.8.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
# which a particular feature is supported.
"zerocopy-core-error-1-81-0",
"zerocopy-diagnostic-on-unimplemented-1-78-0",
"zerocopy-unsized-needs-drop-1-63-0",
"zerocopy-generic-bounds-in-const-fn-1-61-0",
"zerocopy-target-has-atomics-1-60-0",
"zerocopy-aarch64-simd-1-59-0",
Expand Down Expand Up @@ -93,6 +94,8 @@ jobs:
features: "--all-features"
- toolchain: "zerocopy-diagnostic-on-unimplemented-1-78-0"
features: "--all-features"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
features: "--all-features"
- toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
features: "--all-features"
- toolchain: "zerocopy-target-has-atomics-1-60-0"
Expand All @@ -117,6 +120,8 @@ jobs:
toolchain: "zerocopy-core-error-1-81-0"
- crate: "zerocopy-derive"
toolchain: "zerocopy-diagnostic-on-unimplemented-1-78-0"
- crate: "zerocopy-derive"
toolchain: "zerocopy-unsized-needs-drop-1-63-0"
- crate: "zerocopy-derive"
toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
- crate: "zerocopy-derive"
Expand Down Expand Up @@ -212,6 +217,28 @@ jobs:
target: "thumbv6m-none-eabi"
- toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
target: "wasm32-wasi"
# Exclude most targets targets from the
# `zerocopy-unsized-needs-drop-1-63-0` toolchain since the
# `zerocopy-unsized-needs-drop-1-63-0` feature is unrelated to
# compilation target. This only leaves i686 and x86_64 targets.
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "arm-unknown-linux-gnueabi"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "aarch64-unknown-linux-gnu"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "powerpc-unknown-linux-gnu"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "powerpc64-unknown-linux-gnu"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "riscv64gc-unknown-linux-gnu"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "s390x-unknown-linux-gnu"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "x86_64-pc-windows-msvc"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "thumbv6m-none-eabi"
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
target: "wasm32-wasi"
# Exclude `thumbv6m-none-eabi` combined with any feature that implies
# the `std` feature since `thumbv6m-none-eabi` does not include a
# pre-compiled std.
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ zerocopy-core-error-1-81-0 = "1.81.0"
# From 1.78.0, Rust supports the `#[diagnostic::on_unimplemented]` attribute.
zerocopy-diagnostic-on-unimplemented-1-78-0 = "1.78.0"

# From 1.63.0, Rust supports generic types with trait bounds in `const fn`.
zerocopy-unsized-needs-drop-1-63-0 = "1.63.0"

# From 1.61.0, Rust supports generic types with trait bounds in `const fn`.
zerocopy-generic-bounds-in-const-fn-1-61-0 = "1.61.0"

Expand Down
7 changes: 6 additions & 1 deletion src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(crate) enum MetadataCastError {

impl DstLayout {
/// The minimum possible alignment of a type.
const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
pub(crate) const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
Some(min_align) => min_align,
None => const_unreachable!(),
};
Expand Down Expand Up @@ -598,6 +598,11 @@ impl DstLayout {

Ok((elems, split_at))
}

/// Produces `true` if `self.align` equals 1; otherwise `false`.
pub(crate) const fn is_trivially_aligned(&self) -> bool {
matches!(self.align, DstLayout::MIN_ALIGN)
}
}

// TODO(#67): For some reason, on our MSRV toolchain, this `allow` isn't
Expand Down
46 changes: 46 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,24 @@ pub unsafe trait KnownLayout {
#[doc(hidden)]
const LAYOUT: DstLayout;

/// Does `Self` have a non-trivial destructor?
///
/// This defaulted implementation is appropriate for all types except
/// `UnalignUnsized<T>` which has an explicit `Drop` implementation and is
/// thus unconditionally `mem::needs_drop`, even if `T` is not
/// `mem::needs_drop`.
///
/// # Safety
///
/// Unsafe code may not assume anything about the value of `NEEDS_DROP`.
const NEEDS_DROP: bool = {
#[cfg(zerocopy_unsized_needs_drop_1_63_0)]
let val = core::mem::needs_drop::<Self>();
#[cfg(not(zerocopy_unsized_needs_drop_1_63_0))]
let val = true;
val
};

/// SAFETY: The returned pointer has the same address and provenance as
/// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
/// elements in its trailing slice.
Expand Down Expand Up @@ -797,6 +815,34 @@ pub unsafe trait KnownLayout {
// resulting size would not fit in a `usize`.
meta.size_for_metadata(Self::LAYOUT)
}

/// Run the destructor of `ptr`'s referent.
///
/// # Panics
///
/// Implementations of this function never panic.
///
/// # Compile-Time Assertions
///
/// Implementations of this function must emit a post-monomorphization error
/// if `ptr`'s referent has a non-trivial drop that cannot be run.
///
/// # Safety
///
/// This function may only be called from the destructor (i.e.,
/// `Drop::drop`) of transitive owner of `ptr`'s referent. After invoking
/// this function, it is forbidden to re-use `ptr` or its referent.
#[doc(hidden)]
#[inline]
unsafe fn destroy(ptr: MaybeAligned<'_, Self, invariant::Exclusive>) {
// SAFETY: The preconditions of `destroy_unsized` are identical to that
// of `destroy` and are ensured by the caller.
//
// This defaulted implementation works for all types, but for sized
// types, delegating to `crate::util::destroy::destroy_sized` — which
// does not allocate — is preferable.
unsafe { crate::util::destroy::destroy_unsized(ptr) }
}
}

/// The metadata associated with a [`KnownLayout`] type.
Expand Down
22 changes: 22 additions & 0 deletions src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ where
unsafe { core::ptr::read_unaligned(raw) }
}

/// Reads the value from `MaybeAligned`.
///
/// # Safety
///
/// If `T` has a non-trivial destructor, using the returned `T` (including
/// dropping it) and the original referent may cause undefined behavior. The
/// caller ensures this does not occur.
#[must_use]
#[inline]
pub(crate) unsafe fn read_unaligned_unchecked<R>(self) -> T
where
R: AliasingSafeReason,
T: AliasingSafe<T, Aliasing, R> + Sized,
{
let raw = self.as_non_null().as_ptr();
// SAFETY: By invariant on `MaybeAligned`, `raw` contains
// validly-initialized data for `T`. By `T: AliasingSafe`, we are
// permitted to perform a read of `raw`'s referent. The caller ensures
// that subsequent uses of `T` do not induce UB.
unsafe { core::ptr::read_unaligned(raw) }
}

/// Views the value as an aligned reference.
///
/// This is only available if `T` is [`Unaligned`].
Expand Down
Loading
Loading