moveit/move_ref.rs
1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Move references.
16//!
17//! A move reference represents an owned value that is stored "somewhere else".
18//! We own the value, not the storage.
19//!
20//! A [`MoveRef<'a, T>`] represents a *permanent* unique reference to `T` for
21//! the lifetime `'a`: it is the longest-lived *possible* reference to the
22//! pointee, making it closer to a [`Box<T>`]
23//!
24//! Like [`&mut T`] but unlike [`Box<T>`], a [`MoveRef<T>`] is not responsible
25//! for destroying its storage, meaning that it is storage agnostic. The storage
26//! might be on the stack *or* on the heap; some RAII value on the stack is
27//! responsible for destroying just the storage, once the [`MoveRef<T>`] itself
28//! is gone.
29//!
30//! The main mechanism for obtaining [`MoveRef`]s is the [`moveit!()`] macro,
31//! which is analogous to a theoretical `&move expr` operator. This macro
32//! wraps [`DerefMove`], much like `&mut expr` wraps [`DerefMut`].
33//!
34//! Implementing [`DerefMove`] is a delicate affair; its documentation details
35//! exactly how it should be done.
36//!
37//! # Drop Flags
38//!
39//! In order to be sound, a `MoveRef` must also hold a pointer to a drop flag,
40//! which is used to detect if the `MoveRef` was dropped without destruction.
41//!
42//! In general, [`mem::forget`]ing a `MoveRef` is a very, very bad idea. In the
43//! best case it will leak memory, but in some cases will crash the program in
44//! order to observe safety guarantees.
45
46use core::mem;
47use core::ops::Deref;
48use core::ops::DerefMut;
49use core::pin::Pin;
50use core::ptr;
51
52#[cfg(doc)]
53use {
54 crate::{drop_flag, moveit},
55 alloc::{boxed::Box, rc::Rc, sync::Arc},
56 core::mem::{ManuallyDrop, MaybeUninit},
57};
58
59use crate::drop_flag::DropFlag;
60use crate::slot::DroppingSlot;
61
62/// A `MoveRef<'a, T>` represents an owned `T` whose storage location is valid
63/// but unspecified.
64///
65/// See [the module documentation][self] for more details.
66pub struct MoveRef<'a, T: ?Sized> {
67 ptr: &'a mut T,
68 drop_flag: DropFlag<'a>,
69}
70
71impl<'a, T: ?Sized> MoveRef<'a, T> {
72 /// Creates a new `MoveRef<T>` out of a mutable reference.
73 ///
74 /// # Safety
75 ///
76 /// `ptr` must satisfy the *longest-lived* criterion: after the return value
77 /// goes out of scope, `ptr` must also be out-of-scope. Calling this function
78 /// correctly is non-trivial, and should be left to [`moveit!()`] instead.
79 ///
80 /// In particular, if `ptr` outlives the returned `MoveRef`, it will point
81 /// to dropped memory, which is UB.
82 ///
83 /// `drop_flag`'s value must not be dead, and must be a drop flag governing
84 /// the destruction of `ptr`'s storage in an appropriate manner as described
85 /// in [`moveit::drop_flag`][crate::drop_flag].
86 #[inline]
87 pub unsafe fn new_unchecked(ptr: &'a mut T, drop_flag: DropFlag<'a>) -> Self {
88 Self { ptr, drop_flag }
89 }
90
91 /// Converts a `MoveRef<T>` into a `Pin<MoveRef<T>>`.
92 ///
93 /// Because we own the referent, we are entitled to pin it permanently. See
94 /// [`Box::into_pin()`] for a standard-library equivalent.
95 #[inline]
96 pub fn into_pin(this: Self) -> Pin<Self> {
97 unsafe { Pin::new_unchecked(this) }
98 }
99
100 /// Returns this `MoveRef<T>` as a raw pointer, without creating an
101 /// intermediate reference.
102 ///
103 /// The usual caveats for casting a reference to a pointer apply.
104 #[inline]
105 pub fn as_ptr(this: &Self) -> *const T {
106 this.ptr
107 }
108
109 /// Returns this `MoveRef<T>` as a raw mutable pointer, without creating an
110 /// intermediate reference.
111 ///
112 /// The usual caveats for casting a reference to a pointer apply.
113 #[inline]
114 pub fn as_mut_ptr(this: &mut Self) -> *mut T {
115 this.ptr
116 }
117
118 #[allow(unused)]
119 pub(crate) fn drop_flag(this: &Self) -> DropFlag<'a> {
120 this.drop_flag
121 }
122}
123
124// Extremely dangerous casts used by DerefMove below.
125impl<'a, T> MoveRef<'a, T> {
126 /// Consumes `self`, blindly casting the inner pointer to `U`.
127 pub(crate) unsafe fn cast<U>(mut self) -> MoveRef<'a, U> {
128 let mr = MoveRef {
129 ptr: &mut *Self::as_mut_ptr(&mut self).cast(),
130 drop_flag: self.drop_flag,
131 };
132 mem::forget(self);
133 mr
134 }
135}
136
137impl<'a, T> MoveRef<'a, T> {
138 /// Consume the `MoveRef<T>`, returning the wrapped value.
139 #[inline]
140 pub fn into_inner(this: Self) -> T {
141 unsafe {
142 let val = ptr::read(this.ptr);
143 let _ = this.cast::<()>();
144 val
145 }
146 }
147}
148
149impl<T: ?Sized> Deref for MoveRef<'_, T> {
150 type Target = T;
151
152 #[inline]
153 fn deref(&self) -> &Self::Target {
154 self.ptr
155 }
156}
157
158impl<T: ?Sized> DerefMut for MoveRef<'_, T> {
159 #[inline]
160 fn deref_mut(&mut self) -> &mut Self::Target {
161 self.ptr
162 }
163}
164
165impl<T: ?Sized> Drop for MoveRef<'_, T> {
166 #[inline]
167 fn drop(&mut self) {
168 self.drop_flag.dec_and_check_if_died();
169 unsafe { ptr::drop_in_place(self.ptr) }
170 }
171}
172
173impl<'a, T> From<MoveRef<'a, T>> for Pin<MoveRef<'a, T>> {
174 #[inline]
175 fn from(x: MoveRef<'a, T>) -> Self {
176 MoveRef::into_pin(x)
177 }
178}
179
180/// A trait for getting a pinned [`MoveRef`] for some pointer type `Self`.
181///
182/// Conceptually, this trait is similar to [`DerefMove`], except that where
183/// [`DerefMove::deref_move`] produces a `MoveRef<T>`, [`AsMove::as_move`] produces a
184/// `Pin<MoveRef<T>>`.
185///
186/// `DerefMove` can be seen as a refinement of `AsMove` where stronger guarantees about the memory
187/// behavior (specifically the Pin-safety) of `Self` are present.
188///
189/// Codifying this notion is the fact that `DerefMove` requires that `Self: DerefMut + AsMove`,
190/// whereas `AsMove` only requires the weaker constraints of `Self: Deref`.
191///
192/// Although `AsMove` is a supertrait of `DerefMove`, but `DerefMove` is *not* a supertrait of
193/// `AsMove`, the two traits are nevertheless intended to have their impls for a given type defined
194/// together *simultanteously*.
195///
196/// It is expected in this situation that the impl for one of the traits will be (trivially) defined
197/// in terms of the other, depending on the API for the pointer type `Self` with respect to
198/// [`DerefMut`].
199///
200/// For example, the `Box<T>: AsMove` impl is defined in terms of the `Box<T>: DerefMove` impl,
201/// because it is always the case that `Box<T>: DerefMut` regardless of whether `T: Unpin`. Hence,
202/// `Box<T>: AsMove` simply performs the `Box<T>: DerefMove` operation then subsequently
203/// (and trivially) pins the resulting `MoveRef<T>` with [`MoveRef::into_pin`].
204///
205/// On the other hand, the `cxx::UniquePtr<T>: DerefMove` impl is defined in terms of the
206/// `UniquePtr<T>: AsMove` impl, because a `cxx::UniquePtr<T>: DerefMut` only if `T: Unpin`. Given
207/// that `cxx::UniquePtr<T>` behaves like `Pin<Box<T>>` with respect to `DerefMut`, it is always
208/// possible to safely produce a `Pin<MoveRef<T>>`, but *not* always possible to safely produce a
209/// `MoveRef<T>`. Hence, when `T: Unpin`, only then `cxx::UniquePtr<T>: DerefMove` is defined,
210/// which simply performs the `cxx::UniquePtr<T>: AsMove` operation then subsequently
211/// (and trivially) unpins the resulting `Pin<MoveRef<T>>` with [`Pin::into_inner`].
212pub trait AsMove: Deref + Sized {
213 /// The "pure storage" form of `Self`, which owns the storage but not the
214 /// pointee.
215 type Storage: Sized;
216
217 /// Gets a pinned `MoveRef` out of `Self`.
218 ///
219 /// This function is best paired with [`moveit!()`]:
220 /// ```
221 /// # use core::pin::Pin;
222 /// # use moveit::{moveit, slot::DroppingSlot, move_ref::AsMove};
223 /// let ptr = Box::pin(5);
224 /// moveit::slot!(#[dropping] storage);
225 /// ptr.as_move(storage);
226 /// ```
227 /// Taking a trip through [`moveit!()`] is unavoidable due to the nature of
228 /// `MoveRef`.
229 ///
230 /// Compare with [`Pin::as_mut()`].
231 fn as_move<'frame>(
232 self,
233 storage: DroppingSlot<'frame, Self::Storage>,
234 ) -> Pin<MoveRef<'frame, Self::Target>>
235 where
236 Self: 'frame;
237}
238
239impl<'f, T: ?Sized> AsMove for MoveRef<'f, T> {
240 type Storage = ();
241
242 #[inline]
243 fn as_move<'frame>(
244 self,
245 storage: DroppingSlot<'frame, Self::Storage>,
246 ) -> Pin<MoveRef<'frame, Self::Target>>
247 where
248 Self: 'frame,
249 {
250 MoveRef::into_pin(DerefMove::deref_move(self, storage))
251 }
252}
253
254impl<P: DerefMove> AsMove for Pin<P> {
255 type Storage = P::Storage;
256
257 #[inline]
258 fn as_move<'frame>(
259 self,
260 storage: DroppingSlot<'frame, Self::Storage>,
261 ) -> Pin<MoveRef<'frame, Self::Target>>
262 where
263 Self: 'frame,
264 {
265 unsafe {
266 // SAFETY:
267 //
268 // It is safe to unwrap the `Pin` because `deref_move()` must not move out of the actual
269 // storage, merely shuffle pointers around, and immediately after the call to `deref_move()`
270 // we repin with `MoveRef::into_pin`, so the `Pin` API invariants are not violated later.
271 MoveRef::into_pin(P::deref_move(Pin::into_inner_unchecked(self), storage))
272 }
273 }
274}
275
276/// Moving dereference operations.
277///
278/// *Note: This trait is intended to be defined in conjunction with [`AsMove`],
279/// and there is a subtle interdependency between the two traits. We recommend
280/// also reading it's documentation for a better understanding of how these
281/// traits fit together.*
282///
283/// This trait is the `&move` analogue of [`Deref`], for taking a pointer that
284/// is the *sole owner* its pointee and converting it to a [`MoveRef`]. In
285/// particular, a pointer type `P` owns its contents if dropping it would cause
286/// its pointee's destructor to run.
287///
288/// For example:
289/// - [`MoveRef<T>`] implements `DerefMove` by definition.
290/// - [`Box<T>`] implements `DerefMove`, since it drops the `T` in its
291/// destructor.
292/// - [`&mut T`] does *not* implement `DerefMove`, because it is
293/// necessarily a borrow of a longer-lived, "truly owning" reference.
294/// - [`Rc<T>`] and [`Arc<T>`] do *not* implement `DerefMove`, because even
295/// though they own their pointees, they are not the *sole* owners. Dropping
296/// a reference-counted pointer need not run the destructor if other pointers
297/// are still alive.
298/// - [`Pin<P>`] for `P: DerefMove` implements `DerefMove` only when
299/// `P::Target: Unpin`, since `DerefMove: DerefMut`.
300///
301/// # Principle of Operation
302///
303/// Unfortunately, because we don't yet have language support for `&move`, we
304/// need to break the implementation into two steps:
305/// - Inhibit the "inner destructor" of the pointee, so that the smart pointer
306/// is now managing dumb bytes. This is usually accomplished by converting the
307/// pointee type to [`MaybeUninit<T>`].
308/// - Extract a [`MoveRef`] out of the "deinitialized" pointer.
309///
310/// The first part of this consists of converting the pointer into the
311/// "partially deinitialized" form, represented by the type
312/// [`AsMove::Storage`]: it is the pointer as "pure storage".
313///
314/// This pointer should be placed into the [`DroppingSlot`] passed into
315/// `deref_move`, so that it has a fixed lifetime for the duration of the frame
316/// that the [`MoveRef`] will exist for. The [`DroppingSlot`] will also provide
317/// a drop flag to use to build the returned [`MoveRef`].
318///
319/// The mutable reference returned by the [`DroppingSlot`] should then be
320/// converted into a [`MoveRef`]. The end result is that the [`DroppingSlot`]
321/// owns the "outer" part of the pointer, while the [`MoveRef`] owns the "inner"
322/// part. The `'frame` lifetime enforces the correct destruction order of these
323/// two parts, since the [`MoveRef`] borrows the [`DroppingSlot`].
324///
325/// The [`moveit!()`] macro helps by constructing the [`DroppingSlot`] for you.
326///
327/// ## Worked Example: [`Box<T>`]
328///
329/// To inhibit the inner destructor of [`Box<T>`], we can use `Box<MaybeUninit<T>>`
330/// as [`AsMove::Storage`]. [`MaybeUninit`] is preferred over [`ManuallyDrop`],
331/// since it helps avoid otherwise scary aliasing problems with `Box<&mut T>`.
332///
333/// The first step is to "cast" `Box<T>` into `Box<MaybeUninit<T>>` via
334/// [`Box::into_raw()`] and [`Box::from_raw()`]. This is then placed into the
335/// final storage location using [`DroppingSlot::put()`].
336///
337/// This returns a `&mut Box<MaybeUninit<T>>` and a [`DropFlag`]; the former is
338/// converted into an `&mut T` via [`MaybeUninit::assume_init_mut()`].
339///
340/// Finally, [`MoveRef::new_unchecked()`] is used to combine these into the
341/// return value.
342///
343/// The first step is safe because we construct a `MoveRef` to reinstate the
344/// destructor at the end of the function. The second step is safe because
345/// we know, a priori, that the `Box` contains an initialized value. The final
346/// step is safe, because we know, a priori, that the `Box` owns its pointee.
347///
348/// The use of the drop flag in this way makes it so that dropping the resulting
349/// `MoveRef` will leak the storage on the heap, exactly the same way as if we
350/// had leaked a `Box`.
351///
352/// ## Worked Example: [`MoveRef<T>`]
353///
354/// We don't need to inhibit any destructors: we just need to convert a
355/// `MoveRef<MoveRef<T>>` into a `MoveRef<T>`, which we can do by using
356/// [`MoveRef::into_inner()`]. [`AsMove::Storage`] can be whatever, so we
357/// simply choose [`()`] for this; the choice is arbitrary.
358///
359/// # Safety
360///
361/// Implementing `DerefMove` correctly requires that the uniqueness requirement
362/// of [`MoveRef`] is upheld. In particular, the following function *must not*
363/// violate memory safety:
364/// ```
365/// # use moveit::{DerefMove, MoveRef, moveit};
366/// fn move_out_of<P>(p: P) -> P::Target
367/// where
368/// P: DerefMove,
369/// P::Target: Sized,
370/// {
371/// unsafe {
372/// // Replace `p` with a move reference into it.
373/// moveit!(let p = &move *p);
374///
375/// // Move out of `p`. From this point on, the `P::Target` destructor must
376/// // run when, and only when, the function's return value goes out of
377/// // scope per the usual Rust rules.
378/// //
379/// // In particular, the original `p` or any pointer it came from must not
380/// // run the destructor when they go out of scope, under any circumstance.
381/// MoveRef::into_inner(p)
382/// }
383/// }
384/// ```
385///
386/// `deref_move()` must also be `Pin`-safe; even though it does not accept a
387/// pinned reference, it must take care to not move its contents at any time.
388/// In particular, the implementation of [`AsMove::as_move()`] must be safe by
389/// definition.
390pub unsafe trait DerefMove: DerefMut + AsMove {
391 /// Moves out of `self`, producing a [`MoveRef`] that owns its contents.
392 ///
393 /// `storage` is a location *somewhere* responsible for rooting the lifetime
394 /// of `*this`'s storage. The location is unimportant, so long as it outlives
395 /// the resulting [`MoveRef`], which is enforced by the type signature.
396 ///
397 /// [`moveit!()`] provides a convenient syntax for calling this function.
398 fn deref_move<'frame>(
399 self,
400 storage: DroppingSlot<'frame, Self::Storage>,
401 ) -> MoveRef<'frame, Self::Target>
402 where
403 Self: 'frame;
404}
405
406unsafe impl<'a, T: ?Sized> DerefMove for MoveRef<'a, T> {
407 #[inline]
408 fn deref_move<'frame>(
409 self,
410 _storage: DroppingSlot<'frame, Self::Storage>,
411 ) -> MoveRef<'frame, Self::Target>
412 where
413 Self: 'frame,
414 {
415 self
416 }
417}
418
419/// Note that `DerefMove` cannot be used to move out of a `Pin<P>` when `P::Target: !Unpin`.
420/// ```compile_fail
421/// # use crate::{moveit::{Emplace, MoveRef, moveit}};
422/// # use core::{marker::PhantomPinned, pin::Pin};
423/// // Fails to compile because `Box<PhantomPinned>: Deref<Target = PhantomPinned>` and `PhantomPinned: !Unpin`.
424/// let ptr: Pin<Box<PhantomPinned>> = Box::emplace(moveit::new::default::<PhantomPinned>());
425/// moveit!(let mref = &move *ptr);
426///
427/// // Fails to compile because `MoveRef<PhantomPinned>: Deref<Target = PhantomPinned>` and `PhantomPinned: !Unpin`.
428/// moveit! {
429/// let mref0: Pin<MoveRef<PhantomPinned>> = moveit::new::default::<PhantomPinned>();
430/// let mref1 = &move *mref0;
431/// }
432unsafe impl<P> DerefMove for Pin<P>
433where
434 P: DerefMove, // needed for `AsMove: Pin<P>` for the call to `Self::as_move`
435 P::Target: Unpin, // needed for the call to `Pin::into_inner`
436{
437 #[inline]
438 fn deref_move<'frame>(
439 self,
440 storage: DroppingSlot<'frame, Self::Storage>,
441 ) -> MoveRef<'frame, Self::Target>
442 where
443 Self: 'frame,
444 {
445 Pin::into_inner(self.as_move(storage))
446 }
447}
448
449#[doc(hidden)]
450pub mod __macro {
451 use super::*;
452 use core::marker::PhantomData;
453
454 /// Type-inference helper for `moveit!`.
455 pub struct DerefPhantom<T>(PhantomData<*const T>);
456 impl<T: DerefMove> DerefPhantom<T> {
457 #[inline]
458 pub fn new(_: &T) -> Self {
459 Self(PhantomData)
460 }
461
462 #[inline]
463 pub fn deref_move<'frame>(
464 self,
465 this: T,
466 storage: DroppingSlot<'frame, T::Storage>,
467 ) -> MoveRef<'frame, T::Target>
468 where
469 Self: 'frame,
470 {
471 T::deref_move(this, storage)
472 }
473 }
474}
475
476/// Performs an emplacement operation.
477///
478/// This macro allows for three exotic types of `let` bindings:
479/// ```
480/// # use moveit::{moveit, new, move_ref::MoveRef};
481/// # use core::pin::Pin;
482/// let bx = Box::new(42);
483///
484/// moveit! {
485/// // Use a `New` to construct a new value in place on the stack. This
486/// // produces a value of type `Pin<MoveRef<_>>`.
487/// let x = new::default::<i32>();
488///
489/// // Move out of an existing `DerefMove` type, such as a `Box`. This has
490/// // type `MoveRef<_>`, but can be pinned using `MoveRef::into_pin()`.
491/// let y = &move *bx;
492///
493/// // Create a `MoveRef` of an existing type on the stack. This also has
494/// // type `MoveRef<_>`.
495/// let z = &move y;
496/// }
497/// ```
498///
499/// All three `lets`, including in-place construction, pin to the stack.
500/// Consider using something like [`Box::emplace()`] to perform construction on
501/// the heap.
502///
503/// This macro also has *temporary* forms, where rather than creating a binding,
504/// a temporary (which cannot outlive its complete expression) is created:
505///
506/// ```
507/// # use moveit::{moveit, new, move_ref::MoveRef};
508/// # use core::pin::Pin;
509/// fn do_thing(x: Pin<MoveRef<i32>>) {
510/// // ...
511/// # let _ = x;
512/// }
513///
514/// do_thing(moveit!(new::of(42)));
515/// ```
516///
517/// Note that these bindings cannot outlive the subexpression:
518/// ```compile_fail
519/// # use moveit::{moveit, new};
520/// let x = moveit!(new::of(42));
521/// let y = *x; // Borrow checker error.
522/// ```
523///
524/// [`Box::emplace()`]: crate::new::Emplace::emplace
525#[macro_export]
526macro_rules! moveit {
527 (let $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => {
528 $crate::moveit!(@move $name, $($ty)?, $expr);
529 $crate::moveit!($($($rest)*)?);
530 };
531 (let mut $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => {
532 $crate::moveit!(@move(mut) $name, $($ty)?, $expr);
533 $crate::moveit!($($($rest)*)?);
534 };
535 (let $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => {
536 $crate::moveit!(@put $name, $($ty)?, $expr);
537 $crate::moveit!($($($rest)*)?);
538 };
539 (let mut $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => {
540 $crate::emplace!(@put(mut) $name, $($ty)?, $expr);
541 $crate::emplace!($($($rest)*)?);
542 };
543 (let $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => {
544 $crate::moveit!(@emplace $name, $($ty)?, $expr);
545 $crate::moveit!($($($rest)*)?);
546 };
547 (let mut $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => {
548 $crate::moveit!(@emplace(mut) $name, $($ty)?, $expr);
549 $crate::moveit!($($($rest)*)?);
550 };
551 ($(;)?) => {};
552
553 (&move *$expr:expr) => {
554 $crate::move_ref::DerefMove::deref_move(
555 $expr, $crate::slot!(#[dropping]),
556 )
557 };
558
559 (&move $expr:expr) => {$crate::slot!().put($expr)};
560 ($expr:expr) => {$crate::slot!().emplace($expr)};
561
562 (@move $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => {
563 $crate::slot!(#[dropping] storage);
564
565 #[allow(unused_mut)]
566 let $($mut)? $name $(: $ty)? = $crate::move_ref::DerefMove::deref_move($expr, storage);
567 };
568 (@put $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => {
569 $crate::slot!(slot);
570 let $($mut)? $name $(: $ty)? = slot.put($expr);
571 };
572 (@emplace $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => {
573 $crate::slot!(slot);
574 let $($mut)? $name $(: $ty)? = slot.emplace($expr);
575 };
576}
577
578#[cfg(test)]
579pub(crate) mod test {
580 use crate::new;
581 use crate::MoveNew;
582 use crate::New;
583
584 use super::*;
585 use std::alloc;
586 use std::alloc::Layout;
587 use std::marker::PhantomPinned;
588 use std::mem::MaybeUninit;
589
590 #[test]
591 fn deref_move_of_move_ref() {
592 moveit! {
593 let x: MoveRef<Box<i32>> = &move Box::new(5);
594 let y: MoveRef<Box<i32>> = &move *x;
595 }
596 let _ = y;
597 }
598
599 #[test]
600 fn deref_move_of_box() {
601 let x = Box::new(5);
602 moveit!(let y: MoveRef<i32> = &move *x);
603 let _ = y;
604 }
605
606 #[test]
607 fn move_ref_into_inner() {
608 moveit!(let x: MoveRef<Box<i32>> = &move Box::new(5));
609 let _ = MoveRef::into_inner(x);
610 }
611
612 #[test]
613 #[should_panic]
614 fn unforgettable() {
615 moveit!(let x: MoveRef<i32> = &move 42);
616 mem::forget(x);
617 }
618
619 #[test]
620 #[should_panic]
621 fn unforgettable_temporary() {
622 mem::forget(moveit!(&move 42));
623 }
624
625 #[test]
626 fn forgettable_box() {
627 let mut x = Box::new(5);
628
629 // Save the pointer for later, so that we can free it to make Miri happy.
630 let ptr = x.as_mut() as *mut i32;
631
632 moveit!(let y: MoveRef<i32> = &move *x);
633
634 // This should leak but be otherwise safe.
635 mem::forget(y);
636
637 // Free the leaked pointer; Miri will notice if this turns out to be a
638 // double-free.
639 unsafe {
640 alloc::dealloc(ptr as *mut u8, Layout::new::<i32>());
641 }
642 }
643
644 #[test]
645 fn forgettable_box_temporary() {
646 let mut x = Box::new(5);
647
648 // Save the pointer for later, so that we can free it to make Miri happy.
649 let ptr = x.as_mut() as *mut i32;
650
651 // This should leak but be otherwise safe.
652 mem::forget(moveit!(&move *x));
653
654 // Free the leaked pointer; Miri will notice if this turns out to be a
655 // double-free.
656 unsafe {
657 alloc::dealloc(ptr as *mut u8, Layout::new::<i32>());
658 }
659 }
660
661 // This type is reused in test code in cxx_support.
662 #[derive(Default)]
663 pub(crate) struct Immovable {
664 _pin: PhantomPinned,
665 }
666
667 impl Immovable {
668 pub(crate) fn new() -> impl New<Output = Self> {
669 new::default()
670 }
671 }
672
673 unsafe impl MoveNew for Immovable {
674 unsafe fn move_new(
675 _src: Pin<MoveRef<Self>>,
676 _this: Pin<&mut MaybeUninit<Self>>,
677 ) {
678 }
679 }
680
681 #[test]
682 fn test_mov() {
683 moveit! {
684 let foo = Immovable::new();
685 let _foo = new::mov(foo);
686 }
687 }
688}