-
Notifications
You must be signed in to change notification settings - Fork 13.3k
/
Copy pathtransmutability.rs
248 lines (227 loc) · 9.88 KB
/
transmutability.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
/// Marks that `Src` is transmutable into `Self`.
///
/// # 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`.
///
/// Specifically, this trait models (and
/// [implements](BikeshedIntrinsicFrom::transmute)) the semantics of
/// transmute-via-union; i.e.:
///
/// ```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 supports some transmutations forbidden by
/// [`mem::transmute_copy`](super::transmute_copy); namely, transmutations that
/// extend the bits of `Src` with trailing padding to fill trailing
/// uninitialized bytes of `Self`; e.g.:
///
/// ```
/// #![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) };
/// ```
///
/// ## 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)]
#[rustc_coinductive]
pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
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)
}
}
/// 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 `false`, [`BikeshedIntrinsicFrom`] is not implemented for
/// transmutations that might violate the the alignment requirements of
/// references.
///
/// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
/// that that references in the transmuted value satisfy the alignment
/// requirements of their referent types.
pub alignment: bool,
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
/// transmutations that extend the lifetimes of references.
///
/// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
/// that that references in the transmuted value do not outlive their
/// referents.
pub lifetimes: bool,
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
/// transmutations that might violate the library safety invariants of the
/// return type.
///
/// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
/// that undefined behavior does not arise from using the returned value.
pub safety: bool,
/// When `false`, [`BikeshedIntrinsicFrom`] is not implemented for
/// transmutations that might violate the language-level bit-validity
/// invariant of the return type.
///
/// When `true`, [`BikeshedIntrinsicFrom`] assumes that *you* have ensured
/// that the value being transmuted is a bit-valid instance of the return
/// type.
pub validity: bool,
}
#[unstable(feature = "transmutability", issue = "99571")]
impl ConstParamTy_ for Assume {}
#[unstable(feature = "transmutability", issue = "99571")]
impl UnsizedConstParamTy for Assume {}
impl Assume {
/// Do not assume that *you* have ensured any safety properties are met.
#[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.
#[unstable(feature = "transmutability", issue = "99571")]
pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING };
/// Assume only that lifetime conditions are met.
#[unstable(feature = "transmutability", issue = "99571")]
pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING };
/// Assume only that safety conditions are met.
#[unstable(feature = "transmutability", issue = "99571")]
pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING };
/// Assume only that dynamically-satisfiable validity conditions are met.
#[unstable(feature = "transmutability", issue = "99571")]
pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING };
/// Assume both `self` and `other_assumptions`.
#[unstable(feature = "transmutability", issue = "99571")]
pub const fn and(self, other_assumptions: Self) -> Self {
Self {
alignment: self.alignment || other_assumptions.alignment,
lifetimes: self.lifetimes || other_assumptions.lifetimes,
safety: self.safety || other_assumptions.safety,
validity: self.validity || other_assumptions.validity,
}
}
/// Assume `self`, excepting `other_assumptions`.
#[unstable(feature = "transmutability", issue = "99571")]
pub const fn but_not(self, other_assumptions: Self) -> Self {
Self {
alignment: self.alignment && !other_assumptions.alignment,
lifetimes: self.lifetimes && !other_assumptions.lifetimes,
safety: self.safety && !other_assumptions.safety,
validity: self.validity && !other_assumptions.validity,
}
}
}
// FIXME(jswrenn): This const op is not actually usable. Why?
// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
#[unstable(feature = "transmutability", issue = "99571")]
impl core::ops::Add for Assume {
type Output = Assume;
fn add(self, other_assumptions: Assume) -> Assume {
self.and(other_assumptions)
}
}
// FIXME(jswrenn): This const op is not actually usable. Why?
// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
#[unstable(feature = "transmutability", issue = "99571")]
impl core::ops::Sub for Assume {
type Output = Assume;
fn sub(self, other_assumptions: Assume) -> Assume {
self.but_not(other_assumptions)
}
}