diff options
23 files changed, 586 insertions, 98 deletions
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index a19ba343757..7e27aeb8539 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::Debug; @@ -355,6 +357,30 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +/// An owning iterator over the keys of a `BTreeMap`. +/// +/// This `struct` is created by the [`into_keys`] method on [`BTreeMap`]. +/// See its documentation for more. +/// +/// [`into_keys`]: BTreeMap::into_keys +#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[derive(Debug)] +pub struct IntoKeys<K, V> { + inner: IntoIter<K, V>, +} + +/// An owning iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`into_values`] method on [`BTreeMap`]. +/// See its documentation for more. +/// +/// [`into_values`]: BTreeMap::into_values +#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[derive(Debug)] +pub struct IntoValues<K, V> { + inner: IntoIter<K, V>, +} + /// An iterator over a sub-range of entries in a `BTreeMap`. /// /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its @@ -1291,6 +1317,52 @@ impl<K: Ord, V> BTreeMap<K, V> { self.length = dfs(self.root.as_ref().unwrap().as_ref()); } + + /// Creates a consuming iterator visiting all the keys, in sorted order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_into_keys_values)] + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(2, "b"); + /// a.insert(1, "a"); + /// + /// let keys: Vec<i32> = a.into_keys().collect(); + /// assert_eq!(keys, [1, 2]); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_keys(self) -> IntoKeys<K, V> { + IntoKeys { inner: self.into_iter() } + } + + /// Creates a consuming iterator visiting all the values, in order by key. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_into_keys_values)] + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "hello"); + /// a.insert(2, "goodbye"); + /// + /// let values: Vec<&str> = a.into_values().collect(); + /// assert_eq!(values, ["hello", "goodbye"]); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_values(self) -> IntoValues<K, V> { + IntoValues { inner: self.into_iter() } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1780,6 +1852,82 @@ impl<'a, K, V> Range<'a, K, V> { } } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> Iterator for IntoKeys<K, V> { + type Item = K; + + fn next(&mut self) -> Option<K> { + self.inner.next().map(|(k, _)| k) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } + + fn last(mut self) -> Option<K> { + self.next_back() + } + + fn min(mut self) -> Option<K> { + self.next() + } + + fn max(mut self) -> Option<K> { + self.next_back() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> DoubleEndedIterator for IntoKeys<K, V> { + fn next_back(&mut self) -> Option<K> { + self.inner.next_back().map(|(k, _)| k) + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> ExactSizeIterator for IntoKeys<K, V> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> FusedIterator for IntoKeys<K, V> {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> Iterator for IntoValues<K, V> { + type Item = V; + + fn next(&mut self) -> Option<V> { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } + + fn last(mut self) -> Option<V> { + self.next_back() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> DoubleEndedIterator for IntoValues<K, V> { + fn next_back(&mut self) -> Option<V> { + self.inner.next_back().map(|(_, v)| v) + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> ExactSizeIterator for IntoValues<K, V> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> FusedIterator for IntoValues<K, V> {} + #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 2abd7231711..247b636c808 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -203,13 +203,15 @@ impl<T, A: AllocRef> RawVec<T, A> { /// /// # Safety /// - /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`. + /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given + /// `capacity`. /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit /// systems). ZST vectors may have a capacity up to `usize::MAX`. - /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed. + /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is + /// guaranteed. #[inline] - pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self { - Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a } + pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { + Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc } } /// Gets a raw pointer to the start of the allocation. Note that this is diff --git a/library/alloc/tests/btree/map.rs b/library/alloc/tests/btree/map.rs index f9f81716e35..5777bd60907 100644 --- a/library/alloc/tests/btree/map.rs +++ b/library/alloc/tests/btree/map.rs @@ -1461,3 +1461,27 @@ fn test_into_iter_drop_leak_height_1() { assert_eq!(DROPS.load(Ordering::SeqCst), size); } } + +#[test] +fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: BTreeMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: BTreeMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index c680a3fc25b..3aacd4a687e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -4,6 +4,7 @@ #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(map_first_last)] +#![feature(map_into_keys_values)] #![feature(new_uninit)] #![feature(pattern)] #![feature(str_split_once)] diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 3116815f5d6..3dc0ee2b555 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -119,9 +119,11 @@ pub fn black_box<T>(dummy: T) -> T { // box. This isn't the greatest implementation since it probably deoptimizes // more than we want, but it's so far good enough. + #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. // SAFETY: the inline assembly is a no-op. unsafe { llvm_asm!("" : : "r"(&dummy)); - dummy } + + dummy } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 9f843a57099..d876ab23653 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -117,6 +117,24 @@ impl<T: ?Sized> NonNull<T> { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// When calling this method, you have to ensure that all of the following is true: + /// - `self` is properly aligned + /// - `self` must point to an initialized instance of T; in particular, the pointer must be + /// "dereferencable" in the sense defined [here]. + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime of `self` does not necessarily reflect the actual + /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular, + /// for the duration of this lifetime, the memory the pointer points to must not + /// get mutated (except inside `UnsafeCell`). + /// + /// [here]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub unsafe fn as_ref(&self) -> &T { @@ -130,6 +148,24 @@ impl<T: ?Sized> NonNull<T> { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// When calling this method, you have to ensure that all of the following is true: + /// - `self` is properly aligned + /// - `self` must point to an initialized instance of T; in particular, the pointer must be + /// "dereferenceable" in the sense defined [here]. + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is the only safe approach is to ensure that they are indeed initialized.) + /// + /// Additionally, the lifetime of `self` does not necessarily reflect the actual + /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular, + /// for the duration of this lifetime, the memory this pointer points to must not + /// get accessed (read or written) through any other pointer. + /// + /// [here]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { @@ -224,6 +260,24 @@ impl<T> NonNull<[T]> { unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) } } + /// Returns a raw pointer to the slice's buffer. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// use std::ptr::NonNull; + /// + /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); + /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_mut_ptr(self) -> *mut T { + self.as_non_null_ptr().as_ptr() + } + /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index c40d6119fdf..70f7214e2f1 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -872,6 +872,52 @@ where { self.base.retain(f) } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_into_keys_values)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let vec: Vec<&str> = map.into_keys().collect(); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_keys(self) -> IntoKeys<K, V> { + IntoKeys { inner: self.into_iter() } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_into_keys_values)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let vec: Vec<i32> = map.into_values().collect(); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_values(self) -> IntoValues<K, V> { + IntoValues { inner: self.into_iter() } + } } impl<K, V, S> HashMap<K, V, S> @@ -1154,6 +1200,28 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +/// An owning iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`into_keys`]: HashMap::into_keys +#[unstable(feature = "map_into_keys_values", issue = "75294")] +pub struct IntoKeys<K, V> { + inner: IntoIter<K, V>, +} + +/// An owning iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`into_values`]: HashMap::into_values +#[unstable(feature = "map_into_keys_values", issue = "75294")] +pub struct IntoValues<K, V> { + inner: IntoIter<K, V>, +} + /// A builder for computing where in a HashMap a key-value pair would be stored. /// /// See the [`HashMap::raw_entry_mut`] docs for usage examples. @@ -1827,6 +1895,66 @@ where } } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> Iterator for IntoKeys<K, V> { + type Item = K; + + #[inline] + fn next(&mut self) -> Option<K> { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> ExactSizeIterator for IntoKeys<K, V> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> FusedIterator for IntoKeys<K, V> {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> Iterator for IntoValues<K, V> { + type Item = V; + + #[inline] + fn next(&mut self) -> Option<V> { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> ExactSizeIterator for IntoValues<K, V> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K, V> FusedIterator for IntoValues<K, V> {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() + } +} + #[stable(feature = "drain", since = "1.6.0")] impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V); @@ -3085,6 +3213,30 @@ mod test_map { } #[test] + fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] fn test_find() { let mut m = HashMap::new(); assert!(m.get(&1).is_none()); diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c98008688ab..ff343625a19 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -943,8 +943,7 @@ mod mod_keyword {} /// Capture a [closure]'s environment by value. /// /// `move` converts any variables captured by reference or mutable reference -/// to owned by value variables. The three [`Fn` trait]'s mirror the ways to capture -/// variables, when `move` is used, the closures is represented by the `FnOnce` trait. +/// to owned by value variables. /// /// ```rust /// let capture = "hello"; @@ -953,6 +952,23 @@ mod mod_keyword {} /// }; /// ``` /// +/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though +/// they capture variables by `move`. This is because the traits implemented by +/// a closure type are determined by *what* the closure does with captured +/// values, not *how* it captures them: +/// +/// ```rust +/// fn create_fn() -> impl Fn() { +/// let text = "Fn".to_owned(); +/// +/// move || println!("This is a: {}", text) +/// } +/// +/// let fn_plain = create_fn(); +/// +/// fn_plain(); +/// ``` +/// /// `move` is often used when [threads] are involved. /// /// ```rust diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 26a01f69c99..29cd209e702 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1992,6 +1992,13 @@ impl Path { /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); /// assert_eq!(ancestors.next(), Some(Path::new("/"))); /// assert_eq!(ancestors.next(), None); + /// + /// let mut ancestors = Path::new("../foo/bar").ancestors(); + /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar"))); + /// assert_eq!(ancestors.next(), Some(Path::new("../foo"))); + /// assert_eq!(ancestors.next(), Some(Path::new(".."))); + /// assert_eq!(ancestors.next(), Some(Path::new(""))); + /// assert_eq!(ancestors.next(), None); /// ``` /// /// [`None`]: ../../std/option/enum.Option.html#variant.None @@ -2053,8 +2060,9 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); - /// assert_eq!(path.strip_prefix("test").is_ok(), false); - /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// + /// assert!(path.strip_prefix("test").is_err()); + /// assert!(path.strip_prefix("/haha").is_err()); /// /// let prefix = PathBuf::from("/test/"); /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); @@ -2140,9 +2148,8 @@ impl Path { /// ``` /// use std::path::Path; /// - /// let path = Path::new("foo.rs"); - /// - /// assert_eq!("foo", path.file_stem().unwrap()); + /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap()); + /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_stem(&self) -> Option<&OsStr> { @@ -2166,9 +2173,8 @@ impl Path { /// ``` /// use std::path::Path; /// - /// let path = Path::new("foo.rs"); - /// - /// assert_eq!("rs", path.extension().unwrap()); + /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap()); + /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn extension(&self) -> Option<&OsStr> { @@ -2247,6 +2253,8 @@ impl Path { /// /// let path = Path::new("foo.tar.gz"); /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar")); + /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); + /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 675b82ceb77..8eaf07e52d6 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -106,7 +106,7 @@ pub unsafe extern "C" fn runtime_entry( argv: *const *const c_char, env: *const *const c_char, ) -> ! { - use crate::sys::hermit::fast_thread_local::run_dtors; + use crate::sys::hermit::thread_local_dtor::run_dtors; extern "C" { fn main(argc: isize, argv: *const *const c_char) -> i32; } diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index e11afed6687..7bd71e120de 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -4,7 +4,7 @@ use crate::ffi::CStr; use crate::io; use crate::mem; use crate::sys::hermit::abi; -use crate::sys::hermit::fast_thread_local::run_dtors; +use crate::sys::hermit::thread_local_dtor::run_dtors; use crate::time::Duration; pub type Tid = abi::Tid; diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 9a52371280e..982ec912c44 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -99,43 +99,28 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> { let ptr = haystack.as_ptr(); - let mut len = haystack.len(); let mut start = &haystack[..]; // For performance reasons unfold the loop eight times. - while len >= 8 { - if start[0] == needle { - return Some((start.as_ptr() as usize - ptr as usize) / 2); - } - if start[1] == needle { - return Some((start[1..].as_ptr() as usize - ptr as usize) / 2); - } - if start[2] == needle { - return Some((start[2..].as_ptr() as usize - ptr as usize) / 2); - } - if start[3] == needle { - return Some((start[3..].as_ptr() as usize - ptr as usize) / 2); - } - if start[4] == needle { - return Some((start[4..].as_ptr() as usize - ptr as usize) / 2); - } - if start[5] == needle { - return Some((start[5..].as_ptr() as usize - ptr as usize) / 2); - } - if start[6] == needle { - return Some((start[6..].as_ptr() as usize - ptr as usize) / 2); - } - if start[7] == needle { - return Some((start[7..].as_ptr() as usize - ptr as usize) / 2); + while start.len() >= 8 { + macro_rules! if_return { + ($($n:literal,)+) => { + $( + if start[$n] == needle { + return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2); + } + )+ + } } + if_return!(0, 1, 2, 3, 4, 5, 6, 7,); + start = &start[8..]; - len -= 8; } - for (i, c) in start.iter().enumerate() { + for c in start { if *c == needle { - return Some((start.as_ptr() as usize - ptr as usize) / 2 + i); + return Some((c as *const u16 as usize - ptr as usize) / 2); } } None diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 0c8638b673d..05656774f0e 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -253,14 +253,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start)) }; let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - let is_niche = { - let relative_max = if relative_max == 0 { - // Avoid calling `const_uint`, which wouldn't work for pointers. - // FIXME(eddyb) check the actual primitive type here. - bx.cx().const_null(niche_llty) - } else { - bx.cx().const_uint(niche_llty, relative_max as u64) - }; + let is_niche = if relative_max == 0 { + // Avoid calling `const_uint`, which wouldn't work for pointers. + // Also use canonical == 0 instead of non-canonical u<= 0. + // FIXME(eddyb) check the actual primitive type here. + bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty)) + } else { + let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64); bx.icmp(IntPredicate::IntULE, relative_discr, relative_max) }; diff --git a/src/librustc_error_codes/error_codes/E0271.md b/src/librustc_error_codes/error_codes/E0271.md index 31334069ed8..ddd245b1a2b 100644 --- a/src/librustc_error_codes/error_codes/E0271.md +++ b/src/librustc_error_codes/error_codes/E0271.md @@ -6,25 +6,6 @@ Erroneous code example: trait Trait { type AssociatedType; } fn foo<T>(t: T) where T: Trait<AssociatedType=u32> { - println!("in foo"); -} - -impl Trait for i8 { type AssociatedType = &'static str; } - -foo(3_i8); -``` - -This is because of a type mismatch between the associated type of some -trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`) -and another type `U` that is required to be equal to `T::Bar`, but is not. -Examples follow. - -Here is that same example again, with some explanatory comments: - -```compile_fail,E0271 -trait Trait { type AssociatedType; } - -fn foo<T>(t: T) where T: Trait<AssociatedType=u32> { // ~~~~~~~~ ~~~~~~~~~~~~~~~~~~ // | | // This says `foo` can | @@ -56,11 +37,9 @@ foo(3_i8); // therefore the type-checker complains with this error code. ``` -To avoid those issues, you have to make the types match correctly. -So we can fix the previous examples like this: - +The issue can be resolved by changing the associated type: +1) in the `foo` implementation: ``` -// Basic Example: trait Trait { type AssociatedType; } fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> { @@ -70,13 +49,17 @@ fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> { impl Trait for i8 { type AssociatedType = &'static str; } foo(3_i8); +``` -// For-Loop Example: -let vs = vec![1, 2, 3, 4]; -for v in &vs { - match v { - &1 => {} - _ => {} - } +2) in the `Trait` implementation for `i8`: +``` +trait Trait { type AssociatedType; } + +fn foo<T>(t: T) where T: Trait<AssociatedType = u32> { + println!("in foo"); } + +impl Trait for i8 { type AssociatedType = u32; } + +foo(3_i8); ``` diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs index 592c809c1de..a996b6fb9d9 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/src/librustc_mir/monomorphize/polymorphize.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ self, fold::{TypeFoldable, TypeVisitor}, query::Providers, + subst::SubstsRef, Const, Ty, TyCtxt, }; use rustc_span::symbol::sym; @@ -209,6 +210,25 @@ struct UsedGenericParametersVisitor<'a, 'tcx> { unused_parameters: &'a mut FiniteBitSet<u32>, } +impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> { + /// Invoke `unused_generic_params` on a body contained within the current item (e.g. + /// a closure, generator or constant). + fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { + let unused = self.tcx.unused_generic_params(def_id); + debug!( + "visit_child_body: unused_parameters={:?} unused={:?}", + self.unused_parameters, unused + ); + for (i, arg) in substs.iter().enumerate() { + let i = i.try_into().unwrap(); + if !unused.contains(i).unwrap_or(false) { + arg.visit_with(self); + } + } + debug!("visit_child_body: unused_parameters={:?}", self.unused_parameters); + } +} + impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { debug!("visit_local_decl: local_decl={:?}", local_decl); @@ -249,6 +269,17 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { self.unused_parameters.clear(param.index); false } + ty::ConstKind::Unevaluated(_, _, Some(p)) => { + // If there is a promoted, don't look at the substs - since it will always contain + // the generic parameters, instead, traverse the promoted MIR. + let promoted = self.tcx.promoted_mir(self.def_id); + self.visit_body(&promoted[p]); + false + } + ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => { + self.visit_child_body(def_id.did, unevaluated_substs); + false + } _ => c.super_visit_with(self), } } @@ -269,19 +300,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { // Consider any generic parameters used by any closures/generators as used in the // parent. - let unused = self.tcx.unused_generic_params(def_id); - debug!( - "visit_ty: unused_parameters={:?} unused={:?}", - self.unused_parameters, unused - ); - for (i, arg) in substs.iter().enumerate() { - let i = i.try_into().unwrap(); - if !unused.contains(i).unwrap_or(false) { - arg.visit_with(self); - } - } - debug!("visit_ty: unused_parameters={:?}", self.unused_parameters); - + self.visit_child_body(def_id, substs); false } ty::Param(param) => { diff --git a/src/test/codegen/some-global-nonnull.rs b/src/test/codegen/some-global-nonnull.rs new file mode 100644 index 00000000000..59c47de4129 --- /dev/null +++ b/src/test/codegen/some-global-nonnull.rs @@ -0,0 +1,25 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @test +// CHECK-NEXT: start: +// CHECK-NEXT: tail call void @ext_fn0() +#[no_mangle] +pub fn test() { + test_inner(Some(inner0)); +} + +fn test_inner(f_maybe: Option<fn()>) { + if let Some(f) = f_maybe { + f(); + } +} + +fn inner0() { + unsafe { ext_fn0() }; +} + +extern "C" { + fn ext_fn0(); +} diff --git a/src/test/ui/polymorphization/promoted-function-1.rs b/src/test/ui/polymorphization/promoted-function-1.rs new file mode 100644 index 00000000000..2cd02673442 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-1.rs @@ -0,0 +1,12 @@ +// build-fail +// compile-flags: -Zpolymorphize=on +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +fn foo<'a>(_: &'a ()) {} + +#[rustc_polymorphize_error] +pub fn test<T>() { + //~^ ERROR item has unused generic parameters + foo(&()); +} diff --git a/src/test/ui/polymorphization/promoted-function-1.stderr b/src/test/ui/polymorphization/promoted-function-1.stderr new file mode 100644 index 00000000000..fcbb8694923 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-1.stderr @@ -0,0 +1,8 @@ +error: item has unused generic parameters + --> $DIR/promoted-function-1.rs:9:8 + | +LL | pub fn test<T>() { + | ^^^^ - generic parameter `T` is unused + +error: aborting due to previous error + diff --git a/src/test/ui/polymorphization/promoted-function-2.rs b/src/test/ui/polymorphization/promoted-function-2.rs new file mode 100644 index 00000000000..2831f861f55 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-2.rs @@ -0,0 +1,16 @@ +// build-fail +// compile-flags:-Zpolymorphize=on +#![crate_type = "lib"] +#![feature(lazy_normalization_consts, rustc_attrs)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete + +#[rustc_polymorphize_error] +fn test<T>() { + //~^ ERROR item has unused generic parameters + let x = [0; 3 + 4]; +} + +pub fn caller() { + test::<String>(); + test::<Vec<String>>(); +} diff --git a/src/test/ui/polymorphization/promoted-function-2.stderr b/src/test/ui/polymorphization/promoted-function-2.stderr new file mode 100644 index 00000000000..38d4808c48c --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-2.stderr @@ -0,0 +1,17 @@ +warning: the feature `lazy_normalization_consts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/promoted-function-2.rs:4:12 + | +LL | #![feature(lazy_normalization_consts, rustc_attrs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information + +error: item has unused generic parameters + --> $DIR/promoted-function-2.rs:8:4 + | +LL | fn test<T>() { + | ^^^^ - generic parameter `T` is unused + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/polymorphization/promoted-function.rs b/src/test/ui/polymorphization/promoted-function.rs index 0d3af7a89c2..a56a8e70e4c 100644 --- a/src/test/ui/polymorphization/promoted-function.rs +++ b/src/test/ui/polymorphization/promoted-function.rs @@ -1,4 +1,6 @@ // run-pass +// compile-flags:-Zpolymorphize=on + fn fop<T>() {} fn bar<T>() -> &'static fn() { diff --git a/src/test/ui/polymorphization/unsized_cast.rs b/src/test/ui/polymorphization/unsized_cast.rs index b8facc16070..b803fec2ccf 100644 --- a/src/test/ui/polymorphization/unsized_cast.rs +++ b/src/test/ui/polymorphization/unsized_cast.rs @@ -17,6 +17,7 @@ fn foo<T: Default>() { fn foo2<T: Default>() { let _: T = Default::default(); (|| { + //~^ ERROR item has unused generic parameters let call: extern "rust-call" fn(_, _) = Fn::call; call(&|| {}, ()); //~^ ERROR item has unused generic parameters diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr index d4727acca9a..b51cc5c719f 100644 --- a/src/test/ui/polymorphization/unsized_cast.stderr +++ b/src/test/ui/polymorphization/unsized_cast.stderr @@ -17,7 +17,7 @@ LL | (|| Box::new(|| {}) as Box<dyn Fn()>)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: item has unused generic parameters - --> $DIR/unsized_cast.rs:21:15 + --> $DIR/unsized_cast.rs:22:15 | LL | fn foo2<T: Default>() { | - generic parameter `T` is unused @@ -25,5 +25,19 @@ LL | fn foo2<T: Default>() { LL | call(&|| {}, ()); | ^^^^^ -error: aborting due to 3 previous errors +error: item has unused generic parameters + --> $DIR/unsized_cast.rs:19:5 + | +LL | fn foo2<T: Default>() { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | / (|| { +LL | | +LL | | let call: extern "rust-call" fn(_, _) = Fn::call; +LL | | call(&|| {}, ()); +LL | | +LL | | })(); + | |______^ + +error: aborting due to 4 previous errors |
