Skip to content

Commit 609c77c

Browse files
committed
[wip] UnalignUnsized
1 parent 596521c commit 609c77c

File tree

11 files changed

+764
-16
lines changed

11 files changed

+764
-16
lines changed

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ jobs:
5656
# which a particular feature is supported.
5757
"zerocopy-core-error-1-81-0",
5858
"zerocopy-diagnostic-on-unimplemented-1-78-0",
59+
"zerocopy-unsized-needs-drop-1-63-0",
5960
"zerocopy-generic-bounds-in-const-fn-1-61-0",
6061
"zerocopy-target-has-atomics-1-60-0",
6162
"zerocopy-aarch64-simd-1-59-0",
@@ -93,6 +94,8 @@ jobs:
9394
features: "--all-features"
9495
- toolchain: "zerocopy-diagnostic-on-unimplemented-1-78-0"
9596
features: "--all-features"
97+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
98+
features: "--all-features"
9699
- toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
97100
features: "--all-features"
98101
- toolchain: "zerocopy-target-has-atomics-1-60-0"
@@ -117,6 +120,8 @@ jobs:
117120
toolchain: "zerocopy-core-error-1-81-0"
118121
- crate: "zerocopy-derive"
119122
toolchain: "zerocopy-diagnostic-on-unimplemented-1-78-0"
123+
- crate: "zerocopy-derive"
124+
toolchain: "zerocopy-unsized-needs-drop-1-63-0"
120125
- crate: "zerocopy-derive"
121126
toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
122127
- crate: "zerocopy-derive"
@@ -212,6 +217,28 @@ jobs:
212217
target: "thumbv6m-none-eabi"
213218
- toolchain: "zerocopy-generic-bounds-in-const-fn-1-61-0"
214219
target: "wasm32-wasi"
220+
# Exclude most targets targets from the
221+
# `zerocopy-unsized-needs-drop-1-63-0` toolchain since the
222+
# `zerocopy-unsized-needs-drop-1-63-0` feature is unrelated to
223+
# compilation target. This only leaves i686 and x86_64 targets.
224+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
225+
target: "arm-unknown-linux-gnueabi"
226+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
227+
target: "aarch64-unknown-linux-gnu"
228+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
229+
target: "powerpc-unknown-linux-gnu"
230+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
231+
target: "powerpc64-unknown-linux-gnu"
232+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
233+
target: "riscv64gc-unknown-linux-gnu"
234+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
235+
target: "s390x-unknown-linux-gnu"
236+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
237+
target: "x86_64-pc-windows-msvc"
238+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
239+
target: "thumbv6m-none-eabi"
240+
- toolchain: "zerocopy-unsized-needs-drop-1-63-0"
241+
target: "wasm32-wasi"
215242
# Exclude `thumbv6m-none-eabi` combined with any feature that implies
216243
# the `std` feature since `thumbv6m-none-eabi` does not include a
217244
# pre-compiled std.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ zerocopy-core-error-1-81-0 = "1.81.0"
4242
# From 1.78.0, Rust supports the `#[diagnostic::on_unimplemented]` attribute.
4343
zerocopy-diagnostic-on-unimplemented-1-78-0 = "1.78.0"
4444

45+
# From 1.63.0, Rust supports generic types with trait bounds in `const fn`.
46+
zerocopy-unsized-needs-drop-1-63-0 = "1.63.0"
47+
4548
# From 1.61.0, Rust supports generic types with trait bounds in `const fn`.
4649
zerocopy-generic-bounds-in-const-fn-1-61-0 = "1.61.0"
4750

src/layout.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub(crate) enum MetadataCastError {
9494

9595
impl DstLayout {
9696
/// The minimum possible alignment of a type.
97-
const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
97+
pub(crate) const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
9898
Some(min_align) => min_align,
9999
None => const_unreachable!(),
100100
};
@@ -598,6 +598,11 @@ impl DstLayout {
598598

599599
Ok((elems, split_at))
600600
}
601+
602+
/// Produces `true` if `self.align` equals 1; otherwise `false`.
603+
pub(crate) const fn is_trivially_aligned(&self) -> bool {
604+
matches!(self.align, DstLayout::MIN_ALIGN)
605+
}
601606
}
602607

603608
// TODO(#67): For some reason, on our MSRV toolchain, this `allow` isn't

src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,24 @@ pub unsafe trait KnownLayout {
762762
#[doc(hidden)]
763763
const LAYOUT: DstLayout;
764764

765+
/// Does `Self` have a non-trivial destructor?
766+
///
767+
/// This defaulted implementation is appropriate for all types except
768+
/// `UnalignUnsized<T>` which has an explicit `Drop` implementation and is
769+
/// thus unconditionally `mem::needs_drop`, even if `T` is not
770+
/// `mem::needs_drop`.
771+
///
772+
/// # Safety
773+
///
774+
/// Unsafe code may not assume anything about the value of `NEEDS_DROP`.
775+
const NEEDS_DROP: bool = {
776+
#[cfg(zerocopy_unsized_needs_drop_1_63_0)]
777+
let val = core::mem::needs_drop::<Self>();
778+
#[cfg(not(zerocopy_unsized_needs_drop_1_63_0))]
779+
let val = true;
780+
val
781+
};
782+
765783
/// SAFETY: The returned pointer has the same address and provenance as
766784
/// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
767785
/// elements in its trailing slice.
@@ -797,6 +815,34 @@ pub unsafe trait KnownLayout {
797815
// resulting size would not fit in a `usize`.
798816
meta.size_for_metadata(Self::LAYOUT)
799817
}
818+
819+
/// Run the destructor of `ptr`'s referent.
820+
///
821+
/// # Panics
822+
///
823+
/// Implementations of this function never panic.
824+
///
825+
/// # Compile-Time Assertions
826+
///
827+
/// Implementations of this function must emit a post-monomorphization error
828+
/// if `ptr`'s referent has a non-trivial drop that cannot be run.
829+
///
830+
/// # Safety
831+
///
832+
/// This function may only be called from the destructor (i.e.,
833+
/// `Drop::drop`) of transitive owner of `ptr`'s referent. After invoking
834+
/// this function, it is forbidden to re-use `ptr` or its referent.
835+
#[doc(hidden)]
836+
#[inline]
837+
unsafe fn destroy(ptr: MaybeAligned<'_, Self, invariant::Exclusive>) {
838+
// SAFETY: The preconditions of `destroy_unsized` are identical to that
839+
// of `destroy` and are ensured by the caller.
840+
//
841+
// This defaulted implementation works for all types, but for sized
842+
// types, delegating to `crate::util::destroy::destroy_sized` — which
843+
// does not allocate — is preferable.
844+
unsafe { crate::util::destroy::destroy_unsized(ptr) }
845+
}
800846
}
801847

802848
/// The metadata associated with a [`KnownLayout`] type.

src/pointer/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ where
5555
unsafe { core::ptr::read_unaligned(raw) }
5656
}
5757

58+
/// Reads the value from `MaybeAligned`.
59+
///
60+
/// # Safety
61+
///
62+
/// If `T` has a non-trivial destructor, using the returned `T` (including
63+
/// dropping it) and the original referent may cause undefined behavior. The
64+
/// caller ensures this does not occur.
65+
#[must_use]
66+
#[inline]
67+
pub(crate) unsafe fn read_unaligned_unchecked<R>(self) -> T
68+
where
69+
R: AliasingSafeReason,
70+
T: AliasingSafe<T, Aliasing, R> + Sized,
71+
{
72+
let raw = self.as_non_null().as_ptr();
73+
// SAFETY: By invariant on `MaybeAligned`, `raw` contains
74+
// validly-initialized data for `T`. By `T: AliasingSafe`, we are
75+
// permitted to perform a read of `raw`'s referent. The caller ensures
76+
// that subsequent uses of `T` do not induce UB.
77+
unsafe { core::ptr::read_unaligned(raw) }
78+
}
79+
5880
/// Views the value as an aligned reference.
5981
///
6082
/// This is only available if `T` is [`Unaligned`].

0 commit comments

Comments
 (0)