I have a type Error that I'd like to make unconditionally !RefUnwindSafe by adding an appropriate PhantomData field, without impacting any other auto traits. The question is, what PhantomData can I use to accomplish this in no_std context without writing any unsafe code? My current solution is
pub struct Error {
// other fields...
_not_ref_unwind_safe: PhantomData<UnsafeCell<()>>,
}
// SAFETY only source of !Sync is PhantomData
unsafe impl Sync for Error {}
but I would like a solution that doesn't need unsafe impl Sync or the like.
I sort of thought this was possible for the other auto traits, but after digging around I don't see any way to kill Send but not Sync using only core + alloc (suggestions welcome). As for the rest, you can kill Sync with Cell<()>, UnwindSafe with &mut (), and Unpin with PhantomPinned.
I looked through all the types in core and alloc, and I couldn't find anything stable that matches this description. I only found some unstable types in core that would work, as well as a few different types in #![no_std] libraries:
core::cell::SyncUnsafeCell<()> // unstable
core::ptr::DynMetadata<Cell<()>> // unstable, possibly an oversight
core::sync::Exclusive<Cell<()>> // unstable
qcell::LCell<'static, ()> // possibly an oversight
qcell::QCell<()> // possibly an oversight
spin::Mutex<()>
spin::RwLock<()>
Out of curiosity, why is your type Send + Sync + !RefUnwindSafe? Pretty much all types like that contain non-poisoning mutexes or locks, which seems unusual for a simple Error type.
Because it conditionally includes a std::backtrace::Backtrace, which has the same property, when a specific cfg(...) is active. I need the PhantomData so that flipping on that cfg(...) is not potentially breaking.
In turn, Backtrace is Sync + !RefUnwindSafe because it eventually contains this gadget, which contains an UnsafeCell but also has unsafe impl Sync. Maybe Backtrace should really be RefUnwindSafe too and this was just overlooked, idk.
One more addition—I just realized that trait objects give a simple way to do this that works for any combination of auto traits. For example, if you want to kill only Send and UnwindSafe, you can use PhantomData<dyn Any + Sync + RefUnwindSafe + Unpin>, or with some other trait in place of Any. Seems preferable to looking up the auto trait impls for UnsafeCell every time…