From 95dc353006c23a4493b3d08ba33680e51c2107c8 Mon Sep 17 00:00:00 2001 From: jmaargh Date: Sat, 9 Apr 2022 16:42:26 +0100 Subject: [PATCH 01/24] Fix documentation for with_capacity and reserve families of methods Documentation for the following methods with_capacity with_capacity_in with_capacity_and_hasher reserve reserve_exact try_reserve try_reserve_exact was inconsistent and often not entirely correct where they existed on the following types Vec VecDeque String OsString PathBuf BinaryHeap HashSet HashMap BufWriter LineWriter since the allocator is allowed to allocate more than the requested capacity in all such cases, and will frequently "allocate" much more in the case of zero-sized types (I also checked BufReader, but there the docs appear to be accurate as it appears to actually allocate the exact capacity). Some effort was made to make the documentation more consistent between types as well. Fix with_capacity* methods for Vec Fix *reserve* methods for Vec Fix docs for *reserve* methods of VecDeque Fix docs for String::with_capacity Fix docs for *reserve* methods of String Fix docs for OsString::with_capacity Fix docs for *reserve* methods on OsString Fix docs for with_capacity* methods on HashSet Fix docs for *reserve methods of HashSet Fix docs for with_capacity* methods of HashMap Fix docs for *reserve methods on HashMap Fix expect messages about OOM in doctests Fix docs for BinaryHeap::with_capacity Fix docs for *reserve* methods of BinaryHeap Fix typos Fix docs for with_capacity on BufWriter and LineWriter Fix consistent use of `hasher` between `HashMap` and `HashSet` Fix warning in doc test Add test for capacity of vec with ZST Fix doc test error --- library/alloc/src/collections/binary_heap.rs | 51 ++++++----- .../alloc/src/collections/vec_deque/mod.rs | 16 ++-- library/alloc/src/string.rs | 70 +++++++-------- library/alloc/src/vec/mod.rs | 85 +++++++++++++------ library/alloc/tests/vec.rs | 9 ++ library/std/src/collections/hash/map.rs | 35 +++++--- library/std/src/collections/hash/set.rs | 25 ++++-- library/std/src/ffi/os_str.rs | 22 ++--- library/std/src/io/buffered/bufwriter.rs | 4 +- library/std/src/io/buffered/linewriter.rs | 4 +- 10 files changed, 191 insertions(+), 130 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 3706300dcfeb7..197e7aaaccf3d 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -374,10 +374,11 @@ impl BinaryHeap { BinaryHeap { data: vec![] } } - /// Creates an empty `BinaryHeap` with a specific capacity. - /// This preallocates enough memory for `capacity` elements, - /// so that the `BinaryHeap` does not have to be reallocated - /// until it contains at least that many values. + /// Creates an empty `BinaryHeap` with at least the specified capacity. + /// + /// The binary heap will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the binary heap will not allocate. /// /// # Examples /// @@ -906,16 +907,18 @@ impl BinaryHeap { self.data.capacity() } - /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `BinaryHeap`. Does nothing if the capacity is already sufficient. + /// Reserves the minimum capacity for at least `additional` elements more than + /// the current length. Unlike [`reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future - /// insertions are expected. + /// [`reserve`]: BinaryHeap::reserve /// /// # Panics /// - /// Panics if the new capacity overflows `usize`. + /// Panics if the new capacity overflows [`usize`]. /// /// # Examples /// @@ -935,12 +938,15 @@ impl BinaryHeap { self.data.reserve_exact(additional); } - /// Reserves capacity for at least `additional` more elements to be inserted in the - /// `BinaryHeap`. The collection may reserve more space to avoid frequent reallocations. + /// Reserves capacity for at least `additional` elements more than the + /// current length. The allocator may reserve more space to speculatively + /// avoid frequent allocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. /// /// # Panics /// - /// Panics if the new capacity overflows `usize`. + /// Panics if the new capacity overflows [`usize`]. /// /// # Examples /// @@ -958,10 +964,11 @@ impl BinaryHeap { self.data.reserve(additional); } - /// Tries to reserve the minimum capacity for exactly `additional` - /// elements to be inserted in the given `BinaryHeap`. After calling - /// `try_reserve_exact`, capacity will be greater than or equal to - /// `self.len() + additional` if it returns `Ok(())`. + /// Tries to reserve the minimum capacity for at least `additional` elements + /// more than the current length. Unlike [`try_reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `try_reserve_exact`, capacity will be greater than or + /// equal to `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it @@ -999,11 +1006,11 @@ impl BinaryHeap { self.data.try_reserve_exact(additional) } - /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `BinaryHeap`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `try_reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// Tries to reserve capacity for at least `additional` elements more than the + /// current length. The allocator may reserve more space to speculatively + /// avoid frequent allocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional` if it returns + /// `Ok(())`. Does nothing if capacity is already sufficient. /// /// # Errors /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index f92e5759b6f9e..4d895d83745b2 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -688,7 +688,7 @@ impl VecDeque { self.cap() - 1 } - /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the + /// Reserves the minimum capacity for at least `additional` more elements to be inserted in the /// given deque. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore @@ -716,7 +716,7 @@ impl VecDeque { } /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// deque. The collection may reserve more space to avoid frequent reallocations. + /// deque. The collection may reserve more space to speculatively avoid frequent reallocations. /// /// # Panics /// @@ -748,10 +748,10 @@ impl VecDeque { } } - /// Tries to reserve the minimum capacity for exactly `additional` more elements to + /// Tries to reserve the minimum capacity for at least `additional` more elements to /// be inserted in the given deque. After calling `try_reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. - /// Does nothing if the capacity is already sufficient. + /// capacity will be greater than or equal to `self.len() + additional` if + /// it returns `Ok(())`. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely @@ -791,10 +791,10 @@ impl VecDeque { } /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given deque. The collection may reserve more space to avoid + /// in the given deque. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// greater than or equal to `self.len() + additional` if it returns + /// `Ok(())`. Does nothing if capacity is already sufficient. /// /// # Errors /// diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 668af60611b86..8883880726594 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -455,13 +455,13 @@ impl String { String { vec: Vec::new() } } - /// Creates a new empty `String` with a particular capacity. + /// Creates a new empty `String` with at least the specified capacity. /// /// `String`s have an internal buffer to hold their data. The capacity is /// the length of that buffer, and can be queried with the [`capacity`] /// method. This method creates an empty `String`, but one with an initial - /// buffer that can hold `capacity` bytes. This is useful when you may be - /// appending a bunch of data to the `String`, reducing the number of + /// buffer that can hold at least `capacity` bytes. This is useful when you + /// may be appending a bunch of data to the `String`, reducing the number of /// reallocations it needs to do. /// /// [`capacity`]: String::capacity @@ -979,21 +979,16 @@ impl String { self.vec.capacity() } - /// Ensures that this `String`'s capacity is at least `additional` bytes - /// larger than its length. - /// - /// The capacity may be increased by more than `additional` bytes if it - /// chooses, to prevent frequent reallocations. - /// - /// If you do not want this "at least" behavior, see the [`reserve_exact`] - /// method. + /// Reserves capacity for at least `additional` bytes more than the + /// current length. The allocator may reserve more space to speculatively + /// avoid frequent allocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. /// /// # Panics /// /// Panics if the new capacity overflows [`usize`]. /// - /// [`reserve_exact`]: String::reserve_exact - /// /// # Examples /// /// Basic usage: @@ -1013,15 +1008,16 @@ impl String { /// s.push('a'); /// s.push('b'); /// - /// // s now has a length of 2 and a capacity of 10 + /// // s now has a length of 2 and a capacity of at least 10 + /// let capacity = s.capacity(); /// assert_eq!(2, s.len()); - /// assert_eq!(10, s.capacity()); + /// assert!(capacity >= 10); /// - /// // Since we already have an extra 8 capacity, calling this... + /// // Since we already have at least an extra 8 capacity, calling this... /// s.reserve(8); /// /// // ... doesn't actually increase. - /// assert_eq!(10, s.capacity()); + /// assert_eq!(capacity, s.capacity()); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -1030,17 +1026,18 @@ impl String { self.vec.reserve(additional) } - /// Ensures that this `String`'s capacity is `additional` bytes - /// larger than its length. - /// - /// Consider using the [`reserve`] method unless you absolutely know - /// better than the allocator. + /// Reserves the minimum capacity for at least `additional` bytes more than + /// the current length. Unlike [`reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. /// /// [`reserve`]: String::reserve /// /// # Panics /// - /// Panics if the new capacity overflows `usize`. + /// Panics if the new capacity overflows [`usize`]. /// /// # Examples /// @@ -1061,15 +1058,16 @@ impl String { /// s.push('a'); /// s.push('b'); /// - /// // s now has a length of 2 and a capacity of 10 + /// // s now has a length of 2 and a capacity of at least 10 + /// let capacity = s.capacity(); /// assert_eq!(2, s.len()); - /// assert_eq!(10, s.capacity()); + /// assert!(capacity >= 10); /// - /// // Since we already have an extra 8 capacity, calling this... + /// // Since we already have at least an extra 8 capacity, calling this... /// s.reserve_exact(8); /// /// // ... doesn't actually increase. - /// assert_eq!(10, s.capacity()); + /// assert_eq!(capacity, s.capacity()); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -1078,11 +1076,11 @@ impl String { self.vec.reserve_exact(additional) } - /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `String`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// Tries to reserve capacity for at least `additional` bytes more than the + /// current length. The allocator may reserve more space to speculatively + /// avoid frequent allocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional` if it returns + /// `Ok(())`. Does nothing if capacity is already sufficient. /// /// # Errors /// @@ -1112,9 +1110,11 @@ impl String { self.vec.try_reserve(additional) } - /// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `String`. After calling `try_reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. + /// Tries to reserve the minimum capacity for at least `additional` bytes + /// more than the current length. Unlike [`try_reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `try_reserve_exact`, capacity will be greater than or + /// equal to `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1c0cb6636a134..e25f98d8aa695 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -425,17 +425,25 @@ impl Vec { Vec { buf: RawVec::NEW, len: 0 } } - /// Constructs a new, empty `Vec` with the specified capacity. + /// Constructs a new, empty `Vec` with at least the specified capacity. /// - /// The vector will be able to hold exactly `capacity` elements without - /// reallocating. If `capacity` is 0, the vector will not allocate. + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. /// /// It is important to note that although the returned vector has the - /// *capacity* specified, the vector will have a zero *length*. For an - /// explanation of the difference between length and capacity, see + /// minimum *capacity* specified, the vector will have a zero *length*. For + /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// + /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// always use the [`capacity`] method after construction. + /// + /// For `Vec` where `T` is a zero-sized type, there will be no allocation + /// and the capacity will always be `usize::MAX`. + /// /// [Capacity and reallocation]: #capacity-and-reallocation + /// [`capacity`]: Vec::capacity /// /// # Panics /// @@ -448,19 +456,24 @@ impl Vec { /// /// // The vector contains no items, even though it has capacity for more /// assert_eq!(vec.len(), 0); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// /// // These are all done without reallocating... /// for i in 0..10 { /// vec.push(i); /// } /// assert_eq!(vec.len(), 10); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// /// // ...but this may make the vector reallocate /// vec.push(11); /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); + /// + /// // A vector of a zero-sized type will always over-allocate, since no + /// // allocation is necessary + /// let vec_units = Vec::<()>::with_capacity(10); + /// assert_eq!(vec_units.capacity(), usize::MAX); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -566,18 +579,26 @@ impl Vec { Vec { buf: RawVec::new_in(alloc), len: 0 } } - /// Constructs a new, empty `Vec` with the specified capacity with the provided - /// allocator. + /// Constructs a new, empty `Vec` with at least the specified capacity + /// with the provided allocator. /// - /// The vector will be able to hold exactly `capacity` elements without - /// reallocating. If `capacity` is 0, the vector will not allocate. + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. /// /// It is important to note that although the returned vector has the - /// *capacity* specified, the vector will have a zero *length*. For an - /// explanation of the difference between length and capacity, see + /// minimum *capacity* specified, the vector will have a zero *length*. For + /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// + /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// always use the [`capacity`] method after construction. + /// + /// For `Vec` where `T` is a zero-sized type, there will be no allocation + /// and the capacity will always be `usize::MAX`. + /// /// [Capacity and reallocation]: #capacity-and-reallocation + /// [`capacity`]: Vec::capacity /// /// # Panics /// @@ -607,6 +628,11 @@ impl Vec { /// vec.push(11); /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); + /// + /// // A vector of a zero-sized type will always over-allocate, since no + /// // allocation is necessary + /// let vec_units = Vec::<(), System>::with_capacity_in(10, System); + /// assert_eq!(vec_units.capacity(), usize::MAX); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -793,10 +819,10 @@ impl Vec { } /// Reserves capacity for at least `additional` more elements to be inserted - /// in the given `Vec`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// in the given `Vec`. The collection may reserve more space to + /// speculatively avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. /// /// # Panics /// @@ -815,10 +841,12 @@ impl Vec { self.buf.reserve(self.len, additional); } - /// Reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `Vec`. After calling `reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. - /// Does nothing if the capacity is already sufficient. + /// Reserves the minimum capacity for at least `additional` more elements to + /// be inserted in the given `Vec`. Unlike [`reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely @@ -844,10 +872,10 @@ impl Vec { } /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `Vec`. The collection may reserve more space to avoid + /// in the given `Vec`. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// greater than or equal to `self.len() + additional` if it returns + /// `Ok(())`. Does nothing if capacity is already sufficient. /// /// # Errors /// @@ -879,10 +907,11 @@ impl Vec { self.buf.try_reserve(self.len, additional) } - /// Tries to reserve the minimum capacity for exactly `additional` - /// elements to be inserted in the given `Vec`. After calling - /// `try_reserve_exact`, capacity will be greater than or equal to - /// `self.len() + additional` if it returns `Ok(())`. + /// Tries to reserve the minimum capacity for at least `additional` + /// elements to be inserted in the given `Vec`. Unlike [`try_reserve`], + /// this will not deliberately over-allocate to speculatively avoid frequent + /// allocations. After calling `try_reserve_exact`, capacity will be greater + /// than or equal to `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index cc768c73c0e03..5520f6ebf1904 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -2128,6 +2128,15 @@ fn test_vec_cycle_wrapped() { c3.refs.v[1].set(Some(&c2)); } +#[test] +fn test_zero_sized_capacity() { + for len in [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] { + let v = Vec::<()>::with_capacity(len); + assert_eq!(v.len(), 0); + assert_eq!(v.capacity(), usize::MAX); + } +} + #[test] fn test_zero_sized_vec_push() { const N: usize = 8; diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 192a21f2ffc2d..499c997a36ab2 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -233,10 +233,11 @@ impl HashMap { Default::default() } - /// Creates an empty `HashMap` with the specified capacity. + /// Creates an empty `HashMap` with at least the specified capacity. /// /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the hash set will not allocate. /// /// # Examples /// @@ -282,18 +283,19 @@ impl HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } } - /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` - /// to hash the keys. + /// Creates an empty `HashMap` with at least the specified capacity, using + /// `hasher` to hash the keys. /// /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the hash map will not allocate. /// - /// Warning: `hash_builder` is normally randomly generated, and + /// Warning: `hasher` is normally randomly generated, and /// is designed to allow HashMaps to be resistant to attacks that /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// The `hasher` passed should implement the [`BuildHasher`] trait for /// the HashMap to be useful, see its documentation for details. /// /// # Examples @@ -308,8 +310,8 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) } + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { + HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } } /// Returns the number of elements the map can hold without reallocating. @@ -731,8 +733,10 @@ where S: BuildHasher, { /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. + /// in the `HashMap`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. /// /// # Panics /// @@ -752,8 +756,11 @@ where } /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. + /// in the `HashMap`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional` if + /// it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. /// /// # Errors /// @@ -766,7 +773,7 @@ where /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, isize> = HashMap::new(); - /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// map.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?"); /// ``` #[inline] #[stable(feature = "try_reserve", since = "1.57.0")] diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index fa498a987d6af..abff82788a38d 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -133,10 +133,11 @@ impl HashSet { Default::default() } - /// Creates an empty `HashSet` with the specified capacity. + /// Creates an empty `HashSet` with at least the specified capacity. /// /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the hash set will not allocate. /// /// # Examples /// @@ -379,11 +380,12 @@ impl HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } } - /// Creates an empty `HashSet` with the specified capacity, using + /// Creates an empty `HashSet` with at least the specified capacity, using /// `hasher` to hash the keys. /// /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the hash set will not allocate. /// /// Warning: `hasher` is normally randomly generated, and /// is designed to allow `HashSet`s to be resistant to attacks that @@ -434,8 +436,10 @@ where S: BuildHasher, { /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `HashSet`. The collection may reserve more space to avoid - /// frequent reallocations. + /// in the `HashSet`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. /// /// # Panics /// @@ -456,8 +460,11 @@ where } /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `HashSet`. The collection may reserve more space to avoid - /// frequent reallocations. + /// in the `HashSet`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional` if + /// it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. /// /// # Errors /// @@ -469,7 +476,7 @@ where /// ``` /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); - /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// set.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?"); /// ``` #[inline] #[stable(feature = "try_reserve", since = "1.57.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 95d274c3c91e7..f2bbcc85cecda 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -196,10 +196,11 @@ impl OsString { self.inner.push_slice(&s.as_ref().inner) } - /// Creates a new `OsString` with the given capacity. + /// Creates a new `OsString` with at least the given capacity. /// - /// The string will be able to hold exactly `capacity` length units of other - /// OS strings without reallocating. If `capacity` is 0, the string will not + /// The string will be able to hold at least `capacity` length units of other + /// OS strings without reallocating. This method is allowed to allocate for + /// more units than `capacity`. If `capacity` is 0, the string will not /// allocate. /// /// See the main `OsString` documentation information about encoding and capacity units. @@ -263,9 +264,10 @@ impl OsString { } /// Reserves capacity for at least `additional` more capacity to be inserted - /// in the given `OsString`. + /// in the given `OsString`. Does nothing if the capacity is + /// already sufficient. /// - /// The collection may reserve more space to avoid frequent reallocations. + /// The collection may reserve more space to speculatively avoid frequent reallocations. /// /// See the main `OsString` documentation information about encoding and capacity units. /// @@ -285,10 +287,10 @@ impl OsString { } /// Tries to reserve capacity for at least `additional` more length units - /// in the given `OsString`. The string may reserve more space to avoid + /// in the given `OsString`. The string may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. /// /// See the main `OsString` documentation information about encoding and capacity units. /// @@ -322,7 +324,7 @@ impl OsString { self.inner.try_reserve(additional) } - /// Reserves the minimum capacity for exactly `additional` more capacity to + /// Reserves the minimum capacity for at least `additional` more capacity to /// be inserted in the given `OsString`. Does nothing if the capacity is /// already sufficient. /// @@ -349,7 +351,7 @@ impl OsString { self.inner.reserve_exact(additional) } - /// Tries to reserve the minimum capacity for exactly `additional` + /// Tries to reserve the minimum capacity for at least `additional` /// more length units in the given `OsString`. After calling /// `try_reserve_exact`, capacity will be greater than or equal to /// `self.len() + additional` if it returns `Ok(())`. diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 2d3a0f37b4c2a..6acb937e78479 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -97,11 +97,11 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufWriter` with the specified buffer capacity. + /// Creates a new `BufWriter` with at least the specified buffer capacity. /// /// # Examples /// - /// Creating a buffer with a buffer of a hundred bytes. + /// Creating a buffer with a buffer of at least a hundred bytes. /// /// ```no_run /// use std::io::BufWriter; diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs index d7b620d6f9177..a26a4ab330e7a 100644 --- a/library/std/src/io/buffered/linewriter.rs +++ b/library/std/src/io/buffered/linewriter.rs @@ -89,8 +89,8 @@ impl LineWriter { LineWriter::with_capacity(1024, inner) } - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. + /// Creates a new `LineWriter` with at least the specified capacity for the + /// internal buffer. /// /// # Examples /// From 1deca0425db3e74a61cb732e729c0777904e549c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 19 Jun 2022 13:59:36 -0500 Subject: [PATCH 02/24] Greatly improve error reporting for futures and generators in `note_obligation_cause_code` Most futures don't go through this code path, because they're caught by `maybe_note_obligation_cause_for_async_await`. But all generators do, and `maybe_note` is imperfect and doesn't catch all futures. Improve the error message for those it misses. At some point, we may want to consider unifying this with the code for `maybe_note_async_await`, so that `async_await` notes all parent constraints, and `note_obligation` can point to yield points. But both functions are quite complicated, and it's not clear to me how to combine them; this seems like a good incremental improvement. --- .../src/traits/error_reporting/suggestions.rs | 105 ++++++++++++++++-- src/test/ui/async-await/issue-68112.stderr | 30 +++-- ...e-70935-complex-spans.drop_tracking.stderr | 40 +++++++ ...> issue-70935-complex-spans.normal.stderr} | 8 +- .../async-await/issue-70935-complex-spans.rs | 16 ++- .../partial-drop-partial-reinit.rs | 8 ++ .../partial-drop-partial-reinit.stderr | 20 +++- src/test/ui/closures/closure-move-sync.stderr | 16 ++- src/test/ui/generator/issue-68112.rs | 22 +++- src/test/ui/generator/issue-68112.stderr | 41 +++++-- src/test/ui/generator/not-send-sync.stderr | 11 +- .../print/generator-print-verbose-1.stderr | 33 +++++- .../print/generator-print-verbose-2.stderr | 11 +- src/test/ui/impl-trait/auto-trait-leak2.rs | 18 ++- .../ui/impl-trait/auto-trait-leak2.stderr | 32 ++++-- .../interior-mutability.stderr | 6 +- .../ui/kindck/kindck-nonsendable-1.stderr | 6 +- src/test/ui/no-send-res-ports.stderr | 11 +- src/test/ui/not-clone-closure.stderr | 9 +- .../auto-trait-leakage2.rs | 8 +- .../auto-trait-leakage2.stderr | 10 +- 21 files changed, 389 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr rename src/test/ui/async-await/{issue-70935-complex-spans.stderr => issue-70935-complex-spans.normal.stderr} (81%) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 09b73b982a0c1..159fcf932a1da 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -8,6 +8,7 @@ use crate::infer::InferCtxt; use crate::traits::normalize_to; use hir::HirId; +use rustc_ast::Movability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -2397,24 +2398,104 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); - let ty = parent_trait_ref.skip_binder().self_ty(); - matches!(ty.kind(), ty::Generator(..)) - || matches!(ty.kind(), ty::Closure(..)) + let nested_ty = parent_trait_ref.skip_binder().self_ty(); + matches!(nested_ty.kind(), ty::Generator(..)) + || matches!(nested_ty.kind(), ty::Closure(..)) } else { false } }; + let future_trait = self.tcx.lang_items().future_trait().unwrap(); + let opaque_ty_is_future = |def_id| { + self.tcx.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { + if let ty::PredicateKind::Trait(trait_predicate) = + predicate.kind().skip_binder() + { + trait_predicate.trait_ref.def_id == future_trait + } else { + false + } + }) + }; + + let from_generator = tcx.lang_items().from_generator_fn().unwrap(); + // Don't print the tuple of capture types - if !is_upvar_tys_infer_tuple { - let msg = format!("required because it appears within the type `{}`", ty); - match ty.kind() { - ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { - Some(ident) => err.span_note(ident.span, &msg), - None => err.note(&msg), - }, - _ => err.note(&msg), - }; + 'print: { + if !is_upvar_tys_infer_tuple { + let msg = format!("required because it appears within the type `{}`", ty); + match ty.kind() { + ty::Adt(def, _) => { + // `gen_future` is used in all async functions; it doesn't add any additional info. + if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) { + break 'print; + } + match self.tcx.opt_item_ident(def.did()) { + Some(ident) => err.span_note(ident.span, &msg), + None => err.note(&msg), + } + } + ty::Opaque(def_id, _) => { + // Avoid printing the future from `core::future::from_generator`, it's not helpful + if tcx.parent(*def_id) == from_generator { + break 'print; + } + + // If the previous type is `from_generator`, this is the future generated by the body of an async function. + // Avoid printing it twice (it was already printed in the `ty::Generator` arm below). + let is_future = opaque_ty_is_future(def_id); + debug!( + ?obligated_types, + ?is_future, + "note_obligation_cause_code: check for async fn" + ); + if opaque_ty_is_future(def_id) + && obligated_types.last().map_or(false, |ty| match ty.kind() { + ty::Opaque(last_def_id, _) => { + tcx.parent(*last_def_id) == from_generator + } + _ => false, + }) + { + break 'print; + } + err.span_note(self.tcx.def_span(def_id), &msg) + } + ty::GeneratorWitness(bound_tys) => { + use std::fmt::Write; + + // FIXME: this is kind of an unusual format for rustc, can we make it more clear? + // Maybe we should just remove this note altogether? + // FIXME: only print types which don't meet the trait requirement + let mut msg = + "required because it captures the following types: ".to_owned(); + for ty in bound_tys.skip_binder() { + write!(msg, "`{}`, ", ty).unwrap(); + } + err.note(msg.trim_end_matches(", ")) + } + ty::Generator(def_id, _, movability) => { + let sp = self.tcx.def_span(def_id); + + // Special-case this to say "async block" instead of `[static generator]`. + let kind = if *movability == Movability::Static { + "async block" + } else { + "generator" + }; + err.span_note( + sp, + &format!("required because it's used within this {}", kind), + ) + } + ty::Closure(def_id, _) => err.span_note( + self.tcx.def_span(def_id), + &format!("required because it's used within this closure"), + ), + _ => err.note(&msg), + }; + } } obligated_types.push(ty); diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 28d94b14ac914..b8d3e1540d8a9 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -42,15 +42,27 @@ LL | require_send(send_fut); | = help: the trait `Sync` is not implemented for `RefCell` = note: required because of the requirements on the impl of `Send` for `Arc>` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>` - = note: required because it appears within the type `impl Future>>` - = note: required because it appears within the type `impl Future>>` - = note: required because it appears within the type `impl Future>>` - = note: required because it appears within the type `{ResumeTy, impl Future>>, (), i32, Ready}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>` - = note: required because it appears within the type `impl Future` +note: required because it's used within this async block + --> $DIR/issue-68112.rs:47:31 + | +LL | async fn ready2(t: T) -> T { t } + | ^^^^^ +note: required because it appears within the type `impl Future>>` + --> $DIR/issue-68112.rs:48:31 + | +LL | fn make_non_send_future2() -> impl Future>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `ResumeTy`, `impl Future>>`, `()`, `i32`, `Ready` +note: required because it's used within this async block + --> $DIR/issue-68112.rs:55:26 + | +LL | let send_fut = async { + | __________________________^ +LL | | let non_send_fut = make_non_send_future2(); +LL | | let _ = non_send_fut.await; +LL | | ready(0).await; +LL | | }; + | |_____^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:11:25 | diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr new file mode 100644 index 0000000000000..19fd5eb7c73fb --- /dev/null +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -0,0 +1,40 @@ +error[E0277]: `Sender` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:13:45 + | +LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `Sender` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Sender` + = note: required because of the requirements on the impl of `Send` for `&Sender` +note: required because it's used within this closure + --> $DIR/issue-70935-complex-spans.rs:25:13 + | +LL | baz(|| async{ + | _____________^ +LL | | foo(tx.clone()); +LL | | }).await; + | |_________^ +note: required because it's used within this async block + --> $DIR/issue-70935-complex-spans.rs:9:67 + | +LL | async fn baz(_c: impl FnMut() -> T) where T: Future { + | ___________________________________________________________________^ +LL | | +LL | | } + | |_^ + = note: required because it captures the following types: `ResumeTy`, `impl Future`, `()` +note: required because it's used within this async block + --> $DIR/issue-70935-complex-spans.rs:23:16 + | +LL | async move { + | ________________^ +LL | | +LL | | baz(|| async{ +LL | | foo(tx.clone()); +LL | | }).await; +LL | | } + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr similarity index 81% rename from src/test/ui/async-await/issue-70935-complex-spans.stderr rename to src/test/ui/async-await/issue-70935-complex-spans.normal.stderr index db3099381196b..2174f260a7135 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-70935-complex-spans.rs:10:45 + --> $DIR/issue-70935-complex-spans.rs:13:45 | LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `Sender` note: future is not `Send` as this value is used across an await - --> $DIR/issue-70935-complex-spans.rs:15:11 + --> $DIR/issue-70935-complex-spans.rs:27:11 | LL | baz(|| async{ | _____________- @@ -14,9 +14,9 @@ LL | | foo(tx.clone()); LL | | }).await; | | - ^^^^^^ await occurs here, with the value maybe used later | |_________| - | has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send` + | has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 27:10]` which is not `Send` note: the value is later dropped here - --> $DIR/issue-70935-complex-spans.rs:15:17 + --> $DIR/issue-70935-complex-spans.rs:27:17 | LL | }).await; | ^ diff --git a/src/test/ui/async-await/issue-70935-complex-spans.rs b/src/test/ui/async-await/issue-70935-complex-spans.rs index 2965a7e0654a4..4bf94fe342c1d 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.rs +++ b/src/test/ui/async-await/issue-70935-complex-spans.rs @@ -1,16 +1,28 @@ // edition:2018 +// revisions: normal drop_tracking +// [drop_tracking]compile-flags:-Zdrop-tracking // #70935: Check if we do not emit snippet // with newlines which lead complex diagnostics. use std::future::Future; async fn baz(_c: impl FnMut() -> T) where T: Future { +//[drop_tracking]~^ within this async block } fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { - //~^ ERROR: future cannot be sent between threads safely + //[normal]~^ ERROR: future cannot be sent between threads safely + //[drop_tracking]~^^ ERROR: `Sender` cannot be shared + //[drop_tracking]~| NOTE: cannot be shared + //[drop_tracking]~| NOTE: requirements on the impl of `Send` + //[drop_tracking]~| NOTE: captures the following types + //[drop_tracking]~| NOTE: in this expansion + //[drop_tracking]~| NOTE: in this expansion + //[drop_tracking]~| NOTE: in this expansion + //[drop_tracking]~| NOTE: in this expansion async move { - baz(|| async{ + //[drop_tracking]~^ within this async block + baz(|| async{ //[drop_tracking]~ NOTE: used within this closure foo(tx.clone()); }).await; } diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs index 73f0ca8153cb9..4fcfacea3f886 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.rs +++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs @@ -5,9 +5,15 @@ fn main() { gimme_send(foo()); //~^ ERROR cannot be sent between threads safely + //~| NOTE cannot be sent + //~| NOTE bound introduced by + //~| NOTE appears within the type + //~| NOTE captures the following types } fn gimme_send(t: T) { +//~^ NOTE required by this bound +//~| NOTE required by a bound drop(t); } @@ -20,6 +26,8 @@ impl Drop for NotSend { impl !Send for NotSend {} async fn foo() { +//~^ NOTE used within this async block +//~| NOTE within this `impl Future let mut x = (NotSend {},); drop(x.0); x.0 = NotSend {}; diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr index a1c4957e9843a..96d0c71f103fb 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr @@ -11,13 +11,21 @@ LL | async fn foo() { | = help: within `impl Future`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` - = note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>` - = note: required because it appears within the type `impl Future` - = note: required because it appears within the type `impl Future` + = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future`, `()` +note: required because it's used within this async block + --> $DIR/partial-drop-partial-reinit.rs:28:16 + | +LL | async fn foo() { + | ________________^ +LL | | +LL | | +LL | | let mut x = (NotSend {},); +... | +LL | | bar().await; +LL | | } + | |_^ note: required by a bound in `gimme_send` - --> $DIR/partial-drop-partial-reinit.rs:10:18 + --> $DIR/partial-drop-partial-reinit.rs:14:18 | LL | fn gimme_send(t: T) { | ^^^^ required by this bound in `gimme_send` diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr index 618c9a172473c..cbc4e2e52315f 100644 --- a/src/test/ui/closures/closure-move-sync.stderr +++ b/src/test/ui/closures/closure-move-sync.stderr @@ -6,7 +6,15 @@ LL | let t = thread::spawn(|| { | = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>` = note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]` +note: required because it's used within this closure + --> $DIR/closure-move-sync.rs:6:27 + | +LL | let t = thread::spawn(|| { + | ___________________________^ +LL | | recv.recv().unwrap(); +LL | | +LL | | }); + | |_____^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | @@ -21,7 +29,11 @@ LL | thread::spawn(|| tx.send(()).unwrap()); | = help: the trait `Sync` is not implemented for `Sender<()>` = note: required because of the requirements on the impl of `Send` for `&Sender<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]` +note: required because it's used within this closure + --> $DIR/closure-move-sync.rs:18:19 + | +LL | thread::spawn(|| tx.send(()).unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs index feb07c9bf8802..3fcef773b68ab 100644 --- a/src/test/ui/generator/issue-68112.rs +++ b/src/test/ui/generator/issue-68112.rs @@ -20,6 +20,10 @@ pub fn make_gen1(t: T) -> Ready { } fn require_send(_: impl Send) {} +//~^ NOTE required by a bound +//~| NOTE required by a bound +//~| NOTE required by this bound +//~| NOTE required by this bound fn make_non_send_generator() -> impl Generator>> { make_gen1(Arc::new(RefCell::new(0))) @@ -28,29 +32,39 @@ fn make_non_send_generator() -> impl Generator>> { fn test1() { let send_gen = || { let _non_send_gen = make_non_send_generator(); + //~^ NOTE not `Send` yield; - }; + //~^ NOTE yield occurs here + //~| NOTE value is used across a yield + }; //~ NOTE later dropped here require_send(send_gen); //~^ ERROR generator cannot be sent between threads + //~| NOTE not `Send` } pub fn make_gen2(t: T) -> impl Generator { - || { +//~^ NOTE appears within the type +//~| NOTE expansion of desugaring + || { //~ NOTE used within this generator yield; t } } -fn make_non_send_generator2() -> impl Generator>> { +fn make_non_send_generator2() -> impl Generator>> { //~ NOTE appears within the type +//~^ NOTE expansion of desugaring make_gen2(Arc::new(RefCell::new(0))) } fn test2() { - let send_gen = || { + let send_gen = || { //~ NOTE used within this generator let _non_send_gen = make_non_send_generator2(); yield; }; require_send(send_gen); //~^ ERROR `RefCell` cannot be shared between threads safely + //~| NOTE `RefCell` cannot be shared between threads safely + //~| NOTE requirements on the impl + //~| NOTE captures the following types } fn main() {} diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index a7d7a73254886..83f068c207643 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -1,17 +1,19 @@ error: generator cannot be sent between threads safely - --> $DIR/issue-68112.rs:33:5 + --> $DIR/issue-68112.rs:40:5 | LL | require_send(send_gen); | ^^^^^^^^^^^^ generator is not `Send` | = help: the trait `Sync` is not implemented for `RefCell` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-68112.rs:31:9 + --> $DIR/issue-68112.rs:36:9 | LL | let _non_send_gen = make_non_send_generator(); | ------------- has type `impl Generator>>` which is not `Send` +LL | LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +... LL | }; | - `_non_send_gen` is later dropped here note: required by a bound in `require_send` @@ -21,18 +23,41 @@ LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` error[E0277]: `RefCell` cannot be shared between threads safely - --> $DIR/issue-68112.rs:52:5 + --> $DIR/issue-68112.rs:63:5 | LL | require_send(send_gen); | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `RefCell` = note: required because of the requirements on the impl of `Send` for `Arc>` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]` - = note: required because it appears within the type `impl Generator>>` - = note: required because it appears within the type `impl Generator>>` - = note: required because it appears within the type `{impl Generator>>, ()}` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:48:5 + | +LL | / || { +LL | | yield; +LL | | t +LL | | } + | |_____^ +note: required because it appears within the type `impl Generator>>` + --> $DIR/issue-68112.rs:45:30 + | +LL | pub fn make_gen2(t: T) -> impl Generator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `impl Generator>>` + --> $DIR/issue-68112.rs:53:34 + | +LL | fn make_non_send_generator2() -> impl Generator>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `impl Generator>>`, `()` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:59:20 + | +LL | let send_gen = || { + | ____________________^ +LL | | let _non_send_gen = make_non_send_generator2(); +LL | | yield; +LL | | }; + | |_____^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:22:25 | diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 4d2faa198f1af..edf9ee628a2bc 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -6,7 +6,16 @@ LL | assert_send(|| { | = help: the trait `Sync` is not implemented for `Cell` = note: required because of the requirements on the impl of `Send` for `&Cell` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6]` +note: required because it's used within this generator + --> $DIR/not-send-sync.rs:16:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | drop(&a); +LL | | yield; +LL | | }); + | |_____^ note: required by a bound in `assert_send` --> $DIR/not-send-sync.rs:7:23 | diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr index 2f7faf520d969..3ee4c1458bad3 100644 --- a/src/test/ui/generator/print/generator-print-verbose-1.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -28,11 +28,34 @@ LL | require_send(send_gen); | = help: the trait `Sync` is not implemented for `RefCell` = note: required because of the requirements on the impl of `Send` for `Arc>` - = note: required because it appears within the type `[make_gen2>>::{closure#0} upvar_tys=(Arc>) {()}]` - = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc>])` - = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` - = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), []), ()}` - = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), []), ()}]` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:42:5 + | +LL | / || { +LL | | yield; +LL | | t +LL | | } + | |_____^ +note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc>])` + --> $DIR/generator-print-verbose-1.rs:41:30 + | +LL | pub fn make_gen2(t: T) -> impl Generator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` + --> $DIR/generator-print-verbose-1.rs:47:34 + | +LL | fn make_non_send_generator2() -> impl Generator>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:52:20 + | +LL | let send_gen = || { + | ____________________^ +LL | | let _non_send_gen = make_non_send_generator2(); +LL | | yield; +LL | | }; + | |_____^ note: required by a bound in `require_send` --> $DIR/generator-print-verbose-1.rs:26:25 | diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr index fb2a5754dd306..1356fa5f15295 100644 --- a/src/test/ui/generator/print/generator-print-verbose-2.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -6,7 +6,16 @@ LL | assert_send(|| { | = help: the trait `Sync` is not implemented for `Cell` = note: required because of the requirements on the impl of `Send` for `&'_#4r Cell` - = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#4r Cell) _#17t]` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-2.rs:19:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | drop(&a); +LL | | yield; +LL | | }); + | |_____^ note: required by a bound in `assert_send` --> $DIR/generator-print-verbose-2.rs:10:23 | diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index a464f576dc783..09450089adaa8 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -3,23 +3,37 @@ use std::rc::Rc; // Fast path, main can see the concrete type returned. fn before() -> impl Fn(i32) { +//~^ NOTE within this `impl Fn +//~| NOTE within the type `impl Fn +//~| NOTE expansion of desugaring let p = Rc::new(Cell::new(0)); - move |x| p.set(x) + move |x| p.set(x) //~ NOTE used within this closure } fn send(_: T) {} +//~^ NOTE required by a bound +//~| NOTE required by a bound +//~| NOTE required by this bound +//~| NOTE required by this bound fn main() { send(before()); //~^ ERROR `Rc>` cannot be sent between threads safely + //~| NOTE `Rc>` cannot be sent between threads safely + //~| NOTE required by a bound send(after()); //~^ ERROR `Rc>` cannot be sent between threads safely + //~| NOTE `Rc>` cannot be sent between threads safely + //~| NOTE required by a bound } // Deferred path, main has to wait until typeck finishes, // to check if the return type of after is Send. fn after() -> impl Fn(i32) { +//~^ NOTE within this `impl Fn(i32)` +//~| NOTE in this expansion +//~| NOTE appears within the type let p = Rc::new(Cell::new(0)); - move |x| p.set(x) + move |x| p.set(x) //~ NOTE used within this closure } diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index 37ae3c6802964..d825843492d49 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,5 +1,5 @@ error[E0277]: `Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:13:10 + --> $DIR/auto-trait-leak2.rs:20:10 | LL | fn before() -> impl Fn(i32) { | ------------ within this `impl Fn(i32)` @@ -10,16 +10,24 @@ LL | send(before()); | required by a bound introduced by this call | = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]` - = note: required because it appears within the type `impl Fn(i32)` +note: required because it's used within this closure + --> $DIR/auto-trait-leak2.rs:10:5 + | +LL | move |x| p.set(x) + | ^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `impl Fn(i32)` + --> $DIR/auto-trait-leak2.rs:5:16 + | +LL | fn before() -> impl Fn(i32) { + | ^^^^^^^^^^^^ note: required by a bound in `send` - --> $DIR/auto-trait-leak2.rs:10:12 + --> $DIR/auto-trait-leak2.rs:13:12 | LL | fn send(_: T) {} | ^^^^ required by this bound in `send` error[E0277]: `Rc>` cannot be sent between threads safely - --> $DIR/auto-trait-leak2.rs:16:10 + --> $DIR/auto-trait-leak2.rs:25:10 | LL | send(after()); | ---- ^^^^^^^ `Rc>` cannot be sent between threads safely @@ -30,10 +38,18 @@ LL | fn after() -> impl Fn(i32) { | ------------ within this `impl Fn(i32)` | = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]` - = note: required because it appears within the type `impl Fn(i32)` +note: required because it's used within this closure + --> $DIR/auto-trait-leak2.rs:38:5 + | +LL | move |x| p.set(x) + | ^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `impl Fn(i32)` + --> $DIR/auto-trait-leak2.rs:33:15 + | +LL | fn after() -> impl Fn(i32) { + | ^^^^^^^^^^^^ note: required by a bound in `send` - --> $DIR/auto-trait-leak2.rs:10:12 + --> $DIR/auto-trait-leak2.rs:13:12 | LL | fn send(_: T) {} | ^^^^ required by this bound in `send` diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index cb22d5adb717d..66fe3c74e2c87 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -7,7 +7,11 @@ LL | catch_unwind(|| { x.set(23); }); = help: within `Cell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` = note: required because it appears within the type `Cell` = note: required because of the requirements on the impl of `UnwindSafe` for `&Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35]` +note: required because it's used within this closure + --> $DIR/interior-mutability.rs:5:18 + | +LL | catch_unwind(|| { x.set(23); }); + | ^^^^^^^^^^^^^^^^^ note: required by a bound in `catch_unwind` --> $SRC_DIR/std/src/panic.rs:LL:COL | diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index b3ebe7f5c7dc3..727573a0be4ed 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -7,7 +7,11 @@ LL | bar(move|| foo(x)); | `Rc` cannot be sent between threads safely | = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc` - = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` +note: required because it's used within this closure + --> $DIR/kindck-nonsendable-1.rs:9:9 + | +LL | bar(move|| foo(x)); + | ^^^^^^^^^^^^^ note: required by a bound in `bar` --> $DIR/kindck-nonsendable-1.rs:5:21 | diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index 80708c989fcf7..e4c57c04e7269 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -22,7 +22,16 @@ note: required because it appears within the type `Foo` | LL | struct Foo { | ^^^ - = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` +note: required because it's used within this closure + --> $DIR/no-send-res-ports.rs:25:19 + | +LL | thread::spawn(move|| { + | ___________________^ +LL | | +LL | | let y = x; +LL | | println!("{:?}", y); +LL | | }); + | |_____^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index 78b35569c2162..bebf561b120b5 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -10,7 +10,14 @@ LL | LL | let hello = hello.clone(); | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S` | - = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` +note: required because it's used within this closure + --> $DIR/not-clone-closure.rs:7:17 + | +LL | let hello = move || { + | _________________^ +LL | | println!("Hello {}", a.0); +LL | | }; + | |_____^ help: consider annotating `S` with `#[derive(Clone)]` | LL | #[derive(Clone)] diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.rs index 745379efa6df9..fc89b0e870e39 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.rs +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.rs @@ -4,7 +4,9 @@ mod m { use std::rc::Rc; - type Foo = impl std::fmt::Debug; + type Foo = impl std::fmt::Debug; //~ NOTE appears within the type + //~^ within this `Foo` + //~| expansion of desugaring pub fn foo() -> Foo { Rc::new(22_u32) @@ -12,8 +14,12 @@ mod m { } fn is_send(_: T) {} +//~^ required by this bound +//~| required by a bound fn main() { is_send(m::foo()); //~^ ERROR: `Rc` cannot be sent between threads safely [E0277] + //~| NOTE cannot be sent + //~| NOTE required by a bound } diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr index 0664275b2ad0a..d7247302dd1e0 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr @@ -1,5 +1,5 @@ error[E0277]: `Rc` cannot be sent between threads safely - --> $DIR/auto-trait-leakage2.rs:17:13 + --> $DIR/auto-trait-leakage2.rs:21:13 | LL | type Foo = impl std::fmt::Debug; | -------------------- within this `Foo` @@ -10,9 +10,13 @@ LL | is_send(m::foo()); | required by a bound introduced by this call | = help: within `Foo`, the trait `Send` is not implemented for `Rc` - = note: required because it appears within the type `Foo` +note: required because it appears within the type `Foo` + --> $DIR/auto-trait-leakage2.rs:7:16 + | +LL | type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `is_send` - --> $DIR/auto-trait-leakage2.rs:14:15 + --> $DIR/auto-trait-leakage2.rs:16:15 | LL | fn is_send(_: T) {} | ^^^^ required by this bound in `is_send` From 1e7ab0bbd772d4dab2a66a72af20f8b207c252ab Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 20 Jun 2022 16:29:05 +0900 Subject: [PATCH 03/24] point at private fields in struct literal --- Cargo.lock | 1 + compiler/rustc_typeck/Cargo.toml | 1 + compiler/rustc_typeck/src/check/expr.rs | 80 ++++++++++++++++--- src/test/ui/issues/issue-76077.rs | 2 +- src/test/ui/issues/issue-76077.stderr | 8 +- src/test/ui/privacy/issue-79593.rs | 2 +- src/test/ui/privacy/issue-79593.stderr | 8 +- ...7872-missing-inaccessible-field-literal.rs | 2 +- ...-missing-inaccessible-field-literal.stderr | 8 +- ...issing-private-fields-in-struct-literal.rs | 18 +++++ ...ng-private-fields-in-struct-literal.stderr | 23 ++++++ 11 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/typeck/missing-private-fields-in-struct-literal.rs create mode 100644 src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr diff --git a/Cargo.lock b/Cargo.lock index df6f46f26cf0d..cc0f4cc53e656 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4590,6 +4590,7 @@ dependencies = [ name = "rustc_typeck" version = "0.0.0" dependencies = [ + "itertools", "rustc_arena", "rustc_ast", "rustc_attr", diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index c08023ee6a70a..b3dd695508094 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] rustc_arena = { path = "../rustc_arena" } tracing = "0.1" +itertools = "0.10.1" rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index dc9d76160c4e9..0a017de80f248 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -23,13 +23,14 @@ use crate::type_error_struct; use super::suggest_call_constructor; use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; +use itertools::{Either, Itertools}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::Diagnostic; -use rustc_errors::EmissionGuarantee; -use rustc_errors::ErrorGuaranteed; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, + EmissionGuarantee, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -1672,12 +1673,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys); } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { - let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| { - !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) - }); + debug!(?remaining_fields); + let private_fields: Vec<&ty::FieldDef> = variant + .fields + .iter() + .filter(|field| { + !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + }) + .collect(); - if inaccessible_remaining_fields { - self.report_inaccessible_fields(adt_ty, span); + if !private_fields.is_empty() + && tcx + .visibility(variant.def_id) + .is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + { + self.report_private_fields(adt_ty, span, private_fields, ast_fields); } else { self.report_missing_fields( adt_ty, @@ -1801,7 +1811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Report an error for a struct field expression when there are invisible fields. /// /// ```text - /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + /// error: cannot construct `Foo` with struct literal syntax due to private fields /// --> src/main.rs:8:5 /// | /// 8 | foo::Foo {}; @@ -1809,13 +1819,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// error: aborting due to previous error /// ``` - fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { - self.tcx.sess.span_err( + fn report_private_fields( + &self, + adt_ty: Ty<'tcx>, + span: Span, + private_fields: Vec<&ty::FieldDef>, + used_fields: &'tcx [hir::ExprField<'tcx>], + ) { + let field_names = |fields: Vec, len: usize| match &fields + .iter() + .map(|field| field.to_string()) + .collect::>()[..] + { + _ if len > 6 => String::new(), + [name] => format!("`{name}` "), + [names @ .., last] => { + let names = names.iter().map(|name| format!("`{name}`")).collect::>(); + format!("{} and `{last}` ", names.join(", ")) + } + [] => unreachable!(), + }; + + let mut err = self.tcx.sess.struct_span_err( span, &format!( - "cannot construct `{adt_ty}` with struct literal syntax due to inaccessible fields", + "cannot construct `{adt_ty}` with struct literal syntax due to private fields", ), ); + let (used_private_fields, remaining_private_fields): ( + Vec<(Symbol, Span)>, + Vec<(Symbol, Span)>, + ) = private_fields.iter().partition_map(|field| { + match used_fields.iter().find(|used_field| field.name == used_field.ident.name) { + Some(used_field) => Either::Left((field.name, used_field.span)), + None => Either::Right((field.name, self.tcx.def_span(field.did))), + } + }); + let remaining_private_fields_len = remaining_private_fields.len(); + err.span_labels(used_private_fields.iter().map(|(_, span)| *span), "private field"); + err.span_note( + MultiSpan::from_spans(remaining_private_fields.iter().map(|(_, span)| *span).collect()), + format!( + "missing field{s} {names}{are} private", + s = pluralize!(remaining_private_fields_len), + are = pluralize!("is", remaining_private_fields_len), + names = field_names( + remaining_private_fields.iter().map(|(name, _)| *name).collect(), + remaining_private_fields_len + ) + ), + ); + err.emit(); } fn report_unknown_field( diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs index 1ecd37de2e14a..2d29093b01b02 100644 --- a/src/test/ui/issues/issue-76077.rs +++ b/src/test/ui/issues/issue-76077.rs @@ -6,5 +6,5 @@ pub mod foo { fn main() { foo::Foo {}; - //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields + //~^ ERROR cannot construct `Foo` with struct literal syntax due to private fields } diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr index d834ec5e0edd2..c70a928f6475a 100644 --- a/src/test/ui/issues/issue-76077.stderr +++ b/src/test/ui/issues/issue-76077.stderr @@ -1,8 +1,14 @@ -error: cannot construct `Foo` with struct literal syntax due to inaccessible fields +error: cannot construct `Foo` with struct literal syntax due to private fields --> $DIR/issue-76077.rs:8:5 | LL | foo::Foo {}; | ^^^^^^^^ + | +note: missing field `you_cant_use_this_field` is private + --> $DIR/issue-76077.rs:3:9 + | +LL | you_cant_use_this_field: bool, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/privacy/issue-79593.rs b/src/test/ui/privacy/issue-79593.rs index b94278bfdd221..39c222f7c3414 100644 --- a/src/test/ui/privacy/issue-79593.rs +++ b/src/test/ui/privacy/issue-79593.rs @@ -16,7 +16,7 @@ mod foo { fn correct() { foo::Pub {}; - //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields + //~^ ERROR cannot construct `Pub` with struct literal syntax due to private fields } fn wrong() { diff --git a/src/test/ui/privacy/issue-79593.stderr b/src/test/ui/privacy/issue-79593.stderr index b8c7d4f23a28f..435d4cbf73595 100644 --- a/src/test/ui/privacy/issue-79593.stderr +++ b/src/test/ui/privacy/issue-79593.stderr @@ -10,11 +10,17 @@ error[E0063]: missing field `y` in initializer of `Enum` LL | Enum::Variant { x: () }; | ^^^^^^^^^^^^^ missing `y` -error: cannot construct `Pub` with struct literal syntax due to inaccessible fields +error: cannot construct `Pub` with struct literal syntax due to private fields --> $DIR/issue-79593.rs:18:5 | LL | foo::Pub {}; | ^^^^^^^^ + | +note: missing field `private` is private + --> $DIR/issue-79593.rs:2:22 + | +LL | pub struct Pub { private: () } + | ^^^^^^^^^^^ error[E0063]: missing field `y` in initializer of `Enum` --> $DIR/issue-79593.rs:23:5 diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs index 3176144133760..326e958aaa94f 100644 --- a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs @@ -7,5 +7,5 @@ pub mod foo { fn main() { foo::Foo {}; - //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields + //~^ ERROR cannot construct `Foo` with struct literal syntax due to private fields } diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr index 81b73c00e8600..2ade7aea57b3d 100644 --- a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr @@ -1,8 +1,14 @@ -error: cannot construct `Foo` with struct literal syntax due to inaccessible fields +error: cannot construct `Foo` with struct literal syntax due to private fields --> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5 | LL | foo::Foo {}; | ^^^^^^^^ + | +note: missing field `you_cant_use_this_field` is private + --> $DIR/issue-87872-missing-inaccessible-field-literal.rs:4:9 + | +LL | you_cant_use_this_field: bool, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/missing-private-fields-in-struct-literal.rs b/src/test/ui/typeck/missing-private-fields-in-struct-literal.rs new file mode 100644 index 0000000000000..9f1560bfb8dfe --- /dev/null +++ b/src/test/ui/typeck/missing-private-fields-in-struct-literal.rs @@ -0,0 +1,18 @@ +pub mod m { + pub struct S { + pub visible: bool, + a: (), + b: (), + c: (), + d: (), + e: (), + } +} + +fn main() { + let _ = m::S { //~ ERROR cannot construct `S` with struct literal syntax due to private fields + visible: true, + a: (), + b: (), + }; +} diff --git a/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr b/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr new file mode 100644 index 0000000000000..eb5f460f868e1 --- /dev/null +++ b/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr @@ -0,0 +1,23 @@ +error: cannot construct `S` with struct literal syntax due to private fields + --> $DIR/missing-private-fields-in-struct-literal.rs:13:13 + | +LL | let _ = m::S { + | ^^^^ +LL | visible: true, +LL | a: (), + | ----- private field +LL | b: (), + | ----- private field + | +note: missing fields `c`, `d` and `e` are private + --> $DIR/missing-private-fields-in-struct-literal.rs:6:9 + | +LL | c: (), + | ^^^^^ +LL | d: (), + | ^^^^^ +LL | e: (), + | ^^^^^ + +error: aborting due to previous error + From f00179521d10357d099b419a73a22f50295220f1 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 20 Jun 2022 20:42:58 +0300 Subject: [PATCH 04/24] don't alloc error string if no error emitted --- compiler/rustc_typeck/src/astconv/mod.rs | 65 ++++++++++++------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 4641b36aad1d7..1c53618dd7c30 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2111,14 +2111,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), ) -> bool { let args = segments.clone().flat_map(|segment| segment.args().args); - let types_and_spans: Vec<_> = segments - .clone() - .flat_map(|segment| { - segment.res.and_then(|res| { - if segment.args().args.is_empty() { - None - } else { - Some(( + + let (lt, ty, ct, inf) = + args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg { + hir::GenericArg::Lifetime(_) => (true, ty, ct, inf), + hir::GenericArg::Type(_) => (lt, true, ct, inf), + hir::GenericArg::Const(_) => (lt, ty, true, inf), + hir::GenericArg::Infer(_) => (lt, ty, ct, true), + }); + let mut emitted = false; + if lt || ty || ct || inf { + let types_and_spans: Vec<_> = segments + .clone() + .flat_map(|segment| { + segment.res.and_then(|res| { + if segment.args().args.is_empty() { + None + } else { + Some(( match res { Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()), Res::Def(_, def_id) @@ -2130,32 +2140,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }, segment.ident.span, )) - } + } + }) }) - }) - .collect(); - let this_type = match &types_and_spans[..] { - [.., _, (last, _)] => format!( - "{} and {last}", - types_and_spans[..types_and_spans.len() - 1] - .iter() - .map(|(x, _)| x.as_str()) - .intersperse(&", ") - .collect::() - ), - [(only, _)] => only.to_string(), - [] => "this type".to_string(), - }; + .collect(); + let this_type = match &types_and_spans[..] { + [.., _, (last, _)] => format!( + "{} and {last}", + types_and_spans[..types_and_spans.len() - 1] + .iter() + .map(|(x, _)| x.as_str()) + .intersperse(&", ") + .collect::() + ), + [(only, _)] => only.to_string(), + [] => "this type".to_string(), + }; - let (lt, ty, ct, inf) = - args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg { - hir::GenericArg::Lifetime(_) => (true, ty, ct, inf), - hir::GenericArg::Type(_) => (lt, true, ct, inf), - hir::GenericArg::Const(_) => (lt, ty, true, inf), - hir::GenericArg::Infer(_) => (lt, ty, ct, true), - }); - let mut emitted = false; - if lt || ty || ct || inf { let arg_spans: Vec = args.map(|arg| arg.span()).collect(); let mut kinds = Vec::with_capacity(4); From b37a05bd01a4f1fdcdfda77df4a9008d04236528 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Mon, 20 Jun 2022 12:41:11 -0700 Subject: [PATCH 05/24] rustdoc: optimize loading of source sidebar The source sidebar has a setting to remember whether it should be open or closed. Previously, this setting was handled in source-script.js, which is loaded with `defer`, meaning it is often run after the document is rendered. Since CSS renders the source sidebar as closed by default, changing this after the initial render results in a relayout. Instead, handle the setting in storage.js, which is the first script to load and is the only script that blocks render. This avoids a relayout and means navigating between files with the sidebar open is faster. --- src/librustdoc/html/static/css/rustdoc.css | 35 ++++++++++++------- .../html/static/js/source-script.js | 10 ++---- src/librustdoc/html/static/js/storage.js | 11 ++++++ src/test/rustdoc-gui/sidebar-source-code.goml | 10 +++--- src/test/rustdoc-gui/source-code-page.goml | 2 +- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d0229bdb5f23c..b4b7790eebba1 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -387,16 +387,20 @@ nav.sub { overflow-y: hidden; } +.rustdoc.source .sidebar .sidebar-logo { + display: none; +} + .source .sidebar > *:not(#sidebar-toggle) { opacity: 0; visibility: hidden; } -.source .sidebar.expanded { +.source-sidebar-expanded .source .sidebar { overflow-y: auto; } -.source .sidebar.expanded > *:not(#sidebar-toggle) { +.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) { opacity: 1; visibility: visible; } @@ -1682,11 +1686,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { /* When we expand the sidebar on the source code page, we hide the logo on the left of the search bar to have more space. */ - .sidebar.expanded + main .width-limiter .sub-logo-container.rust-logo { + .source-sidebar-expanded .source .sidebar + main .width-limiter .sub-logo-container.rust-logo { display: none; } - .source .sidebar.expanded { + .source-sidebar-expanded .source .sidebar { width: 300px; } } @@ -1766,7 +1770,7 @@ details.rustdoc-toggle[open] > summary.hideme::after { } .sidebar.shown, - .sidebar.expanded, + .source-sidebar-expanded .source .sidebar, .sidebar:focus-within { left: 0; } @@ -1889,11 +1893,7 @@ details.rustdoc-toggle[open] > summary.hideme::after { left: -11px; } - .sidebar.expanded #sidebar-toggle { - font-size: 1.5rem; - } - - .sidebar:not(.expanded) #sidebar-toggle { + #sidebar-toggle { position: fixed; left: 1px; top: 100px; @@ -1910,6 +1910,14 @@ details.rustdoc-toggle[open] > summary.hideme::after { border-left: 0; } + .source-sidebar-expanded #sidebar-toggle { + left: unset; + top: unset; + width: unset; + border-top-right-radius: unset; + border-bottom-right-radius: unset; + } + #source-sidebar { z-index: 11; } @@ -1952,7 +1960,7 @@ details.rustdoc-toggle[open] > summary.hideme::after { padding-left: 2em; } - .source .sidebar.expanded { + .source-sidebar-expanded .source .sidebar { max-width: 100vw; width: 100vw; } @@ -2010,9 +2018,12 @@ details.rustdoc-toggle[open] > summary.hideme::after { width: 35px; } - .sidebar:not(.expanded) #sidebar-toggle { + #sidebar-toggle { top: 10px; } + .source-sidebar-expanded #sidebar-toggle { + top: unset; + } } .method-toggle summary, diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 14d8a942977d6..45955c6dd052c 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -76,14 +76,13 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) { } function toggleSidebar() { - const sidebar = document.querySelector("nav.sidebar"); const child = this.children[0]; if (child.innerText === ">") { - sidebar.classList.add("expanded"); + addClass(document.documentElement, "source-sidebar-expanded"); child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { - sidebar.classList.remove("expanded"); + removeClass(document.documentElement, "source-sidebar-expanded"); child.innerText = ">"; updateLocalStorage("source-sidebar-show", "false"); } @@ -119,11 +118,6 @@ function createSourceSidebar() { const sidebar = document.createElement("div"); sidebar.id = "source-sidebar"; - if (getCurrentValue("source-sidebar-show") !== "true") { - container.classList.remove("expanded"); - } else { - container.classList.add("expanded"); - } const currentFile = getCurrentFilePath(); let hasFoundFile = false; diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 4fcf049923491..1c4c88344888c 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -1,3 +1,8 @@ +// storage.js is loaded in the `` of all rustdoc pages and doesn't +// use `async` or `defer`. That means it blocks further parsing and rendering +// of the page: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script. +// This makes it the correct place to act on settings that affect the display of +// the page, so we don't see major layout changes during the load of the page. "use strict"; const darkThemes = ["dark", "ayu"]; @@ -236,6 +241,12 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { switchToSavedTheme(); } +if (getSettingValue("source-sidebar-show") === "true") { + // At this point in page load, `document.body` is not available yet. + // Set a class on the `` element instead. + addClass(document.documentElement, "source-sidebar-expanded"); +} + // If we navigate away (for example to a settings page), and then use the back or // forward button to get back to a page, the theme may have changed in the meantime. // But scripts may not be re-loaded in such a case due to the bfcache diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml index 8b4a8bd40dd7e..724520bc399d0 100644 --- a/src/test/rustdoc-gui/sidebar-source-code.goml +++ b/src/test/rustdoc-gui/sidebar-source-code.goml @@ -8,12 +8,12 @@ assert-css: ("nav.sidebar", {"width": "50px"}) // We now click on the button to expand the sidebar. click: (10, 10) // We wait for the sidebar to be expanded. -wait-for-css: ("nav.sidebar.expanded", {"width": "300px"}) -assert-css: ("nav.sidebar.expanded a", {"font-size": "14px"}) +wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "300px"}) +assert-css: (".source-sidebar-expanded nav.sidebar a", {"font-size": "14px"}) // We collapse the sidebar. click: (10, 10) // We ensure that the class has been removed. -wait-for: "nav.sidebar:not(.expanded)" +wait-for: "html:not(.expanded)" assert: "nav.sidebar" // We now switch to mobile mode. @@ -22,11 +22,11 @@ size: (600, 600) assert-css: ("nav.sidebar", {"width": "1px"}) // We expand the sidebar. click: "#sidebar-toggle" -assert-css: ("nav.sidebar.expanded", {"width": "600px"}) +assert-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"}) // We collapse the sidebar. click: (10, 10) // We ensure that the class has been removed. -assert-false: "nav.sidebar.expanded" +assert-false: ".source-sidebar-expanded" assert: "nav.sidebar" // Check that the topbar is not visible diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml index 188b2605f0f13..b45512601f208 100644 --- a/src/test/rustdoc-gui/source-code-page.goml +++ b/src/test/rustdoc-gui/source-code-page.goml @@ -32,7 +32,7 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH) // First we "open" it. click: "#sidebar-toggle" -assert: ".sidebar.expanded" +assert: ".source-sidebar-expanded" // We check that the first entry of the sidebar is collapsed (which, for whatever reason, // is number 2 and not 1...). From e900a3549624860a466c33c04742ccfa026bdc6d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 21 Jun 2022 03:47:25 +0000 Subject: [PATCH 06/24] Give name if anonymous region appears in impl signature --- .../src/diagnostics/outlives_suggestion.rs | 3 +- .../src/diagnostics/region_name.rs | 58 +++++++++++++++++-- src/test/ui/nll/issue-98170.rs | 25 ++++++++ src/test/ui/nll/issue-98170.stderr | 44 ++++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/nll/issue-98170.rs create mode 100644 src/test/ui/nll/issue-98170.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 9d81330745fe2..d359d7efb6268 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -62,7 +62,8 @@ impl OutlivesSuggestionBuilder { | RegionNameSource::AnonRegionFromUpvar(..) | RegionNameSource::AnonRegionFromOutput(..) | RegionNameSource::AnonRegionFromYieldTy(..) - | RegionNameSource::AnonRegionFromAsyncFn(..) => { + | RegionNameSource::AnonRegionFromAsyncFn(..) + | RegionNameSource::AnonRegionFromImplSignature(..) => { debug!("Region {:?} is NOT suggestable", name); false } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index d6b5089712ab4..b5ae85fd042c2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -45,6 +45,8 @@ pub(crate) enum RegionNameSource { AnonRegionFromYieldTy(Span, String), /// An anonymous region from an async fn. AnonRegionFromAsyncFn(Span), + /// An anonymous region from an impl self type or trait + AnonRegionFromImplSignature(Span, &'static str), } /// Describes what to highlight to explain to the user that we're giving an anonymous region a @@ -75,7 +77,8 @@ impl RegionName { | RegionNameSource::AnonRegionFromUpvar(..) | RegionNameSource::AnonRegionFromOutput(..) | RegionNameSource::AnonRegionFromYieldTy(..) - | RegionNameSource::AnonRegionFromAsyncFn(..) => false, + | RegionNameSource::AnonRegionFromAsyncFn(..) + | RegionNameSource::AnonRegionFromImplSignature(..) => false, } } @@ -87,7 +90,8 @@ impl RegionName { | RegionNameSource::SynthesizedFreeEnvRegion(span, _) | RegionNameSource::AnonRegionFromUpvar(span, _) | RegionNameSource::AnonRegionFromYieldTy(span, _) - | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span), + | RegionNameSource::AnonRegionFromAsyncFn(span) + | RegionNameSource::AnonRegionFromImplSignature(span, _) => Some(span), RegionNameSource::AnonRegionFromArgument(ref highlight) | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight { RegionNameHighlight::MatchedHirTy(span) @@ -166,6 +170,12 @@ impl RegionName { RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { diag.span_label(*span, format!("yield type is {type_name}")); } + RegionNameSource::AnonRegionFromImplSignature(span, location) => { + diag.span_label( + *span, + format!("lifetime `{self}` appears in the `impl`'s {location}"), + ); + } RegionNameSource::Static => {} } } @@ -240,7 +250,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)); + .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)); if let Some(ref value) = value { self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); @@ -840,4 +851,43 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), }) } + + fn give_name_if_anonymous_region_appears_in_impl_signature( + &self, + fr: RegionVid, + ) -> Option { + let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + return None; + }; + if region.has_name() { + return None; + }; + + let tcx = self.infcx.tcx; + let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?; + if tcx.parent(region.def_id) != body_parent_did + || tcx.def_kind(body_parent_did) != DefKind::Impl + { + return None; + } + + let mut found = false; + tcx.fold_regions(tcx.type_of(body_parent_did), &mut true, |r: ty::Region<'tcx>, _| { + if *r == ty::ReEarlyBound(region) { + found = true; + } + r + }); + + Some(RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::AnonRegionFromImplSignature( + tcx.def_span(region.def_id), + // FIXME(compiler-errors): Does this ever actually show up + // anywhere other than the self type? I couldn't create an + // example of a `'_` in the impl's trait being referenceable. + if found { "self type" } else { "header" }, + ), + }) + } } diff --git a/src/test/ui/nll/issue-98170.rs b/src/test/ui/nll/issue-98170.rs new file mode 100644 index 0000000000000..6bb12f52d3f3e --- /dev/null +++ b/src/test/ui/nll/issue-98170.rs @@ -0,0 +1,25 @@ +pub struct MyStruct<'a> { + field: &'a [u32], +} + +impl MyStruct<'_> { + pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> { + Self { field } + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + } +} + +trait Trait<'a> { + fn new(field: &'a [u32]) -> MyStruct<'a>; +} + +impl<'a> Trait<'a> for MyStruct<'_> { + fn new(field: &'a [u32]) -> MyStruct<'a> { + Self { field } + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-98170.stderr b/src/test/ui/nll/issue-98170.stderr new file mode 100644 index 0000000000000..0d17365e71b4a --- /dev/null +++ b/src/test/ui/nll/issue-98170.stderr @@ -0,0 +1,44 @@ +error: lifetime may not live long enough + --> $DIR/issue-98170.rs:7:9 + | +LL | impl MyStruct<'_> { + | -- lifetime `'1` appears in the `impl`'s self type +LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> { + | -- lifetime `'a` defined here +LL | Self { field } + | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/issue-98170.rs:7:16 + | +LL | impl MyStruct<'_> { + | -- lifetime `'1` appears in the `impl`'s self type +LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> { + | -- lifetime `'a` defined here +LL | Self { field } + | ^^^^^ this usage requires that `'a` must outlive `'1` + +error: lifetime may not live long enough + --> $DIR/issue-98170.rs:19:9 + | +LL | impl<'a> Trait<'a> for MyStruct<'_> { + | -- -- lifetime `'1` appears in the `impl`'s self type + | | + | lifetime `'a` defined here +LL | fn new(field: &'a [u32]) -> MyStruct<'a> { +LL | Self { field } + | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/issue-98170.rs:19:16 + | +LL | impl<'a> Trait<'a> for MyStruct<'_> { + | -- -- lifetime `'1` appears in the `impl`'s self type + | | + | lifetime `'a` defined here +LL | fn new(field: &'a [u32]) -> MyStruct<'a> { +LL | Self { field } + | ^^^^^ this usage requires that `'a` must outlive `'1` + +error: aborting due to 4 previous errors + From f924e74fb1c238b0e6c06c23b51c087f1e6aa0d5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 Jun 2022 18:21:01 -0700 Subject: [PATCH 07/24] Provide a segment res in more cases --- compiler/rustc_resolve/src/ident.rs | 1 + src/test/ui/error-codes/E0109.stderr | 4 +- src/test/ui/error-codes/E0110.stderr | 4 +- .../cannot-infer-closure-circular.rs | 4 +- .../cannot-infer-closure-circular.stderr | 12 +-- .../enum-variant-generic-args.rs | 6 +- .../enum-variant-generic-args.stderr | 12 +-- src/test/ui/type/issue-91268.rs | 2 +- src/test/ui/type/issue-91268.stderr | 4 +- src/test/ui/typeck/prim-with-args.fixed | 44 +++++----- src/test/ui/typeck/prim-with-args.rs | 44 +++++----- src/test/ui/typeck/prim-with-args.stderr | 88 +++++++++---------- src/test/ui/usize-generic-argument-parent.rs | 2 +- .../ui/usize-generic-argument-parent.stderr | 4 +- 14 files changed, 116 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e934e189f05f3..0cc6d05d1d086 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1502,6 +1502,7 @@ impl<'a> Resolver<'a> { return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { self.lint_if_path_starts_with_module(finalize, path, second_binding); + record_segment_res(self, res); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - i - 1, diff --git a/src/test/ui/error-codes/E0109.stderr b/src/test/ui/error-codes/E0109.stderr index da00fdde6bd0a..8f4cb86de99a0 100644 --- a/src/test/ui/error-codes/E0109.stderr +++ b/src/test/ui/error-codes/E0109.stderr @@ -1,10 +1,10 @@ -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u32` --> $DIR/E0109.rs:1:14 | LL | type X = u32; | --- ^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u32` | help: primitive type `u32` doesn't have generic parameters | diff --git a/src/test/ui/error-codes/E0110.stderr b/src/test/ui/error-codes/E0110.stderr index 5babb5c2961b7..4ce2a0a410ce4 100644 --- a/src/test/ui/error-codes/E0110.stderr +++ b/src/test/ui/error-codes/E0110.stderr @@ -1,10 +1,10 @@ -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `u32` --> $DIR/E0110.rs:1:14 | LL | type X = u32<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u32` | help: primitive type `u32` doesn't have generic parameters | diff --git a/src/test/ui/inference/cannot-infer-closure-circular.rs b/src/test/ui/inference/cannot-infer-closure-circular.rs index ae879db68ec13..affb481496d02 100644 --- a/src/test/ui/inference/cannot-infer-closure-circular.rs +++ b/src/test/ui/inference/cannot-infer-closure-circular.rs @@ -4,10 +4,10 @@ fn main() { // error handles this gracefully, and in particular doesn't generate an extra // note about the `?` operator in the closure body, which isn't relevant to // the inference. - let x = |r| { + let x = |r| { //~ ERROR type annotations needed for `Result<(), E>` let v = r?; Ok(v) }; - let _ = x(x(Ok(()))); //~ ERROR type annotations needed for `Result<(), E>` + let _ = x(x(Ok(()))); } diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr index 3ad8e3cda16e5..b706cd2bc36e8 100644 --- a/src/test/ui/inference/cannot-infer-closure-circular.stderr +++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr @@ -1,13 +1,13 @@ error[E0282]: type annotations needed for `Result<(), E>` - --> $DIR/cannot-infer-closure-circular.rs:12:9 + --> $DIR/cannot-infer-closure-circular.rs:7:14 | -LL | let _ = x(x(Ok(()))); - | ^ +LL | let x = |r| { + | ^ | -help: consider giving this pattern a type, where the type for type parameter `E` is specified +help: consider giving this closure parameter an explicit type, where the type for type parameter `E` is specified | -LL | let _: Result<(), E> = x(x(Ok(()))); - | +++++++++++++++ +LL | let x = |r: Result<(), E>| { + | +++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs index e6f45036f8514..0031a4665c814 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.rs @@ -52,7 +52,7 @@ fn main() { // Tuple struct variant Enum::<()>::TSVariant::<()>(()); - //~^ ERROR type arguments are not allowed on this type [E0109] + //~^ ERROR type arguments are not allowed on tuple variant `TSVariant` [E0109] Alias::TSVariant::<()>(()); //~^ ERROR type arguments are not allowed on this type [E0109] @@ -70,7 +70,7 @@ fn main() { // Struct variant Enum::<()>::SVariant::<()> { v: () }; - //~^ ERROR type arguments are not allowed on this type [E0109] + //~^ ERROR type arguments are not allowed on variant `SVariant` [E0109] Alias::SVariant::<()> { v: () }; //~^ ERROR type arguments are not allowed on this type [E0109] @@ -88,7 +88,7 @@ fn main() { // Unit variant Enum::<()>::UVariant::<()>; - //~^ ERROR type arguments are not allowed on this type [E0109] + //~^ ERROR type arguments are not allowed on unit variant `UVariant` [E0109] Alias::UVariant::<()>; //~^ ERROR type arguments are not allowed on this type [E0109] diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr index 9601bdce4c503..5467f61bee40f 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr @@ -272,13 +272,13 @@ LL | Self::<()>::UVariant::<()>; | | | not allowed on this type -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on tuple variant `TSVariant` --> $DIR/enum-variant-generic-args.rs:54:29 | LL | Enum::<()>::TSVariant::<()>(()); | --------- ^^ type argument not allowed | | - | not allowed on this type + | not allowed on tuple variant `TSVariant` error[E0109]: type arguments are not allowed on this type --> $DIR/enum-variant-generic-args.rs:57:24 @@ -340,13 +340,13 @@ LL | AliasFixed::<()>::TSVariant::<()>(()); | | | not allowed on this type -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on variant `SVariant` --> $DIR/enum-variant-generic-args.rs:72:28 | LL | Enum::<()>::SVariant::<()> { v: () }; | -------- ^^ type argument not allowed | | - | not allowed on this type + | not allowed on variant `SVariant` | = note: enum variants can't have type parameters @@ -438,13 +438,13 @@ LL - AliasFixed::<()>::SVariant::<()> { v: () }; LL + AliasFixed::<()>::SVariant { v: () }; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on unit variant `UVariant` --> $DIR/enum-variant-generic-args.rs:90:28 | LL | Enum::<()>::UVariant::<()>; | -------- ^^ type argument not allowed | | - | not allowed on this type + | not allowed on unit variant `UVariant` error[E0109]: type arguments are not allowed on this type --> $DIR/enum-variant-generic-args.rs:93:23 diff --git a/src/test/ui/type/issue-91268.rs b/src/test/ui/type/issue-91268.rs index 01ed9ea9e231f..f1e16bc7bd3c1 100644 --- a/src/test/ui/type/issue-91268.rs +++ b/src/test/ui/type/issue-91268.rs @@ -1,7 +1,7 @@ // error-pattern: this file contains an unclosed delimiter // error-pattern: cannot find type `Å£` in this scope // error-pattern: parenthesized type parameters may only be used with a `Fn` trait -// error-pattern: type arguments are not allowed on this type +// error-pattern: type arguments are not allowed on builtin type `u8` // error-pattern: mismatched types // ignore-tidy-trailing-newlines // `Å£` must be the last character in this file, it cannot be followed by a newline diff --git a/src/test/ui/type/issue-91268.stderr b/src/test/ui/type/issue-91268.stderr index e426f450b11bb..6c9ee9945844d 100644 --- a/src/test/ui/type/issue-91268.stderr +++ b/src/test/ui/type/issue-91268.stderr @@ -35,13 +35,13 @@ help: use angle brackets instead LL | 0: u8<Å£> | ~ + -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u8` --> $DIR/issue-91268.rs:9:11 | LL | 0: u8(Å£ | -- ^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u8` | help: primitive type `u8` doesn't have generic parameters | diff --git a/src/test/ui/typeck/prim-with-args.fixed b/src/test/ui/typeck/prim-with-args.fixed index 1c5fd7508676a..e3f99479a3809 100644 --- a/src/test/ui/typeck/prim-with-args.fixed +++ b/src/test/ui/typeck/prim-with-args.fixed @@ -1,28 +1,28 @@ // run-rustfix fn main() { -let _x: isize; //~ ERROR type arguments are not allowed on this type -let _x: i8; //~ ERROR type arguments are not allowed on this type -let _x: i16; //~ ERROR type arguments are not allowed on this type -let _x: i32; //~ ERROR type arguments are not allowed on this type -let _x: i64; //~ ERROR type arguments are not allowed on this type -let _x: usize; //~ ERROR type arguments are not allowed on this type -let _x: u8; //~ ERROR type arguments are not allowed on this type -let _x: u16; //~ ERROR type arguments are not allowed on this type -let _x: u32; //~ ERROR type arguments are not allowed on this type -let _x: u64; //~ ERROR type arguments are not allowed on this type -let _x: char; //~ ERROR type arguments are not allowed on this type +let _x: isize; //~ ERROR type arguments are not allowed on builtin type +let _x: i8; //~ ERROR type arguments are not allowed on builtin type +let _x: i16; //~ ERROR type arguments are not allowed on builtin type +let _x: i32; //~ ERROR type arguments are not allowed on builtin type +let _x: i64; //~ ERROR type arguments are not allowed on builtin type +let _x: usize; //~ ERROR type arguments are not allowed on builtin type +let _x: u8; //~ ERROR type arguments are not allowed on builtin type +let _x: u16; //~ ERROR type arguments are not allowed on builtin type +let _x: u32; //~ ERROR type arguments are not allowed on builtin type +let _x: u64; //~ ERROR type arguments are not allowed on builtin type +let _x: char; //~ ERROR type arguments are not allowed on builtin type -let _x: isize; //~ ERROR lifetime arguments are not allowed on this type -let _x: i8; //~ ERROR lifetime arguments are not allowed on this type -let _x: i16; //~ ERROR lifetime arguments are not allowed on this type -let _x: i32; //~ ERROR lifetime arguments are not allowed on this type -let _x: i64; //~ ERROR lifetime arguments are not allowed on this type -let _x: usize; //~ ERROR lifetime arguments are not allowed on this type -let _x: u8; //~ ERROR lifetime arguments are not allowed on this type -let _x: u16; //~ ERROR lifetime arguments are not allowed on this type -let _x: u32; //~ ERROR lifetime arguments are not allowed on this type -let _x: u64; //~ ERROR lifetime arguments are not allowed on this type -let _x: char; //~ ERROR lifetime arguments are not allowed on this type +let _x: isize; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i8; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i16; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i32; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i64; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: usize; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u8; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u16; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u32; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u64; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: char; //~ ERROR lifetime arguments are not allowed on builtin type } diff --git a/src/test/ui/typeck/prim-with-args.rs b/src/test/ui/typeck/prim-with-args.rs index b05d6c1cb4e4a..b10471eccee68 100644 --- a/src/test/ui/typeck/prim-with-args.rs +++ b/src/test/ui/typeck/prim-with-args.rs @@ -1,28 +1,28 @@ // run-rustfix fn main() { -let _x: isize; //~ ERROR type arguments are not allowed on this type -let _x: i8; //~ ERROR type arguments are not allowed on this type -let _x: i16; //~ ERROR type arguments are not allowed on this type -let _x: i32; //~ ERROR type arguments are not allowed on this type -let _x: i64; //~ ERROR type arguments are not allowed on this type -let _x: usize; //~ ERROR type arguments are not allowed on this type -let _x: u8; //~ ERROR type arguments are not allowed on this type -let _x: u16; //~ ERROR type arguments are not allowed on this type -let _x: u32; //~ ERROR type arguments are not allowed on this type -let _x: u64; //~ ERROR type arguments are not allowed on this type -let _x: char; //~ ERROR type arguments are not allowed on this type +let _x: isize; //~ ERROR type arguments are not allowed on builtin type +let _x: i8; //~ ERROR type arguments are not allowed on builtin type +let _x: i16; //~ ERROR type arguments are not allowed on builtin type +let _x: i32; //~ ERROR type arguments are not allowed on builtin type +let _x: i64; //~ ERROR type arguments are not allowed on builtin type +let _x: usize; //~ ERROR type arguments are not allowed on builtin type +let _x: u8; //~ ERROR type arguments are not allowed on builtin type +let _x: u16; //~ ERROR type arguments are not allowed on builtin type +let _x: u32; //~ ERROR type arguments are not allowed on builtin type +let _x: u64; //~ ERROR type arguments are not allowed on builtin type +let _x: char; //~ ERROR type arguments are not allowed on builtin type -let _x: isize<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: i8<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: i16<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: i32<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: i64<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: usize<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: u8<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: u16<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: u32<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: u64<'static>; //~ ERROR lifetime arguments are not allowed on this type -let _x: char<'static>; //~ ERROR lifetime arguments are not allowed on this type +let _x: isize<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i8<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i16<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i32<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: i64<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: usize<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u8<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u16<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u32<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: u64<'static>; //~ ERROR lifetime arguments are not allowed on builtin type +let _x: char<'static>; //~ ERROR lifetime arguments are not allowed on builtin type } diff --git a/src/test/ui/typeck/prim-with-args.stderr b/src/test/ui/typeck/prim-with-args.stderr index c45fd00bae9a5..2ddad5ad71e46 100644 --- a/src/test/ui/typeck/prim-with-args.stderr +++ b/src/test/ui/typeck/prim-with-args.stderr @@ -1,10 +1,10 @@ -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `isize` --> $DIR/prim-with-args.rs:4:15 | LL | let _x: isize; | ----- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `isize` | help: primitive type `isize` doesn't have generic parameters | @@ -12,13 +12,13 @@ LL - let _x: isize; LL + let _x: isize; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `i8` --> $DIR/prim-with-args.rs:5:12 | LL | let _x: i8; | -- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i8` | help: primitive type `i8` doesn't have generic parameters | @@ -26,13 +26,13 @@ LL - let _x: i8; LL + let _x: i8; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `i16` --> $DIR/prim-with-args.rs:6:13 | LL | let _x: i16; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i16` | help: primitive type `i16` doesn't have generic parameters | @@ -40,13 +40,13 @@ LL - let _x: i16; LL + let _x: i16; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `i32` --> $DIR/prim-with-args.rs:7:13 | LL | let _x: i32; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i32` | help: primitive type `i32` doesn't have generic parameters | @@ -54,13 +54,13 @@ LL - let _x: i32; LL + let _x: i32; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `i64` --> $DIR/prim-with-args.rs:8:13 | LL | let _x: i64; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i64` | help: primitive type `i64` doesn't have generic parameters | @@ -68,13 +68,13 @@ LL - let _x: i64; LL + let _x: i64; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `usize` --> $DIR/prim-with-args.rs:9:15 | LL | let _x: usize; | ----- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `usize` | help: primitive type `usize` doesn't have generic parameters | @@ -82,13 +82,13 @@ LL - let _x: usize; LL + let _x: usize; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u8` --> $DIR/prim-with-args.rs:10:12 | LL | let _x: u8; | -- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u8` | help: primitive type `u8` doesn't have generic parameters | @@ -96,13 +96,13 @@ LL - let _x: u8; LL + let _x: u8; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u16` --> $DIR/prim-with-args.rs:11:13 | LL | let _x: u16; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u16` | help: primitive type `u16` doesn't have generic parameters | @@ -110,13 +110,13 @@ LL - let _x: u16; LL + let _x: u16; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u32` --> $DIR/prim-with-args.rs:12:13 | LL | let _x: u32; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u32` | help: primitive type `u32` doesn't have generic parameters | @@ -124,13 +124,13 @@ LL - let _x: u32; LL + let _x: u32; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `u64` --> $DIR/prim-with-args.rs:13:13 | LL | let _x: u64; | --- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u64` | help: primitive type `u64` doesn't have generic parameters | @@ -138,13 +138,13 @@ LL - let _x: u64; LL + let _x: u64; | -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on builtin type `char` --> $DIR/prim-with-args.rs:14:14 | LL | let _x: char; | ---- ^^^^^ type argument not allowed | | - | not allowed on this type + | not allowed on builtin type `char` | help: primitive type `char` doesn't have generic parameters | @@ -152,13 +152,13 @@ LL - let _x: char; LL + let _x: char; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `isize` --> $DIR/prim-with-args.rs:16:15 | LL | let _x: isize<'static>; | ----- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `isize` | help: primitive type `isize` doesn't have generic parameters | @@ -166,13 +166,13 @@ LL - let _x: isize<'static>; LL + let _x: isize; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `i8` --> $DIR/prim-with-args.rs:17:12 | LL | let _x: i8<'static>; | -- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i8` | help: primitive type `i8` doesn't have generic parameters | @@ -180,13 +180,13 @@ LL - let _x: i8<'static>; LL + let _x: i8; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `i16` --> $DIR/prim-with-args.rs:18:13 | LL | let _x: i16<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i16` | help: primitive type `i16` doesn't have generic parameters | @@ -194,13 +194,13 @@ LL - let _x: i16<'static>; LL + let _x: i16; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `i32` --> $DIR/prim-with-args.rs:19:13 | LL | let _x: i32<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i32` | help: primitive type `i32` doesn't have generic parameters | @@ -208,13 +208,13 @@ LL - let _x: i32<'static>; LL + let _x: i32; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `i64` --> $DIR/prim-with-args.rs:20:13 | LL | let _x: i64<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `i64` | help: primitive type `i64` doesn't have generic parameters | @@ -222,13 +222,13 @@ LL - let _x: i64<'static>; LL + let _x: i64; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `usize` --> $DIR/prim-with-args.rs:21:15 | LL | let _x: usize<'static>; | ----- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `usize` | help: primitive type `usize` doesn't have generic parameters | @@ -236,13 +236,13 @@ LL - let _x: usize<'static>; LL + let _x: usize; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `u8` --> $DIR/prim-with-args.rs:22:12 | LL | let _x: u8<'static>; | -- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u8` | help: primitive type `u8` doesn't have generic parameters | @@ -250,13 +250,13 @@ LL - let _x: u8<'static>; LL + let _x: u8; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `u16` --> $DIR/prim-with-args.rs:23:13 | LL | let _x: u16<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u16` | help: primitive type `u16` doesn't have generic parameters | @@ -264,13 +264,13 @@ LL - let _x: u16<'static>; LL + let _x: u16; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `u32` --> $DIR/prim-with-args.rs:24:13 | LL | let _x: u32<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u32` | help: primitive type `u32` doesn't have generic parameters | @@ -278,13 +278,13 @@ LL - let _x: u32<'static>; LL + let _x: u32; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `u64` --> $DIR/prim-with-args.rs:25:13 | LL | let _x: u64<'static>; | --- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `u64` | help: primitive type `u64` doesn't have generic parameters | @@ -292,13 +292,13 @@ LL - let _x: u64<'static>; LL + let _x: u64; | -error[E0109]: lifetime arguments are not allowed on this type +error[E0109]: lifetime arguments are not allowed on builtin type `char` --> $DIR/prim-with-args.rs:26:14 | LL | let _x: char<'static>; | ---- ^^^^^^^ lifetime argument not allowed | | - | not allowed on this type + | not allowed on builtin type `char` | help: primitive type `char` doesn't have generic parameters | diff --git a/src/test/ui/usize-generic-argument-parent.rs b/src/test/ui/usize-generic-argument-parent.rs index 6d17ba9b5b261..4ab80d944a56f 100644 --- a/src/test/ui/usize-generic-argument-parent.rs +++ b/src/test/ui/usize-generic-argument-parent.rs @@ -1,5 +1,5 @@ fn foo() { - let x: usize; //~ ERROR const arguments are not allowed on this type + let x: usize; //~ ERROR const arguments are not allowed on builtin type `usize` } fn main() {} diff --git a/src/test/ui/usize-generic-argument-parent.stderr b/src/test/ui/usize-generic-argument-parent.stderr index abe8c09b739f7..131c476aa55c0 100644 --- a/src/test/ui/usize-generic-argument-parent.stderr +++ b/src/test/ui/usize-generic-argument-parent.stderr @@ -1,10 +1,10 @@ -error[E0109]: const arguments are not allowed on this type +error[E0109]: const arguments are not allowed on builtin type `usize` --> $DIR/usize-generic-argument-parent.rs:2:18 | LL | let x: usize; | ----- ^^^ const argument not allowed | | - | not allowed on this type + | not allowed on builtin type `usize` | help: primitive type `usize` doesn't have generic parameters | From 761c846a0751ea48c45b246b0b21407e72e906b1 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 21 Jun 2022 18:56:04 +0100 Subject: [PATCH 08/24] Add `create_err` and `emit_err` to `ExtCtxt` --- compiler/rustc_expand/src/base.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 75b6b1cc9195b..245719bff1202 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -14,7 +14,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; -use rustc_session::{parse::ParseSess, Limit, Session}; +use rustc_session::{parse::ParseSess, Limit, Session, SessionDiagnostic}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; @@ -1085,6 +1085,17 @@ impl<'a> ExtCtxt<'a> { self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) } + pub fn create_err( + &self, + err: impl SessionDiagnostic<'a>, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + self.sess.create_err(err) + } + + pub fn emit_err(&self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { + self.sess.emit_err(err) + } + /// Emit `msg` attached to `sp`, without immediately stopping /// compilation. /// From d6072e53cd975839ad5e4c2d3ae101ce7ea0c3c0 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 21 Jun 2022 19:28:22 +0100 Subject: [PATCH 09/24] Add UI test for `cfg!(foo, bar)` --- src/test/ui/macros/cfg.rs | 1 + src/test/ui/macros/cfg.stderr | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/ui/macros/cfg.rs b/src/test/ui/macros/cfg.rs index 222161a8183a2..2aac50a9d011a 100644 --- a/src/test/ui/macros/cfg.rs +++ b/src/test/ui/macros/cfg.rs @@ -2,4 +2,5 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern cfg!(123); //~ ERROR expected identifier cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string + cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern } diff --git a/src/test/ui/macros/cfg.stderr b/src/test/ui/macros/cfg.stderr index 4785ef9aae482..2633d5f720d70 100644 --- a/src/test/ui/macros/cfg.stderr +++ b/src/test/ui/macros/cfg.stderr @@ -18,6 +18,14 @@ error[E0565]: literal in `cfg` predicate value must be a string LL | cfg!(foo = 123); | ^^^ -error: aborting due to 3 previous errors +error: expected 1 cfg-pattern + --> $DIR/cfg.rs:5:5 + | +LL | cfg!(foo, bar); + | ^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0565`. From 6264ffbfef035448661222ec9baf4648b1d9cb77 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 21 Jun 2022 20:10:31 +0100 Subject: [PATCH 10/24] Migrate `builtin-macros-requires-cfg-pattern` to `SessionDiagnostic` --- Cargo.lock | 1 + compiler/rustc_builtin_macros/Cargo.toml | 1 + compiler/rustc_builtin_macros/src/cfg.rs | 17 ++++++++++++----- .../locales/en-US/builtin_macros.ftl | 3 +++ compiler/rustc_error_messages/src/lib.rs | 1 + 5 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl diff --git a/Cargo.lock b/Cargo.lock index 1ca6ce25ba151..692474f2657b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3669,6 +3669,7 @@ dependencies = [ "rustc_feature", "rustc_lexer", "rustc_lint_defs", + "rustc_macros", "rustc_parse", "rustc_parse_format", "rustc_session", diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 9031c3b2ecfbb..7dc947f7d9a14 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -16,6 +16,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } +rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index f5ef4765df64f..2a6adc216643f 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -8,6 +8,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; use rustc_expand::base::{self, *}; +use rustc_macros::SessionDiagnostic; use rustc_span::Span; pub fn expand_cfg( @@ -34,13 +35,19 @@ pub fn expand_cfg( } } -fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { +#[derive(SessionDiagnostic)] +#[error(slug = "builtin-macros-requires-cfg-pattern")] +struct RequiresCfgPattern { + #[primary_span] + #[label] + span: Span, +} + +fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - let mut err = cx.struct_span_err(sp, "macro requires a cfg-pattern as an argument"); - err.span_label(sp, "cfg-pattern required"); - return Err(err); + return Err(cx.create_err(RequiresCfgPattern { span })); } let cfg = p.parse_meta_item()?; @@ -48,7 +55,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a let _ = p.eat(&token::Comma); if !p.eat(&token::Eof) { - return Err(cx.struct_span_err(sp, "expected 1 cfg-pattern")); + return Err(cx.struct_span_err(span, "expected 1 cfg-pattern")); } Ok(cfg) diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl new file mode 100644 index 0000000000000..89cd9fe579d6b --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -0,0 +1,3 @@ +builtin-macros-requires-cfg-pattern = + macro requires a cfg-pattern as an argument + .label = cfg-pattern required diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index ba7cc4908b80f..7211c05432698 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -33,6 +33,7 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { parser => "../locales/en-US/parser.ftl", typeck => "../locales/en-US/typeck.ftl", + builtin_macros => "../locales/en-US/builtin_macros.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; From be5337cde53eabca8a242d7de11f6702a40a1237 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 21 Jun 2022 20:20:00 +0100 Subject: [PATCH 11/24] Migrate `builtin-macros-expected-one-cfg-pattern` to `SessionDiagnostic` --- compiler/rustc_builtin_macros/src/cfg.rs | 9 ++++++++- .../locales/en-US/builtin_macros.ftl | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 2a6adc216643f..c75d83bd0a0e3 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -43,6 +43,13 @@ struct RequiresCfgPattern { span: Span, } +#[derive(SessionDiagnostic)] +#[error(slug = "builtin-macros-expected-one-cfg-pattern")] +struct OneCfgPattern { + #[primary_span] + span: Span, +} + fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); @@ -55,7 +62,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult< let _ = p.eat(&token::Comma); if !p.eat(&token::Eof) { - return Err(cx.struct_span_err(span, "expected 1 cfg-pattern")); + return Err(cx.create_err(OneCfgPattern { span })); } Ok(cfg) diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl index 89cd9fe579d6b..1d3e33c81851f 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -1,3 +1,5 @@ builtin-macros-requires-cfg-pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required + +builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern From 8e09f42042b5644aff05931b08112154c0575d5d Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Tue, 21 Jun 2022 13:19:44 -0700 Subject: [PATCH 12/24] Update Emscripten's no_default_libraries handling --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8ac5f094cf6ee..b5b63942e2c6e 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1140,7 +1140,7 @@ impl<'a> Linker for EmLinker<'a> { fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) { - self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); + self.cmd.arg("-nodefaultlibs"); } fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { From b052d76586988040c6ae8aef609794ae16cc28dc Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 21 Jun 2022 19:43:46 -0500 Subject: [PATCH 13/24] Address review comments from #98259 It got merged so fast I didn't have time to make changes xD --- compiler/rustc_middle/src/ty/context.rs | 16 +++++++++++- .../src/traits/error_reporting/suggestions.rs | 26 +++---------------- src/test/ui/async-await/issue-68112.stderr | 4 +-- ...e-70935-complex-spans.drop_tracking.stderr | 4 +-- .../async-await/issue-70935-complex-spans.rs | 4 +-- .../partial-drop-partial-reinit.rs | 2 +- .../partial-drop-partial-reinit.stderr | 2 +- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c43cf07b3ad0a..0765928e9b95c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -74,7 +74,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::RvalueScopes; +use super::{ImplPolarity, RvalueScopes}; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -2224,6 +2224,20 @@ impl<'tcx> TyCtxt<'tcx> { }) } + /// Given a `ty`, return whether it's an `impl Future<...>`. + pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool { + let ty::Opaque(def_id, _) = ty.kind() else { return false }; + let future_trait = self.lang_items().future_trait().unwrap(); + + self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { + let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { + return false; + }; + trait_predicate.trait_ref.def_id == future_trait + && trait_predicate.polarity == ImplPolarity::Positive + }) + } + /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 159fcf932a1da..19318a85a0125 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -8,7 +8,6 @@ use crate::infer::InferCtxt; use crate::traits::normalize_to; use hir::HirId; -use rustc_ast::Movability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -2406,19 +2405,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }; - let future_trait = self.tcx.lang_items().future_trait().unwrap(); - let opaque_ty_is_future = |def_id| { - self.tcx.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { - if let ty::PredicateKind::Trait(trait_predicate) = - predicate.kind().skip_binder() - { - trait_predicate.trait_ref.def_id == future_trait - } else { - false - } - }) - }; - let from_generator = tcx.lang_items().from_generator_fn().unwrap(); // Don't print the tuple of capture types @@ -2444,13 +2430,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If the previous type is `from_generator`, this is the future generated by the body of an async function. // Avoid printing it twice (it was already printed in the `ty::Generator` arm below). - let is_future = opaque_ty_is_future(def_id); + let is_future = tcx.ty_is_opaque_future(ty); debug!( ?obligated_types, ?is_future, "note_obligation_cause_code: check for async fn" ); - if opaque_ty_is_future(def_id) + if is_future && obligated_types.last().map_or(false, |ty| match ty.kind() { ty::Opaque(last_def_id, _) => { tcx.parent(*last_def_id) == from_generator @@ -2475,15 +2461,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } err.note(msg.trim_end_matches(", ")) } - ty::Generator(def_id, _, movability) => { + ty::Generator(def_id, _, _) => { let sp = self.tcx.def_span(def_id); // Special-case this to say "async block" instead of `[static generator]`. - let kind = if *movability == Movability::Static { - "async block" - } else { - "generator" - }; + let kind = tcx.generator_kind(def_id).unwrap(); err.span_note( sp, &format!("required because it's used within this {}", kind), diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index b8d3e1540d8a9..4285fbbeceb60 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -42,7 +42,7 @@ LL | require_send(send_fut); | = help: the trait `Sync` is not implemented for `RefCell` = note: required because of the requirements on the impl of `Send` for `Arc>` -note: required because it's used within this async block +note: required because it's used within this `async fn` body --> $DIR/issue-68112.rs:47:31 | LL | async fn ready2(t: T) -> T { t } @@ -53,7 +53,7 @@ note: required because it appears within the type `impl Future impl Future>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `ResumeTy`, `impl Future>>`, `()`, `i32`, `Ready` -note: required because it's used within this async block +note: required because it's used within this `async` block --> $DIR/issue-68112.rs:55:26 | LL | let send_fut = async { diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 19fd5eb7c73fb..43b7cb8cece36 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -14,7 +14,7 @@ LL | baz(|| async{ LL | | foo(tx.clone()); LL | | }).await; | |_________^ -note: required because it's used within this async block +note: required because it's used within this `async fn` body --> $DIR/issue-70935-complex-spans.rs:9:67 | LL | async fn baz(_c: impl FnMut() -> T) where T: Future { @@ -23,7 +23,7 @@ LL | | LL | | } | |_^ = note: required because it captures the following types: `ResumeTy`, `impl Future`, `()` -note: required because it's used within this async block +note: required because it's used within this `async` block --> $DIR/issue-70935-complex-spans.rs:23:16 | LL | async move { diff --git a/src/test/ui/async-await/issue-70935-complex-spans.rs b/src/test/ui/async-await/issue-70935-complex-spans.rs index 4bf94fe342c1d..f45ce1f25efa0 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.rs +++ b/src/test/ui/async-await/issue-70935-complex-spans.rs @@ -7,7 +7,7 @@ use std::future::Future; async fn baz(_c: impl FnMut() -> T) where T: Future { -//[drop_tracking]~^ within this async block +//[drop_tracking]~^ within this `async fn` body } fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { @@ -21,7 +21,7 @@ fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { //[drop_tracking]~| NOTE: in this expansion //[drop_tracking]~| NOTE: in this expansion async move { - //[drop_tracking]~^ within this async block + //[drop_tracking]~^ within this `async` block baz(|| async{ //[drop_tracking]~ NOTE: used within this closure foo(tx.clone()); }).await; diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs index 4fcfacea3f886..fe0fce7afd9f9 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.rs +++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs @@ -26,7 +26,7 @@ impl Drop for NotSend { impl !Send for NotSend {} async fn foo() { -//~^ NOTE used within this async block +//~^ NOTE used within this `async fn` body //~| NOTE within this `impl Future let mut x = (NotSend {},); drop(x.0); diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr index 96d0c71f103fb..05f5358340a98 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr @@ -12,7 +12,7 @@ LL | async fn foo() { = help: within `impl Future`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future`, `()` -note: required because it's used within this async block +note: required because it's used within this `async fn` body --> $DIR/partial-drop-partial-reinit.rs:28:16 | LL | async fn foo() { From f847261478de5fa72d7e1d2ec3341e31a794fcaf Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 22 Jun 2022 12:01:41 +0900 Subject: [PATCH 14/24] stop pointing at definitions of missing fields --- Cargo.lock | 1 - compiler/rustc_typeck/Cargo.toml | 1 - compiler/rustc_typeck/src/check/expr.rs | 69 ++++++++----------- src/test/ui/issues/issue-76077.stderr | 6 +- src/test/ui/privacy/issue-79593.stderr | 6 +- ...-missing-inaccessible-field-literal.stderr | 6 +- ...ng-private-fields-in-struct-literal.stderr | 10 +-- 7 files changed, 33 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc0f4cc53e656..df6f46f26cf0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4590,7 +4590,6 @@ dependencies = [ name = "rustc_typeck" version = "0.0.0" dependencies = [ - "itertools", "rustc_arena", "rustc_ast", "rustc_attr", diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index b3dd695508094..c08023ee6a70a 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -10,7 +10,6 @@ doctest = false [dependencies] rustc_arena = { path = "../rustc_arena" } tracing = "0.1" -itertools = "0.10.1" rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 0a017de80f248..e5048fc513217 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -23,13 +23,12 @@ use crate::type_error_struct; use super::suggest_call_constructor; use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; -use itertools::{Either, Itertools}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - EmissionGuarantee, ErrorGuaranteed, MultiSpan, + EmissionGuarantee, ErrorGuaranteed, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -1682,11 +1681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - if !private_fields.is_empty() - && tcx - .visibility(variant.def_id) - .is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) - { + if !private_fields.is_empty() { self.report_private_fields(adt_ty, span, private_fields, ast_fields); } else { self.report_missing_fields( @@ -1826,12 +1821,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { private_fields: Vec<&ty::FieldDef>, used_fields: &'tcx [hir::ExprField<'tcx>], ) { - let field_names = |fields: Vec, len: usize| match &fields + let mut err = self.tcx.sess.struct_span_err( + span, + &format!( + "cannot construct `{adt_ty}` with struct literal syntax due to private fields", + ), + ); + let (used_private_fields, remaining_private_fields): ( + Vec<(Symbol, Span, bool)>, + Vec<(Symbol, Span, bool)>, + ) = private_fields + .iter() + .map(|field| { + match used_fields.iter().find(|used_field| field.name == used_field.ident.name) { + Some(used_field) => (field.name, used_field.span, true), + None => (field.name, self.tcx.def_span(field.did), false), + } + }) + .partition(|field| field.2); + let remaining_private_fields_len = remaining_private_fields.len(); + let names = match &remaining_private_fields .iter() - .map(|field| field.to_string()) + .map(|(name, _, _)| name.to_string()) .collect::>()[..] { - _ if len > 6 => String::new(), + _ if remaining_private_fields_len > 6 => String::new(), [name] => format!("`{name}` "), [names @ .., last] => { let names = names.iter().map(|name| format!("`{name}`")).collect::>(); @@ -1839,36 +1853,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } [] => unreachable!(), }; - - let mut err = self.tcx.sess.struct_span_err( - span, - &format!( - "cannot construct `{adt_ty}` with struct literal syntax due to private fields", - ), - ); - let (used_private_fields, remaining_private_fields): ( - Vec<(Symbol, Span)>, - Vec<(Symbol, Span)>, - ) = private_fields.iter().partition_map(|field| { - match used_fields.iter().find(|used_field| field.name == used_field.ident.name) { - Some(used_field) => Either::Left((field.name, used_field.span)), - None => Either::Right((field.name, self.tcx.def_span(field.did))), - } - }); - let remaining_private_fields_len = remaining_private_fields.len(); - err.span_labels(used_private_fields.iter().map(|(_, span)| *span), "private field"); - err.span_note( - MultiSpan::from_spans(remaining_private_fields.iter().map(|(_, span)| *span).collect()), - format!( - "missing field{s} {names}{are} private", - s = pluralize!(remaining_private_fields_len), - are = pluralize!("is", remaining_private_fields_len), - names = field_names( - remaining_private_fields.iter().map(|(name, _)| *name).collect(), - remaining_private_fields_len - ) - ), - ); + err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field"); + err.note(format!( + "... and other private field{s} {names}that were not provided", + s = pluralize!(remaining_private_fields_len), + )); err.emit(); } diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr index c70a928f6475a..57f7abe3931a4 100644 --- a/src/test/ui/issues/issue-76077.stderr +++ b/src/test/ui/issues/issue-76077.stderr @@ -4,11 +4,7 @@ error: cannot construct `Foo` with struct literal syntax due to private fields LL | foo::Foo {}; | ^^^^^^^^ | -note: missing field `you_cant_use_this_field` is private - --> $DIR/issue-76077.rs:3:9 - | -LL | you_cant_use_this_field: bool, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ... and other private field `you_cant_use_this_field` that were not provided error: aborting due to previous error diff --git a/src/test/ui/privacy/issue-79593.stderr b/src/test/ui/privacy/issue-79593.stderr index 435d4cbf73595..d878e1c023ff1 100644 --- a/src/test/ui/privacy/issue-79593.stderr +++ b/src/test/ui/privacy/issue-79593.stderr @@ -16,11 +16,7 @@ error: cannot construct `Pub` with struct literal syntax due to private fields LL | foo::Pub {}; | ^^^^^^^^ | -note: missing field `private` is private - --> $DIR/issue-79593.rs:2:22 - | -LL | pub struct Pub { private: () } - | ^^^^^^^^^^^ + = note: ... and other private field `private` that were not provided error[E0063]: missing field `y` in initializer of `Enum` --> $DIR/issue-79593.rs:23:5 diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr index 2ade7aea57b3d..fa1c661ef244e 100644 --- a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr @@ -4,11 +4,7 @@ error: cannot construct `Foo` with struct literal syntax due to private fields LL | foo::Foo {}; | ^^^^^^^^ | -note: missing field `you_cant_use_this_field` is private - --> $DIR/issue-87872-missing-inaccessible-field-literal.rs:4:9 - | -LL | you_cant_use_this_field: bool, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ... and other private field `you_cant_use_this_field` that were not provided error: aborting due to previous error diff --git a/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr b/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr index eb5f460f868e1..234110f31f79c 100644 --- a/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr +++ b/src/test/ui/typeck/missing-private-fields-in-struct-literal.stderr @@ -9,15 +9,7 @@ LL | a: (), LL | b: (), | ----- private field | -note: missing fields `c`, `d` and `e` are private - --> $DIR/missing-private-fields-in-struct-literal.rs:6:9 - | -LL | c: (), - | ^^^^^ -LL | d: (), - | ^^^^^ -LL | e: (), - | ^^^^^ + = note: ... and other private fields `c`, `d` and `e` that were not provided error: aborting due to previous error From 46b2454bad71b844ef5eb40860fb50131b6fe168 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Jun 2022 17:11:28 -0700 Subject: [PATCH 15/24] clarify Arc::clone overflow check comment --- library/alloc/src/sync.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 2670b15982ad9..24e849aab4cce 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1355,15 +1355,16 @@ impl Clone for Arc { // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) let old_size = self.inner().strong.fetch_add(1, Relaxed); - // However we need to guard against massive refcounts in case someone - // is `mem::forget`ing Arcs. If we don't do this the count can overflow - // and users will use-after free. We racily saturate to `isize::MAX` on - // the assumption that there aren't ~2 billion threads incrementing - // the reference count at once. This branch will never be taken in - // any realistic program. + // However we need to guard against massive refcounts in case someone is `mem::forget`ing + // Arcs. If we don't do this the count can overflow and users will use-after free. This + // branch will never be taken in any realistic program. We abort because such a program is + // incredibly degenerate, and we don't care to support it. // - // We abort because such a program is incredibly degenerate, and we - // don't care to support it. + // This check is not 100% water-proof: we error when the refcount grows beyond `isize::MAX`. + // But we do that check *after* having done the increment, so there is a chance here that + // the worst already happened and we actually do overflow the `usize` counter. However, that + // requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment + // above and the `abort` below, which seems exceedingly unlikely. if old_size > MAX_REFCOUNT { abort(); } From eb86daa1383d5330a18aa4e78270a6ca5b4ea469 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 22 Jun 2022 14:56:40 +0900 Subject: [PATCH 16/24] add "was" to pluralize macro and use it --- compiler/rustc_lint_defs/src/lib.rs | 3 ++ compiler/rustc_typeck/src/check/expr.rs | 39 ++++++++++--------- src/test/ui/issues/issue-76077.stderr | 2 +- src/test/ui/privacy/issue-79593.stderr | 2 +- ...-missing-inaccessible-field-literal.stderr | 2 +- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cb1c6f4098767..1cd19c7eaab35 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -26,6 +26,9 @@ macro_rules! pluralize { ("is", $x:expr) => { if $x == 1 { "is" } else { "are" } }; + ("was", $x:expr) => { + if $x == 1 { "was" } else { "were" } + }; ("this", $x:expr) => { if $x == 1 { "this" } else { "these" } }; diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e5048fc513217..c69de6434539a 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1839,25 +1839,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) .partition(|field| field.2); - let remaining_private_fields_len = remaining_private_fields.len(); - let names = match &remaining_private_fields - .iter() - .map(|(name, _, _)| name.to_string()) - .collect::>()[..] - { - _ if remaining_private_fields_len > 6 => String::new(), - [name] => format!("`{name}` "), - [names @ .., last] => { - let names = names.iter().map(|name| format!("`{name}`")).collect::>(); - format!("{} and `{last}` ", names.join(", ")) - } - [] => unreachable!(), - }; err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field"); - err.note(format!( - "... and other private field{s} {names}that were not provided", - s = pluralize!(remaining_private_fields_len), - )); + if !remaining_private_fields.is_empty() { + let remaining_private_fields_len = remaining_private_fields.len(); + let names = match &remaining_private_fields + .iter() + .map(|(name, _, _)| name.to_string()) + .collect::>()[..] + { + _ if remaining_private_fields_len > 6 => String::new(), + [name] => format!("`{name}` "), + [names @ .., last] => { + let names = names.iter().map(|name| format!("`{name}`")).collect::>(); + format!("{} and `{last}` ", names.join(", ")) + } + [] => unreachable!(), + }; + err.note(format!( + "... and other private field{s} {names}that {were} not provided", + s = pluralize!(remaining_private_fields_len), + were = pluralize!("was", remaining_private_fields_len), + )); + } err.emit(); } diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr index 57f7abe3931a4..197ca8d5a7b25 100644 --- a/src/test/ui/issues/issue-76077.stderr +++ b/src/test/ui/issues/issue-76077.stderr @@ -4,7 +4,7 @@ error: cannot construct `Foo` with struct literal syntax due to private fields LL | foo::Foo {}; | ^^^^^^^^ | - = note: ... and other private field `you_cant_use_this_field` that were not provided + = note: ... and other private field `you_cant_use_this_field` that was not provided error: aborting due to previous error diff --git a/src/test/ui/privacy/issue-79593.stderr b/src/test/ui/privacy/issue-79593.stderr index d878e1c023ff1..21ba760ad0bcc 100644 --- a/src/test/ui/privacy/issue-79593.stderr +++ b/src/test/ui/privacy/issue-79593.stderr @@ -16,7 +16,7 @@ error: cannot construct `Pub` with struct literal syntax due to private fields LL | foo::Pub {}; | ^^^^^^^^ | - = note: ... and other private field `private` that were not provided + = note: ... and other private field `private` that was not provided error[E0063]: missing field `y` in initializer of `Enum` --> $DIR/issue-79593.rs:23:5 diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr index fa1c661ef244e..f0bd3e0ddf768 100644 --- a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr @@ -4,7 +4,7 @@ error: cannot construct `Foo` with struct literal syntax due to private fields LL | foo::Foo {}; | ^^^^^^^^ | - = note: ... and other private field `you_cant_use_this_field` that were not provided + = note: ... and other private field `you_cant_use_this_field` that was not provided error: aborting due to previous error From 53481a5a8fde83ed1a5d7e8302be028a4c7d8da5 Mon Sep 17 00:00:00 2001 From: Rose Hudson Date: Wed, 22 Jun 2022 14:06:13 +0100 Subject: [PATCH 17/24] implement `iter_projections` function on `PlaceRef` this makes the api more flexible. the original function now calls the PlaceRef version to avoid duplicating the code. --- compiler/rustc_middle/src/mir/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4265559cd3197..3f5b16d5ea5f7 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2145,10 +2145,7 @@ impl<'tcx> Place<'tcx> { pub fn iter_projections( self, ) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { - self.projection.iter().enumerate().map(move |(i, proj)| { - let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; - (base, proj) - }) + self.as_ref().iter_projections() } /// Generates a new place by appending `more_projections` to the existing ones @@ -2208,6 +2205,23 @@ impl<'tcx> PlaceRef<'tcx> { None } } + + /// Iterate over the projections in evaluation order, i.e., the first element is the base with + /// its projection and then subsequently more projections are added. + /// As a concrete example, given the place a.b.c, this would yield: + /// - (a, .b) + /// - (a.b, .c) + /// + /// Given a place without projections, the iterator is empty. + #[inline] + pub fn iter_projections( + self, + ) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { + self.projection.iter().enumerate().map(move |(i, proj)| { + let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; + (base, *proj) + }) + } } impl Debug for Place<'_> { From 8e40d936473c41342e935ab323d755210af285e0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jun 2022 16:26:04 +0200 Subject: [PATCH 18/24] Filter out keyword items in rustdoc JSON output --- src/librustdoc/json/conversions.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4fde63c99d4b9..c627dcc30d667 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -43,7 +43,7 @@ impl JsonRenderer<'_> { let span = item.span(self.tcx); let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item; let inner = match *item.kind { - clean::StrippedItem(_) => return None, + clean::StrippedItem(_) | clean::KeywordItem(_) => return None, _ => from_clean_item(item, self.tcx), }; Some(Item { @@ -254,11 +254,8 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { }, // FIXME: do not map to Typedef but to a custom variant AssocTypeItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)), - // `convert_item` early returns `None` for striped items - StrippedItem(_) => unreachable!(), - KeywordItem(_) => { - panic!("{:?} is not supported for JSON output", item) - } + // `convert_item` early returns `None` for striped items and keywords. + StrippedItem(_) | KeywordItem(_) => unreachable!(), ExternCrateItem { ref src } => ItemEnum::ExternCrate { name: name.as_ref().unwrap().to_string(), rename: src.map(|x| x.to_string()), @@ -764,7 +761,7 @@ impl FromWithTcx for ItemKind { fn ids(items: impl IntoIterator, tcx: TyCtxt<'_>) -> Vec { items .into_iter() - .filter(|x| !x.is_stripped()) + .filter(|x| !x.is_stripped() && !x.is_keyword()) .map(|i| from_item_id_with_name(i.item_id, tcx, i.name)) .collect() } From 75ad2f7a76170943aaf543c74097927e57a89f32 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 22 Jun 2022 16:26:22 +0200 Subject: [PATCH 19/24] Add test for keywords in rustdoc JSON output --- src/test/rustdoc-json/keyword.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/rustdoc-json/keyword.rs diff --git a/src/test/rustdoc-json/keyword.rs b/src/test/rustdoc-json/keyword.rs new file mode 100644 index 0000000000000..78a843aca7b95 --- /dev/null +++ b/src/test/rustdoc-json/keyword.rs @@ -0,0 +1,21 @@ +// Regression test for . + +// Keywords should not be generated in rustdoc JSON output and this test +// ensures it. + +#![feature(rustdoc_internals)] +#![no_std] + +// @has keyword.json +// @!has - "$.index[*][?(@.name=='match')]" +// @has - "$.index[*][?(@.name=='foo')]" + +#[doc(keyword = "match")] +/// this is a test! +pub mod foo {} + +// @!has - "$.index[*][?(@.name=='hello')]" +// @!has - "$.index[*][?(@.name=='bar')]" +#[doc(keyword = "hello")] +/// hello +mod bar {} From 96cc0c691a0b91e02a3011ecd2cdf8c087ecc470 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 22 Jun 2022 14:01:31 -0700 Subject: [PATCH 20/24] triagebot.toml: Allow applying nominated labels This seems likely to help more than it would hurt; let's see how it goes. --- triagebot.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 25e2c384624e9..dbaee7983bbc2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,14 +1,12 @@ [relabel] allow-unauthenticated = [ - "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", + "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", "I-*", "D-*", "needs-fcp", "relnotes", "requires-nightly", "regression-*", "perf-*", - # I-* without I-*nominated - "I-*", "!I-*nominated", "AsyncAwait-OnDeck", ] From 5cf5a5236f298d701bb59941125acbd953d1ebfb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 22 Jun 2022 14:02:48 -0700 Subject: [PATCH 21/24] triagebot.toml: Sort and wrap the list of allowed labels --- triagebot.toml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index dbaee7983bbc2..cef78cc3b336e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,16 @@ [relabel] allow-unauthenticated = [ - "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", "I-*", + "A-*", + "C-*", "D-*", + "E-*", + "F-*", + "I-*", + "NLL-*", + "O-*", + "S-*", + "T-*", + "WG-*", "needs-fcp", "relnotes", "requires-nightly", From 24e0c44eb66fb3c1a2305cc67fea0e042e678b7f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 22 Jun 2022 16:11:10 -0700 Subject: [PATCH 22/24] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 396fdb69de7fb..efbafdba36184 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 396fdb69de7fb18f24b15c7ad13491b1c1fa7231 +Subproject commit efbafdba3618487fbc9305318fcab9775132ac15 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index cbb494f96da32..e17dcef5e9634 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit cbb494f96da3268c2925bdadc65ca83d42f2d4ef +Subproject commit e17dcef5e96346ee3d7fa56820ddc7e5c39636bc diff --git a/src/doc/reference b/src/doc/reference index 683bfe5cd64d5..9fce337a55ee4 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 683bfe5cd64d589c6a1645312ab5f93b6385ccbb +Subproject commit 9fce337a55ee4a4629205f6094656195cecad231 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index dbb7e5e2345ee..1095df2a5850f 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit dbb7e5e2345ee26199ffba218156b6009016a20c +Subproject commit 1095df2a5850f2d345fad43a30633133365875ba diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 6e4d6435db89b..048d925f0a955 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 6e4d6435db89bcc027b1bba9742e4f59666f5412 +Subproject commit 048d925f0a955aac601c4160c0e7f05771bcf63b From b96ae9b20442b59c471baec6c4d612e3434d893c Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Wed, 22 Jun 2022 17:43:10 -0700 Subject: [PATCH 23/24] Set no_default_libraries: false in wasm32_emscripten target --- compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 975051100b039..6a1a5e7a1d712 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -28,6 +28,7 @@ pub fn target() -> Target { linker: None, is_like_emscripten: true, panic_strategy: PanicStrategy::Unwind, + no_default_libraries: false, post_link_args, families: cvs!["unix", "wasm"], ..options From 137d3c7067a96d45ea96d53f523d482928668619 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Jun 2022 13:04:29 +0200 Subject: [PATCH 24/24] Update browser-ui-test version to 0.9.6 This update provides a better error message when chromium crashes --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 03834411d1529..9cf038687f117 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.9.5 \ No newline at end of file +0.9.6 \ No newline at end of file