From 31dda6d53d4d014e88ca599ecee7a5fbdb88b9c1 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 17 Jan 2025 14:22:31 +1100 Subject: [PATCH] Make io::Error Sync Currently we use a marker that contains an `UnsafeCell` but `UnsafeCell` is not `Sync` so this makes `io::Error` not `Sync`. We can instead wrap the `UnsafeCell` and implement `Sync` for it. Fix: #3883 --- io/src/error.rs | 17 +++++++++++++---- io/tests/api.rs | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/io/src/error.rs b/io/src/error.rs index 6ef943e42..ae5b5e44a 100644 --- a/io/src/error.rs +++ b/io/src/error.rs @@ -6,10 +6,12 @@ use core::fmt; #[derive(Debug)] pub struct Error { kind: ErrorKind, - /// Indicates that the `struct` can pretend to own a mutable static reference - /// and an [`UnsafeCell`](core::cell::UnsafeCell), which are not unwind safe. - /// This is so that it does not introduce non-additive cargo features. - _not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>, + /// We want this type to be `?UnwindSafe` and `?RefUnwindSafe` - the same as `std::io::Error`. + /// + /// In `std` builds the existence of `dyn std::error:Error` prevents `UnwindSafe` and + /// `RefUnwindSafe` from being automatically implemented. But in `no-std` builds without the + /// marker nothing prevents it. + _not_unwind_safe: core::marker::PhantomData, #[cfg(feature = "std")] error: Option>, @@ -100,6 +102,13 @@ impl From for std::io::Error { } } +/// Useful for preventing `UnwindSafe` and `RefUnwindSafe` from being automatically implemented. +struct NotUnwindSafe { + _not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>, +} + +unsafe impl Sync for NotUnwindSafe {} + macro_rules! define_errorkind { ($($(#[$($attr:tt)*])* $kind:ident),*) => { #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] diff --git a/io/tests/api.rs b/io/tests/api.rs index 608969c02..efc64f2e6 100644 --- a/io/tests/api.rs +++ b/io/tests/api.rs @@ -137,4 +137,8 @@ fn all_non_error_tyes_implement_send_sync() { // Types are `Send` and `Sync` where possible (C-SEND-SYNC). assert_send::(); assert_sync::(); + + // Error types are meaningful and well-behaved (C-GOOD-ERR) + assert_send::(); + assert_sync::(); }