about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-29 21:01:45 +0000
committerbors <bors@rust-lang.org>2022-03-29 21:01:45 +0000
commit9c06e1ba47e1077725a950e0b5d1870a89c8b536 (patch)
treecbbd2f53a1af15c37af805341655f7a82be2962d /library/std/src
parent5e1d19d30723c287f049662474021f2b9a9894ce (diff)
parent24715028a078fe592b546870c33de68d16a9ca3f (diff)
Auto merge of #95448 - Dylan-DPC:rollup-wpj5yto, r=Dylan-DPC
Rollup of 4 pull requests

Successful merges:

 - #93840 (Stabilize Termination and ExitCode)
 - #95256 (Ensure io::Error's bitpacked repr doesn't accidentally impl UnwindSafe)
 - #95386 (Suggest wrapping patterns in enum variants)
 - #95437 (diagnostics: regression test for derive bounds)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs20
-rw-r--r--library/std/src/process.rs92
2 files changed, 83 insertions, 29 deletions
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 1a0538f861a..208d5a80c5a 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -104,6 +104,7 @@
 
 use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
 use alloc::boxed::Box;
+use core::marker::PhantomData;
 use core::mem::{align_of, size_of};
 use core::ptr::NonNull;
 
@@ -114,8 +115,17 @@ const TAG_CUSTOM: usize = 0b01;
 const TAG_OS: usize = 0b10;
 const TAG_SIMPLE: usize = 0b11;
 
+/// The internal representation.
+///
+/// See the module docs for more, this is just a way to hack in a check that we
+/// indeed are not unwind-safe.
+///
+/// ```compile_fail,E0277
+/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
+/// is_unwind_safe::<std::io::Error>();
+/// ```
 #[repr(transparent)]
-pub(super) struct Repr(NonNull<()>);
+pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
 
 // All the types `Repr` stores internally are Send + Sync, and so is it.
 unsafe impl Send for Repr {}
@@ -145,7 +155,7 @@ impl Repr {
         // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
         // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
         // `new_unchecked` is safe.
-        let res = Self(unsafe { NonNull::new_unchecked(tagged) });
+        let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
@@ -156,7 +166,7 @@ impl Repr {
     pub(super) fn new_os(code: i32) -> Self {
         let utagged = ((code as usize) << 32) | TAG_OS;
         // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -170,7 +180,7 @@ impl Repr {
     pub(super) fn new_simple(kind: ErrorKind) -> Self {
         let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
         // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -184,7 +194,7 @@ impl Repr {
     #[inline]
     pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
         // Safety: References are never null.
-        Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) })
+        Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData)
     }
 
     #[inline]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index b6edf8bca0a..d3c8d864b0c 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1417,6 +1417,15 @@ impl From<fs::File> for Stdio {
 /// For proper error reporting of failed processes, print the value of `ExitStatus` or
 /// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
 ///
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
 /// [`status`]: Command::status
 /// [`wait`]: Child::wait
 //
@@ -1649,8 +1658,16 @@ impl fmt::Display for ExitStatusError {
 #[unstable(feature = "exit_status_error", issue = "84908")]
 impl crate::error::Error for ExitStatusError {}
 
-/// This type represents the status code a process can return to its
-/// parent under normal termination.
+/// This type represents the status code the current process can return
+/// to its parent under normal termination.
+///
+/// `ExitCode` is intended to be consumed only by the standard library (via
+/// [`Termination::report()`]), and intentionally does not provide accessors like
+/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the
+/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for
+/// ExitCode` for constructing other arbitrary exit codes.
+///
+/// # Portability
 ///
 /// Numeric values used in this type don't have portable meanings, and
 /// different platforms may mask different amounts of them.
@@ -1661,52 +1678,78 @@ impl crate::error::Error for ExitStatusError {}
 /// [`SUCCESS`]: ExitCode::SUCCESS
 /// [`FAILURE`]: ExitCode::FAILURE
 ///
-/// **Warning**: While various forms of this were discussed in [RFC #1937],
-/// it was ultimately cut from that RFC, and thus this type is more subject
-/// to change even than the usual unstable item churn.
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
+/// # Examples
+///
+/// `ExitCode` can be returned from the `main` function of a crate, as it implements
+/// [`Termination`]:
+///
+/// ```
+/// use std::process::ExitCode;
+/// # fn check_foo() -> bool { true }
 ///
-/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
+/// fn main() -> ExitCode {
+///     if !check_foo() {
+///         return ExitCode::from(42);
+///     }
+///
+///     ExitCode::SUCCESS
+/// }
+/// ```
 #[derive(Clone, Copy, Debug)]
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 pub struct ExitCode(imp::ExitCode);
 
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 impl ExitCode {
-    /// The canonical ExitCode for successful termination on this platform.
+    /// The canonical `ExitCode` for successful termination on this platform.
     ///
     /// Note that a `()`-returning `main` implicitly results in a successful
     /// termination, so there's no need to return this from `main` unless
     /// you're also returning other possible codes.
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    #[stable(feature = "process_exitcode", since = "1.60.0")]
     pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
 
-    /// The canonical ExitCode for unsuccessful termination on this platform.
+    /// The canonical `ExitCode` for unsuccessful termination on this platform.
     ///
     /// If you're only returning this and `SUCCESS` from `main`, consider
     /// instead returning `Err(_)` and `Ok(())` respectively, which will
     /// return the same codes (but will also `eprintln!` the error).
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    #[stable(feature = "process_exitcode", since = "1.60.0")]
     pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
 }
 
 impl ExitCode {
-    // This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve
+    // This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve
     // all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we
     // likely want to isolate users anything that could restrict the platform specific
     // representation of an ExitCode
     //
     // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426
-    /// Convert an ExitCode into an i32
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    /// Convert an `ExitCode` into an i32
+    #[unstable(
+        feature = "process_exitcode_internals",
+        reason = "exposed only for libstd",
+        issue = "none"
+    )]
     #[inline]
+    #[doc(hidden)]
     pub fn to_i32(self) -> i32 {
         self.0.as_i32()
     }
 }
 
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 impl From<u8> for ExitCode {
-    /// Construct an exit code from an arbitrary u8 value.
+    /// Construct an `ExitCode` from an arbitrary u8 value.
     fn from(code: u8) -> Self {
         ExitCode(imp::ExitCode::from(code))
     }
@@ -2049,7 +2092,7 @@ pub fn id() -> u32 {
 /// standard library's runtime for convenience. Other runtimes are not required
 /// to provide similar functionality.
 #[cfg_attr(not(test), lang = "termination")]
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 #[rustc_on_unimplemented(
     message = "`main` has invalid return type `{Self}`",
     label = "`main` can only return types that implement `{Termination}`"
@@ -2057,10 +2100,11 @@ pub fn id() -> u32 {
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
     /// This status code is returned to the operating system.
+    #[stable(feature = "termination_trait_lib", since = "1.60.0")]
     fn report(self) -> ExitCode;
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for () {
     #[inline]
     fn report(self) -> ExitCode {
@@ -2068,7 +2112,7 @@ impl Termination for () {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<(), E> {
     fn report(self) -> ExitCode {
         match self {
@@ -2078,14 +2122,14 @@ impl<E: fmt::Debug> Termination for Result<(), E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for ! {
     fn report(self) -> ExitCode {
         self
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2094,7 +2138,7 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2102,7 +2146,7 @@ impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for ExitCode {
     #[inline]
     fn report(self) -> ExitCode {