authorbors <bors@rust-lang.org> 2026-06-29 00:40:20 UTC
committerbors <bors@rust-lang.org> 2026-06-29 00:40:20 UTC
log7fb284d9037fa54f6a9b24261c82b394472cbfd7
tree538b8d54cec93c05e9ff4187624db4c4562543ab
parentdf6ee909ef35c75aa58aa45af6ac071a9b8285c2
parent3fa872ca7932853d12ef66a37c39988cd7bec92b

Auto merge of #155625 - bushrat011899:core_io_error, r=Mark-Simulacrum

Move `std::io::Error` into `core` ACP: https://github.com/rust-lang/libs-team/issues/755 Tracking issue: https://github.com/rust-lang/rust/issues/154046 Related: https://github.com/rust-lang/rust/pull/155574 Related: https://github.com/rust-lang/rust/pull/152918 ## Description Moves `std::io::Error` into `core`, deferring `Box`-adjacent methods to incoherent implementations in `alloc`, and `RawOsError` methods to `std`. This requires some substantial changes to the internals of `Error`, but none of them are breaking changes or externally visible. Notably, I've replaced usage of `Box` with a wrapper around a pointer and an appropriate drop function. This requires the addition of quite a few lines of unsafe, but is required to work around `Box` only being accessible from `alloc`. Additionally, an atomic pointer to a VTable is used for working with `RawOsError` in `core`, since we cannot know the required implementations without `std`. As mention in [this comment](https://github.com/rust-lang/rust/pull/155625#issuecomment-4744932682), there may be concern around having a static `AtomicPtr` in `core` for certain users. I've added a configuration option `no_io_statics` which (similar to `no_sync`/etc. in `alloc`) can be used to prevent their inclusion in `core`. When active, the fallback default implementation will always be used. --- ## Notes * This PR adopts the VTable technique from rust-lang/rust#152918 * This PR builds on my previous PR rust-lang/rust#155574 * No AI tooling of any kind was used during the creation of this PR.

21 files changed, 1592 insertions(+), 1164 deletions(-)

library/alloc/src/io/error.rs created+274
......@@ -0,0 +1,274 @@
1use core::io::Custom;
2#[cfg_attr(no_global_oom_handling, expect(unused_imports))]
3use core::io::CustomOwner;
4use core::{error, result};
5
6use crate::boxed::Box;
7#[cfg_attr(any(no_rc, no_sync, no_global_oom_handling), expect(unused_imports))]
8use crate::io::const_error;
9use crate::io::{Error, ErrorKind};
10
11impl Error {
12 /// Creates a new I/O error from a known kind of error as well as an
13 /// arbitrary error payload.
14 ///
15 /// This function is used to generically create I/O errors which do not
16 /// originate from the OS itself. The `error` argument is an arbitrary
17 /// payload which will be contained in this [`Error`].
18 ///
19 /// Note that this function allocates memory on the heap.
20 /// If no extra payload is required, use the `From` conversion from
21 /// `ErrorKind`.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// use std::io::{Error, ErrorKind};
27 ///
28 /// // errors can be created from strings
29 /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
30 ///
31 /// // errors can also be created from other errors
32 /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
33 ///
34 /// // creating an error without payload (and without memory allocation)
35 /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
36 /// ```
37 #[cfg(not(no_global_oom_handling))]
38 #[stable(feature = "rust1", since = "1.0.0")]
39 #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")]
40 #[inline(never)]
41 #[rustc_allow_incoherent_impl]
42 pub fn new<E>(kind: ErrorKind, error: E) -> Error
43 where
44 E: Into<Box<dyn error::Error + Send + Sync>>,
45 {
46 let custom = custom_owner_from_box(kind, error.into());
47
48 // SAFETY: `custom_owner` has been constructed from a `Box` from the `alloc` crate.
49 unsafe { Self::from_custom_owner(custom) }
50 }
51
52 /// Creates a new I/O error from an arbitrary error payload.
53 ///
54 /// This function is used to generically create I/O errors which do not
55 /// originate from the OS itself. It is a shortcut for [`Error::new`][new]
56 /// with [`ErrorKind::Other`].
57 ///
58 /// [new]: struct.Error.html#method.new
59 ///
60 /// # Examples
61 ///
62 /// ```
63 /// use std::io::Error;
64 ///
65 /// // errors can be created from strings
66 /// let custom_error = Error::other("oh no!");
67 ///
68 /// // errors can also be created from other errors
69 /// let custom_error2 = Error::other(custom_error);
70 /// ```
71 #[cfg(not(no_global_oom_handling))]
72 #[stable(feature = "io_error_other", since = "1.74.0")]
73 #[rustc_allow_incoherent_impl]
74 pub fn other<E>(error: E) -> Error
75 where
76 E: Into<Box<dyn error::Error + Send + Sync>>,
77 {
78 Self::new(ErrorKind::Other, error)
79 }
80
81 /// Consumes the `Error`, returning its inner error (if any).
82 ///
83 /// If this [`Error`] was constructed via [`new`][new] or [`other`][other],
84 /// then this function will return [`Some`],
85 /// otherwise it will return [`None`].
86 ///
87 /// [new]: struct.Error.html#method.new
88 /// [other]: struct.Error.html#method.other
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// use std::io::{Error, ErrorKind};
94 ///
95 /// fn print_error(err: Error) {
96 /// if let Some(inner_err) = err.into_inner() {
97 /// println!("Inner error: {inner_err}");
98 /// } else {
99 /// println!("No inner error");
100 /// }
101 /// }
102 ///
103 /// fn main() {
104 /// // Will print "No inner error".
105 /// print_error(Error::last_os_error());
106 /// // Will print "Inner error: ...".
107 /// print_error(Error::new(ErrorKind::Other, "oh no!"));
108 /// }
109 /// ```
110 #[stable(feature = "io_error_inner", since = "1.3.0")]
111 #[must_use = "`self` will be dropped if the result is not used"]
112 #[inline]
113 #[rustc_allow_incoherent_impl]
114 pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
115 let custom_owner = self.into_custom_owner().ok()?;
116
117 let ptr = custom_owner.into_raw().as_ptr();
118
119 // SAFETY:
120 // `Error` can only contain a `CustomOwner` if it was constructed using `Box::into_raw`.
121 let custom = unsafe { Box::<Custom>::from_raw(ptr) };
122
123 let ptr = custom.into_raw().as_ptr();
124
125 // SAFETY:
126 // Any `CustomOwner` from an `Error` was constructed by the `alloc` crate
127 // to contain a `Custom` which itself was constructed with `Box::into_raw`.
128 Some(unsafe { Box::from_raw(ptr) })
129 }
130
131 /// Attempts to downcast the custom boxed error to `E`.
132 ///
133 /// If this [`Error`] contains a custom boxed error,
134 /// then it would attempt downcasting on the boxed error,
135 /// otherwise it will return [`Err`].
136 ///
137 /// If the custom boxed error has the same type as `E`, it will return [`Ok`],
138 /// otherwise it will also return [`Err`].
139 ///
140 /// This method is meant to be a convenience routine for calling
141 /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
142 /// [`Error::into_inner`][into_inner].
143 ///
144 /// [into_inner]: struct.Error.html#method.into_inner
145 ///
146 /// # Examples
147 ///
148 /// ```
149 /// use std::fmt;
150 /// use std::io;
151 /// use std::error::Error;
152 ///
153 /// #[derive(Debug)]
154 /// enum E {
155 /// Io(io::Error),
156 /// SomeOtherVariant,
157 /// }
158 ///
159 /// impl fmt::Display for E {
160 /// // ...
161 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 /// # todo!()
163 /// # }
164 /// }
165 /// impl Error for E {}
166 ///
167 /// impl From<io::Error> for E {
168 /// fn from(err: io::Error) -> E {
169 /// err.downcast::<E>()
170 /// .unwrap_or_else(E::Io)
171 /// }
172 /// }
173 ///
174 /// impl From<E> for io::Error {
175 /// fn from(err: E) -> io::Error {
176 /// match err {
177 /// E::Io(io_error) => io_error,
178 /// e => io::Error::new(io::ErrorKind::Other, e),
179 /// }
180 /// }
181 /// }
182 ///
183 /// # fn main() {
184 /// let e = E::SomeOtherVariant;
185 /// // Convert it to an io::Error
186 /// let io_error = io::Error::from(e);
187 /// // Cast it back to the original variant
188 /// let e = E::from(io_error);
189 /// assert!(matches!(e, E::SomeOtherVariant));
190 ///
191 /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
192 /// // Convert it to E
193 /// let e = E::from(io_error);
194 /// // Cast it back to the original variant
195 /// let io_error = io::Error::from(e);
196 /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
197 /// assert!(io_error.get_ref().is_none());
198 /// assert!(io_error.raw_os_error().is_none());
199 /// # }
200 /// ```
201 #[stable(feature = "io_error_downcast", since = "1.79.0")]
202 #[rustc_allow_incoherent_impl]
203 pub fn downcast<E>(self) -> result::Result<E, Self>
204 where
205 E: error::Error + Send + Sync + 'static,
206 {
207 if let Some(e) = self.get_ref()
208 && e.is::<E>()
209 {
210 if let Some(b) = self.into_inner()
211 && let Ok(err) = b.downcast::<E>()
212 {
213 Ok(*err)
214 } else {
215 // Safety: We have just checked that the condition is true
216 unsafe { core::hint::unreachable_unchecked() }
217 }
218 } else {
219 Err(self)
220 }
221 }
222}
223
224#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
225#[stable(feature = "rust1", since = "1.0.0")]
226impl From<crate::ffi::NulError> for Error {
227 /// Converts a [`crate::ffi::NulError`] into a [`Error`].
228 fn from(_: crate::ffi::NulError) -> Error {
229 const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
230 }
231}
232
233#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
234impl From<crate::collections::TryReserveError> for Error {
235 /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
236 ///
237 /// `TryReserveError` won't be available as the error `source()`,
238 /// but this may change in the future.
239 fn from(_: crate::collections::TryReserveError) -> Error {
240 // ErrorData::Custom allocates, which isn't great for handling OOM errors.
241 ErrorKind::OutOfMemory.into()
242 }
243}
244
245#[cfg(not(no_global_oom_handling))]
246fn custom_owner_from_box(
247 kind: ErrorKind,
248 error: Box<dyn core::error::Error + Send + Sync>,
249) -> CustomOwner {
250 /// # Safety
251 ///
252 /// `ptr` must be valid to pass into `Box::from_raw`.
253 unsafe fn drop_box_raw<T: ?Sized>(ptr: *mut T) {
254 // SAFETY
255 // Caller ensures `ptr` is valid to pass into `Box::from_raw`.
256 drop(unsafe { Box::from_raw(ptr) })
257 }
258
259 // SAFETY: the pointer returned by Box::into_raw is non-null.
260 let error = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(error)) };
261
262 // SAFETY:
263 // * `error` is valid up to a static lifetime, and owns its pointee.
264 // * `drop_box_raw` is safe to call for the pointer `error` exactly once.
265 // * `drop_box_raw` is safe to call on a pointer to this instance of `Custom`,
266 // and will be stored in a `CustomOwner`.
267 let custom = unsafe { Custom::from_raw(kind, error, drop_box_raw, drop_box_raw) };
268
269 // SAFETY: the pointer returned by Box::into_raw is non-null.
270 let custom = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(custom))) };
271
272 // SAFETY: the `outer_drop` provided to `custom` is valid for itself.
273 unsafe { CustomOwner::from_raw(custom) }
274}
library/alloc/src/io/mod.rs created+20
......@@ -0,0 +1,20 @@
1//! Traits, helpers, and type definitions for core I/O functionality.
2
3mod error;
4
5#[unstable(feature = "raw_os_error_ty", issue = "107792")]
6pub use core::io::RawOsError;
7#[unstable(feature = "io_const_error_internals", issue = "none")]
8pub use core::io::SimpleMessage;
9#[unstable(feature = "io_const_error", issue = "133448")]
10pub use core::io::const_error;
11#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
12pub use core::io::{BorrowedBuf, BorrowedCursor};
13#[unstable(feature = "alloc_io", issue = "154046")]
14pub use core::io::{
15 Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Sink, Take, empty,
16 repeat, sink,
17};
18#[doc(hidden)]
19#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
20pub use core::io::{OsFunctions, chain, take};
library/alloc/src/lib.rs+8
......@@ -116,6 +116,9 @@
116116#![feature(const_try)]
117117#![feature(copied_into_inner)]
118118#![feature(core_intrinsics)]
119#![feature(core_io)]
120#![feature(core_io_borrowed_buf)]
121#![feature(core_io_internals)]
119122#![feature(deprecated_suggestion)]
120123#![feature(deref_pure_trait)]
121124#![feature(diagnostic_on_move)]
......@@ -133,6 +136,8 @@
133136#![feature(generic_atomic)]
134137#![feature(hasher_prefixfree_extras)]
135138#![feature(inplace_iteration)]
139#![feature(io_const_error)]
140#![feature(io_const_error_internals)]
136141#![feature(iter_advance_by)]
137142#![feature(iter_next_chunk)]
138143#![feature(layout_for_ptr)]
......@@ -147,6 +152,7 @@
147152#![feature(ptr_cast_slice)]
148153#![feature(ptr_internals)]
149154#![feature(ptr_metadata)]
155#![feature(raw_os_error_ty)]
150156#![feature(rev_into_inner)]
151157#![feature(set_ptr_value)]
152158#![feature(share_trait)]
......@@ -236,6 +242,8 @@ pub mod collections;
236242pub mod ffi;
237243pub mod fmt;
238244pub mod intrinsics;
245#[unstable(feature = "alloc_io", issue = "154046")]
246pub mod io;
239247#[cfg(not(no_rc))]
240248pub mod rc;
241249pub mod slice;
library/core/Cargo.toml+3
......@@ -40,5 +40,8 @@ check-cfg = [
4040 'cfg(target_has_reliable_f128)',
4141 'cfg(target_has_reliable_f128_math)',
4242 'cfg(llvm_enzyme)',
43 # Prevents use of a static variable for providing platform specific RawOsError
44 # functionality
45 'cfg(no_io_statics)',
4346
4447]
library/core/src/io/error.rs+708-7
......@@ -1,6 +1,708 @@
11#![unstable(feature = "core_io", issue = "154046")]
22
3use crate::fmt;
3// On 64-bit platforms, `io::Error` may use a bit-packed representation to
4// reduce size. However, this representation assumes that error codes are
5// always 32-bit wide.
6//
7// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit.
8// Therefore, the packed representation is explicitly disabled for UEFI
9// targets, and the unpacked representation must be used instead.
10#[cfg_attr(
11 all(target_pointer_width = "64", not(target_os = "uefi")),
12 path = "error/repr_bitpacked.rs"
13)]
14#[cfg_attr(
15 not(all(target_pointer_width = "64", not(target_os = "uefi"))),
16 path = "error/repr_unpacked.rs"
17)]
18mod repr;
19
20#[cfg_attr(
21 all(target_has_atomic_load_store = "ptr", not(no_io_statics)),
22 path = "error/os_functions_atomic.rs"
23)]
24#[cfg_attr(
25 not(all(target_has_atomic_load_store = "ptr", not(no_io_statics))),
26 path = "error/os_functions.rs"
27)]
28mod os_functions;
29
30use self::os_functions::{decode_error_kind, format_os_error, is_interrupted, set_functions};
31use self::repr::Repr;
32use crate::{error, fmt, result};
33
34/// A specialized [`Result`] type for I/O operations.
35///
36/// This type is broadly used across [`std::io`] for any operation which may
37/// produce an error.
38///
39/// This type alias is generally used to avoid writing out [`io::Error`] directly and
40/// is otherwise a direct mapping to [`Result`].
41///
42/// While usual Rust style is to import types directly, aliases of [`Result`]
43/// often are not, to make it easier to distinguish between them. [`Result`] is
44/// generally assumed to be [`core::result::Result`][`Result`], and so users of this alias
45/// will generally use `io::Result` instead of shadowing the [prelude]'s import
46/// of [`core::result::Result`][`Result`].
47///
48/// [`std::io`]: ../../std/io/index.html
49/// [`io::Error`]: Error
50/// [`Result`]: crate::result::Result
51/// [prelude]: crate::prelude
52///
53/// # Examples
54///
55/// A convenience function that bubbles an `io::Result` to its caller:
56///
57/// ```
58/// use std::io;
59///
60/// fn get_string() -> io::Result<String> {
61/// let mut buffer = String::new();
62///
63/// io::stdin().read_line(&mut buffer)?;
64///
65/// Ok(buffer)
66/// }
67/// ```
68#[stable(feature = "rust1", since = "1.0.0")]
69#[doc(search_unbox)]
70pub type Result<T> = result::Result<T, Error>;
71
72/// The error type for I/O operations of the [`Read`][Read], [`Write`][Write], [`Seek`][Seek], and
73/// associated traits.
74///
75/// Errors mostly originate from the underlying OS, but custom instances of
76/// `Error` can be created with crafted error messages and a particular value of
77/// [`ErrorKind`].
78///
79/// [Read]: ../../std/io/trait.Read.html
80/// [Write]: ../../std/io/trait.Write.html
81/// [Seek]: ../../std/io/trait.Seek.html
82#[stable(feature = "rust1", since = "1.0.0")]
83#[rustc_has_incoherent_inherent_impls]
84pub struct Error {
85 repr: Repr,
86}
87
88#[stable(feature = "rust1", since = "1.0.0")]
89impl fmt::Debug for Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 fmt::Debug::fmt(&self.repr, f)
92 }
93}
94
95/// Common errors constants for use in std
96#[doc(hidden)]
97impl Error {
98 #[doc(hidden)]
99 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
100 pub const INVALID_UTF8: Self =
101 const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
102
103 #[doc(hidden)]
104 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
105 pub const READ_EXACT_EOF: Self =
106 const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
107
108 #[doc(hidden)]
109 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
110 pub const UNKNOWN_THREAD_COUNT: Self = const_error!(
111 ErrorKind::NotFound,
112 "the number of hardware threads is not known for the target platform",
113 );
114
115 #[doc(hidden)]
116 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
117 pub const UNSUPPORTED_PLATFORM: Self =
118 const_error!(ErrorKind::Unsupported, "operation not supported on this platform");
119
120 #[doc(hidden)]
121 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
122 pub const WRITE_ALL_EOF: Self =
123 const_error!(ErrorKind::WriteZero, "failed to write whole buffer");
124
125 #[doc(hidden)]
126 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
127 pub const ZERO_TIMEOUT: Self =
128 const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
129
130 #[doc(hidden)]
131 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
132 pub const NO_ADDRESSES: Self =
133 const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
134}
135
136// Only derive debug in tests, to make sure it
137// doesn't accidentally get printed.
138#[cfg_attr(test, derive(Debug))]
139enum ErrorData<C> {
140 Os(RawOsError),
141 Simple(ErrorKind),
142 SimpleMessage(&'static SimpleMessage),
143 Custom(C),
144}
145
146// `#[repr(align(4))]` is probably redundant, it should have that value or
147// higher already. We include it just because repr_bitpacked.rs's encoding
148// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
149// alignment required by the struct, only increase it).
150//
151// If we add more variants to ErrorData, this can be increased to 8, but it
152// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
153// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
154// that version needs the alignment, and 8 is higher than the alignment we'll
155// have on 32 bit platforms.
156//
157// (For the sake of being explicit: the alignment requirement here only matters
158// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
159// matter at all)
160#[doc(hidden)]
161#[unstable(feature = "io_const_error_internals", issue = "none")]
162#[repr(align(4))]
163#[derive(Debug)]
164pub struct SimpleMessage {
165 pub kind: ErrorKind,
166 pub message: &'static str,
167}
168
169/// Creates a new I/O error from a known kind of error and a string literal.
170///
171/// Contrary to [`Error::new`][new], this macro does not allocate and can be used in
172/// `const` contexts.
173///
174/// [new]: ../../alloc/io/struct.Error.html#method.new
175///
176/// # Example
177/// ```
178/// #![feature(io_const_error)]
179/// use std::io::{const_error, Error, ErrorKind};
180///
181/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works");
182///
183/// fn not_here() -> Result<(), Error> {
184/// Err(FAIL)
185/// }
186/// ```
187#[rustc_macro_transparency = "semiopaque"]
188#[unstable(feature = "io_const_error", issue = "133448")]
189#[allow_internal_unstable(core_io, hint_must_use, io_const_error_internals)]
190pub macro const_error($kind:expr, $message:expr $(,)?) {
191 $crate::hint::must_use($crate::io::Error::from_static_message(
192 const { &$crate::io::SimpleMessage { kind: $kind, message: $message } },
193 ))
194}
195
196/// Intended for use for errors not exposed to the user, where allocating onto
197/// the heap (for normal construction via Error::new) is too costly.
198#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
199impl From<ErrorKind> for Error {
200 /// Converts an [`ErrorKind`] into an [`Error`].
201 ///
202 /// This conversion creates a new error with a simple representation of error kind.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use std::io::{Error, ErrorKind};
208 ///
209 /// let not_found = ErrorKind::NotFound;
210 /// let error = Error::from(not_found);
211 /// assert_eq!("entity not found", format!("{error}"));
212 /// ```
213 #[inline]
214 fn from(kind: ErrorKind) -> Error {
215 Error { repr: Repr::new_simple(kind) }
216 }
217}
218
219impl Error {
220 /// # Safety
221 ///
222 /// The provided `CustomOwner` must have been constructed from a `Box` from the `alloc` crate.
223 #[doc(hidden)]
224 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
225 #[must_use]
226 #[inline]
227 pub unsafe fn from_custom_owner(custom: CustomOwner) -> Error {
228 Error { repr: Repr::new_custom(custom) }
229 }
230
231 #[doc(hidden)]
232 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
233 #[must_use]
234 #[inline]
235 pub fn into_custom_owner(self) -> result::Result<CustomOwner, Self> {
236 if matches!(self.repr.data(), ErrorData::Custom(..)) {
237 let ErrorData::Custom(c) = self.repr.into_data() else {
238 // SAFETY: Checked above using `matches!`.
239 unsafe { crate::hint::unreachable_unchecked() }
240 };
241 Ok(c)
242 } else {
243 Err(self)
244 }
245 }
246
247 /// Creates a new I/O error from a known kind of error as well as a constant
248 /// message.
249 ///
250 /// This function does not allocate.
251 ///
252 /// You should not use this directly, and instead use the `const_error!`
253 /// macro: `io::const_error!(ErrorKind::Something, "some_message")`.
254 ///
255 /// This function should maybe change to `from_static_message<const MSG: &'static
256 /// str>(kind: ErrorKind)` in the future, when const generics allow that.
257 #[inline]
258 #[doc(hidden)]
259 #[unstable(feature = "io_const_error_internals", issue = "none")]
260 pub const fn from_static_message(msg: &'static SimpleMessage) -> Error {
261 Self { repr: Repr::new_simple_message(msg) }
262 }
263
264 /// # Safety
265 ///
266 /// `functions` must point to data that is entirely constant; it must
267 /// not be created during runtime.
268 #[doc(hidden)]
269 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
270 #[must_use]
271 #[inline]
272 pub unsafe fn from_raw_os_error_with_functions(
273 code: RawOsError,
274 functions: &'static OsFunctions,
275 ) -> Error {
276 // SAFETY: Caller ensures `functions` is a constant not created at runtime.
277 unsafe {
278 set_functions(functions);
279 }
280 Error { repr: Repr::new_os(code) }
281 }
282
283 /// Returns the OS error that this error represents (if any).
284 ///
285 /// If this [`Error`] was constructed via [`last_os_error`][last_os_error] or
286 /// [`from_raw_os_error`][from_raw_os_error], then this function will return [`Some`], otherwise
287 /// it will return [`None`].
288 ///
289 /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error
290 /// [from_raw_os_error]: ../../std/io/struct.Error.html#method.from_raw_os_error
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// use std::io::{Error, ErrorKind};
296 ///
297 /// fn print_os_error(err: &Error) {
298 /// if let Some(raw_os_err) = err.raw_os_error() {
299 /// println!("raw OS error: {raw_os_err:?}");
300 /// } else {
301 /// println!("Not an OS error");
302 /// }
303 /// }
304 ///
305 /// fn main() {
306 /// // Will print "raw OS error: ...".
307 /// print_os_error(&Error::last_os_error());
308 /// // Will print "Not an OS error".
309 /// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
310 /// }
311 /// ```
312 #[stable(feature = "rust1", since = "1.0.0")]
313 #[must_use]
314 #[inline]
315 pub fn raw_os_error(&self) -> Option<RawOsError> {
316 match self.repr.data() {
317 ErrorData::Os(i) => Some(i),
318 ErrorData::Custom(..) => None,
319 ErrorData::Simple(..) => None,
320 ErrorData::SimpleMessage(..) => None,
321 }
322 }
323
324 /// Returns a reference to the inner error wrapped by this error (if any).
325 ///
326 /// If this [`Error`] was constructed via [`new`][new] then this function will
327 /// return [`Some`], otherwise it will return [`None`].
328 ///
329 /// [new]: ../../alloc/io/struct.Error.html#method.new
330 ///
331 /// # Examples
332 ///
333 /// ```
334 /// use std::io::{Error, ErrorKind};
335 ///
336 /// fn print_error(err: &Error) {
337 /// if let Some(inner_err) = err.get_ref() {
338 /// println!("Inner error: {inner_err:?}");
339 /// } else {
340 /// println!("No inner error");
341 /// }
342 /// }
343 ///
344 /// fn main() {
345 /// // Will print "No inner error".
346 /// print_error(&Error::last_os_error());
347 /// // Will print "Inner error: ...".
348 /// print_error(&Error::new(ErrorKind::Other, "oh no!"));
349 /// }
350 /// ```
351 #[stable(feature = "io_error_inner", since = "1.3.0")]
352 #[must_use]
353 #[inline]
354 pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
355 match self.repr.data() {
356 ErrorData::Os(..) => None,
357 ErrorData::Simple(..) => None,
358 ErrorData::SimpleMessage(..) => None,
359 ErrorData::Custom(c) => Some(c.error_ref()),
360 }
361 }
362
363 /// Returns a mutable reference to the inner error wrapped by this error
364 /// (if any).
365 ///
366 /// If this [`Error`] was constructed via [`new`][new] then this function will
367 /// return [`Some`], otherwise it will return [`None`].
368 ///
369 /// [new]: ../../alloc/io/struct.Error.html#method.new
370 ///
371 /// # Examples
372 ///
373 /// ```
374 /// use std::io::{Error, ErrorKind};
375 /// use std::{error, fmt};
376 /// use std::fmt::Display;
377 ///
378 /// #[derive(Debug)]
379 /// struct MyError {
380 /// v: String,
381 /// }
382 ///
383 /// impl MyError {
384 /// fn new() -> MyError {
385 /// MyError {
386 /// v: "oh no!".to_string()
387 /// }
388 /// }
389 ///
390 /// fn change_message(&mut self, new_message: &str) {
391 /// self.v = new_message.to_string();
392 /// }
393 /// }
394 ///
395 /// impl error::Error for MyError {}
396 ///
397 /// impl Display for MyError {
398 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399 /// write!(f, "MyError: {}", self.v)
400 /// }
401 /// }
402 ///
403 /// fn change_error(mut err: Error) -> Error {
404 /// if let Some(inner_err) = err.get_mut() {
405 /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
406 /// }
407 /// err
408 /// }
409 ///
410 /// fn print_error(err: &Error) {
411 /// if let Some(inner_err) = err.get_ref() {
412 /// println!("Inner error: {inner_err}");
413 /// } else {
414 /// println!("No inner error");
415 /// }
416 /// }
417 ///
418 /// fn main() {
419 /// // Will print "No inner error".
420 /// print_error(&change_error(Error::last_os_error()));
421 /// // Will print "Inner error: ...".
422 /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
423 /// }
424 /// ```
425 #[stable(feature = "io_error_inner", since = "1.3.0")]
426 #[must_use]
427 #[inline]
428 pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
429 match self.repr.data_mut() {
430 ErrorData::Os(..) => None,
431 ErrorData::Simple(..) => None,
432 ErrorData::SimpleMessage(..) => None,
433 ErrorData::Custom(c) => Some(c.error_mut()),
434 }
435 }
436
437 /// Returns the corresponding [`ErrorKind`] for this error.
438 ///
439 /// This may be a value set by Rust code constructing custom `io::Error`s,
440 /// or if this `io::Error` was sourced from the operating system,
441 /// it will be a value inferred from the system's error encoding.
442 /// See [`last_os_error`][last_os_error] for more details.
443 ///
444 /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error
445 ///
446 /// # Examples
447 ///
448 /// ```
449 /// use std::io::{Error, ErrorKind};
450 ///
451 /// fn print_error(err: Error) {
452 /// println!("{:?}", err.kind());
453 /// }
454 ///
455 /// fn main() {
456 /// // As no error has (visibly) occurred, this may print anything!
457 /// // It likely prints a placeholder for unidentified (non-)errors.
458 /// print_error(Error::last_os_error());
459 /// // Will print "AddrInUse".
460 /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
461 /// }
462 /// ```
463 #[stable(feature = "rust1", since = "1.0.0")]
464 #[must_use]
465 #[inline]
466 pub fn kind(&self) -> ErrorKind {
467 match self.repr.data() {
468 ErrorData::Os(code) => decode_error_kind(code),
469 ErrorData::Custom(c) => c.kind,
470 ErrorData::Simple(kind) => kind,
471 ErrorData::SimpleMessage(m) => m.kind,
472 }
473 }
474
475 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
476 #[doc(hidden)]
477 #[inline]
478 pub fn is_interrupted(&self) -> bool {
479 match self.repr.data() {
480 ErrorData::Os(code) => is_interrupted(code),
481 ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
482 ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
483 ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
484 }
485 }
486}
487
488impl fmt::Debug for Repr {
489 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
490 match self.data() {
491 ErrorData::Os(code) => fmt
492 .debug_struct("Os")
493 .field("code", &code)
494 .field("kind", &decode_error_kind(code))
495 .field(
496 "message",
497 &fmt::from_fn(|fmt| {
498 write!(fmt, "\"{}\"", fmt::from_fn(|fmt| format_os_error(code, fmt)))
499 }),
500 )
501 .finish(),
502 ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
503 ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
504 ErrorData::SimpleMessage(msg) => fmt
505 .debug_struct("Error")
506 .field("kind", &msg.kind)
507 .field("message", &msg.message)
508 .finish(),
509 }
510 }
511}
512
513#[stable(feature = "rust1", since = "1.0.0")]
514impl fmt::Display for Error {
515 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
516 match self.repr.data() {
517 ErrorData::Os(code) => {
518 let detail = fmt::from_fn(|fmt| format_os_error(code, fmt));
519 write!(fmt, "{detail} (os error {code})")
520 }
521 ErrorData::Custom(c) => fmt::Display::fmt(c.error_ref(), fmt),
522 ErrorData::Simple(kind) => kind.fmt(fmt),
523 ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
524 }
525 }
526}
527
528#[stable(feature = "rust1", since = "1.0.0")]
529impl error::Error for Error {
530 #[allow(deprecated)]
531 fn cause(&self) -> Option<&dyn error::Error> {
532 match self.repr.data() {
533 ErrorData::Os(..) => None,
534 ErrorData::Simple(..) => None,
535 ErrorData::SimpleMessage(..) => None,
536 ErrorData::Custom(c) => c.error_ref().cause(),
537 }
538 }
539
540 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
541 match self.repr.data() {
542 ErrorData::Os(..) => None,
543 ErrorData::Simple(..) => None,
544 ErrorData::SimpleMessage(..) => None,
545 ErrorData::Custom(c) => c.error_ref().source(),
546 }
547 }
548}
549
550fn _assert_error_is_sync_send() {
551 fn _is_sync_send<T: Sync + Send>() {}
552 _is_sync_send::<Error>();
553}
554
555#[doc(hidden)]
556#[derive(Debug)]
557#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
558pub struct OsFunctions {
559 pub format_os_error: fn(_: RawOsError, _: &mut fmt::Formatter<'_>) -> fmt::Result,
560 pub decode_error_kind: fn(_: RawOsError) -> ErrorKind,
561 pub is_interrupted: fn(_: RawOsError) -> bool,
562}
563
564impl OsFunctions {
565 const DEFAULT: &'static OsFunctions = &OsFunctions {
566 format_os_error: |_, _| Ok(()),
567 decode_error_kind: |_| ErrorKind::Uncategorized,
568 is_interrupted: |_| false,
569 };
570}
571
572// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
573// repr_bitpacked's encoding requires it. In practice it almost certainly be
574// already be this high or higher.
575#[doc(hidden)]
576#[repr(align(4))]
577#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
578pub struct Custom {
579 kind: ErrorKind,
580 error: crate::ptr::NonNull<dyn error::Error + Send + Sync>,
581 error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)),
582 outer_drop: unsafe fn(*mut Self),
583}
584
585// SAFETY: All members of `Custom` are `Send`
586#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
587unsafe impl Send for Custom {}
588
589// SAFETY: All members of `Custom` are `Sync`
590#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
591unsafe impl Sync for Custom {}
592
593#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
594impl fmt::Debug for Custom {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 f.debug_struct("Custom").field("kind", &self.kind).field("error", self.error_ref()).finish()
597 }
598}
599
600#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
601impl Drop for Custom {
602 fn drop(&mut self) {
603 // SAFETY: `Custom::from_raw` ensures this call is safe.
604 unsafe {
605 (self.error_drop)(self.error.as_ptr());
606 }
607 }
608}
609
610impl Custom {
611 /// # Safety
612 ///
613 /// * `error` must be valid for up to a static lifetime, and own its pointee.
614 /// * `error_drop` must be safe to call for the pointer `error` exactly once.
615 /// * `outer_drop` must be safe to call on a pointer to this instance of `Custom`
616 /// if it were stored within a [`CustomOwner`].
617 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
618 pub unsafe fn from_raw(
619 kind: ErrorKind,
620 error: crate::ptr::NonNull<dyn error::Error + Send + Sync>,
621 error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)),
622 outer_drop: unsafe fn(*mut Self),
623 ) -> Custom {
624 Custom { kind, error, error_drop, outer_drop }
625 }
626
627 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
628 pub fn into_raw(self) -> crate::ptr::NonNull<dyn error::Error + Send + Sync> {
629 let ptr = self.error;
630 core::mem::forget(self);
631 ptr
632 }
633
634 fn error_ref(&self) -> &(dyn error::Error + Send + Sync + 'static) {
635 // SAFETY:
636 // `from_raw` ensures `error` is a valid pointer up to a static lifetime
637 // and is owned by `self`
638 unsafe { self.error.as_ref() }
639 }
640
641 fn error_mut(&mut self) -> &mut (dyn error::Error + Send + Sync + 'static) {
642 // SAFETY:
643 // `from_raw` ensures `error` is a valid pointer up to a static lifetime
644 // and is owned by `self`
645 unsafe { self.error.as_mut() }
646 }
647}
648
649#[derive(Debug)]
650#[repr(transparent)]
651#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
652#[doc(hidden)]
653pub struct CustomOwner(crate::ptr::NonNull<Custom>);
654
655// SAFETY: Custom is `Send`
656#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
657unsafe impl Send for CustomOwner {}
658
659// SAFETY: Custom is `Sync`
660#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
661unsafe impl Sync for CustomOwner {}
662
663#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
664impl Drop for CustomOwner {
665 fn drop(&mut self) {
666 // SAFETY: `CustomOwner::from_raw` ensures this call is safe.
667 unsafe {
668 (self.0.as_ref().outer_drop)(self.0.as_ptr());
669 }
670 }
671}
672
673impl CustomOwner {
674 /// # Safety
675 ///
676 /// * The `outer_drop` of the provided `custom` must be safe to call exactly once.
677 #[doc(hidden)]
678 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
679 pub unsafe fn from_raw(custom: crate::ptr::NonNull<Custom>) -> CustomOwner {
680 CustomOwner(custom)
681 }
682
683 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
684 pub fn into_raw(self) -> crate::ptr::NonNull<Custom> {
685 let ptr = self.0;
686 core::mem::forget(self);
687 ptr
688 }
689
690 #[allow(dead_code, reason = "only used for unpacked representation")]
691 fn custom_ref(&self) -> &Custom {
692 // SAFETY:
693 // `from_raw` ensures `0` is a valid pointer up to a static lifetime
694 // and is owned by `self`
695 unsafe { self.0.as_ref() }
696 }
697
698 #[allow(dead_code, reason = "only used for unpacked representation")]
699 fn custom_mut(&mut self) -> &mut Custom {
700 // SAFETY:
701 // `from_raw` ensures `0` is a valid pointer up to a static lifetime
702 // and is owned by `self`
703 unsafe { self.0.as_mut() }
704 }
705}
4706
5707/// The type of raw OS error codes.
6708///
......@@ -23,7 +725,7 @@ pub type RawOsError = cfg_select! {
23725///
24726/// It is used with the [`io::Error`][error] type.
25727///
26/// [error]: ../../std/io/struct.Error.html
728/// [error]: Error
27729///
28730/// # Handling errors and matching on `ErrorKind`
29731///
......@@ -258,7 +960,7 @@ pub enum ErrorKind {
258960 /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern.
259961 /// New [`ErrorKind`]s might be added in the future for some of those.
260962 ///
261 /// [error]: ../../std/io/struct.Error.html
963 /// [error]: Error
262964 #[stable(feature = "rust1", since = "1.0.0")]
263965 Other,
264966
......@@ -273,7 +975,7 @@ pub enum ErrorKind {
273975}
274976
275977impl ErrorKind {
276 pub(crate) const fn as_str(&self) -> &'static str {
978 const fn as_str(&self) -> &'static str {
277979 use ErrorKind::*;
278980 match *self {
279981 // tidy-alphabetical-start
......@@ -328,9 +1030,8 @@ impl ErrorKind {
3281030 // unsafe, or to hard-code max ErrorKind or its size in a way the compiler
3291031 // couldn't verify.
3301032 #[inline]
331 #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
332 #[doc(hidden)]
333 pub const fn from_prim(ek: u32) -> Option<Self> {
1033 #[allow(dead_code, reason = "only used for packed representation")]
1034 const fn from_prim(ek: u32) -> Option<Self> {
3341035 macro_rules! from_prim {
3351036 ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{
3361037 // Force a compile error if the list gets out of date.
library/core/src/io/error/os_functions.rs created+30
......@@ -0,0 +1,30 @@
1use super::{ErrorKind, OsFunctions, RawOsError};
2use crate::fmt;
3
4/// # Safety
5///
6/// The provided reference must point to data that is entirely constant; it must
7/// not be created during runtime.
8#[inline]
9pub(super) unsafe fn set_functions(f: &'static OsFunctions) {
10 // FIXME: externally implementable items may allow for weak linkage, allowing
11 // these methods to be overridden even when atomic pointers are not supported.
12}
13
14#[inline]
15pub(super) fn format_os_error(errno: RawOsError, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
16 let f = OsFunctions::DEFAULT;
17 (f.format_os_error)(errno, fmt)
18}
19
20#[inline]
21pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind {
22 let f = OsFunctions::DEFAULT;
23 (f.decode_error_kind)(errno)
24}
25
26#[inline]
27pub(super) fn is_interrupted(errno: RawOsError) -> bool {
28 let f = OsFunctions::DEFAULT;
29 (f.is_interrupted)(errno)
30}
library/core/src/io/error/os_functions_atomic.rs created+61
......@@ -0,0 +1,61 @@
1//! OS-dependent functions
2//!
3//! `Error` needs OS functionalities to work interpret raw OS errors, but
4//! we can't link to anythink here in `alloc`. Therefore, we restrict
5//! creation of `Error` from raw OS errors in `std`, and require providing
6//! a vtable of operations when creating one.
7
8// FIXME: replace this with externally implementable items once they are more stable
9
10use super::{ErrorKind, OsFunctions, RawOsError};
11use crate::fmt;
12use crate::sync::atomic;
13
14/// These default functions are not reachable, but have them just to be safe.
15static OS_FUNCTIONS: atomic::AtomicPtr<OsFunctions> =
16 atomic::AtomicPtr::new(OsFunctions::DEFAULT as *const _ as *mut _);
17
18fn get_os_functions() -> &'static OsFunctions {
19 // SAFETY:
20 // * `OS_FUNCTIONS` is initially a pointer to `OsFunctions::DEFAULT`, which is valid for a static lifetime.
21 // * `OS_FUNCTIONS` can only be changed by `set_functions`, which only accepts `&'static OsFunctions`.
22 // * Therefore, `OS_FUNCTIONS` must always contain a valid non-null pointer with a static lifetime.
23 // * `Relaxed` ordering is sufficient as the only way to write to `OS_FUNCTIONS` is through
24 // `set_functions`, which has as a safety precondition that any value passed in must
25 // be constant and not created during runtime.
26 unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) }
27}
28
29/// # Safety
30///
31/// The provided reference must point to data that is entirely constant; it must
32/// not be created during runtime.
33#[inline]
34pub(super) unsafe fn set_functions(f: &'static OsFunctions) {
35 #[cold]
36 fn set_functions_inner(f: &'static OsFunctions) {
37 OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed);
38 }
39
40 if OS_FUNCTIONS.load(atomic::Ordering::Relaxed) != f as *const _ as *mut _ {
41 set_functions_inner(f);
42 }
43}
44
45#[inline]
46pub(super) fn format_os_error(errno: RawOsError, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
47 let f = get_os_functions();
48 (f.format_os_error)(errno, fmt)
49}
50
51#[inline]
52pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind {
53 let f = get_os_functions();
54 (f.decode_error_kind)(errno)
55}
56
57#[inline]
58pub(super) fn is_interrupted(errno: RawOsError) -> bool {
59 let f = get_os_functions();
60 (f.is_interrupted)(errno)
61}
library/core/src/io/error/repr_bitpacked.rs created+351
......@@ -0,0 +1,351 @@
1//! This is a densely packed error representation which is used on targets with
2//! 64-bit pointers.
3//!
4//! (Note that `bitpacked` vs `unpacked` here has no relationship to
5//! `#[repr(packed)]`, it just refers to attempting to use any available bits in
6//! a more clever manner than `rustc`'s default layout algorithm would).
7//!
8//! Conceptually, it stores the same data as the "unpacked" equivalent we use on
9//! other targets. Specifically, you can imagine it as an optimized version of
10//! the following enum (which is roughly equivalent to what's stored by
11//! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`):
12//!
13//! ```ignore (exposition-only)
14//! enum ErrorData {
15//! Os(i32),
16//! Simple(ErrorKind),
17//! SimpleMessage(&'static SimpleMessage),
18//! Custom(Box<Custom>),
19//! }
20//! ```
21//!
22//! However, it packs this data into a 64bit non-zero value.
23//!
24//! This optimization not only allows `io::Error` to occupy a single pointer,
25//! but improves `io::Result` as well, especially for situations like
26//! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now
27//! 128 bits), which are quite common.
28//!
29//! # Layout
30//! Tagged values are 64 bits, with the 2 least significant bits used for the
31//! tag. This means there are 4 "variants":
32//!
33//! - **Tag 0b00**: The first variant is equivalent to
34//! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
35//!
36//! `SimpleMessage` has an alignment >= 4 (which is requested with
37//! `#[repr(align)]` and checked statically at the bottom of this file), which
38//! means every `&'static SimpleMessage` should have the both tag bits as 0,
39//! meaning its tagged and untagged representation are equivalent.
40//!
41//! This means we can skip tagging it, which is necessary as this variant can
42//! be constructed from a `const fn`, which probably cannot tag pointers (or
43//! at least it would be difficult).
44//!
45//! - **Tag 0b01**: The other pointer variant holds the data for
46//! `ErrorData::Custom` and the remaining 62 bits are used to store a
47//! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
48//! are free to use for the tag.
49//!
50//! The only important thing to note is that `ptr::wrapping_add` and
51//! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise
52//! operations. This should preserve the pointer's provenance, which would
53//! otherwise be lost.
54//!
55//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
56//! in the pointer's most significant 32 bits, and don't use the bits `2..32`
57//! for anything. Using the top 32 bits is just to let us easily recover the
58//! `i32` code with the correct sign.
59//!
60//! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This
61//! stores the `ErrorKind` in the top 32 bits as well, although it doesn't
62//! occupy nearly that many. Most of the bits are unused here, but it's not
63//! like we need them for anything else yet.
64//!
65//! # Use of `NonNull<()>`
66//!
67//! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a
68//! purpose.
69//!
70//! Conceptually you might think of this more like:
71//!
72//! ```ignore (exposition-only)
73//! union Repr {
74//! // holds integer (Simple/Os) variants, and
75//! // provides access to the tag bits.
76//! bits: NonZero<u64>,
77//! // Tag is 0, so this is stored untagged.
78//! msg: &'static SimpleMessage,
79//! // Tagged (offset) `Box<Custom>` pointer.
80//! tagged_custom: NonNull<()>,
81//! }
82//! ```
83//!
84//! But there are a few problems with this:
85//!
86//! 1. Union access is equivalent to a transmute, so this representation would
87//! require we transmute between integers and pointers in at least one
88//! direction, which may be UB (and even if not, it is likely harder for a
89//! compiler to reason about than explicit ptr->int operations).
90//!
91//! 2. Even if all fields of a union have a niche, the union itself doesn't,
92//! although this may change in the future. This would make things like
93//! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of
94//! the motivation of this bitpacking.
95//!
96//! Storing everything in a `NonZero<usize>` (or some other integer) would be a
97//! bit more traditional for pointer tagging, but it would lose provenance
98//! information, couldn't be constructed from a `const fn`, and would probably
99//! run into other issues as well.
100//!
101//! The `NonNull<()>` seems like the only alternative, even if it's fairly odd
102//! to use a pointer type to store something that may hold an integer, some of
103//! the time.
104
105use core::marker::PhantomData;
106use core::num::NonZeroUsize;
107use core::ptr::NonNull;
108
109use super::{Custom, CustomOwner, ErrorData, ErrorKind, RawOsError, SimpleMessage};
110
111// The 2 least-significant bits are used as tag.
112const TAG_MASK: usize = 0b11;
113const TAG_SIMPLE_MESSAGE: usize = 0b00;
114const TAG_CUSTOM: usize = 0b01;
115const TAG_OS: usize = 0b10;
116const TAG_SIMPLE: usize = 0b11;
117
118/// The internal representation.
119///
120/// See the module docs for more, this is just a way to hack in a check that we
121/// indeed are not unwind-safe.
122///
123/// ```compile_fail,E0277
124/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
125/// is_unwind_safe::<std::io::Error>();
126/// ```
127#[repr(transparent)]
128#[rustc_insignificant_dtor]
129pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<CustomOwner>>);
130
131// All the types `Repr` stores internally are Send + Sync, and so is it.
132unsafe impl Send for Repr {}
133unsafe impl Sync for Repr {}
134
135impl Repr {
136 pub(super) fn new_custom(b: CustomOwner) -> Self {
137 let p = b.into_raw().as_ptr().cast::<u8>();
138 // Should only be possible if an allocator handed out a pointer with
139 // wrong alignment.
140 debug_assert_eq!(p.addr() & TAG_MASK, 0);
141 // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
142 // end of file), and both the start and end of the expression must be
143 // valid without address space wraparound due to `Box`'s semantics.
144 //
145 // This means it would be correct to implement this using `ptr::add`
146 // (rather than `ptr::wrapping_add`), but it's unclear this would give
147 // any benefit, so we just use `wrapping_add` instead.
148 let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>();
149 // SAFETY:
150 // `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`,
151 // because `p`'s alignment means it isn't allowed to have any of the
152 // `TAG_BITS` set (you can verify that addition and bitwise-or are the
153 // same when the operands have no bits in common using a truth table).
154 //
155 // Then, `TAG_CUSTOM | p` is not zero, as that would require
156 // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a
157 // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
158 // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
159 // `new_unchecked` is safe.
160 let ptr = unsafe { NonNull::new_unchecked(tagged) };
161 let res = Self(ptr, PhantomData);
162 // quickly smoke-check we encoded the right thing (This generally will
163 // only run in std's tests, unless the user uses -Zbuild-std)
164 debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
165 res
166 }
167
168 #[inline]
169 pub(super) fn new_os(code: RawOsError) -> Self {
170 let utagged = ((code as usize) << 32) | TAG_OS;
171 // SAFETY: `TAG_OS` is not zero, so the result of the `|` is not 0.
172 let utagged = unsafe { NonZeroUsize::new_unchecked(utagged) };
173 let res = Self(NonNull::without_provenance(utagged), PhantomData);
174 // quickly smoke-check we encoded the right thing (This generally will
175 // only run in std's tests, unless the user uses -Zbuild-std)
176 debug_assert!(
177 matches!(res.data(), ErrorData::Os(c) if c == code),
178 "repr(os) encoding failed for {code}"
179 );
180 res
181 }
182
183 #[inline]
184 pub(super) fn new_simple(kind: ErrorKind) -> Self {
185 let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
186 // SAFETY: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
187 let utagged = unsafe { NonZeroUsize::new_unchecked(utagged) };
188 let res = Self(NonNull::without_provenance(utagged), PhantomData);
189 // quickly smoke-check we encoded the right thing (This generally will
190 // only run in std's tests, unless the user uses -Zbuild-std)
191 debug_assert!(
192 matches!(res.data(), ErrorData::Simple(k) if k == kind),
193 "repr(simple) encoding failed {:?}",
194 kind,
195 );
196 res
197 }
198
199 #[inline]
200 pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
201 // SAFETY: References are never null.
202 let ptr = unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) };
203 Self(ptr, PhantomData)
204 }
205
206 #[inline]
207 pub(super) fn data(&self) -> ErrorData<&Custom> {
208 // SAFETY: We're a Repr, decode_repr is fine.
209 unsafe { decode_repr(self.0, |c| &*c) }
210 }
211
212 #[inline]
213 pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
214 // SAFETY: We're a Repr, decode_repr is fine.
215 unsafe { decode_repr(self.0, |c| &mut *c) }
216 }
217
218 #[inline]
219 pub(super) fn into_data(self) -> ErrorData<CustomOwner> {
220 let this = core::mem::ManuallyDrop::new(self);
221 // SAFETY: We're a Repr, decode_repr is fine. The `Box::from_raw` is
222 // safe because we prevent double-drop using `ManuallyDrop`.
223 unsafe {
224 decode_repr(this.0, |p| CustomOwner::from_raw(core::ptr::NonNull::new_unchecked(p)))
225 }
226 }
227}
228
229impl Drop for Repr {
230 #[inline]
231 fn drop(&mut self) {
232 // SAFETY: We're a Repr, decode_repr is fine. The `Box::from_raw` is
233 // safe because we're being dropped.
234 unsafe {
235 let _ = decode_repr(self.0, |p| {
236 CustomOwner::from_raw(core::ptr::NonNull::new_unchecked(p))
237 });
238 }
239 }
240}
241
242// Shared helper to decode a `Repr`'s internal pointer into an ErrorData.
243//
244// Safety: `ptr`'s bits should be encoded as described in the document at the
245// top (it should `some_repr.0`)
246#[inline]
247unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
248where
249 F: FnOnce(*mut Custom) -> C,
250{
251 let bits = ptr.as_ptr().addr();
252 match bits & TAG_MASK {
253 TAG_OS => {
254 let code = ((bits as i64) >> 32) as RawOsError;
255 ErrorData::Os(code)
256 }
257 TAG_SIMPLE => {
258 let kind_bits = (bits >> 32) as u32;
259 let kind = ErrorKind::from_prim(kind_bits).unwrap_or_else(|| {
260 debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits);
261 // SAFETY: This means the `ptr` passed in was not valid, which violates
262 // the unsafe contract of `decode_repr`.
263 //
264 // Using this rather than unwrap meaningfully improves the code
265 // for callers which only care about one variant (usually
266 // `Custom`)
267 unsafe { core::hint::unreachable_unchecked() };
268 });
269 ErrorData::Simple(kind)
270 }
271 TAG_SIMPLE_MESSAGE => {
272 // SAFETY: per tag
273 unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) }
274 }
275 TAG_CUSTOM => {
276 // It would be correct for us to use `ptr::byte_sub` here (see the
277 // comment above the `wrapping_add` call in `new_custom` for why),
278 // but it isn't clear that it makes a difference, so we don't.
279 let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
280 ErrorData::Custom(make_custom(custom))
281 }
282 _ => {
283 // Can't happen, and compiler can tell
284 unreachable!();
285 }
286 }
287}
288
289// Some static checking to alert us if a change breaks any of the assumptions
290// that our encoding relies on for correctness and soundness. (Some of these are
291// a bit overly thorough/cautious, admittedly)
292//
293// If any of these are hit on a platform that std supports, we should likely
294// just use `repr_unpacked.rs` there instead (unless the fix is easy).
295macro_rules! static_assert {
296 ($condition:expr) => {
297 const _: () = assert!($condition);
298 };
299 (@usize_eq: $lhs:expr, $rhs:expr) => {
300 const _: [(); $lhs] = [(); $rhs];
301 };
302}
303
304// The bitpacking we use requires pointers be exactly 64 bits.
305static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8);
306
307// We also require pointers and usize be the same size.
308static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>());
309
310// `Custom` and `SimpleMessage` need to be thin pointers.
311static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8);
312static_assert!(@usize_eq: size_of::<CustomOwner>(), 8);
313
314static_assert!((TAG_MASK + 1).is_power_of_two());
315// And they must have sufficient alignment.
316static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
317static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
318
319static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE);
320static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM);
321static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS);
322static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE);
323
324// This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
325// offset a pointer by this value, and expect it to both be within the same
326// object, and to not wrap around the address space. See the comment in that
327// function for further details.
328//
329// Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this
330// check isn't needed for that one, although the assertion that we don't
331// actually wrap around in that wrapping_add does simplify the safety reasoning
332// elsewhere considerably.
333static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
334
335// These two store a payload which is allowed to be zero, so they must be
336// non-zero to preserve the `NonNull`'s range invariant.
337static_assert!(TAG_OS != 0);
338static_assert!(TAG_SIMPLE != 0);
339// We can't tag `SimpleMessage`s, the tag must be 0.
340static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0);
341
342// Check that the point of all of this still holds.
343//
344// We'd check against `io::Error`, but *technically* it's allowed to vary,
345// as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but
346// the `#[repr()]` would show up in rustdoc, which might be seen as a stable
347// commitment.
348static_assert!(@usize_eq: size_of::<Repr>(), 8);
349static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8);
350static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8);
351static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16);
library/core/src/io/error/repr_unpacked.rs created+50
......@@ -0,0 +1,50 @@
1//! This is a fairly simple unpacked error representation that's used on
2//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
3//! would have no benefit.
4
5use super::{Custom, CustomOwner, ErrorData, ErrorKind, RawOsError, SimpleMessage};
6
7type Inner = ErrorData<CustomOwner>;
8
9pub(super) struct Repr(Inner);
10
11impl Repr {
12 #[inline]
13 pub(super) fn new_custom(b: CustomOwner) -> Self {
14 Self(Inner::Custom(b))
15 }
16 #[inline]
17 pub(super) fn new_os(code: RawOsError) -> Self {
18 Self(Inner::Os(code))
19 }
20 #[inline]
21 pub(super) fn new_simple(kind: ErrorKind) -> Self {
22 Self(Inner::Simple(kind))
23 }
24 #[inline]
25 pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
26 Self(Inner::SimpleMessage(m))
27 }
28 #[inline]
29 pub(super) fn into_data(self) -> ErrorData<CustomOwner> {
30 self.0
31 }
32 #[inline]
33 pub(super) fn data(&self) -> ErrorData<&Custom> {
34 match &self.0 {
35 Inner::Os(c) => ErrorData::Os(*c),
36 Inner::Simple(k) => ErrorData::Simple(*k),
37 Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
38 Inner::Custom(m) => ErrorData::Custom(m.custom_ref()),
39 }
40 }
41 #[inline]
42 pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
43 match &mut self.0 {
44 Inner::Os(c) => ErrorData::Os(*c),
45 Inner::Simple(k) => ErrorData::Simple(*k),
46 Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
47 Inner::Custom(m) => ErrorData::Custom(m.custom_mut()),
48 }
49 }
50}
library/core/src/io/mod.rs+14-8
......@@ -8,16 +8,22 @@ mod util;
88
99#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
1010pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor};
11#[unstable(feature = "core_io", issue = "154046")]
12pub use self::cursor::Cursor;
13#[unstable(feature = "core_io", issue = "154046")]
14pub use self::error::ErrorKind;
1511#[unstable(feature = "raw_os_error_ty", issue = "107792")]
1612pub use self::error::RawOsError;
13#[unstable(feature = "io_const_error_internals", issue = "none")]
14pub use self::error::SimpleMessage;
15#[unstable(feature = "io_const_error", issue = "133448")]
16pub use self::error::const_error;
1717#[unstable(feature = "core_io", issue = "154046")]
18pub use self::io_slice::{IoSlice, IoSliceMut};
19#[unstable(feature = "core_io", issue = "154046")]
20pub use self::util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink};
18pub use self::{
19 cursor::Cursor,
20 error::{Error, ErrorKind, Result},
21 io_slice::{IoSlice, IoSliceMut},
22 util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink},
23};
2124#[doc(hidden)]
2225#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
23pub use self::util::{chain, take};
26pub use self::{
27 error::{Custom, CustomOwner, OsFunctions},
28 util::{chain, take},
29};
library/core/src/lib.rs+1
......@@ -96,6 +96,7 @@
9696#![feature(core_intrinsics)]
9797#![feature(coverage_attribute)]
9898#![feature(disjoint_bitor)]
99#![feature(io_const_error)]
99100#![feature(offset_of_enum)]
100101#![feature(panic_internals)]
101102#![feature(pattern_type_macro)]
library/std/src/io/error.rs+23-699
......@@ -1,310 +1,20 @@
11#[cfg(test)]
22mod tests;
33
4#[stable(feature = "rust1", since = "1.0.0")]
5pub use core::io::ErrorKind;
6#[unstable(feature = "raw_os_error_ty", issue = "107792")]
7pub use core::io::RawOsError;
8
9// On 64-bit platforms, `io::Error` may use a bit-packed representation to
10// reduce size. However, this representation assumes that error codes are
11// always 32-bit wide.
12//
13// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit.
14// Therefore, the packed representation is explicitly disabled for UEFI
15// targets, and the unpacked representation must be used instead.
16#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
17mod repr_bitpacked;
18#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
19use repr_bitpacked::Repr;
20
21#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
22mod repr_unpacked;
23#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
24use repr_unpacked::Repr;
25
26use crate::{error, fmt, result, sys};
27
28/// A specialized [`Result`] type for I/O operations.
29///
30/// This type is broadly used across [`std::io`] for any operation which may
31/// produce an error.
32///
33/// This type alias is generally used to avoid writing out [`io::Error`] directly and
34/// is otherwise a direct mapping to [`Result`].
35///
36/// While usual Rust style is to import types directly, aliases of [`Result`]
37/// often are not, to make it easier to distinguish between them. [`Result`] is
38/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
39/// will generally use `io::Result` instead of shadowing the [prelude]'s import
40/// of [`std::result::Result`][`Result`].
41///
42/// [`std::io`]: crate::io
43/// [`io::Error`]: Error
44/// [`Result`]: crate::result::Result
45/// [prelude]: crate::prelude
46///
47/// # Examples
48///
49/// A convenience function that bubbles an `io::Result` to its caller:
50///
51/// ```
52/// use std::io;
53///
54/// fn get_string() -> io::Result<String> {
55/// let mut buffer = String::new();
56///
57/// io::stdin().read_line(&mut buffer)?;
58///
59/// Ok(buffer)
60/// }
61/// ```
62#[stable(feature = "rust1", since = "1.0.0")]
63#[doc(search_unbox)]
64pub type Result<T> = result::Result<T, Error>;
65
66/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
67/// associated traits.
68///
69/// Errors mostly originate from the underlying OS, but custom instances of
70/// `Error` can be created with crafted error messages and a particular value of
71/// [`ErrorKind`].
72///
73/// [`Read`]: crate::io::Read
74/// [`Write`]: crate::io::Write
75/// [`Seek`]: crate::io::Seek
76#[stable(feature = "rust1", since = "1.0.0")]
77pub struct Error {
78 repr: Repr,
79}
80
81#[stable(feature = "rust1", since = "1.0.0")]
82impl fmt::Debug for Error {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 fmt::Debug::fmt(&self.repr, f)
85 }
86}
87
88/// Common errors constants for use in std
89#[allow(dead_code)]
90impl Error {
91 pub(crate) const INVALID_UTF8: Self =
92 const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
93
94 pub(crate) const READ_EXACT_EOF: Self =
95 const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
96
97 pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!(
98 ErrorKind::NotFound,
99 "the number of hardware threads is not known for the target platform",
100 );
101
102 pub(crate) const UNSUPPORTED_PLATFORM: Self =
103 const_error!(ErrorKind::Unsupported, "operation not supported on this platform");
104
105 pub(crate) const WRITE_ALL_EOF: Self =
106 const_error!(ErrorKind::WriteZero, "failed to write whole buffer");
107
108 pub(crate) const ZERO_TIMEOUT: Self =
109 const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
110
111 pub(crate) const NO_ADDRESSES: Self =
112 const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
113}
114
115#[stable(feature = "rust1", since = "1.0.0")]
116impl From<alloc::ffi::NulError> for Error {
117 /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
118 fn from(_: alloc::ffi::NulError) -> Error {
119 const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
120 }
121}
122
123#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
124impl From<alloc::collections::TryReserveError> for Error {
125 /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
126 ///
127 /// `TryReserveError` won't be available as the error `source()`,
128 /// but this may change in the future.
129 fn from(_: alloc::collections::TryReserveError) -> Error {
130 // ErrorData::Custom allocates, which isn't great for handling OOM errors.
131 ErrorKind::OutOfMemory.into()
132 }
133}
134
135// Only derive debug in tests, to make sure it
136// doesn't accidentally get printed.
137#[cfg_attr(test, derive(Debug))]
138enum ErrorData<C> {
139 Os(RawOsError),
140 Simple(ErrorKind),
141 SimpleMessage(&'static SimpleMessage),
142 Custom(C),
143}
144
145// `#[repr(align(4))]` is probably redundant, it should have that value or
146// higher already. We include it just because repr_bitpacked.rs's encoding
147// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
148// alignment required by the struct, only increase it).
149//
150// If we add more variants to ErrorData, this can be increased to 8, but it
151// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
152// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
153// that version needs the alignment, and 8 is higher than the alignment we'll
154// have on 32 bit platforms.
155//
156// (For the sake of being explicit: the alignment requirement here only matters
157// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
158// matter at all)
159#[doc(hidden)]
160#[unstable(feature = "io_const_error_internals", issue = "none")]
161#[repr(align(4))]
162#[derive(Debug)]
163pub struct SimpleMessage {
164 pub kind: ErrorKind,
165 pub message: &'static str,
166}
167
168/// Creates a new I/O error from a known kind of error and a string literal.
169///
170/// Contrary to [`Error::new`], this macro does not allocate and can be used in
171/// `const` contexts.
172///
173/// # Example
174/// ```
175/// #![feature(io_const_error)]
176/// use std::io::{const_error, Error, ErrorKind};
177///
178/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works");
179///
180/// fn not_here() -> Result<(), Error> {
181/// Err(FAIL)
182/// }
183/// ```
184#[rustc_macro_transparency = "semiopaque"]
185#[unstable(feature = "io_const_error", issue = "133448")]
186#[allow_internal_unstable(hint_must_use, io_const_error_internals)]
187pub macro const_error($kind:expr, $message:expr $(,)?) {
188 $crate::hint::must_use($crate::io::Error::from_static_message(
189 const { &$crate::io::SimpleMessage { kind: $kind, message: $message } },
190 ))
191}
192
193// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
194// repr_bitpacked's encoding requires it. In practice it almost certainly be
195// already be this high or higher.
196#[derive(Debug)]
197#[repr(align(4))]
198struct Custom {
199 kind: ErrorKind,
200 error: Box<dyn error::Error + Send + Sync>,
201}
202
203/// Intended for use for errors not exposed to the user, where allocating onto
204/// the heap (for normal construction via Error::new) is too costly.
205#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
206impl From<ErrorKind> for Error {
207 /// Converts an [`ErrorKind`] into an [`Error`].
208 ///
209 /// This conversion creates a new error with a simple representation of error kind.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use std::io::{Error, ErrorKind};
215 ///
216 /// let not_found = ErrorKind::NotFound;
217 /// let error = Error::from(not_found);
218 /// assert_eq!("entity not found", format!("{error}"));
219 /// ```
220 #[inline]
221 fn from(kind: ErrorKind) -> Error {
222 Error { repr: Repr::new_simple(kind) }
223 }
224}
225
4#[cfg_attr(
5 test,
6 expect(unused, reason = "only used in implementation for non-test compilation")
7)]
8use crate::{
9 io::{Error, OsFunctions, RawOsError},
10 sys::io::{decode_error_kind, errno, error_string, is_interrupted},
11};
12
13// Because std is linked in during testing, these incoherent implementations would
14// be duplicated if this was unconditionally included.
15// See #2912 for details.
16#[cfg(not(test))]
22617impl Error {
227 /// Creates a new I/O error from a known kind of error as well as an
228 /// arbitrary error payload.
229 ///
230 /// This function is used to generically create I/O errors which do not
231 /// originate from the OS itself. The `error` argument is an arbitrary
232 /// payload which will be contained in this [`Error`].
233 ///
234 /// Note that this function allocates memory on the heap.
235 /// If no extra payload is required, use the `From` conversion from
236 /// `ErrorKind`.
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// use std::io::{Error, ErrorKind};
242 ///
243 /// // errors can be created from strings
244 /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
245 ///
246 /// // errors can also be created from other errors
247 /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
248 ///
249 /// // creating an error without payload (and without memory allocation)
250 /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
251 /// ```
252 #[stable(feature = "rust1", since = "1.0.0")]
253 #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")]
254 #[inline(never)]
255 pub fn new<E>(kind: ErrorKind, error: E) -> Error
256 where
257 E: Into<Box<dyn error::Error + Send + Sync>>,
258 {
259 Self::_new(kind, error.into())
260 }
261
262 /// Creates a new I/O error from an arbitrary error payload.
263 ///
264 /// This function is used to generically create I/O errors which do not
265 /// originate from the OS itself. It is a shortcut for [`Error::new`]
266 /// with [`ErrorKind::Other`].
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use std::io::Error;
272 ///
273 /// // errors can be created from strings
274 /// let custom_error = Error::other("oh no!");
275 ///
276 /// // errors can also be created from other errors
277 /// let custom_error2 = Error::other(custom_error);
278 /// ```
279 #[stable(feature = "io_error_other", since = "1.74.0")]
280 pub fn other<E>(error: E) -> Error
281 where
282 E: Into<Box<dyn error::Error + Send + Sync>>,
283 {
284 Self::_new(ErrorKind::Other, error.into())
285 }
286
287 fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
288 Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
289 }
290
291 /// Creates a new I/O error from a known kind of error as well as a constant
292 /// message.
293 ///
294 /// This function does not allocate.
295 ///
296 /// You should not use this directly, and instead use the `const_error!`
297 /// macro: `io::const_error!(ErrorKind::Something, "some_message")`.
298 ///
299 /// This function should maybe change to `from_static_message<const MSG: &'static
300 /// str>(kind: ErrorKind)` in the future, when const generics allow that.
301 #[inline]
302 #[doc(hidden)]
303 #[unstable(feature = "io_const_error_internals", issue = "none")]
304 pub const fn from_static_message(msg: &'static SimpleMessage) -> Error {
305 Self { repr: Repr::new_simple_message(msg) }
306 }
307
30818 /// Returns an error representing the last OS error which occurred.
30919 ///
31020 /// This function reads the value of `errno` for the target platform (e.g.
......@@ -324,13 +34,14 @@ impl Error {
32434 /// let os_error = Error::last_os_error();
32535 /// println!("last OS error: {os_error:?}");
32636 /// ```
37 #[rustc_allow_incoherent_impl]
32738 #[stable(feature = "rust1", since = "1.0.0")]
32839 #[doc(alias = "GetLastError")]
32940 #[doc(alias = "errno")]
33041 #[must_use]
33142 #[inline]
33243 pub fn last_os_error() -> Error {
333 Error::from_raw_os_error(sys::io::errno())
44 Error::from_raw_os_error(errno())
33445 }
33546
33647 /// Creates a new instance of an [`Error`] from a particular OS error code.
......@@ -358,405 +69,18 @@ impl Error {
35869 /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
35970 /// # }
36071 /// ```
72 #[rustc_allow_incoherent_impl]
36173 #[stable(feature = "rust1", since = "1.0.0")]
36274 #[must_use]
36375 #[inline]
36476 pub fn from_raw_os_error(code: RawOsError) -> Error {
365 Error { repr: Repr::new_os(code) }
366 }
77 const FUNCTIONS: &'static OsFunctions = &OsFunctions {
78 format_os_error: |code, fmt| fmt.write_str(&error_string(code)),
79 decode_error_kind,
80 is_interrupted,
81 };
36782
368 /// Returns the OS error that this error represents (if any).
369 ///
370 /// If this [`Error`] was constructed via [`last_os_error`] or
371 /// [`from_raw_os_error`], then this function will return [`Some`], otherwise
372 /// it will return [`None`].
373 ///
374 /// [`last_os_error`]: Error::last_os_error
375 /// [`from_raw_os_error`]: Error::from_raw_os_error
376 ///
377 /// # Examples
378 ///
379 /// ```
380 /// use std::io::{Error, ErrorKind};
381 ///
382 /// fn print_os_error(err: &Error) {
383 /// if let Some(raw_os_err) = err.raw_os_error() {
384 /// println!("raw OS error: {raw_os_err:?}");
385 /// } else {
386 /// println!("Not an OS error");
387 /// }
388 /// }
389 ///
390 /// fn main() {
391 /// // Will print "raw OS error: ...".
392 /// print_os_error(&Error::last_os_error());
393 /// // Will print "Not an OS error".
394 /// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
395 /// }
396 /// ```
397 #[stable(feature = "rust1", since = "1.0.0")]
398 #[must_use]
399 #[inline]
400 pub fn raw_os_error(&self) -> Option<RawOsError> {
401 match self.repr.data() {
402 ErrorData::Os(i) => Some(i),
403 ErrorData::Custom(..) => None,
404 ErrorData::Simple(..) => None,
405 ErrorData::SimpleMessage(..) => None,
406 }
83 // SAFETY: `FUNCTIONS` is a constant and not created at runtime.
84 unsafe { Error::from_raw_os_error_with_functions(code, FUNCTIONS) }
40785 }
408
409 /// Returns a reference to the inner error wrapped by this error (if any).
410 ///
411 /// If this [`Error`] was constructed via [`new`] then this function will
412 /// return [`Some`], otherwise it will return [`None`].
413 ///
414 /// [`new`]: Error::new
415 ///
416 /// # Examples
417 ///
418 /// ```
419 /// use std::io::{Error, ErrorKind};
420 ///
421 /// fn print_error(err: &Error) {
422 /// if let Some(inner_err) = err.get_ref() {
423 /// println!("Inner error: {inner_err:?}");
424 /// } else {
425 /// println!("No inner error");
426 /// }
427 /// }
428 ///
429 /// fn main() {
430 /// // Will print "No inner error".
431 /// print_error(&Error::last_os_error());
432 /// // Will print "Inner error: ...".
433 /// print_error(&Error::new(ErrorKind::Other, "oh no!"));
434 /// }
435 /// ```
436 #[stable(feature = "io_error_inner", since = "1.3.0")]
437 #[must_use]
438 #[inline]
439 pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
440 match self.repr.data() {
441 ErrorData::Os(..) => None,
442 ErrorData::Simple(..) => None,
443 ErrorData::SimpleMessage(..) => None,
444 ErrorData::Custom(c) => Some(&*c.error),
445 }
446 }
447
448 /// Returns a mutable reference to the inner error wrapped by this error
449 /// (if any).
450 ///
451 /// If this [`Error`] was constructed via [`new`] then this function will
452 /// return [`Some`], otherwise it will return [`None`].
453 ///
454 /// [`new`]: Error::new
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// use std::io::{Error, ErrorKind};
460 /// use std::{error, fmt};
461 /// use std::fmt::Display;
462 ///
463 /// #[derive(Debug)]
464 /// struct MyError {
465 /// v: String,
466 /// }
467 ///
468 /// impl MyError {
469 /// fn new() -> MyError {
470 /// MyError {
471 /// v: "oh no!".to_string()
472 /// }
473 /// }
474 ///
475 /// fn change_message(&mut self, new_message: &str) {
476 /// self.v = new_message.to_string();
477 /// }
478 /// }
479 ///
480 /// impl error::Error for MyError {}
481 ///
482 /// impl Display for MyError {
483 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 /// write!(f, "MyError: {}", self.v)
485 /// }
486 /// }
487 ///
488 /// fn change_error(mut err: Error) -> Error {
489 /// if let Some(inner_err) = err.get_mut() {
490 /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
491 /// }
492 /// err
493 /// }
494 ///
495 /// fn print_error(err: &Error) {
496 /// if let Some(inner_err) = err.get_ref() {
497 /// println!("Inner error: {inner_err}");
498 /// } else {
499 /// println!("No inner error");
500 /// }
501 /// }
502 ///
503 /// fn main() {
504 /// // Will print "No inner error".
505 /// print_error(&change_error(Error::last_os_error()));
506 /// // Will print "Inner error: ...".
507 /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
508 /// }
509 /// ```
510 #[stable(feature = "io_error_inner", since = "1.3.0")]
511 #[must_use]
512 #[inline]
513 pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
514 match self.repr.data_mut() {
515 ErrorData::Os(..) => None,
516 ErrorData::Simple(..) => None,
517 ErrorData::SimpleMessage(..) => None,
518 ErrorData::Custom(c) => Some(&mut *c.error),
519 }
520 }
521
522 /// Consumes the `Error`, returning its inner error (if any).
523 ///
524 /// If this [`Error`] was constructed via [`new`] or [`other`],
525 /// then this function will return [`Some`],
526 /// otherwise it will return [`None`].
527 ///
528 /// [`new`]: Error::new
529 /// [`other`]: Error::other
530 ///
531 /// # Examples
532 ///
533 /// ```
534 /// use std::io::{Error, ErrorKind};
535 ///
536 /// fn print_error(err: Error) {
537 /// if let Some(inner_err) = err.into_inner() {
538 /// println!("Inner error: {inner_err}");
539 /// } else {
540 /// println!("No inner error");
541 /// }
542 /// }
543 ///
544 /// fn main() {
545 /// // Will print "No inner error".
546 /// print_error(Error::last_os_error());
547 /// // Will print "Inner error: ...".
548 /// print_error(Error::new(ErrorKind::Other, "oh no!"));
549 /// }
550 /// ```
551 #[stable(feature = "io_error_inner", since = "1.3.0")]
552 #[must_use = "`self` will be dropped if the result is not used"]
553 #[inline]
554 pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
555 match self.repr.into_data() {
556 ErrorData::Os(..) => None,
557 ErrorData::Simple(..) => None,
558 ErrorData::SimpleMessage(..) => None,
559 ErrorData::Custom(c) => Some(c.error),
560 }
561 }
562
563 /// Attempts to downcast the custom boxed error to `E`.
564 ///
565 /// If this [`Error`] contains a custom boxed error,
566 /// then it would attempt downcasting on the boxed error,
567 /// otherwise it will return [`Err`].
568 ///
569 /// If the custom boxed error has the same type as `E`, it will return [`Ok`],
570 /// otherwise it will also return [`Err`].
571 ///
572 /// This method is meant to be a convenience routine for calling
573 /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
574 /// [`Error::into_inner`].
575 ///
576 ///
577 /// # Examples
578 ///
579 /// ```
580 /// use std::fmt;
581 /// use std::io;
582 /// use std::error::Error;
583 ///
584 /// #[derive(Debug)]
585 /// enum E {
586 /// Io(io::Error),
587 /// SomeOtherVariant,
588 /// }
589 ///
590 /// impl fmt::Display for E {
591 /// // ...
592 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593 /// # todo!()
594 /// # }
595 /// }
596 /// impl Error for E {}
597 ///
598 /// impl From<io::Error> for E {
599 /// fn from(err: io::Error) -> E {
600 /// err.downcast::<E>()
601 /// .unwrap_or_else(E::Io)
602 /// }
603 /// }
604 ///
605 /// impl From<E> for io::Error {
606 /// fn from(err: E) -> io::Error {
607 /// match err {
608 /// E::Io(io_error) => io_error,
609 /// e => io::Error::new(io::ErrorKind::Other, e),
610 /// }
611 /// }
612 /// }
613 ///
614 /// # fn main() {
615 /// let e = E::SomeOtherVariant;
616 /// // Convert it to an io::Error
617 /// let io_error = io::Error::from(e);
618 /// // Cast it back to the original variant
619 /// let e = E::from(io_error);
620 /// assert!(matches!(e, E::SomeOtherVariant));
621 ///
622 /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
623 /// // Convert it to E
624 /// let e = E::from(io_error);
625 /// // Cast it back to the original variant
626 /// let io_error = io::Error::from(e);
627 /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
628 /// assert!(io_error.get_ref().is_none());
629 /// assert!(io_error.raw_os_error().is_none());
630 /// # }
631 /// ```
632 #[stable(feature = "io_error_downcast", since = "1.79.0")]
633 pub fn downcast<E>(self) -> result::Result<E, Self>
634 where
635 E: error::Error + Send + Sync + 'static,
636 {
637 if let ErrorData::Custom(c) = self.repr.data()
638 && c.error.is::<E>()
639 {
640 if let ErrorData::Custom(b) = self.repr.into_data()
641 && let Ok(err) = b.error.downcast::<E>()
642 {
643 Ok(*err)
644 } else {
645 // Safety: We have just checked that the condition is true
646 unsafe { crate::hint::unreachable_unchecked() }
647 }
648 } else {
649 Err(self)
650 }
651 }
652
653 /// Returns the corresponding [`ErrorKind`] for this error.
654 ///
655 /// This may be a value set by Rust code constructing custom `io::Error`s,
656 /// or if this `io::Error` was sourced from the operating system,
657 /// it will be a value inferred from the system's error encoding.
658 /// See [`last_os_error`] for more details.
659 ///
660 /// [`last_os_error`]: Error::last_os_error
661 ///
662 /// # Examples
663 ///
664 /// ```
665 /// use std::io::{Error, ErrorKind};
666 ///
667 /// fn print_error(err: Error) {
668 /// println!("{:?}", err.kind());
669 /// }
670 ///
671 /// fn main() {
672 /// // As no error has (visibly) occurred, this may print anything!
673 /// // It likely prints a placeholder for unidentified (non-)errors.
674 /// print_error(Error::last_os_error());
675 /// // Will print "AddrInUse".
676 /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
677 /// }
678 /// ```
679 #[stable(feature = "rust1", since = "1.0.0")]
680 #[must_use]
681 #[inline]
682 pub fn kind(&self) -> ErrorKind {
683 match self.repr.data() {
684 ErrorData::Os(code) => sys::io::decode_error_kind(code),
685 ErrorData::Custom(c) => c.kind,
686 ErrorData::Simple(kind) => kind,
687 ErrorData::SimpleMessage(m) => m.kind,
688 }
689 }
690
691 #[inline]
692 pub(crate) fn is_interrupted(&self) -> bool {
693 match self.repr.data() {
694 ErrorData::Os(code) => sys::io::is_interrupted(code),
695 ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
696 ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
697 ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
698 }
699 }
700}
701
702impl fmt::Debug for Repr {
703 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
704 match self.data() {
705 ErrorData::Os(code) => fmt
706 .debug_struct("Os")
707 .field("code", &code)
708 .field("kind", &sys::io::decode_error_kind(code))
709 .field("message", &sys::io::error_string(code))
710 .finish(),
711 ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
712 ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
713 ErrorData::SimpleMessage(msg) => fmt
714 .debug_struct("Error")
715 .field("kind", &msg.kind)
716 .field("message", &msg.message)
717 .finish(),
718 }
719 }
720}
721
722#[stable(feature = "rust1", since = "1.0.0")]
723impl fmt::Display for Error {
724 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
725 match self.repr.data() {
726 ErrorData::Os(code) => {
727 let detail = sys::io::error_string(code);
728 write!(fmt, "{detail} (os error {code})")
729 }
730 ErrorData::Custom(ref c) => c.error.fmt(fmt),
731 ErrorData::Simple(kind) => kind.fmt(fmt),
732 ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
733 }
734 }
735}
736
737#[stable(feature = "rust1", since = "1.0.0")]
738impl error::Error for Error {
739 #[allow(deprecated)]
740 fn cause(&self) -> Option<&dyn error::Error> {
741 match self.repr.data() {
742 ErrorData::Os(..) => None,
743 ErrorData::Simple(..) => None,
744 ErrorData::SimpleMessage(..) => None,
745 ErrorData::Custom(c) => c.error.cause(),
746 }
747 }
748
749 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
750 match self.repr.data() {
751 ErrorData::Os(..) => None,
752 ErrorData::Simple(..) => None,
753 ErrorData::SimpleMessage(..) => None,
754 ErrorData::Custom(c) => c.error.source(),
755 }
756 }
757}
758
759fn _assert_error_is_sync_send() {
760 fn _is_sync_send<T: Sync + Send>() {}
761 _is_sync_send::<Error>();
76286}
library/std/src/io/error/repr_bitpacked.rs deleted-348
......@@ -1,348 +0,0 @@
1//! This is a densely packed error representation which is used on targets with
2//! 64-bit pointers.
3//!
4//! (Note that `bitpacked` vs `unpacked` here has no relationship to
5//! `#[repr(packed)]`, it just refers to attempting to use any available bits in
6//! a more clever manner than `rustc`'s default layout algorithm would).
7//!
8//! Conceptually, it stores the same data as the "unpacked" equivalent we use on
9//! other targets. Specifically, you can imagine it as an optimized version of
10//! the following enum (which is roughly equivalent to what's stored by
11//! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`):
12//!
13//! ```ignore (exposition-only)
14//! enum ErrorData {
15//! Os(i32),
16//! Simple(ErrorKind),
17//! SimpleMessage(&'static SimpleMessage),
18//! Custom(Box<Custom>),
19//! }
20//! ```
21//!
22//! However, it packs this data into a 64bit non-zero value.
23//!
24//! This optimization not only allows `io::Error` to occupy a single pointer,
25//! but improves `io::Result` as well, especially for situations like
26//! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now
27//! 128 bits), which are quite common.
28//!
29//! # Layout
30//! Tagged values are 64 bits, with the 2 least significant bits used for the
31//! tag. This means there are 4 "variants":
32//!
33//! - **Tag 0b00**: The first variant is equivalent to
34//! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
35//!
36//! `SimpleMessage` has an alignment >= 4 (which is requested with
37//! `#[repr(align)]` and checked statically at the bottom of this file), which
38//! means every `&'static SimpleMessage` should have the both tag bits as 0,
39//! meaning its tagged and untagged representation are equivalent.
40//!
41//! This means we can skip tagging it, which is necessary as this variant can
42//! be constructed from a `const fn`, which probably cannot tag pointers (or
43//! at least it would be difficult).
44//!
45//! - **Tag 0b01**: The other pointer variant holds the data for
46//! `ErrorData::Custom` and the remaining 62 bits are used to store a
47//! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
48//! are free to use for the tag.
49//!
50//! The only important thing to note is that `ptr::wrapping_add` and
51//! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise
52//! operations. This should preserve the pointer's provenance, which would
53//! otherwise be lost.
54//!
55//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
56//! in the pointer's most significant 32 bits, and don't use the bits `2..32`
57//! for anything. Using the top 32 bits is just to let us easily recover the
58//! `i32` code with the correct sign.
59//!
60//! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This
61//! stores the `ErrorKind` in the top 32 bits as well, although it doesn't
62//! occupy nearly that many. Most of the bits are unused here, but it's not
63//! like we need them for anything else yet.
64//!
65//! # Use of `NonNull<()>`
66//!
67//! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a
68//! purpose.
69//!
70//! Conceptually you might think of this more like:
71//!
72//! ```ignore (exposition-only)
73//! union Repr {
74//! // holds integer (Simple/Os) variants, and
75//! // provides access to the tag bits.
76//! bits: NonZero<u64>,
77//! // Tag is 0, so this is stored untagged.
78//! msg: &'static SimpleMessage,
79//! // Tagged (offset) `Box<Custom>` pointer.
80//! tagged_custom: NonNull<()>,
81//! }
82//! ```
83//!
84//! But there are a few problems with this:
85//!
86//! 1. Union access is equivalent to a transmute, so this representation would
87//! require we transmute between integers and pointers in at least one
88//! direction, which may be UB (and even if not, it is likely harder for a
89//! compiler to reason about than explicit ptr->int operations).
90//!
91//! 2. Even if all fields of a union have a niche, the union itself doesn't,
92//! although this may change in the future. This would make things like
93//! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of
94//! the motivation of this bitpacking.
95//!
96//! Storing everything in a `NonZero<usize>` (or some other integer) would be a
97//! bit more traditional for pointer tagging, but it would lose provenance
98//! information, couldn't be constructed from a `const fn`, and would probably
99//! run into other issues as well.
100//!
101//! The `NonNull<()>` seems like the only alternative, even if it's fairly odd
102//! to use a pointer type to store something that may hold an integer, some of
103//! the time.
104
105use core::marker::PhantomData;
106use core::num::NonZeroUsize;
107use core::ptr::NonNull;
108
109use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
110
111// The 2 least-significant bits are used as tag.
112const TAG_MASK: usize = 0b11;
113const TAG_SIMPLE_MESSAGE: usize = 0b00;
114const TAG_CUSTOM: usize = 0b01;
115const TAG_OS: usize = 0b10;
116const TAG_SIMPLE: usize = 0b11;
117
118/// The internal representation.
119///
120/// See the module docs for more, this is just a way to hack in a check that we
121/// indeed are not unwind-safe.
122///
123/// ```compile_fail,E0277
124/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
125/// is_unwind_safe::<std::io::Error>();
126/// ```
127#[repr(transparent)]
128#[rustc_insignificant_dtor]
129pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
130
131// All the types `Repr` stores internally are Send + Sync, and so is it.
132unsafe impl Send for Repr {}
133unsafe impl Sync for Repr {}
134
135impl Repr {
136 pub(super) fn new_custom(b: Box<Custom>) -> Self {
137 let p = Box::into_raw(b).cast::<u8>();
138 // Should only be possible if an allocator handed out a pointer with
139 // wrong alignment.
140 debug_assert_eq!(p.addr() & TAG_MASK, 0);
141 // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
142 // end of file), and both the start and end of the expression must be
143 // valid without address space wraparound due to `Box`'s semantics.
144 //
145 // This means it would be correct to implement this using `ptr::add`
146 // (rather than `ptr::wrapping_add`), but it's unclear this would give
147 // any benefit, so we just use `wrapping_add` instead.
148 let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>();
149 // Safety: `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`,
150 // because `p`'s alignment means it isn't allowed to have any of the
151 // `TAG_BITS` set (you can verify that addition and bitwise-or are the
152 // same when the operands have no bits in common using a truth table).
153 //
154 // Then, `TAG_CUSTOM | p` is not zero, as that would require
155 // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a
156 // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
157 // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
158 // `new_unchecked` is safe.
159 let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
160 // quickly smoke-check we encoded the right thing (This generally will
161 // only run in std's tests, unless the user uses -Zbuild-std)
162 debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
163 res
164 }
165
166 #[inline]
167 pub(super) fn new_os(code: RawOsError) -> Self {
168 let utagged = ((code as usize) << 32) | TAG_OS;
169 // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
170 let res = Self(
171 NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }),
172 PhantomData,
173 );
174 // quickly smoke-check we encoded the right thing (This generally will
175 // only run in std's tests, unless the user uses -Zbuild-std)
176 debug_assert!(
177 matches!(res.data(), ErrorData::Os(c) if c == code),
178 "repr(os) encoding failed for {code}"
179 );
180 res
181 }
182
183 #[inline]
184 pub(super) fn new_simple(kind: ErrorKind) -> Self {
185 let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
186 // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
187 let res = Self(
188 NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }),
189 PhantomData,
190 );
191 // quickly smoke-check we encoded the right thing (This generally will
192 // only run in std's tests, unless the user uses -Zbuild-std)
193 debug_assert!(
194 matches!(res.data(), ErrorData::Simple(k) if k == kind),
195 "repr(simple) encoding failed {:?}",
196 kind,
197 );
198 res
199 }
200
201 #[inline]
202 pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
203 // Safety: References are never null.
204 Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData)
205 }
206
207 #[inline]
208 pub(super) fn data(&self) -> ErrorData<&Custom> {
209 // Safety: We're a Repr, decode_repr is fine.
210 unsafe { decode_repr(self.0, |c| &*c) }
211 }
212
213 #[inline]
214 pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
215 // Safety: We're a Repr, decode_repr is fine.
216 unsafe { decode_repr(self.0, |c| &mut *c) }
217 }
218
219 #[inline]
220 pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
221 let this = core::mem::ManuallyDrop::new(self);
222 // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
223 // safe because we prevent double-drop using `ManuallyDrop`.
224 unsafe { decode_repr(this.0, |p| Box::from_raw(p)) }
225 }
226}
227
228impl Drop for Repr {
229 #[inline]
230 fn drop(&mut self) {
231 // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
232 // safe because we're being dropped.
233 unsafe {
234 let _ = decode_repr(self.0, |p| Box::<Custom>::from_raw(p));
235 }
236 }
237}
238
239// Shared helper to decode a `Repr`'s internal pointer into an ErrorData.
240//
241// Safety: `ptr`'s bits should be encoded as described in the document at the
242// top (it should `some_repr.0`)
243#[inline]
244unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
245where
246 F: FnOnce(*mut Custom) -> C,
247{
248 let bits = ptr.as_ptr().addr();
249 match bits & TAG_MASK {
250 TAG_OS => {
251 let code = ((bits as i64) >> 32) as RawOsError;
252 ErrorData::Os(code)
253 }
254 TAG_SIMPLE => {
255 let kind_bits = (bits >> 32) as u32;
256 let kind = ErrorKind::from_prim(kind_bits).unwrap_or_else(|| {
257 debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits);
258 // This means the `ptr` passed in was not valid, which violates
259 // the unsafe contract of `decode_repr`.
260 //
261 // Using this rather than unwrap meaningfully improves the code
262 // for callers which only care about one variant (usually
263 // `Custom`)
264 unsafe { core::hint::unreachable_unchecked() };
265 });
266 ErrorData::Simple(kind)
267 }
268 TAG_SIMPLE_MESSAGE => {
269 // SAFETY: per tag
270 unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) }
271 }
272 TAG_CUSTOM => {
273 // It would be correct for us to use `ptr::byte_sub` here (see the
274 // comment above the `wrapping_add` call in `new_custom` for why),
275 // but it isn't clear that it makes a difference, so we don't.
276 let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
277 ErrorData::Custom(make_custom(custom))
278 }
279 _ => {
280 // Can't happen, and compiler can tell
281 unreachable!();
282 }
283 }
284}
285
286// Some static checking to alert us if a change breaks any of the assumptions
287// that our encoding relies on for correctness and soundness. (Some of these are
288// a bit overly thorough/cautious, admittedly)
289//
290// If any of these are hit on a platform that std supports, we should likely
291// just use `repr_unpacked.rs` there instead (unless the fix is easy).
292macro_rules! static_assert {
293 ($condition:expr) => {
294 const _: () = assert!($condition);
295 };
296 (@usize_eq: $lhs:expr, $rhs:expr) => {
297 const _: [(); $lhs] = [(); $rhs];
298 };
299}
300
301// The bitpacking we use requires pointers be exactly 64 bits.
302static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8);
303
304// We also require pointers and usize be the same size.
305static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>());
306
307// `Custom` and `SimpleMessage` need to be thin pointers.
308static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8);
309static_assert!(@usize_eq: size_of::<Box<Custom>>(), 8);
310
311static_assert!((TAG_MASK + 1).is_power_of_two());
312// And they must have sufficient alignment.
313static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
314static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
315
316static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE);
317static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM);
318static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS);
319static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE);
320
321// This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
322// offset a pointer by this value, and expect it to both be within the same
323// object, and to not wrap around the address space. See the comment in that
324// function for further details.
325//
326// Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this
327// check isn't needed for that one, although the assertion that we don't
328// actually wrap around in that wrapping_add does simplify the safety reasoning
329// elsewhere considerably.
330static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
331
332// These two store a payload which is allowed to be zero, so they must be
333// non-zero to preserve the `NonNull`'s range invariant.
334static_assert!(TAG_OS != 0);
335static_assert!(TAG_SIMPLE != 0);
336// We can't tag `SimpleMessage`s, the tag must be 0.
337static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0);
338
339// Check that the point of all of this still holds.
340//
341// We'd check against `io::Error`, but *technically* it's allowed to vary,
342// as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but
343// the `#[repr()]` would show up in rustdoc, which might be seen as a stable
344// commitment.
345static_assert!(@usize_eq: size_of::<Repr>(), 8);
346static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8);
347static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8);
348static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16);
library/std/src/io/error/repr_unpacked.rs deleted-50
......@@ -1,50 +0,0 @@
1//! This is a fairly simple unpacked error representation that's used on
2//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
3//! would have no benefit.
4
5use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
6
7type Inner = ErrorData<Box<Custom>>;
8
9pub(super) struct Repr(Inner);
10
11impl Repr {
12 #[inline]
13 pub(super) fn new_custom(b: Box<Custom>) -> Self {
14 Self(Inner::Custom(b))
15 }
16 #[inline]
17 pub(super) fn new_os(code: RawOsError) -> Self {
18 Self(Inner::Os(code))
19 }
20 #[inline]
21 pub(super) fn new_simple(kind: ErrorKind) -> Self {
22 Self(Inner::Simple(kind))
23 }
24 #[inline]
25 pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
26 Self(Inner::SimpleMessage(m))
27 }
28 #[inline]
29 pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
30 self.0
31 }
32 #[inline]
33 pub(super) fn data(&self) -> ErrorData<&Custom> {
34 match &self.0 {
35 Inner::Os(c) => ErrorData::Os(*c),
36 Inner::Simple(k) => ErrorData::Simple(*k),
37 Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
38 Inner::Custom(m) => ErrorData::Custom(&*m),
39 }
40 }
41 #[inline]
42 pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
43 match &mut self.0 {
44 Inner::Os(c) => ErrorData::Os(*c),
45 Inner::Simple(k) => ErrorData::Simple(*k),
46 Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
47 Inner::Custom(m) => ErrorData::Custom(&mut *m),
48 }
49 }
50}
library/std/src/io/error/tests.rs+11-34
......@@ -1,4 +1,4 @@
1use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error};
1use crate::io::{Error, ErrorKind, const_error};
22use crate::sys::io::{decode_error_kind, error_string};
33use crate::{assert_matches, error, fmt};
44
......@@ -12,12 +12,7 @@ fn test_debug_error() {
1212 let code = 6;
1313 let msg = error_string(code);
1414 let kind = decode_error_kind(code);
15 let err = Error {
16 repr: Repr::new_custom(Box::new(Custom {
17 kind: ErrorKind::InvalidInput,
18 error: Box::new(Error { repr: super::Repr::new_os(code) }),
19 })),
20 };
15 let err = Error::new(ErrorKind::InvalidInput, Error::from_raw_os_error(code));
2116 let expected = format!(
2217 "Custom {{ \
2318 kind: InvalidInput, \
......@@ -70,10 +65,6 @@ fn test_os_packing() {
7065 for code in -20..20 {
7166 let e = Error::from_raw_os_error(code);
7267 assert_eq!(e.raw_os_error(), Some(code));
73 assert_matches!(
74 e.repr.data(),
75 ErrorData::Os(c) if c == code,
76 );
7768 }
7869}
7970
......@@ -82,28 +73,17 @@ fn test_errorkind_packing() {
8273 assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
8374 assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
8475 assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
85 // Check that the innards look like what we want.
86 assert_matches!(
87 Error::from(ErrorKind::OutOfMemory).repr.data(),
88 ErrorData::Simple(ErrorKind::OutOfMemory),
89 );
9076}
9177
9278#[test]
9379fn test_simple_message_packing() {
94 use super::ErrorKind::*;
95 use super::SimpleMessage;
80 use ErrorKind::*;
9681 macro_rules! check_simple_msg {
9782 ($err:expr, $kind:ident, $msg:literal) => {{
9883 let e = &$err;
9984 // Check that the public api is right.
10085 assert_eq!(e.kind(), $kind);
10186 assert!(format!("{e:?}").contains($msg));
102 // and we got what we expected
103 assert_matches!(
104 e.repr.data(),
105 ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg })
106 );
10787 }};
10888 }
10989
......@@ -128,14 +108,11 @@ impl fmt::Display for Bojji {
128108
129109#[test]
130110fn test_custom_error_packing() {
131 use super::Custom;
132111 let test = Error::new(ErrorKind::Uncategorized, Bojji(true));
112 assert_eq!(test.kind(), ErrorKind::Uncategorized);
133113 assert_matches!(
134 test.repr.data(),
135 ErrorData::Custom(Custom {
136 kind: ErrorKind::Uncategorized,
137 error,
138 }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
114 test.get_ref(),
115 Some(error) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
139116 );
140117}
141118
......@@ -181,11 +158,11 @@ fn test_std_io_error_downcast() {
181158 assert_eq!(kind, io_error.kind());
182159
183160 // Case 5: simple message
184 const SIMPLE_MESSAGE: SimpleMessage =
185 SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" };
186 let io_error = Error::from_static_message(&SIMPLE_MESSAGE);
161 const KIND: ErrorKind = ErrorKind::Other;
162 const MESSAGE: &str = "simple message error test";
163 let io_error = const_error!(KIND, MESSAGE);
187164 let io_error = io_error.downcast::<E>().unwrap_err();
188165
189 assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind());
190 assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}"));
166 assert_eq!(KIND, io_error.kind());
167 assert_eq!(MESSAGE, format!("{io_error}"));
191168}
library/std/src/io/mod.rs+15-12
......@@ -297,23 +297,27 @@
297297#[cfg(test)]
298298mod tests;
299299
300#[unstable(feature = "read_buf", issue = "78485")]
301pub use core::io::{BorrowedBuf, BorrowedCursor};
302#[stable(feature = "rust1", since = "1.0.0")]
303pub use core::io::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink};
304#[stable(feature = "iovec", since = "1.36.0")]
305pub use core::io::{IoSlice, IoSliceMut};
306300use core::slice::memchr;
307301
308#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
309pub use self::buffered::WriterPanicked;
302use alloc_crate::io::OsFunctions;
310303#[unstable(feature = "raw_os_error_ty", issue = "107792")]
311pub use self::error::RawOsError;
304pub use alloc_crate::io::RawOsError;
312305#[doc(hidden)]
313306#[unstable(feature = "io_const_error_internals", issue = "none")]
314pub use self::error::SimpleMessage;
307pub use alloc_crate::io::SimpleMessage;
315308#[unstable(feature = "io_const_error", issue = "133448")]
316pub use self::error::const_error;
309pub use alloc_crate::io::const_error;
310#[unstable(feature = "read_buf", issue = "78485")]
311pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor};
312#[stable(feature = "rust1", since = "1.0.0")]
313pub use alloc_crate::io::{
314 Chain, Empty, Error, ErrorKind, Repeat, Result, Sink, Take, empty, repeat, sink,
315};
316#[stable(feature = "iovec", since = "1.36.0")]
317pub use alloc_crate::io::{IoSlice, IoSliceMut};
318
319#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
320pub use self::buffered::WriterPanicked;
317321#[stable(feature = "anonymous_pipe", since = "1.87.0")]
318322pub use self::pipe::{PipeReader, PipeWriter, pipe};
319323#[stable(feature = "is_terminal", since = "1.70.0")]
......@@ -330,7 +334,6 @@ pub use self::{
330334 buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
331335 copy::copy,
332336 cursor::Cursor,
333 error::{Error, ErrorKind, Result},
334337 stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout},
335338};
336339use crate::mem::MaybeUninit;
library/std/src/lib.rs+1
......@@ -390,6 +390,7 @@
390390//
391391// Library features (alloc):
392392// tidy-alphabetical-start
393#![feature(alloc_io)]
393394#![feature(allocator_api)]
394395#![feature(clone_from_ref)]
395396#![feature(get_mut_unchecked)]
library/std/src/os/unix/process.rs+2-2
......@@ -102,8 +102,8 @@ pub impl(self) trait CommandExt {
102102 /// [POSIX fork() specification]:
103103 /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
104104 /// [`std::env`]: mod@crate::env
105 /// [`Error::new`]: crate::io::Error::new
106 /// [`Error::other`]: crate::io::Error::other
105 /// [`Error::new`]: ../../../io/struct.Error.html#method.new
106 /// [`Error::other`]: ../../../io/struct.Error.html#method.other
107107 #[stable(feature = "process_pre_exec", since = "1.34.0")]
108108 unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
109109 where
src/tools/linkchecker/main.rs+16
......@@ -92,6 +92,22 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
9292 "core\\io\\slice::sort_by_key",
9393 "#method.sort_by_cached_key"
9494 ]),
95 ("alloc/io/struct.IoSlice.html", &[
96 "#method.to_ascii_uppercase",
97 "#method.to_ascii_lowercase",
98 "alloc/io/slice::sort_by_key",
99 "alloc\\io\\slice::sort_by_key",
100 "#method.sort_by_key",
101 "#method.sort_by_cached_key"
102 ]),
103 ("alloc/io/struct.IoSliceMut.html", &[
104 "#method.to_ascii_uppercase",
105 "#method.to_ascii_lowercase",
106 "alloc/io/slice::sort_by_key",
107 "alloc\\io\\slice::sort_by_key",
108 "#method.sort_by_key",
109 "#method.sort_by_cached_key"
110 ]),
95111];
96112
97113#[rustfmt::skip]
tests/run-make/wasm-panic-small/rmake.rs+1-1
......@@ -24,5 +24,5 @@ fn test(cfg: &str) {
2424
2525 let bytes = rfs::read("foo.wasm");
2626 println!("{}", bytes.len());
27 assert!(bytes.len() < 40_000, "bytes len was: {}", bytes.len());
27 assert!(bytes.len() < 45_000, "bytes len was: {}", bytes.len());
2828}
tests/ui/binop/binary-op-not-allowed-issue-125631.stderr+3-3
......@@ -12,7 +12,7 @@ note: an implementation of `PartialEq` might be missing for `T1`
1212LL | struct T1;
1313 | ^^^^^^^^^ must implement `PartialEq`
1414note: `std::io::Error` does not implement `PartialEq`
15 --> $SRC_DIR/std/src/io/error.rs:LL:COL
15 --> $SRC_DIR/core/src/io/error.rs:LL:COL
1616 |
1717 = note: `std::io::Error` is defined in another crate
1818help: consider annotating `T1` with `#[derive(PartialEq)]`
......@@ -34,7 +34,7 @@ note: `Thread` does not implement `PartialEq`
3434 |
3535 = note: `Thread` is defined in another crate
3636note: `std::io::Error` does not implement `PartialEq`
37 --> $SRC_DIR/std/src/io/error.rs:LL:COL
37 --> $SRC_DIR/core/src/io/error.rs:LL:COL
3838 |
3939 = note: `std::io::Error` is defined in another crate
4040
......@@ -58,7 +58,7 @@ note: `Thread` does not implement `PartialEq`
5858 |
5959 = note: `Thread` is defined in another crate
6060note: `std::io::Error` does not implement `PartialEq`
61 --> $SRC_DIR/std/src/io/error.rs:LL:COL
61 --> $SRC_DIR/core/src/io/error.rs:LL:COL
6262 |
6363 = note: `std::io::Error` is defined in another crate
6464help: consider annotating `T1` with `#[derive(PartialEq)]`