Skip to content

Commit 7952754

Browse files
committed
Move io::Error to alloc
1 parent df672eb commit 7952754

13 files changed

Lines changed: 318 additions & 186 deletions

File tree

Lines changed: 129 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
#[cfg(test)]
2-
mod tests;
3-
41
#[stable(feature = "rust1", since = "1.0.0")]
52
pub use core::io::ErrorKind;
3+
use core::{error, fmt, result};
4+
5+
use crate::boxed::Box;
66

77
// On 64-bit platforms, `io::Error` may use a bit-packed representation to
88
// reduce size. However, this representation assumes that error codes are
@@ -11,17 +11,94 @@ pub use core::io::ErrorKind;
1111
// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit.
1212
// Therefore, the packed representation is explicitly disabled for UEFI
1313
// targets, and the unpacked representation must be used instead.
14-
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
15-
mod repr_bitpacked;
16-
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
17-
use repr_bitpacked::Repr;
1814

19-
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
20-
mod repr_unpacked;
21-
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
22-
use repr_unpacked::Repr;
15+
cfg_select! {
16+
all(target_pointer_width = "64", not(target_os = "uefi")) => {
17+
use repr_bitpacked::Repr;
18+
mod repr_bitpacked;
19+
}
20+
_ => {
21+
mod repr_unpacked;
22+
use repr_unpacked::Repr;
23+
}
24+
}
25+
26+
#[cfg(target_has_atomic = "ptr")]
27+
pub(super) mod os {
28+
//! OS-dependent functions
29+
//!
30+
//! `Error` needs OS functionalities to work interpret raw OS errors, but
31+
//! we can't link to anythink here in `alloc`. Therefore, we restrict
32+
//! creation of `Error` from raw OS errors in `std`, and require providing
33+
//! a vtable of operations when creating one.
34+
35+
// FIXME: replace this with externally implementable items once they are more stable
36+
37+
use core::sync::atomic;
38+
39+
use super::{ErrorKind, RawOsError};
40+
use crate::string::String;
41+
42+
#[doc(hidden)]
43+
#[derive(Debug)]
44+
pub struct OsFunctions {
45+
pub error_string: fn(_: RawOsError) -> String,
46+
pub decode_error_kind: fn(_: RawOsError) -> ErrorKind,
47+
pub is_interrupted: fn(_: RawOsError) -> bool,
48+
}
49+
50+
/// These default functions are not reachable, but have them just to be safe.
51+
const DEFAULT_FUNCTIONS: &'static OsFunctions = &OsFunctions {
52+
error_string: |_| String::new(),
53+
decode_error_kind: |_| ErrorKind::Uncategorized,
54+
is_interrupted: |_| false,
55+
};
56+
static OS_FUNCTIONS: atomic::AtomicPtr<OsFunctions> =
57+
atomic::AtomicPtr::new(DEFAULT_FUNCTIONS as *const _ as *mut _);
2358

24-
use crate::{error, fmt, result, sys};
59+
#[inline]
60+
pub(super) fn set_functions(f: &'static OsFunctions) {
61+
OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed);
62+
}
63+
64+
#[inline]
65+
pub(super) fn error_string(errno: RawOsError) -> String {
66+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
67+
(f.error_string)(errno)
68+
}
69+
70+
#[inline]
71+
pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind {
72+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
73+
(f.decode_error_kind)(errno)
74+
}
75+
76+
#[inline]
77+
pub(super) fn is_interrupted(errno: RawOsError) -> bool {
78+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
79+
(f.is_interrupted)(errno)
80+
}
81+
}
82+
83+
// Disable these on target without atomics, they don't support `std` anyway
84+
#[cfg(not(target_has_atomic = "ptr"))]
85+
pub(super) mod os {
86+
use super::{ErrorKind, RawOsError};
87+
use crate::string::String;
88+
89+
#[inline]
90+
pub(super) fn error_string(_: RawOsError) -> String {
91+
String::new()
92+
}
93+
#[inline]
94+
pub(super) fn decode_error_kind(_: RawOsError) -> ErrorKind {
95+
ErrorKind::Uncategorized
96+
}
97+
#[inline]
98+
pub(super) fn is_interrupted(_: RawOsError) -> bool {
99+
false
100+
}
101+
}
25102

26103
/// A specialized [`Result`] type for I/O operations.
27104
///
@@ -39,7 +116,7 @@ use crate::{error, fmt, result, sys};
39116
///
40117
/// [`std::io`]: crate::io
41118
/// [`io::Error`]: Error
42-
/// [`Result`]: crate::result::Result
119+
/// [`Result`]: core::result::Result
43120
///
44121
/// # Examples
45122
///
@@ -66,6 +143,7 @@ pub type Result<T> = result::Result<T, Error>;
66143
/// `Error` can be created with crafted error messages and a particular value of
67144
/// [`ErrorKind`].
68145
#[stable(feature = "rust1", since = "1.0.0")]
146+
#[rustc_has_incoherent_inherent_impls]
69147
pub struct Error {
70148
repr: Repr,
71149
}
@@ -78,47 +156,48 @@ impl fmt::Debug for Error {
78156
}
79157

80158
/// Common errors constants for use in std
81-
#[allow(dead_code)]
159+
#[doc(hidden)]
160+
#[unstable(feature = "io_error_internals", issue = "none")]
82161
impl Error {
83-
pub(crate) const INVALID_UTF8: Self =
162+
pub const INVALID_UTF8: Self =
84163
const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
85164

86-
pub(crate) const READ_EXACT_EOF: Self =
165+
pub const READ_EXACT_EOF: Self =
87166
const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
88167

89-
pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!(
168+
pub const UNKNOWN_THREAD_COUNT: Self = const_error!(
90169
ErrorKind::NotFound,
91170
"the number of hardware threads is not known for the target platform",
92171
);
93172

94-
pub(crate) const UNSUPPORTED_PLATFORM: Self =
173+
pub const UNSUPPORTED_PLATFORM: Self =
95174
const_error!(ErrorKind::Unsupported, "operation not supported on this platform");
96175

97-
pub(crate) const WRITE_ALL_EOF: Self =
176+
pub const WRITE_ALL_EOF: Self =
98177
const_error!(ErrorKind::WriteZero, "failed to write whole buffer");
99178

100-
pub(crate) const ZERO_TIMEOUT: Self =
179+
pub const ZERO_TIMEOUT: Self =
101180
const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
102181

103-
pub(crate) const NO_ADDRESSES: Self =
182+
pub const NO_ADDRESSES: Self =
104183
const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
105184
}
106185

107186
#[stable(feature = "rust1", since = "1.0.0")]
108-
impl From<alloc::ffi::NulError> for Error {
109-
/// Converts a [`alloc::ffi::NulError`] into a [`Error`].
110-
fn from(_: alloc::ffi::NulError) -> Error {
187+
impl From<crate::ffi::NulError> for Error {
188+
/// Converts a [`crate::ffi::NulError`] into a [`Error`].
189+
fn from(_: crate::ffi::NulError) -> Error {
111190
const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
112191
}
113192
}
114193

115194
#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
116-
impl From<alloc::collections::TryReserveError> for Error {
195+
impl From<crate::collections::TryReserveError> for Error {
117196
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
118197
///
119198
/// `TryReserveError` won't be available as the error `source()`,
120199
/// but this may change in the future.
121-
fn from(_: alloc::collections::TryReserveError) -> Error {
200+
fn from(_: crate::collections::TryReserveError) -> Error {
122201
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
123202
ErrorKind::OutOfMemory.into()
124203
}
@@ -142,8 +221,11 @@ enum ErrorData<C> {
142221
/// portability.
143222
///
144223
/// [`into`]: Into::into
145-
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
146-
pub type RawOsError = sys::io::RawOsError;
224+
#[allow(unreachable_pub)]
225+
pub type RawOsError = cfg_select! {
226+
target_os = "uefi" => usize,
227+
_ => i32,
228+
};
147229

148230
// `#[repr(align(4))]` is probably redundant, it should have that value or
149231
// higher already. We include it just because repr_bitpacked.rs's encoding
@@ -186,9 +268,9 @@ pub struct SimpleMessage {
186268
/// ```
187269
#[rustc_macro_transparency = "semiopaque"]
188270
#[unstable(feature = "io_const_error", issue = "133448")]
189-
#[allow_internal_unstable(hint_must_use, io_const_error_internals)]
271+
#[allow_internal_unstable(alloc_io, hint_must_use, io_const_error_internals, liballoc_internals)]
190272
pub macro const_error($kind:expr, $message:expr $(,)?) {
191-
$crate::hint::must_use($crate::io::Error::from_static_message(
273+
$crate::__export::must_use($crate::io::Error::from_static_message(
192274
const { &$crate::io::SimpleMessage { kind: $kind, message: $message } },
193275
))
194276
}
@@ -308,99 +390,21 @@ impl Error {
308390
Self { repr: Repr::new_simple_message(msg) }
309391
}
310392

311-
/// Returns an error representing the last OS error which occurred.
312-
///
313-
/// This function reads the value of `errno` for the target platform (e.g.
314-
/// `GetLastError` on Windows) and will return a corresponding instance of
315-
/// [`Error`] for the error code.
316-
///
317-
/// This should be called immediately after a call to a platform function,
318-
/// otherwise the state of the error value is indeterminate. In particular,
319-
/// other standard library functions may call platform functions that may
320-
/// (or may not) reset the error value even if they succeed.
321-
///
322-
/// # Examples
323-
///
324-
/// ```
325-
/// use std::io::Error;
326-
///
327-
/// let os_error = Error::last_os_error();
328-
/// println!("last OS error: {os_error:?}");
329-
/// ```
330-
#[stable(feature = "rust1", since = "1.0.0")]
331-
#[doc(alias = "GetLastError")]
332-
#[doc(alias = "errno")]
333-
#[must_use]
393+
#[unstable(feature = "io_error_internals", issue = "none")]
334394
#[inline]
335-
pub fn last_os_error() -> Error {
336-
Error::from_raw_os_error(sys::io::errno())
337-
}
338-
339-
/// Creates a new instance of an [`Error`] from a particular OS error code.
340-
///
341-
/// # Examples
342-
///
343-
/// On Linux:
344-
///
345-
/// ```
346-
/// # if cfg!(target_os = "linux") {
347-
/// use std::io;
348-
///
349-
/// let error = io::Error::from_raw_os_error(22);
350-
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
351-
/// # }
352-
/// ```
353-
///
354-
/// On Windows:
355-
///
356-
/// ```
357-
/// # if cfg!(windows) {
358-
/// use std::io;
359-
///
360-
/// let error = io::Error::from_raw_os_error(10022);
361-
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
362-
/// # }
363-
/// ```
364-
#[stable(feature = "rust1", since = "1.0.0")]
365395
#[must_use]
366-
#[inline]
367-
pub fn from_raw_os_error(code: RawOsError) -> Error {
396+
#[doc(hidden)]
397+
#[cfg(target_has_atomic = "ptr")]
398+
pub fn _from_raw_os_error(code: RawOsError, os: &'static os::OsFunctions) -> Error {
399+
os::set_functions(os);
368400
Error { repr: Repr::new_os(code) }
369401
}
370402

371-
/// Returns the OS error that this error represents (if any).
372-
///
373-
/// If this [`Error`] was constructed via [`last_os_error`] or
374-
/// [`from_raw_os_error`], then this function will return [`Some`], otherwise
375-
/// it will return [`None`].
376-
///
377-
/// [`last_os_error`]: Error::last_os_error
378-
/// [`from_raw_os_error`]: Error::from_raw_os_error
379-
///
380-
/// # Examples
381-
///
382-
/// ```
383-
/// use std::io::{Error, ErrorKind};
384-
///
385-
/// fn print_os_error(err: &Error) {
386-
/// if let Some(raw_os_err) = err.raw_os_error() {
387-
/// println!("raw OS error: {raw_os_err:?}");
388-
/// } else {
389-
/// println!("Not an OS error");
390-
/// }
391-
/// }
392-
///
393-
/// fn main() {
394-
/// // Will print "raw OS error: ...".
395-
/// print_os_error(&Error::last_os_error());
396-
/// // Will print "Not an OS error".
397-
/// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
398-
/// }
399-
/// ```
400-
#[stable(feature = "rust1", since = "1.0.0")]
403+
#[unstable(feature = "io_error_internals", issue = "none")]
401404
#[must_use]
402405
#[inline]
403-
pub fn raw_os_error(&self) -> Option<RawOsError> {
406+
#[doc(hidden)]
407+
pub fn _raw_os_error(&self) -> Option<RawOsError> {
404408
match self.repr.data() {
405409
ErrorData::Os(i) => Some(i),
406410
ErrorData::Custom(..) => None,
@@ -646,7 +650,7 @@ impl Error {
646650
Ok(*err)
647651
} else {
648652
// Safety: We have just checked that the condition is true
649-
unsafe { crate::hint::unreachable_unchecked() }
653+
unsafe { core::hint::unreachable_unchecked() }
650654
}
651655
} else {
652656
Err(self)
@@ -658,9 +662,6 @@ impl Error {
658662
/// This may be a value set by Rust code constructing custom `io::Error`s,
659663
/// or if this `io::Error` was sourced from the operating system,
660664
/// it will be a value inferred from the system's error encoding.
661-
/// See [`last_os_error`] for more details.
662-
///
663-
/// [`last_os_error`]: Error::last_os_error
664665
///
665666
/// # Examples
666667
///
@@ -684,17 +685,19 @@ impl Error {
684685
#[inline]
685686
pub fn kind(&self) -> ErrorKind {
686687
match self.repr.data() {
687-
ErrorData::Os(code) => sys::io::decode_error_kind(code),
688+
ErrorData::Os(code) => os::decode_error_kind(code),
688689
ErrorData::Custom(c) => c.kind,
689690
ErrorData::Simple(kind) => kind,
690691
ErrorData::SimpleMessage(m) => m.kind,
691692
}
692693
}
693694

695+
#[unstable(feature = "io_error_internals", issue = "none")]
696+
#[doc(hidden)]
694697
#[inline]
695-
pub(crate) fn is_interrupted(&self) -> bool {
698+
pub fn is_interrupted(&self) -> bool {
696699
match self.repr.data() {
697-
ErrorData::Os(code) => sys::io::is_interrupted(code),
700+
ErrorData::Os(code) => os::is_interrupted(code),
698701
ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
699702
ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
700703
ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
@@ -708,8 +711,8 @@ impl fmt::Debug for Repr {
708711
ErrorData::Os(code) => fmt
709712
.debug_struct("Os")
710713
.field("code", &code)
711-
.field("kind", &sys::io::decode_error_kind(code))
712-
.field("message", &sys::io::error_string(code))
714+
.field("kind", &os::decode_error_kind(code))
715+
.field("message", &os::error_string(code))
713716
.finish(),
714717
ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
715718
ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
@@ -727,7 +730,7 @@ impl fmt::Display for Error {
727730
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
728731
match self.repr.data() {
729732
ErrorData::Os(code) => {
730-
let detail = sys::io::error_string(code);
733+
let detail = os::error_string(code);
731734
write!(fmt, "{detail} (os error {code})")
732735
}
733736
ErrorData::Custom(ref c) => c.error.fmt(fmt),

library/std/src/io/error/repr_bitpacked.rs renamed to library/alloc/src/io/error/repr_bitpacked.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ use core::num::NonZeroUsize;
107107
use core::ptr::NonNull;
108108

109109
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
110+
use crate::boxed::Box;
110111

111112
// The 2 least-significant bits are used as tag.
112113
const TAG_MASK: usize = 0b11;

0 commit comments

Comments
 (0)