1- #[ cfg( test) ]
2- mod tests;
3-
41#[ stable( feature = "rust1" , since = "1.0.0" ) ]
52pub 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]
69147pub 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" ) ]
82161impl 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 ) ]
190272pub 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) ,
0 commit comments