1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 use core::mem::{ManuallyDrop, MaybeUninit}; 6 use core::ops::{Deref, DerefMut}; 7 8 /// This type is intended to be similar to the type `MaybeDangling<T>` 9 /// proposed in [RFC 3336]. 10 /// 11 /// The effect of this is that in Rust's safety model, types inside here are not 12 /// expected to have any memory dependent validity properties (`dereferenceable`, `noalias`). 13 /// 14 /// See [#3696] for a testcase where `Yoke` fails under miri's field-retagging mode if not using 15 /// KindaSortaDangling. 16 /// 17 /// This has `T: 'static` since we don't need anything 18 /// else and we don't want to have to think (more) about variance over lifetimes or dropck. 19 /// 20 /// After [RFC 3336] lands we can use `MaybeDangling` instead. 21 /// 22 /// Note that a version of this type also exists publicly as the [`maybe_dangling`] 23 /// crate; which also exports a patched `ManuallyDrop` with similar semantics and 24 /// does not require `T: 'static`. Consider using this if you need something more general 25 /// and are okay with adding dependencies. 26 /// 27 /// [RFC 3336]: https://github.com/rust-lang/rfcs/pull/3336 28 /// [#3696]: https://github.com/unicode-org/icu4x/issues/3696 29 /// [`maybe_dangling`](https://docs.rs/maybe-dangling/0.1.0/maybe_dangling/struct.MaybeDangling.html) 30 #[repr(transparent)] 31 pub(crate) struct KindaSortaDangling<T: 'static> { 32 /// Safety invariant: This is always an initialized T, never uninit or other 33 /// invalid bit patterns. Its drop glue will execute during Drop::drop rather than 34 /// during the drop glue for KindaSortaDangling, which means that we have to be careful about 35 /// not touching the values as initialized during `drop` after that, but that's a short period of time. 36 dangle: MaybeUninit<T>, 37 } 38 39 impl<T: 'static> KindaSortaDangling<T> { 40 #[inline] new(dangle: T) -> Self41 pub(crate) const fn new(dangle: T) -> Self { 42 KindaSortaDangling { 43 dangle: MaybeUninit::new(dangle), 44 } 45 } 46 #[inline] into_inner(self) -> T47 pub(crate) fn into_inner(self) -> T { 48 // Self has a destructor, we want to avoid having it be called 49 let manual = ManuallyDrop::new(self); 50 // Safety: 51 // We can call assume_init_read() due to the library invariant on this type, 52 // however since it is a read() we must be careful about data duplication. 53 // The only code using `self` after this is the drop glue, which we have disabled via 54 // the ManuallyDrop. 55 unsafe { manual.dangle.assume_init_read() } 56 } 57 } 58 59 impl<T: 'static> Deref for KindaSortaDangling<T> { 60 type Target = T; 61 #[inline] deref(&self) -> &T62 fn deref(&self) -> &T { 63 // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always 64 // initialized as deref is never called during drop. 65 unsafe { self.dangle.assume_init_ref() } 66 } 67 } 68 69 impl<T: 'static> DerefMut for KindaSortaDangling<T> { 70 #[inline] deref_mut(&mut self) -> &mut T71 fn deref_mut(&mut self) -> &mut T { 72 // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always 73 // initialized as deref_mut is never called during drop. 74 unsafe { self.dangle.assume_init_mut() } 75 } 76 } 77 78 impl<T: 'static> Drop for KindaSortaDangling<T> { 79 #[inline] drop(&mut self)80 fn drop(&mut self) { 81 // Safety: We are reading and dropping a valid initialized T. 82 // 83 // As `drop_in_place()` is a `read()`-like duplication operation we must be careful that the original value isn't 84 // used afterwards. It won't be because this is drop and the only 85 // code that will run after this is `self`'s drop glue, and that drop glue is empty 86 // because MaybeUninit has no drop. 87 // 88 // We use `drop_in_place()` instead of `let _ = ... .assume_init_read()` to avoid creating a move 89 // of the inner `T` (without `KindaSortaDangling` protection!) type into a local -- we don't want to 90 // assert any of `T`'s memory-related validity properties here. 91 unsafe { 92 self.dangle.as_mut_ptr().drop_in_place(); 93 } 94 } 95 } 96