about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-20 13:24:31 +0000
committerbors <bors@rust-lang.org>2022-06-20 13:24:31 +0000
commitb12708f7f40463b2131f0c47d1e8a4ffb543a422 (patch)
treefbde1d289f8eda1a64d846142d65d5c0ef7b060c
parent1d6010816c37186e2bee316709f0c0197c427513 (diff)
parent7bde23bb4f0cc74c5566e85501a43426c1be1bef (diff)
downloadrust-b12708f7f40463b2131f0c47d1e8a4ffb543a422.tar.gz
rust-b12708f7f40463b2131f0c47d1e8a4ffb543a422.zip
Auto merge of #98292 - Dylan-DPC:rollup-hueb8tm, r=Dylan-DPC
Rollup of 8 pull requests

Successful merges:

 - #93080 (Implement `core::slice::IterMut::as_mut_slice` and `impl<T> AsMut<[T]> for IterMut<'_, T>`)
 - #94855 (Panic when advance_slices()'ing too far and update docs.)
 - #96609 (Add `{Arc, Rc}::downcast_unchecked`)
 - #96719 (Fix the generator example for `pin!()`)
 - #97149 (Windows: `CommandExt::async_pipes`)
 - #97150 (`Stdio::makes_pipe`)
 - #97837 (Document Rust's stance on `/proc/self/mem`)
 - #98159 (Include ForeignItem when visiting types for WF check)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_typeck/src/hir_wf_check.rs5
-rw-r--r--library/alloc/src/rc.rs40
-rw-r--r--library/alloc/src/sync.rs45
-rw-r--r--library/core/src/pin.rs7
-rw-r--r--library/core/src/slice/iter.rs48
-rw-r--r--library/std/src/io/mod.rs50
-rw-r--r--library/std/src/io/tests.rs8
-rw-r--r--library/std/src/os/unix/io/mod.rs19
-rw-r--r--library/std/src/os/windows/process.rs40
-rw-r--r--library/std/src/process.rs16
-rw-r--r--src/test/ui/wf/issue-95665.rs18
-rw-r--r--src/test/ui/wf/issue-95665.stderr15
12 files changed, 282 insertions, 29 deletions
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index b4b438a561a..4392b9aada9 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -1,7 +1,7 @@
 use crate::collect::ItemCtxt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::HirId;
+use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
@@ -141,6 +141,9 @@ fn diagnostic_hir_wf_check<'tcx>(
                 ref item => bug!("Unexpected item {:?}", item),
             },
             hir::Node::Field(field) => Some(field.ty),
+            hir::Node::ForeignItem(ForeignItem {
+                kind: ForeignItemKind::Static(ty, _), ..
+            }) => Some(*ty),
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 2b3736019ba..a248cd458df 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1254,8 +1254,6 @@ impl<T: Clone> Rc<T> {
 }
 
 impl Rc<dyn Any> {
-    #[inline]
-    #[stable(feature = "rc_downcast", since = "1.29.0")]
     /// Attempt to downcast the `Rc<dyn Any>` to a concrete type.
     ///
     /// # Examples
@@ -1274,6 +1272,8 @@ impl Rc<dyn Any> {
     /// print_if_string(Rc::new(my_string));
     /// print_if_string(Rc::new(0i8));
     /// ```
+    #[inline]
+    #[stable(feature = "rc_downcast", since = "1.29.0")]
     pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<dyn Any>> {
         if (*self).is::<T>() {
             unsafe {
@@ -1285,6 +1285,42 @@ impl Rc<dyn Any> {
             Err(self)
         }
     }
+
+    /// Downcasts the `Rc<dyn Any>` to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    /// use std::rc::Rc;
+    ///
+    /// let x: Rc<dyn Any> = Rc::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Rc<T> {
+        unsafe {
+            let ptr = self.ptr.cast::<RcBox<T>>();
+            mem::forget(self);
+            Rc::from_inner(ptr)
+        }
+    }
 }
 
 impl<T: ?Sized> Rc<T> {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 55d51e0a3c4..2670b15982a 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1705,8 +1705,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> {
 }
 
 impl Arc<dyn Any + Send + Sync> {
-    #[inline]
-    #[stable(feature = "rc_downcast", since = "1.29.0")]
     /// Attempt to downcast the `Arc<dyn Any + Send + Sync>` to a concrete type.
     ///
     /// # Examples
@@ -1725,9 +1723,11 @@ impl Arc<dyn Any + Send + Sync> {
     /// print_if_string(Arc::new(my_string));
     /// print_if_string(Arc::new(0i8));
     /// ```
+    #[inline]
+    #[stable(feature = "rc_downcast", since = "1.29.0")]
     pub fn downcast<T>(self) -> Result<Arc<T>, Self>
     where
-        T: Any + Send + Sync + 'static,
+        T: Any + Send + Sync,
     {
         if (*self).is::<T>() {
             unsafe {
@@ -1739,6 +1739,45 @@ impl Arc<dyn Any + Send + Sync> {
             Err(self)
         }
     }
+
+    /// Downcasts the `Arc<dyn Any + Send + Sync>` to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    /// use std::sync::Arc;
+    ///
+    /// let x: Arc<dyn Any + Send + Sync> = Arc::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T>(self) -> Arc<T>
+    where
+        T: Any + Send + Sync,
+    {
+        unsafe {
+            let ptr = self.ptr.cast::<ArcInner<T>>();
+            mem::forget(self);
+            Arc::from_inner(ptr)
+        }
+    }
 }
 
 impl<T> Weak<T> {
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 720317b05e0..ccef35b4532 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1006,9 +1006,10 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 ///  // Allow generator to be self-referential (not `Unpin`)
 ///  // vvvvvv        so that locals can cross yield points.
 ///     static || {
-///         let foo = String::from("foo"); // --+
-///         yield 0;                         // | <- crosses yield point!
-///         println!("{}", &foo); // <----------+
+///         let foo = String::from("foo");
+///         let foo_ref = &foo; // ------+
+///         yield 0;                  // | <- crosses yield point!
+///         println!("{foo_ref}"); // <--+
 ///         yield foo.len();
 ///     }
 /// }
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 772a9698d84..35d00b9dda6 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -306,6 +306,47 @@ impl<'a, T> IterMut<'a, T> {
     pub fn as_slice(&self) -> &[T] {
         self.make_slice()
     }
+
+    /// Views the underlying data as a mutable subslice of the original data.
+    ///
+    /// To avoid creating `&mut [T]` references that alias, the returned slice
+    /// borrows its lifetime from the iterator the method is applied on.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(slice_iter_mut_as_mut_slice)]
+    ///
+    /// let mut slice: &mut [usize] = &mut [1, 2, 3];
+    ///
+    /// // First, we get the iterator:
+    /// let mut iter = slice.iter_mut();
+    /// // Then, we get a mutable slice from it:
+    /// let mut_slice = iter.as_mut_slice();
+    /// // So if we check what the `as_mut_slice` method returned, we have "[1, 2, 3]":
+    /// assert_eq!(mut_slice, &mut [1, 2, 3]);
+    ///
+    /// // We can use it to mutate the slice:
+    /// mut_slice[0] = 4;
+    /// mut_slice[2] = 5;
+    ///
+    /// // Next, we can move to the second element of the slice, checking that
+    /// // it yields the value we just wrote:
+    /// assert_eq!(iter.next(), Some(&mut 4));
+    /// // Now `as_mut_slice` returns "[2, 5]":
+    /// assert_eq!(iter.as_mut_slice(), &mut [2, 5]);
+    /// ```
+    #[must_use]
+    // FIXME: Uncomment the `AsMut<[T]>` impl when this gets stabilized.
+    #[unstable(feature = "slice_iter_mut_as_mut_slice", issue = "93079")]
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        // SAFETY: the iterator was created from a mutable slice with pointer
+        // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites
+        // for `from_raw_parts_mut` are fulfilled.
+        unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
+    }
 }
 
 #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")]
@@ -315,6 +356,13 @@ impl<T> AsRef<[T]> for IterMut<'_, T> {
     }
 }
 
+// #[stable(feature = "slice_iter_mut_as_mut_slice", since = "FIXME")]
+// impl<T> AsMut<[T]> for IterMut<'_, T> {
+//     fn as_mut(&mut self) -> &mut [T] {
+//         self.as_mut_slice()
+//     }
+// }
+
 iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
 
 /// An internal abstraction over the splitting iterators, so that
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 94812e3fe3b..cad1fab7b8f 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1084,6 +1084,10 @@ impl<'a> IoSliceMut<'a> {
     /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of
     /// multiple buffers.
     ///
+    /// # Panics
+    ///
+    /// Panics when trying to advance beyond the end of the slice.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1105,15 +1109,18 @@ impl<'a> IoSliceMut<'a> {
         self.0.advance(n)
     }
 
-    /// Advance the internal cursor of the slices.
+    /// Advance a slice of slices.
     ///
-    /// # Notes
+    /// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over.
+    /// If the cursor ends up in the middle of an `IoSliceMut`, it is modified
+    /// to start at that cursor.
     ///
-    /// Elements in the slice may be modified if the cursor is not advanced to
-    /// the end of the slice. For example if we have a slice of buffers with 2
-    /// `IoSliceMut`s, both of length 8, and we advance the cursor by 10 bytes
-    /// the first `IoSliceMut` will be untouched however the second will be
-    /// modified to remove the first 2 bytes (10 - 8).
+    /// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes,
+    /// the result will only include the second `IoSliceMut`, advanced by 2 bytes.
+    ///
+    /// # Panics
+    ///
+    /// Panics when trying to advance beyond the end of the slices.
     ///
     /// # Examples
     ///
@@ -1154,7 +1161,9 @@ impl<'a> IoSliceMut<'a> {
         }
 
         *bufs = &mut replace(bufs, &mut [])[remove..];
-        if !bufs.is_empty() {
+        if bufs.is_empty() {
+            assert!(n == accumulated_len, "advancing io slices beyond their length");
+        } else {
             bufs[0].advance(n - accumulated_len)
         }
     }
@@ -1219,6 +1228,10 @@ impl<'a> IoSlice<'a> {
     /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple
     /// buffers.
     ///
+    /// # Panics
+    ///
+    /// Panics when trying to advance beyond the end of the slice.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1240,15 +1253,18 @@ impl<'a> IoSlice<'a> {
         self.0.advance(n)
     }
 
-    /// Advance the internal cursor of the slices.
+    /// Advance a slice of slices.
     ///
-    /// # Notes
+    /// Shrinks the slice to remove any `IoSlice`s that are fully advanced over.
+    /// If the cursor ends up in the middle of an `IoSlice`, it is modified
+    /// to start at that cursor.
     ///
-    /// Elements in the slice may be modified if the cursor is not advanced to
-    /// the end of the slice. For example if we have a slice of buffers with 2
-    /// `IoSlice`s, both of length 8, and we advance the cursor by 10 bytes the
-    /// first `IoSlice` will be untouched however the second will be modified to
-    /// remove the first 2 bytes (10 - 8).
+    /// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes,
+    /// the result will only include the second `IoSlice`, advanced by 2 bytes.
+    ///
+    /// # Panics
+    ///
+    /// Panics when trying to advance beyond the end of the slices.
     ///
     /// # Examples
     ///
@@ -1288,7 +1304,9 @@ impl<'a> IoSlice<'a> {
         }
 
         *bufs = &mut replace(bufs, &mut [])[remove..];
-        if !bufs.is_empty() {
+        if bufs.is_empty() {
+            assert!(n == accumulated_len, "advancing io slices beyond their length");
+        } else {
             bufs[0].advance(n - accumulated_len)
         }
     }
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index eb626348564..d5a8c93b0ce 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -423,18 +423,18 @@ fn io_slice_mut_advance_slices() {
 }
 
 #[test]
+#[should_panic]
 fn io_slice_mut_advance_slices_empty_slice() {
     let mut empty_bufs = &mut [][..];
-    // Shouldn't panic.
     IoSliceMut::advance_slices(&mut empty_bufs, 1);
 }
 
 #[test]
+#[should_panic]
 fn io_slice_mut_advance_slices_beyond_total_length() {
     let mut buf1 = [1; 8];
     let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
 
-    // Going beyond the total length should be ok.
     IoSliceMut::advance_slices(&mut bufs, 9);
     assert!(bufs.is_empty());
 }
@@ -463,18 +463,18 @@ fn io_slice_advance_slices() {
 }
 
 #[test]
+#[should_panic]
 fn io_slice_advance_slices_empty_slice() {
     let mut empty_bufs = &mut [][..];
-    // Shouldn't panic.
     IoSlice::advance_slices(&mut empty_bufs, 1);
 }
 
 #[test]
+#[should_panic]
 fn io_slice_advance_slices_beyond_total_length() {
     let buf1 = [1; 8];
     let mut bufs = &mut [IoSlice::new(&buf1)][..];
 
-    // Going beyond the total length should be ok.
     IoSlice::advance_slices(&mut bufs, 9);
     assert!(bufs.is_empty());
 }
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 7556d3ad0b2..3ab5606f889 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -54,6 +54,25 @@
 //! Like boxes, `OwnedFd` values conceptually own the resource they point to,
 //! and free (close) it when they are dropped.
 //!
+//! ## `/proc/self/mem` and similar OS features
+//!
+//! Some platforms have special files, such as `/proc/self/mem`, which
+//! provide read and write access to the process's memory. Such reads
+//! and writes happen outside the control of the Rust compiler, so they do not
+//! uphold Rust's memory safety guarantees.
+//!
+//! This does not mean that all APIs that might allow `/proc/self/mem`
+//! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
+//! only cover what the program itself can do, and not what entities outside
+//! the program can do to it. `/proc/self/mem` is considered to be such an
+//! external entity, along with debugging interfaces, and people with physical access to
+//! the hardware. This is true even in cases where the program is controlling
+//! the external entity.
+//!
+//! If you desire to comprehensively prevent programs from reaching out and
+//! causing external entities to reach back in and violate memory safety, it's
+//! necessary to use *sandboxing*, which is outside the scope of `std`.
+//!
 //! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
 
 #![stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 24b0888b112..a6b75493e6e 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -161,6 +161,37 @@ pub trait CommandExt: Sealed {
     /// `CommandLineToArgvW` escaping rules.
     #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
     fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
+
+    /// When [`process::Command`] creates pipes, request that our side is always async.
+    ///
+    /// By default [`process::Command`] may choose to use pipes where both ends
+    /// are opened for synchronous read or write operations. By using
+    /// `async_pipes(true)`, this behavior is overridden so that our side is
+    /// always async.
+    ///
+    /// This is important because if doing async I/O a pipe or a file has to be
+    /// opened for async access.
+    ///
+    /// The end of the pipe sent to the child process will always be synchronous
+    /// regardless of this option.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(windows_process_extensions_async_pipes)]
+    /// use std::os::windows::process::CommandExt;
+    /// use std::process::{Command, Stdio};
+    ///
+    /// # let program = "";
+    ///
+    /// Command::new(program)
+    ///     .async_pipes(true)
+    ///     .stdin(Stdio::piped())
+    ///     .stdout(Stdio::piped())
+    ///     .stderr(Stdio::piped());
+    /// ```
+    #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
+    fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
 }
 
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -179,6 +210,15 @@ impl CommandExt for process::Command {
         self.as_inner_mut().raw_arg(raw_text.as_ref());
         self
     }
+
+    fn async_pipes(&mut self, always_async: bool) -> &mut process::Command {
+        // FIXME: This currently has an intentional no-op implementation.
+        // For the time being our side of the pipes will always be async.
+        // Once the ecosystem has adjusted, we may then be able to start making
+        // use of synchronous pipes within the standard library.
+        let _ = always_async;
+        self
+    }
 }
 
 #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index da8eee9030b..ab1a1e6c76f 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1273,6 +1273,22 @@ impl Stdio {
     pub fn null() -> Stdio {
         Stdio(imp::Stdio::Null)
     }
+
+    /// Returns `true` if this requires [`Command`] to create a new pipe.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(stdio_makes_pipe)]
+    /// use std::process::Stdio;
+    ///
+    /// let io = Stdio::piped();
+    /// assert_eq!(io.makes_pipe(), true);
+    /// ```
+    #[unstable(feature = "stdio_makes_pipe", issue = "98288")]
+    pub fn makes_pipe(&self) -> bool {
+        matches!(self.0, imp::Stdio::MakePipe)
+    }
 }
 
 impl FromInner<imp::Stdio> for Stdio {
diff --git a/src/test/ui/wf/issue-95665.rs b/src/test/ui/wf/issue-95665.rs
new file mode 100644
index 00000000000..67923cbb2d6
--- /dev/null
+++ b/src/test/ui/wf/issue-95665.rs
@@ -0,0 +1,18 @@
+// Regression test for the ICE described in #95665.
+// Ensure that the expected error is output (and thus that there is no ICE)
+
+pub trait Trait: {}
+
+pub struct Struct<T: Trait> {
+    member: T,
+}
+
+// uncomment and bug goes away
+// impl Trait for u8 {}
+
+extern "C" {
+    static VAR: Struct<u8>;
+                //~^ 14:17: 14:27: the trait bound `u8: Trait` is not satisfied [E0277]
+}
+
+fn main() {}
diff --git a/src/test/ui/wf/issue-95665.stderr b/src/test/ui/wf/issue-95665.stderr
new file mode 100644
index 00000000000..b1cda59a916
--- /dev/null
+++ b/src/test/ui/wf/issue-95665.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/issue-95665.rs:14:17
+   |
+LL |     static VAR: Struct<u8>;
+   |                 ^^^^^^^^^^ the trait `Trait` is not implemented for `u8`
+   |
+note: required by a bound in `Struct`
+  --> $DIR/issue-95665.rs:6:22
+   |
+LL | pub struct Struct<T: Trait> {
+   |                      ^^^^^ required by this bound in `Struct`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.