Skip to content

Teach transmute_{ref,mut}! to handle slice DSTs#2428

Merged
jswrenn merged 1 commit intomainfrom
Ib4bc62202e0b3b09d155333b525087f7aa8f02c2
Jun 3, 2025
Merged

Teach transmute_{ref,mut}! to handle slice DSTs#2428
jswrenn merged 1 commit intomainfrom
Ib4bc62202e0b3b09d155333b525087f7aa8f02c2

Conversation

@joshlf
Copy link
Copy Markdown
Member

@joshlf joshlf commented Mar 7, 2025

We generalize our existing support in util::macro_util, now relying on
PMEs to detect when transmutes cannot be supported. In order to continue
to support sized reference transmutation in a const context, we use
the autoref specialization trick to fall back to our old (const-safe)
implementation when both the source and destination type are Sized.

The main challenge in generalizing this support is making a trait
implementation available conditional on a PME. We do this using the
unsafe_with_size_eq! helper macro, which introduces
#[repr(transparent)] wrapper types, Src and Dst. Internal to this
macro, we implement SizeEq<Src<T>> for Dst<U>, with the implementation
of SizeEq::cast_from_raw containing the PME logic for size equality.
The macro's caller must promise to only use the Src and Dst types
to wrap the T and U types for which this PME logic has been applied
(or else the SizeEq impl could "leak" to types for which it is
unsound).

In addition, we generalize our prior support for transmuting between
unsized types. In particular, we previously used the SizeEq trait to
denote that two types have equal sizes in the face of a cast operation
(in particular, that *const T as *const U preserves referent size). In
this commit, we add support for metadata fix-up, which means that we
support casts for which *const T as *const U does not preserve
referent size. Instead, we compute an affine function at compile time
and apply it at runtime - computing the destination type's metadata as a
function of the source metadata, dst_meta = A + src_meta * B. A and
B are computed at compile time.

We generalize SizeEq to permit its cast_from_raw method to perform a
runtime metadata fix-up operation.

Makes progress on #1817

Co-authored-by: Jack Wrenn jswrenn@amazon.com


This PR is on branch transmute-ref-dst.

@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 6 times, most recently from 829b199 to a7c40db Compare March 8, 2025 16:58
@joshlf joshlf force-pushed the I70d5aa5ace6bd2e39e679eac7f00a66d4b843d57 branch from 4d09d7c to f2ec335 Compare March 8, 2025 16:58
Base automatically changed from I70d5aa5ace6bd2e39e679eac7f00a66d4b843d57 to main March 8, 2025 19:16
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 3 times, most recently from 98bbab7 to 5196fac Compare March 9, 2025 01:10
Comment thread src/layout.rs Outdated
Comment thread src/layout.rs Outdated
Comment thread src/layout.rs Outdated
Comment thread src/layout.rs Outdated
Comment thread src/macros.rs Outdated
Comment thread src/util/macros.rs Outdated
Comment thread src/util/macros.rs Outdated
Comment thread src/util/macros.rs Outdated
Comment thread src/util/macros.rs Outdated
Comment thread src/util/macros.rs Outdated
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 2 times, most recently from 398966d to 976b234 Compare March 9, 2025 03:03
@joshlf joshlf changed the base branch from main to I691b42ce8c0c3c6e5990e7684fc66f8f5dd73d85 March 9, 2025 03:03
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 4 times, most recently from bd3b50a to e972a2c Compare March 9, 2025 06:47
Comment thread src/pointer/transmute.rs Outdated
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 2 times, most recently from e2b7f7d to 459de15 Compare March 11, 2025 18:51
Base automatically changed from I691b42ce8c0c3c6e5990e7684fc66f8f5dd73d85 to main March 11, 2025 19:21
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch from 459de15 to 424ddb4 Compare March 11, 2025 20:19
@joshlf joshlf changed the base branch from main to Icdb256acfdb274f34312cf5b216a02ca426338a1 March 11, 2025 20:19
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 7 times, most recently from ac7fd3f to 85cbc73 Compare March 25, 2025 19:17
Comment thread src/layout.rs Outdated
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 2 times, most recently from 5ebdc1a to 7d27689 Compare March 25, 2025 19:36
Comment thread src/util/macro_util.rs
Comment thread src/pointer/transmute.rs Outdated
Comment on lines +323 to +325
/// Implementations of `cast_from_raw` must satisfy that method's safety
/// post-condition.
pub unsafe trait SizeCompat<Src: ?Sized> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to do this now, but it'd be more idiomatic to name this CastFrom, after its method (and source of safety conditions). That name also conveys directionality, unlike SizeCompat.

Comment thread src/util/macros.rs
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 2 times, most recently from c5ae106 to 2d585bc Compare March 25, 2025 19:48
jswrenn
jswrenn previously approved these changes Mar 25, 2025
@joshlf joshlf force-pushed the Ib4bc62202e0b3b09d155333b525087f7aa8f02c2 branch 2 times, most recently from 8a04b30 to 3931fcf Compare March 25, 2025 19:58
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 25, 2025

Codecov Report

❌ Patch coverage is 73.20000% with 67 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.85%. Comparing base (f9c9703) to head (f5fcda2).
⚠️ Report is 349 commits behind head on main.

Files with missing lines Patch % Lines
src/layout.rs 33.33% 28 Missing ⚠️
src/macros.rs 80.64% 18 Missing ⚠️
src/impls.rs 0.00% 8 Missing ⚠️
src/doctests.rs 0.00% 4 Missing ⚠️
src/lib.rs 55.55% 4 Missing ⚠️
src/pointer/transmute.rs 40.00% 3 Missing ⚠️
src/util/macros.rs 88.23% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2428      +/-   ##
==========================================
- Coverage   89.25%   88.85%   -0.40%     
==========================================
  Files          19       20       +1     
  Lines        5126     5312     +186     
==========================================
+ Hits         4575     4720     +145     
- Misses        551      592      +41     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/pointer/transmute.rs Outdated
}
}

// TODO: Update all `TransmuteFrom` safety proofs.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Comment thread src/util/macros.rs
Comment thread src/util/macros.rs
// so permits interior mutation exactly when `T` does.
unsafe_impl!(T: ?Sized + Immutable => Immutable for $dst<T>);

$blk
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if the outer unsafe required to currently call this macro leaks into cover $blk.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried offline; turned out to be very difficult, so we're going to punt for now.

Comment thread src/util/macros.rs
Comment on lines +888 to +899
if 1 == 0 {
let ptr = <$t as KnownLayout>::raw_dangling();
#[allow(unused_unsafe)]
// SAFETY: This call is never executed.
let ptr = unsafe { crate::pointer::PtrInner::new(ptr) };
#[allow(unused_unsafe)]
// SAFETY: This call is never executed.
let ptr = unsafe { cast!(ptr) };
let _ = <$dst<$u> as SizeEq<$src<$t>>>::cast_from_raw(ptr);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should drop a comment as to why this block exists.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this okay? Can we rely on this PME occuring despite this code being dead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment: Done.

Can we rely on the PME: Maybe not, but the follow-up PR will ensure that it's sound since SizeEq will no longer convey a safety post-condition that can be consumed by unsafe code - the only way to use it will be via SizeEq::cast_from_raw, which will guarantee that the PME is triggered.

We generalize our existing support in `util::macro_util`, now relying on
PMEs to detect when transmutes cannot be supported. In order to continue
to support sized reference transmutation in a `const` context, we use
the autoref specialization trick to fall back to our old (`const`-safe)
implementation when both the source and destination type are `Sized`.

The main challenge in generalizing this support is making a trait
implementation available conditional on a PME. We do this using the
`unsafe_with_size_eq!` helper macro, which introduces
`#[repr(transparent)]` wrapper types, `Src` and `Dst`. Internal to this
macro, we implement `SizeEq<Src<T>> for Dst<U>`, with the implementation
of `SizeEq::cast_from_raw` containing the PME logic for size equality.
The macro's caller must promise to only use the `Src` and `Dst` types
to wrap the `T` and `U` types for which this PME logic has been applied
(or else the `SizeEq` impl could "leak" to types for which it is
unsound).

In addition, we generalize our prior support for transmuting between
unsized types. In particular, we previously used the `SizeEq` trait to
denote that two types have equal sizes in the face of a cast operation
(in particular, that `*const T as *const U` preserves referent size). In
this commit, we add support for metadata fix-up, which means that we
support casts for which `*const T as *const U` does *not* preserve
referent size. Instead, we compute an affine function at compile time
and apply it at runtime - computing the destination type's metadata as a
function of the source metadata, `dst_meta = A + src_meta * B`. `A` and
`B` are computed at compile time.

We generalize `SizeEq` to permit its `cast_from_raw` method to perform a
runtime metadata fix-up operation.

Makes progress on #1817

Co-authored-by: Jack Wrenn <jswrenn@amazon.com>
gherrit-pr-id: Ib4bc62202e0b3b09d155333b525087f7aa8f02c2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants