diff options
Diffstat (limited to 'library/std/src')
46 files changed, 518 insertions, 281 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 27f7191831d..233afa92389 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + #[cfg(test)] mod tests; @@ -842,6 +844,37 @@ where self.base.insert(k, v) } + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(map_try_insert)] + /// + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// let err = map.try_insert(37, "b").unwrap_err(); + /// assert_eq!(err.entry.key(), &37); + /// assert_eq!(err.entry.get(), &"a"); + /// assert_eq!(err.value, "b"); + /// ``` + #[unstable(feature = "map_try_insert", issue = "82766")] + pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> { + match self.entry(key) { + Occupied(entry) => Err(OccupiedError { entry, value }), + Vacant(entry) => Ok(entry.insert(value)), + } + } + /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. /// @@ -1851,6 +1884,41 @@ impl<K: Debug, V> Debug for VacantEntry<'_, K, V> { } } +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +#[unstable(feature = "map_try_insert", issue = "82766")] +pub struct OccupiedError<'a, K: 'a, V: 'a> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<K: Debug, V: Debug> Debug for OccupiedError<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> { type Item = (&'a K, &'a V); diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 467968354e2..819be142227 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -774,11 +774,11 @@ fn test_occupied_entry_key() { let key = "hello there"; let value = "value goes here"; assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); + a.insert(key, value); assert_eq!(a.len(), 1); assert_eq!(a[key], value); - match a.entry(key.clone()) { + match a.entry(key) { Vacant(_) => panic!(), Occupied(e) => assert_eq!(key, *e.key()), } @@ -793,11 +793,11 @@ fn test_vacant_entry_key() { let value = "value goes here"; assert!(a.is_empty()); - match a.entry(key.clone()) { + match a.entry(key) { Occupied(_) => panic!(), Vacant(e) => { assert_eq!(key, *e.key()); - e.insert(value.clone()); + e.insert(value); } } assert_eq!(a.len(), 1); diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 605d953f5da..80c35307d52 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -30,6 +30,7 @@ use crate::mem::transmute; use crate::num; use crate::str; use crate::string; +use crate::sync::Arc; /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result<T, E>`]. Errors must describe @@ -469,6 +470,24 @@ impl Error for char::DecodeUtf16Error { } } +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: Debug + Ord, V: Debug> Error + for crate::collections::btree_map::OccupiedError<'a, K, V> +{ + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> { + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + #[stable(feature = "box_error", since = "1.8.0")] impl<T: Error> Error for Box<T> { #[allow(deprecated, deprecated_in_future)] @@ -507,6 +526,27 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } } +#[stable(feature = "arc_error", since = "1.52.0")] +impl<T: Error + ?Sized> Error for Arc<T> { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn backtrace(&self) -> Option<&Backtrace> { + Error::backtrace(&**self) + } +} + #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index f51b2c24621..c16d27fa1f5 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -503,7 +503,7 @@ impl f32 { unsafe { cmath::fdimf(self, other) } } - /// Returns the cubic root of a number. + /// Returns the cube root of a number. /// /// # Examples /// diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 8c41e448686..4c95df5ffe0 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -505,7 +505,7 @@ impl f64 { unsafe { cmath::fdim(self, other) } } - /// Returns the cubic root of a number. + /// Returns the cube root of a number. /// /// # Examples /// diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 230ef0b23db..945bfda1b78 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -62,20 +62,18 @@ use crate::sys; /// u8` argument which is not necessarily nul-terminated, plus another /// argument with the length of the string — like C's `strndup()`. /// You can of course get the slice's length with its -/// [`len`][slice.len] method. +/// [`len`][slice::len] method. /// /// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you /// can use [`CString::as_bytes_with_nul`] instead. /// /// Once you have the kind of slice you need (with or without a nul /// terminator), you can call the slice's own -/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to +/// [`as_ptr`][slice::as_ptr] method to get a read-only raw pointer to pass to /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// /// [`&str`]: prim@str -/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr -/// [slice.len]: ../primitive.slice.html#method.len /// [`Deref`]: ops::Deref /// [`&CStr`]: CStr /// diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 5bb3f6bdcfd..272eccda894 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,6 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf, @@ -93,6 +94,7 @@ impl crate::sealed::Sealed for OsString {} /// /// [`&str`]: str /// [conversions]: super#conversions +#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `OsStr::from_inner` current implementation relies diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 987371f50ec..02b0fc0c57d 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -1,6 +1,8 @@ use crate::cmp; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE}; +use crate::io::{ + self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, +}; /// The `BufReader<R>` struct adds buffering to any reader. /// @@ -90,10 +92,9 @@ impl<R: Read> BufReader<R> { #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { unsafe { - let mut buffer = Vec::with_capacity(capacity); - buffer.set_len(capacity); - inner.initializer().initialize(&mut buffer); - BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } + let mut buf = Box::new_uninit_slice(capacity).assume_init(); + inner.initializer().initialize(&mut buf); + BufReader { inner, buf, pos: 0, cap: 0 } } } } @@ -435,3 +436,9 @@ impl<R: Seek> Seek for BufReader<R> { }) } } + +impl<T> SizeHint for BufReader<T> { + fn lower_bound(&self) -> usize { + self.buffer().len() + } +} diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 3780f2044cb..eb60df214c4 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -106,7 +106,7 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> { Ok(0) => return Ok(len), // EOF reached Ok(bytes_read) => { assert!(bytes_read <= spare_cap.len()); - // Safety: The initializer contract guarantees that either it or `read` + // SAFETY: The initializer contract guarantees that either it or `read` // will have initialized these bytes. And we just checked that the number // of bytes is within the buffer capacity. unsafe { buf.set_len(buf.len() + bytes_read) }; diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 00bf8b9af73..9870cfc4c95 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests; +use crate::alloc::Allocator; use crate::cmp; use crate::fmt; use crate::io::{ @@ -357,7 +358,7 @@ impl Write for &mut [u8] { /// Write is implemented for `Vec<u8>` by appending to the vector. /// The vector will grow as needed. #[stable(feature = "rust1", since = "1.0.0")] -impl Write for Vec<u8> { +impl<A: Allocator> Write for Vec<u8, A> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.extend_from_slice(buf); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index db3b0e2628f..17002e3b860 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -482,7 +482,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ /// } /// ``` /// -/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`: +/// Read from [`&str`] because [`&[u8]`][prim@slice] implements `Read`: /// /// ```no_run /// # use std::io; @@ -504,7 +504,6 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ /// [`&str`]: prim@str /// [`std::io`]: self /// [`File`]: crate::fs::File -/// [slice]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] pub trait Read { @@ -2239,6 +2238,19 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> { } } +impl<T, U> SizeHint for Chain<T, U> { + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) + } + + fn upper_bound(&self) -> Option<usize> { + match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { + (Some(first), Some(second)) => Some(first + second), + _ => None, + } + } +} + /// Reader adaptor which limits the bytes read from an underlying reader. /// /// This struct is generally created by calling [`take`] on a reader. @@ -2465,6 +2477,30 @@ impl<R: Read> Iterator for Bytes<R> { }; } } + + fn size_hint(&self) -> (usize, Option<usize>) { + SizeHint::size_hint(&self.inner) + } +} + +trait SizeHint { + fn lower_bound(&self) -> usize; + + fn upper_bound(&self) -> Option<usize>; + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.lower_bound(), self.upper_bound()) + } +} + +impl<T> SizeHint for T { + default fn lower_bound(&self) -> usize { + 0 + } + + default fn upper_bound(&self) -> Option<usize> { + None + } } /// An iterator over the contents of an instance of `BufRead` split on a diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index d1f9049c8fa..1e72c9e0611 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -497,7 +497,7 @@ pub struct Stdout { /// A locked reference to the [`Stdout`] handle. /// /// This handle implements the [`Write`] trait, and is constructed via -/// the [`Stdout::lock`] method. +/// the [`Stdout::lock`] method. See its documentation for more. /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support @@ -711,7 +711,7 @@ pub struct Stderr { /// A locked reference to the [`Stderr`] handle. /// /// This handle implements the [`Write`] trait and is constructed via -/// the [`Stderr::lock`] method. +/// the [`Stderr::lock`] method. See its documentation for more. /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f176c2f088c..a85dd0d9827 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,7 +1,7 @@ use super::{repeat, Cursor, SeekFrom}; use crate::cmp::{self, min}; use crate::io::{self, IoSlice, IoSliceMut}; -use crate::io::{BufRead, Read, Seek, Write}; +use crate::io::{BufRead, BufReader, Read, Seek, Write}; use crate::ops::Deref; #[test] @@ -199,6 +199,53 @@ fn chain_bufread() { } #[test] +fn bufreader_size_hint() { + let testdata = b"ABCDEFGHIJKL"; + let mut buf_reader = BufReader::new(&testdata[..]); + assert_eq!(buf_reader.buffer().len(), 0); + + let buffer_length = testdata.len(); + buf_reader.fill_buf().unwrap(); + + // Check that size hint matches buffer contents + let mut buffered_bytes = buf_reader.bytes(); + let (lower_bound, _upper_bound) = buffered_bytes.size_hint(); + assert_eq!(lower_bound, buffer_length); + + // Check that size hint matches buffer contents after advancing + buffered_bytes.next().unwrap().unwrap(); + let (lower_bound, _upper_bound) = buffered_bytes.size_hint(); + assert_eq!(lower_bound, buffer_length - 1); +} + +#[test] +fn empty_size_hint() { + let size_hint = io::empty().bytes().size_hint(); + assert_eq!(size_hint, (0, Some(0))); +} + +#[test] +fn chain_empty_size_hint() { + let chain = io::empty().chain(io::empty()); + let size_hint = chain.bytes().size_hint(); + assert_eq!(size_hint, (0, Some(0))); +} + +#[test] +fn chain_size_hint() { + let testdata = b"ABCDEFGHIJKL"; + let mut buf_reader_1 = BufReader::new(&testdata[..6]); + let mut buf_reader_2 = BufReader::new(&testdata[6..]); + + buf_reader_1.fill_buf().unwrap(); + buf_reader_2.fill_buf().unwrap(); + + let chain = buf_reader_1.chain(buf_reader_2); + let size_hint = chain.bytes().size_hint(); + assert_eq!(size_hint, (testdata.len(), None)); +} + +#[test] fn chain_zero_length_read_is_not_eof() { let a = b"A"; let b = b"B"; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index e43ce4cdb4b..f472361f916 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -4,7 +4,9 @@ mod tests; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; +use crate::io::{ + self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, +}; /// A reader which is always at EOF. /// @@ -80,6 +82,12 @@ impl fmt::Debug for Empty { } } +impl SizeHint for Empty { + fn upper_bound(&self) -> Option<usize> { + Some(0) + } +} + /// A reader which yields one byte over and over and over and over and over and... /// /// This struct is generally created by calling [`repeat()`]. Please diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 6b06539a094..383eaf2e3a2 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -42,7 +42,7 @@ /// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions /// [`crate`]: keyword.crate.html /// [`use`]: keyword.use.html -/// [const-cast]: primitive.pointer.html#method.cast +/// [const-cast]: pointer::cast /// [mut-cast]: primitive.pointer.html#method.cast-1 mod as_keyword {} @@ -181,9 +181,8 @@ mod break_keyword {} /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const /// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. /// -/// [pointer primitive]: primitive.pointer.html -/// [Rust Book]: -/// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants +/// [pointer primitive]: pointer +/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants /// [Reference]: ../reference/items/constant-items.html /// [const-eval]: ../reference/const_eval.html mod const_keyword {} @@ -371,7 +370,6 @@ mod else_keyword {} /// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [Rust Book]: ../book/ch06-01-defining-an-enum.html /// [Reference]: ../reference/items/enumerations.html -/// [`!`]: primitive.never.html mod enum_keyword {} #[doc(keyword = "extern")] diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index 68f57958bb2..974851a8bd6 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -177,7 +177,10 @@ impl<T> SyncOnceCell<T> { /// Sets the contents of this cell to `value`. /// - /// Returns `Ok(())` if the cell's value was updated. + /// May block if another thread is currently attempting to initialize the cell. The cell is + /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// + /// Returns `Ok(())` if the cell's value was set by this call. /// /// # Examples /// @@ -440,13 +443,17 @@ impl<T> SyncOnceCell<T> { res } - /// Safety: The value must be initialized + /// # Safety + /// + /// The value must be initialized unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); (&*self.value.get()).assume_init_ref() } - /// Safety: The value must be initialized + /// # Safety + /// + /// The value must be initialized unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); (&mut *self.value.get()).assume_init_mut() @@ -456,7 +463,7 @@ impl<T> SyncOnceCell<T> { unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> { fn drop(&mut self) { if self.is_initialized() { - // Safety: The cell is initialized and being dropped, so it can't + // SAFETY: The cell is initialized and being dropped, so it can't // be accessed again. We also don't touch the `T` other than // dropping it, which validates our usage of #[may_dangle]. unsafe { (&mut *self.value.get()).assume_init_drop() }; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5e46d2c17c9..247d39743be 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -61,14 +61,14 @@ //! type, but not the all-important methods. //! //! So for example there is a [page for the primitive type -//! `i32`](primitive.i32.html) that lists all the methods that can be called on +//! `i32`](primitive::i32) that lists all the methods that can be called on //! 32-bit integers (very useful), and there is a [page for the module //! `std::i32`] that documents the constant values [`MIN`] and [`MAX`] (rarely //! useful). //! -//! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also +//! Note the documentation for the primitives [`str`] and [`[T]`][prim@slice] (also //! called 'slice'). Many method calls on [`String`] and [`Vec<T>`] are actually -//! calls to methods on [`str`] and [`[T]`][slice] respectively, via [deref +//! calls to methods on [`str`] and [`[T]`][prim@slice] respectively, via [deref //! coercions][deref-coercions]. //! //! Third, the standard library defines [The Rust Prelude], a small collection @@ -111,8 +111,8 @@ //! regions of memory: //! //! * [`Vec<T>`] - A heap-allocated *vector* that is resizable at runtime. -//! * [`[T; n]`][array] - An inline *array* with a fixed size at compile time. -//! * [`[T]`][slice] - A dynamically sized *slice* into any other kind of contiguous +//! * [`[T; N]`][prim@array] - An inline *array* with a fixed size at compile time. +//! * [`[T]`][prim@slice] - A dynamically sized *slice* into any other kind of contiguous //! storage, whether heap-allocated or not. //! //! Slices can only be handled through some kind of *pointer*, and as such come @@ -185,8 +185,8 @@ //! [other]: #what-is-in-the-standard-library-documentation //! [primitive types]: ../book/ch03-02-data-types.html //! [rust-discord]: https://discord.gg/rust-lang -#![cfg_attr(not(bootstrap), doc = "[array]: prim@array")] -#![cfg_attr(not(bootstrap), doc = "[slice]: prim@slice")] +//! [array]: prim@array +//! [slice]: prim@slice #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( @@ -228,11 +228,13 @@ #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_accessible)] +#![cfg_attr(not(bootstrap), feature(cfg_eval))] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] @@ -264,7 +266,6 @@ #![feature(exhaustive_patterns)] #![feature(extend_one)] #![feature(extended_key_value_attributes)] -#![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] @@ -276,12 +277,13 @@ #![feature(int_error_matching)] #![feature(integer_atomics)] #![feature(into_future)] -#![cfg_attr(not(bootstrap), feature(intra_doc_pointers))] +#![feature(intra_doc_pointers)] #![feature(lang_items)] #![feature(link_args)] #![feature(linkage)] #![feature(llvm_asm)] #![feature(log_syntax)] +#![feature(map_try_insert)] #![feature(maybe_uninit_extra)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] @@ -290,6 +292,7 @@ #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] +#![feature(new_uninit)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] @@ -315,7 +318,6 @@ #![feature(stdsimd)] #![feature(stmt_expr_attributes)] #![feature(str_internals)] -#![feature(str_split_once)] #![feature(test)] #![feature(thread_local)] #![feature(thread_local_internals)] @@ -325,7 +327,7 @@ #![feature(try_blocks)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unsafe_block_in_unsafe_fn)] +#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))] #![feature(unsafe_cell_raw_get)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] @@ -393,7 +395,11 @@ pub use alloc_crate::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use core::any; #[stable(feature = "simd_arch", since = "1.27.0")] -#[doc(no_inline)] +// The `no_inline`-attribute is required to make the documentation of all +// targets available. +// See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for +// more information. +#[doc(no_inline)] // Note (#82861): required for correct documentation pub use core::arch; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; @@ -552,8 +558,8 @@ pub use std_detect::detect; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::{ - assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo, - unimplemented, unreachable, write, writeln, + assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches, + debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln, }; // Re-export built-in macros defined through libcore. diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 0ce6542cb72..b729349cf53 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -4,22 +4,7 @@ //! library. Each macro is available for use when linking against the standard //! library. -#[cfg(bootstrap)] -#[doc(include = "../../core/src/macros/panic.md")] -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable(libstd_sys_internals)] -#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")] -macro_rules! panic { - () => ({ $crate::panic!("explicit panic") }); - ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) }); - ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+)) - }); -} - -#[cfg(not(bootstrap))] -#[doc(include = "../../core/src/macros/panic.md")] +#[doc = include_str!("../../core/src/macros/panic.md")] #[macro_export] #[rustc_builtin_macro = "std_panic"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index fd6ee088e96..b95511e43d8 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -3,40 +3,48 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, nonstandard_style, missing_debug_implementations)] -cfg_if::cfg_if! { - if #[cfg(doc)] { +// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main +// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set. +// This should help show platform-specific functionality in a hopefully cross-platform way in the +// documentation. +// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make +// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038 - // When documenting libstd we want to show unix/windows/linux modules as - // these are the "main modules" that are used across platforms. This - // should help show platform-specific functionality in a hopefully - // cross-platform way in the documentation +#[cfg(doc)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::unix_ext as unix; - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::unix_ext as unix; +#[cfg(doc)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::windows_ext as windows; - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::windows_ext as windows; +#[cfg(doc)] +#[doc(cfg(target_os = "linux"))] +pub mod linux; - #[doc(cfg(target_os = "linux"))] - pub mod linux; - } else { +#[cfg(doc)] +#[stable(feature = "wasi_ext_doc", since = "1.35.0")] +pub use crate::sys::wasi_ext as wasi; - // If we're not documenting libstd then we just expose the main modules - // as we otherwise would. +// If we're not documenting libstd then we just expose the main modules as we otherwise would. - #[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))] - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext as unix; +#[cfg(not(doc))] +#[cfg(any(unix, target_os = "hermit"))] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::ext as unix; - #[cfg(windows)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext as windows; +#[cfg(not(doc))] +#[cfg(windows)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys::ext as windows; - #[cfg(any(target_os = "linux", target_os = "l4re"))] - pub mod linux; +#[cfg(not(doc))] +#[cfg(any(target_os = "linux", target_os = "l4re"))] +pub mod linux; - } -} +#[cfg(not(doc))] +#[cfg(target_os = "wasi")] +pub mod wasi; #[cfg(target_os = "android")] pub mod android; @@ -68,7 +76,5 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "vxworks")] pub mod vxworks; -#[cfg(target_os = "wasi")] -pub mod wasi; pub mod raw; diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 22c98d7ade9..50464a050c7 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -18,7 +18,7 @@ macro_rules! type_alias_no_nz { $Docfile:tt, $Alias:ident = $Real:ty; $( $Cfg:tt )* } => { - #[doc(include = $Docfile)] + #[doc = include_str!($Docfile)] $( $Cfg )* #[stable(feature = "raw_os", since = "1.1.0")] pub type $Alias = $Real; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 581c09e23df..de3b57df44e 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {} /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `PathBuf::as_mut_vec` current implementation relies @@ -1719,6 +1720,7 @@ impl AsRef<OsStr> for PathBuf { /// let extension = path.extension(); /// assert_eq!(extension, Some(OsStr::new("txt"))); /// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `Path::new` current implementation relies diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index ef9aec54a4c..7181dc6e710 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -67,6 +67,15 @@ pub use core::prelude::v1::derive; #[doc(hidden)] pub use core::prelude::v1::cfg_accessible; +#[cfg(not(bootstrap))] +#[unstable( + feature = "cfg_eval", + issue = "82679", + reason = "`cfg_eval` is a recently implemented feature" +)] +#[doc(hidden)] +pub use core::prelude::v1::cfg_eval; + // The file so far is equivalent to src/libcore/prelude/v1.rs, // and below to src/liballoc/prelude.rs. // Those files are duplicated rather than using glob imports diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 876b2b8a3f6..d4bb2083d00 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -468,8 +468,8 @@ mod prim_unit {} /// /// [`null`]: ptr::null /// [`null_mut`]: ptr::null_mut -/// [`is_null`]: ../std/primitive.pointer.html#method.is_null -/// [`offset`]: ../std/primitive.pointer.html#method.offset +/// [`is_null`]: pointer::is_null +/// [`offset`]: pointer::offset /// [`into_raw`]: Box::into_raw /// [`drop`]: mem::drop /// [`write`]: ptr::write @@ -564,7 +564,7 @@ mod prim_pointer {} /// move_away(roa); /// ``` /// -/// [slice]: primitive.slice.html +/// [slice]: prim@slice /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash /// [`Borrow`]: borrow::Borrow diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index db0777ee9f0..b12e7eeb138 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -310,6 +310,7 @@ mod cache_aligned; /// println!("{}", recv.recv().unwrap()); // Received after 2 seconds /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Receiver")] pub struct Receiver<T> { inner: UnsafeCell<Flavor<T>>, } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index d967779ce36..0298f59228c 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -23,7 +23,9 @@ use crate::sys_common::rwlock as sys; /// /// The priority policy of the lock is dependent on the underlying operating /// system's implementation, and this type does not guarantee that any -/// particular policy will be used. +/// particular policy will be used. In particular, a writer which is waiting to +/// acquire the lock in `write` might or might not block concurrent calls to +/// `read`. /// /// The type parameter `T` represents the data that this lock protects. It is /// required that `T` satisfies [`Send`] to be shared across threads and diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index d48d9cb0efc..1e79a5c3f9b 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -61,9 +61,9 @@ cfg_if::cfg_if! { #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as unix_ext; } else if #[cfg(any(target_os = "hermit", - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "wasi")), all(target_vendor = "fortanix", target_env = "sgx")))] { - // On wasm right now the module below doesn't compile + // On non-WASI wasm right now the module below doesn't compile // (missing things in `libc` which is empty) so just omit everything // with an empty module #[unstable(issue = "none", feature = "std_internals")] @@ -85,9 +85,9 @@ cfg_if::cfg_if! { #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as windows_ext; } else if #[cfg(any(target_os = "hermit", - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "wasi")), all(target_vendor = "fortanix", target_env = "sgx")))] { - // On wasm right now the shim below doesn't compile, so + // On non-WASI wasm right now the shim below doesn't compile, so // just omit it #[unstable(issue = "none", feature = "std_internals")] #[allow(missing_docs)] @@ -106,3 +106,26 @@ cfg_if::cfg_if! { pub mod windows_ext; } } + +#[cfg(doc)] +cfg_if::cfg_if! { + if #[cfg(target_os = "wasi")] { + // On WASI we'll document what's already available + #[stable(feature = "wasi_ext_doc", since = "1.35.0")] + pub use self::ext as wasi_ext; + } else if #[cfg(any(target_os = "hermit", + target_arch = "wasm32", + all(target_vendor = "fortanix", target_env = "sgx")))] { + // On non-WASI wasm right now the module below doesn't compile + // (missing things in `libc` which is empty) so just omit everything + // with an empty module + #[unstable(issue = "none", feature = "std_internals")] + #[allow(missing_docs)] + pub mod wasi_ext {} + } else { + // On other platforms like Windows document the bare bones of WASI + #[path = "wasi/ext/mod.rs"] + #[stable(feature = "wasi_ext_doc", since = "1.35.0")] + pub mod wasi_ext; + } +} diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs index da899773dbb..3753fdd3536 100644 --- a/library/std/src/sys/sgx/abi/mem.rs +++ b/library/std/src/sys/sgx/abi/mem.rs @@ -47,20 +47,46 @@ pub fn image_base() -> u64 { /// Returns `true` if the specified memory range is in the enclave. /// -/// `p + len` must not overflow. +/// For safety, this function also checks whether the range given overflows, +/// returning `false` if so. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn is_enclave_range(p: *const u8, len: usize) -> bool { - let start = p as u64; - let end = start + (len as u64); - start >= image_base() && end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant + let start = p as usize; + + // Subtract one from `len` when calculating `end` in case `p + len` is + // exactly at the end of addressable memory (`p + len` would overflow, but + // the range is still valid). + let end = if len == 0 { + start + } else if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; + }; + + let base = image_base() as usize; + start >= base && end <= base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant } /// Returns `true` if the specified memory range is in userspace. /// -/// `p + len` must not overflow. +/// For safety, this function also checks whether the range given overflows, +/// returning `false` if so. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn is_user_range(p: *const u8, len: usize) -> bool { - let start = p as u64; - let end = start + (len as u64); - end <= image_base() || start >= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant + let start = p as usize; + + // Subtract one from `len` when calculating `end` in case `p + len` is + // exactly at the end of addressable memory (`p + len` would overflow, but + // the range is still valid). + let end = if len == 0 { + start + } else if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; + }; + + let base = image_base() as usize; + end < base || start > base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant } diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 0964b6335aa..33d6a39af07 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,6 +1,6 @@ use super::{sockaddr_un, SocketAddr}; use crate::convert::TryFrom; -use crate::io::{self, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; @@ -68,7 +68,7 @@ pub(super) fn recv_vectored_with_ancillary_from( pub(super) fn send_vectored_with_ancillary_to( socket: &Socket, path: Option<&Path>, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result<usize> { unsafe { @@ -78,7 +78,7 @@ pub(super) fn send_vectored_with_ancillary_to( let mut msg: libc::msghdr = zeroed(); msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = msg_namelen; - msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); cfg_if::cfg_if! { if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { @@ -567,7 +567,7 @@ impl<'a> SocketAncillary<'a> { /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary}; /// use std::os::unix::io::AsRawFd; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixStream::connect("/tmp/sock")?; @@ -577,7 +577,7 @@ impl<'a> SocketAncillary<'a> { /// ancillary.add_fds(&[sock.as_raw_fd()][..]); /// /// let mut buf = [1; 8]; - /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..]; /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; /// Ok(()) /// } diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 0f532c47c8f..a8c13fbb874 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -19,7 +19,7 @@ use super::{sockaddr_un, SocketAddr}; target_os = "netbsd", target_os = "openbsd", ))] -use crate::io::IoSliceMut; +use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; @@ -506,23 +506,24 @@ impl UnixDatagram { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock") + /// .expect("send_vectored_with_ancillary_to function failed"); /// Ok(()) /// } /// ``` @@ -538,7 +539,7 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, path: P, ) -> io::Result<usize> { @@ -554,23 +555,24 @@ impl UnixDatagram { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary) + /// .expect("send_vectored_with_ancillary function failed"); /// Ok(()) /// } /// ``` @@ -586,7 +588,7 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result<usize> { send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 9fe6b85837e..fc08edacb82 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -530,23 +530,24 @@ impl UnixStream { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary) + /// .expect("send_vectored_with_ancillary function failed"); /// Ok(()) /// } /// ``` @@ -562,7 +563,7 @@ impl UnixStream { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result<usize> { send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 97a016904b4..bd9b6dd727b 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -485,14 +485,14 @@ fn test_unix_datagram_peek_from() { fn test_send_vectored_fds_unix_stream() { let (s1, s2) = or_panic!(UnixStream::pair()); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); - let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; @@ -542,8 +542,8 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { or_panic!(bsock2.set_passcred(true)); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); @@ -554,7 +554,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = - or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; @@ -603,15 +603,15 @@ fn test_send_vectored_with_ancillary_unix_datagram() { let bsock1 = or_panic!(UnixDatagram::bind(&path1)); let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); or_panic!(bsock1.connect(&path2)); - let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 6dc2033289a..4e170a8bb1c 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -172,6 +172,8 @@ impl CommandExt for process::Command { } fn exec(&mut self) -> io::Error { + // NOTE: This may *not* be safe to call after `libc::fork`, because it + // may allocate. That may be worth fixing at some point in the future. self.as_inner_mut().exec(sys::process::Stdio::Inherit) } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 7198a2f08d6..587ffe15981 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -195,6 +195,7 @@ impl Socket { // glibc 2.10 and musl 0.9.5. cfg_if::cfg_if! { if #[cfg(any( + target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", @@ -206,13 +207,6 @@ impl Socket { libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) })?; Ok(Socket(FileDesc::new(fd))) - // While the Android kernel supports the syscall, - // it is not included in all versions of Android's libc. - } else if #[cfg(target_os = "android")] { - let fd = cvt_r(|| unsafe { - libc::syscall(libc::SYS_accept4, self.0.raw(), storage, len, libc::SOCK_CLOEXEC) - })?; - Ok(Socket(FileDesc::new(fd as c_int))) } else { let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; let fd = FileDesc::new(fd); diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 1d1118aa694..d5e14bec765 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -22,7 +22,6 @@ use crate::str; use crate::sys::cvt; use crate::sys::fd; use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; -use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -491,20 +490,20 @@ pub unsafe fn environ() -> *mut *const *const c_char { extern "C" { static mut environ: *const *const c_char; } - ptr::addr_of_mut!(environ) + &mut environ } -static ENV_LOCK: StaticRWLock = StaticRWLock::new(); - -pub fn env_read_lock() -> RWLockReadGuard { - ENV_LOCK.read_with_guard() +pub unsafe fn env_lock() -> StaticMutexGuard { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); + ENV_LOCK.lock() } /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { unsafe { - let _guard = env_read_lock(); + let _guard = env_lock(); let mut environ = *environ(); let mut result = Vec::new(); if !environ.is_null() { @@ -541,7 +540,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - let _guard = env_read_lock(); + let _guard = env_lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None @@ -557,7 +556,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = env_lock(); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) } } @@ -566,7 +565,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = env_lock(); cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) } } diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index a96d4aa6a45..b9dcc4e4b9e 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -60,25 +60,13 @@ cfg_if::cfg_if! { //////////////////////////////////////////////////////////////////////////////// pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. program: CString, args: Vec<CString>, + /// Exactly what will be passed to `execvp`. + /// + /// First element is a pointer to `program`, followed by pointers to + /// `args`, followed by a `null`. Be careful when modifying `program` or + /// `args` to properly update this as well. argv: Argv, env: CommandEnv, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index d2ef0eb128c..2fdbabae277 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -47,7 +47,7 @@ impl Command { // a lock any more because the parent won't do anything and the child is // in its own process. let result = unsafe { - let _env_lock = sys::os::env_read_lock(); + let _env_lock = sys::os::env_lock(); cvt(libc::fork())? }; @@ -124,7 +124,7 @@ impl Command { // Similar to when forking, we want to ensure that access to // the environment is synchronized, so make sure to grab the // environment lock before we try to exec. - let _lock = sys::os::env_read_lock(); + let _lock = sys::os::env_lock(); let Err(e) = self.do_exec(theirs, envp.as_ref()); e @@ -404,7 +404,7 @@ impl Command { cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource - let _env_lock = sys::os::env_read_lock(); + let _env_lock = sys::os::env_lock(); let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); cvt_nz(libc::posix_spawnp( &mut p.pid, diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index d8474205352..d7bba50c76a 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -34,7 +34,7 @@ impl Drop for Handler { target_os = "freebsd", target_os = "solaris", target_os = "illumos", - all(target_os = "netbsd", not(target_vendor = "rumprun")), + target_os = "netbsd", target_os = "openbsd" ))] mod imp { @@ -218,7 +218,7 @@ mod imp { target_os = "freebsd", target_os = "solaris", target_os = "illumos", - all(target_os = "netbsd", not(target_vendor = "rumprun")), + target_os = "netbsd", target_os = "openbsd", )))] mod imp { diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index cda17eb4bd2..40c96307514 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -202,7 +202,7 @@ impl Drop for Thread { not(target_os = "linux"), not(target_os = "freebsd"), not(target_os = "macos"), - not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), + not(target_os = "netbsd"), not(target_os = "openbsd"), not(target_os = "solaris") ))] @@ -222,7 +222,7 @@ pub mod guard { target_os = "linux", target_os = "freebsd", target_os = "macos", - all(target_os = "netbsd", not(target_vendor = "rumprun")), + target_os = "netbsd", target_os = "openbsd", target_os = "solaris" ))] diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs index a8da003d550..6472642f034 100644 --- a/library/std/src/sys/wasi/ext/fs.rs +++ b/library/std/src/sys/wasi/ext/fs.rs @@ -3,11 +3,14 @@ #![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "none")] +use crate::ffi::OsStr; use crate::fs::{self, File, Metadata, OpenOptions}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::path::{Path, PathBuf}; -use crate::sys::fs::osstr2str; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +// Used for `File::read` on intra-doc links +#[allow(unused_imports)] +use io::{Read, Write}; /// WASI-specific extensions to [`File`]. pub trait FileExt { @@ -54,11 +57,11 @@ pub trait FileExt { /// # Errors /// /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation /// will continue. /// /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`]. /// The contents of `buf` are unspecified in this case. /// /// If any other read error is encountered then this function immediately @@ -131,16 +134,16 @@ pub trait FileExt { /// The current file cursor is not affected by this function. /// /// This method will continuously call [`write_at`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is /// returned. This method will not return until the entire buffer has been /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be /// returned. /// /// # Errors /// /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. /// /// [`write_at`]: FileExt::write_at #[stable(feature = "rw_exact_all_at", since = "1.33.0")] @@ -397,6 +400,8 @@ pub trait MetadataExt { fn ino(&self) -> u64; /// Returns the `st_nlink` field of the internal `filestat_t` fn nlink(&self) -> u64; + /// Returns the `st_size` field of the internal `filestat_t` + fn size(&self) -> u64; /// Returns the `st_atim` field of the internal `filestat_t` fn atim(&self) -> u64; /// Returns the `st_mtim` field of the internal `filestat_t` @@ -415,6 +420,9 @@ impl MetadataExt for fs::Metadata { fn nlink(&self) -> u64 { self.as_inner().as_wasi().nlink } + fn size(&self) -> u64 { + self.as_inner().as_wasi().size + } fn atim(&self) -> u64 { self.as_inner().as_wasi().atim } @@ -426,7 +434,7 @@ impl MetadataExt for fs::Metadata { } } -/// WASI-specific extensions for [`FileType`]. +/// WASI-specific extensions for [`fs::FileType`]. /// /// Adds support for special WASI file types such as block/character devices, /// pipes, and sockets. @@ -517,8 +525,12 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>( /// Create a symbolic link. /// -/// This is a convenience API similar to [`std::os::unix::fs::symlink`] and -/// [`std::os::windows::fs::symlink_file`] and [`symlink_dir`](std::os::windows::fs::symlink_dir). +/// This is a convenience API similar to `std::os::unix::fs::symlink` and +/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`. pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> { crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref()) } + +fn osstr2str(f: &OsStr) -> io::Result<&str> { + f.to_str().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "input must be utf-8")) +} diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index 81413f39dc1..3c480aa8e19 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -145,36 +145,36 @@ impl IntoRawFd for fs::File { impl AsRawFd for io::Stdin { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stdin.as_raw_fd() + libc::STDIN_FILENO as RawFd } } impl AsRawFd for io::Stdout { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stdout.as_raw_fd() + libc::STDOUT_FILENO as RawFd } } impl AsRawFd for io::Stderr { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stderr.as_raw_fd() + libc::STDERR_FILENO as RawFd } } impl<'a> AsRawFd for io::StdinLock<'a> { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stdin.as_raw_fd() + libc::STDIN_FILENO as RawFd } } impl<'a> AsRawFd for io::StdoutLock<'a> { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stdout.as_raw_fd() + libc::STDOUT_FILENO as RawFd } } impl<'a> AsRawFd for io::StderrLock<'a> { fn as_raw_fd(&self) -> RawFd { - sys::stdio::Stderr.as_raw_fd() + libc::STDERR_FILENO as RawFd } } diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs index 1cda30edcad..b08402f0776 100644 --- a/library/std/src/sys/wasi/ext/mod.rs +++ b/library/std/src/sys/wasi/ext/mod.rs @@ -1,4 +1,32 @@ +//! Platform-specific extensions to `std` for WASI. +//! +//! Provides access to platform-level information on WASI, and exposes +//! WASI-specific functions that would otherwise be inappropriate as +//! part of the core `std` library. +//! +//! It exposes more ways to deal with platform-specific strings (`OsStr`, +//! `OsString`), allows to set permissions more granularly, extract low-level +//! file descriptors from files and sockets, and has platform-specific helpers +//! for spawning processes. +//! +//! # Examples +//! +//! ```no_run +//! use std::fs::File; +//! use std::os::wasi::prelude::*; +//! +//! fn main() -> std::io::Result<()> { +//! let f = File::create("foo.txt")?; +//! let fd = f.as_raw_fd(); +//! +//! // use fd with native WASI bindings +//! +//! Ok(()) +//! } +//! ``` + #![deny(unsafe_op_in_unsafe_fn)] +#![doc(cfg(target_os = "wasi"))] pub mod ffi; pub mod fs; @@ -11,14 +39,14 @@ pub mod io; pub mod prelude { #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext::ffi::{OsStrExt, OsStringExt}; + pub use super::ffi::{OsStrExt, OsStringExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext::fs::FileTypeExt; + pub use super::fs::FileTypeExt; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt}; + pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 4134ef67671..bcf7da46b4b 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -1,5 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] +use super::fd::WasiFd; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; @@ -9,7 +10,6 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; -use crate::sys::fd::WasiFd; use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::FromInner; @@ -557,12 +557,8 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { pub fn link(original: &Path, link: &Path) -> io::Result<()> { let (original, original_file) = open_parent(original)?; let (link, link_file) = open_parent(link)?; - original.link( - wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, - osstr2str(original_file.as_ref())?, - &link, - osstr2str(link_file.as_ref())?, - ) + // Pass 0 as the flags argument, meaning don't follow symlinks. + original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?) } pub fn stat(p: &Path) -> io::Result<FileAttr> { diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index 8fd4bb76d85..3f294e7df41 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -1,10 +1,10 @@ #![deny(unsafe_op_in_unsafe_fn)] +use super::fd::WasiFd; use crate::convert::TryFrom; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use crate::sys::fd::WasiFd; use crate::sys::{unsupported, Void}; use crate::sys_common::FromInner; use crate::time::Duration; diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index d82f6f41186..209d5b996e5 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -1,8 +1,8 @@ #![deny(unsafe_op_in_unsafe_fn)] +use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; -use crate::sys::fd::WasiFd; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index c10c0df4a3a..b8f512f6a23 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -8,7 +8,9 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -// Safety: `bytes` must be a valid wtf8 encoded slice +/// # Safety +/// +/// `bytes` must be a valid wtf8 encoded slice #[inline] unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, @@ -130,7 +132,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. let path = &path.bytes()[separator_end..]; - // Safety: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') + // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') // is encoded in a single byte, therefore `bytes[separator_start]` and // `bytes[separator_end]` must be code point boundaries and thus // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 41e8ad77294..3705d641a1b 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -86,62 +86,3 @@ impl RWLock { self.0.destroy() } } - -// the cfg annotations only exist due to dead code warnings. the code itself is portable -#[cfg(unix)] -pub struct StaticRWLock(RWLock); - -#[cfg(unix)] -impl StaticRWLock { - pub const fn new() -> StaticRWLock { - StaticRWLock(RWLock::new()) - } - - /// Acquires shared access to the underlying lock, blocking the current - /// thread to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn read_with_guard(&'static self) -> RWLockReadGuard { - // Safety: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.read(); - } - RWLockReadGuard(&self.0) - } - - /// Acquires write access to the underlying lock, blocking the current thread - /// to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn write_with_guard(&'static self) -> RWLockWriteGuard { - // Safety: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.write(); - } - RWLockWriteGuard(&self.0) - } -} - -#[cfg(unix)] -pub struct RWLockReadGuard(&'static RWLock); - -#[cfg(unix)] -impl Drop for RWLockReadGuard { - fn drop(&mut self) { - unsafe { self.0.read_unlock() } - } -} - -#[cfg(unix)] -pub struct RWLockWriteGuard(&'static RWLock); - -#[cfg(unix)] -impl Drop for RWLockWriteGuard { - fn drop(&mut self) { - unsafe { self.0.write_unlock() } - } -} |
