From cd7c161294eac4c2cce5c503f1c5b05ce24864a7 Mon Sep 17 00:00:00 2001 From: Antoine PLASKOWSKI Date: Tue, 2 May 2023 20:36:48 +0200 Subject: [PATCH 01/55] Add known issue of let binding to format_args doc --- library/core/src/macros/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7c93c93b4a01..a9818371f9ea 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -868,6 +868,14 @@ pub(crate) mod builtin { /// let s = fmt::format(format_args!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world")); /// ``` + /// + /// # Lifetime limitation + /// + /// Except when no formatting arguments are used, + /// the produced `fmt::Arguments` value borrows temporary values, + /// which means it can only be used within the same expression + /// and cannot be stored for later use. + /// This is a known limitation, see [#92698](https://github.com/rust-lang/rust/issues/92698). #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "format_args_macro")] #[allow_internal_unsafe] From 9d84589a96c4f14cb9ac955b8708412854f9246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 11 Jan 2024 00:00:00 +0000 Subject: [PATCH 02/55] Waker::will_wake: Compare vtable address instead of its content Optimize will_wake implementation by comparing vtable address instead of its content. The existing best practice to avoid false negatives from will_wake is to define a waker vtable as a static item. That approach continues to works with the new implementation. While this potentially changes the observable behaviour, the function is documented to work on a best-effort basis. The PartialEq impl for RawWaker remains as it was. --- library/core/src/task/wake.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 9c41b8b4f46a..d6169c4a1191 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -313,7 +313,9 @@ impl Waker { #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] pub fn will_wake(&self, other: &Waker) -> bool { - self.waker == other.waker + let RawWaker { data: a_data, vtable: a_vtable } = self.waker; + let RawWaker { data: b_data, vtable: b_vtable } = other.waker; + a_data == b_data && ptr::eq(a_vtable, b_vtable) } /// Creates a new `Waker` from [`RawWaker`]. From 57e0dea178eba21de2b001f731aeb95692ee84b9 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 15:39:19 +0100 Subject: [PATCH 03/55] Document requirements for unsized {Rc,Arc}::from_raw --- library/alloc/src/rc.rs | 20 ++++++++++++++------ library/alloc/src/sync.rs | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 7705c86001e6..5e85746656ec 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1181,12 +1181,19 @@ impl Rc { /// Constructs an `Rc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] where `U` must have the same size - /// and alignment as `T`. This is trivially true if `U` is `T`. - /// Note that if `U` is not `T` but has the same size and alignment, this is - /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what - /// restrictions apply in this case. + /// [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. /// /// The raw pointer must point to a block of memory allocated by the global allocator /// @@ -1198,6 +1205,7 @@ impl Rc { /// /// [into_raw]: Rc::into_raw /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 48c8d9d113b0..95cf2da0ecf7 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1329,12 +1329,19 @@ impl Arc { /// Constructs an `Arc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Arc::into_raw`][into_raw] where `U` must have the same size and - /// alignment as `T`. This is trivially true if `U` is `T`. - /// Note that if `U` is not `T` but has the same size and alignment, this is - /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what - /// restrictions apply in this case. + /// [`Arc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. /// /// The user of `from_raw` has to make sure a specific value of `T` is only /// dropped once. @@ -1344,6 +1351,7 @@ impl Arc { /// /// [into_raw]: Arc::into_raw /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples /// From d4adb3af585daac5077c8852bc0b26bb661330c8 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 16:07:07 +0100 Subject: [PATCH 04/55] Add examples for unsized {Rc,Arc}::from_raw --- library/alloc/src/rc.rs | 14 ++++++++++++++ library/alloc/src/sync.rs | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 5e85746656ec..0a959738b97e 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1225,6 +1225,20 @@ impl Rc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x: Rc<[u32]> = Rc::new([1, 2, 3]); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()) + /// assert_eq!(x.as_ref(), &[1, 2, 3]); + /// } + /// ``` #[inline] #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 95cf2da0ecf7..708f11edc448 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1371,6 +1371,20 @@ impl Arc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x: Arc<[u32]> = Arc::new([1, 2, 3]); + /// let x_ptr: *const [u32] = Arc::into_raw(x); + /// + /// unsafe { + /// let x: Arc<[u32; 3]> = Arc::from_raw(x_ptr.cast::<[u32; 3]>()) + /// assert_eq!(x.as_ref(), &[1, 2, 3]); + /// } + /// ``` #[inline] #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { From 23c83fab2b16d79b248b1b5f2faf7b538afec9f6 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 16:12:09 +0100 Subject: [PATCH 05/55] Tidy up --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0a959738b97e..1d16095db1e4 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1182,7 +1182,7 @@ impl Rc { /// /// The raw pointer must have been previously returned by a call to /// [`Rc::into_raw`][into_raw] with the following requirements: - /// + /// /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 708f11edc448..0487dc5a8583 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1330,7 +1330,7 @@ impl Arc { /// /// The raw pointer must have been previously returned by a call to /// [`Arc::into_raw`][into_raw] with the following requirements: - /// + /// /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and From d63384d689ef9dab759eee57e3c2b0f82dfef4e3 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 16:38:38 +0100 Subject: [PATCH 06/55] Fix doctest --- library/alloc/src/rc.rs | 4 ++-- library/alloc/src/sync.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1d16095db1e4..8331a2d63a01 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1235,8 +1235,8 @@ impl Rc { /// let x_ptr: *const [u32] = Rc::into_raw(x); /// /// unsafe { - /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()) - /// assert_eq!(x.as_ref(), &[1, 2, 3]); + /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()); + /// assert_eq!(&*x, &[1, 2, 3]); /// } /// ``` #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 0487dc5a8583..bfbdfce57186 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1381,8 +1381,8 @@ impl Arc { /// let x_ptr: *const [u32] = Arc::into_raw(x); /// /// unsafe { - /// let x: Arc<[u32; 3]> = Arc::from_raw(x_ptr.cast::<[u32; 3]>()) - /// assert_eq!(x.as_ref(), &[1, 2, 3]); + /// let x: Arc<[u32; 3]> = Arc::from_raw(x_ptr.cast::<[u32; 3]>()); + /// assert_eq!(&*x, &[1, 2, 3]); /// } /// ``` #[inline] From eebc7207579d06ccdb38bd79c01bec08f1c29bde Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 17:00:13 +0100 Subject: [PATCH 07/55] Replicate documentation in {Rc,Arc}::from_raw_in --- library/alloc/src/rc.rs | 43 +++++++++++++++++++++++++++++++-------- library/alloc/src/sync.rs | 39 ++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 8331a2d63a01..ebd816fba813 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1186,8 +1186,8 @@ impl Rc { /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Arc` was constructed - /// through `Arc` and then converted to `Arc` through an [unsized + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized /// coercion]. /// /// Note that if `U` or `U`'s data pointer is not `T` but has the same size @@ -1363,13 +1363,20 @@ impl Rc { /// Constructs an `Rc` from a raw pointer in the provided allocator. /// - /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] where `U` must have the same size - /// and alignment as `T`. This is trivially true if `U` is `T`. - /// Note that if `U` is not `T` but has the same size and alignment, this is - /// basically like transmuting references of different types. See - /// [`mem::transmute`] for more information on what - /// restrictions apply in this case. + /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. /// /// The raw pointer must point to a block of memory allocated by `alloc` /// @@ -1380,6 +1387,7 @@ impl Rc { /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples /// @@ -1402,6 +1410,23 @@ impl Rc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x: Rc<[u32]> = Rc::new_in([1, 2, 3], System); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3]> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { let offset = unsafe { data_offset(ptr) }; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index bfbdfce57186..96f8f57f9e09 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1514,13 +1514,20 @@ impl Arc { /// Constructs an `Arc` from a raw pointer. /// - /// The raw pointer must have been previously returned by a call to - /// [`Arc::into_raw`][into_raw] where `U` must have the same size and - /// alignment as `T`. This is trivially true if `U` is `T`. - /// Note that if `U` is not `T` but has the same size and alignment, this is - /// basically like transmuting references of different types. See - /// [`mem::transmute`] for more information on what - /// restrictions apply in this case. + /// The raw pointer must have been previously returned by a call to [`Arc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. /// /// The raw pointer must point to a block of memory allocated by `alloc` /// @@ -1531,6 +1538,7 @@ impl Arc { /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples /// @@ -1553,6 +1561,23 @@ impl Arc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::sync::Arc; + /// use std::alloc::System; + /// + /// let x: Arc<[u32]> = Arc::new_in([1, 2, 3], System); + /// let x_ptr: *const [u32] = Arc::into_raw(x); + /// + /// unsafe { + /// let x: Arc<[u32; 3]> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { From bdbbf04a03311a79a193196f7ac64e5fd164af44 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 28 Jan 2024 17:33:17 +0100 Subject: [PATCH 08/55] Fix doctest --- library/alloc/src/rc.rs | 5 +++-- library/alloc/src/sync.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index ebd816fba813..ca4ddaa92a54 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1387,6 +1387,7 @@ impl Rc { /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples @@ -1419,11 +1420,11 @@ impl Rc { /// use std::rc::Rc; /// use std::alloc::System; /// - /// let x: Rc<[u32]> = Rc::new_in([1, 2, 3], System); + /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); /// let x_ptr: *const [u32] = Rc::into_raw(x); /// /// unsafe { - /// let x: Rc<[u32; 3]> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); /// assert_eq!(&*x, &[1, 2, 3]); /// } /// ``` diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 96f8f57f9e09..9bf4881869ed 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1538,6 +1538,7 @@ impl Arc { /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// /// # Examples @@ -1570,11 +1571,11 @@ impl Arc { /// use std::sync::Arc; /// use std::alloc::System; /// - /// let x: Arc<[u32]> = Arc::new_in([1, 2, 3], System); + /// let x: Arc<[u32], _> = Arc::new_in([1, 2, 3], System); /// let x_ptr: *const [u32] = Arc::into_raw(x); /// /// unsafe { - /// let x: Arc<[u32; 3]> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// let x: Arc<[u32; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); /// assert_eq!(&*x, &[1, 2, 3]); /// } /// ``` From adb7607189e04a20e67fe089d23d418826177186 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 30 Jan 2024 17:51:20 +0000 Subject: [PATCH 09/55] Fix BTreeMap's Cursor::remove_{next,prev} These would incorrectly leave `current` as `None` after a failed attempt to remove an element (due to the cursor already being at the start/end). --- library/alloc/src/collections/btree/map.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b585e2082f13..6e0b79b9640f 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -3198,9 +3198,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn remove_next(&mut self) -> Option<(K, V)> { let current = self.current.take()?; + if current.reborrow().next_kv().is_err() { + self.current = Some(current); + return None; + } let mut emptied_internal_root = false; let (kv, pos) = current .next_kv() + // This should be unwrap(), but that doesn't work because NodeRef + // doesn't implement Debug. The condition is checked above. .ok()? .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); self.current = Some(pos); @@ -3221,9 +3227,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn remove_prev(&mut self) -> Option<(K, V)> { let current = self.current.take()?; + if current.reborrow().next_back_kv().is_err() { + self.current = Some(current); + return None; + } let mut emptied_internal_root = false; let (kv, pos) = current .next_back_kv() + // This should be unwrap(), but that doesn't work because NodeRef + // doesn't implement Debug. The condition is checked above. .ok()? .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); self.current = Some(pos); From 01fa7209d597c770a51c44839a97d2731419392c Mon Sep 17 00:00:00 2001 From: Marcondiro <46560192+Marcondiro@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:24:27 +0100 Subject: [PATCH 10/55] Bump Unicode to version 15.1.0, regenerate tables --- library/core/src/unicode/unicode_data.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index b25e9df28680..dd2ad9a58f67 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -99,21 +99,21 @@ fn skip_search( offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (15, 1, 0); #[rustfmt::skip] pub mod alphabetic { - static SHORT_OFFSET_RUNS: [u32; 53] = [ + static SHORT_OFFSET_RUNS: [u32; 54] = [ 706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392, 1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214, 1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200, 2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240, 2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678, 2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408, - 3038947040, 3041048378, 3045248674, 3053644769, 3057842176, 3059939870, 3062038528, - 3064140619, 3066241968, 3071550384, + 3038947040, 3041048378, 3045248674, 3053644769, 3057839710, 3062036480, 3064134174, + 3066232832, 3068334923, 3070436272, 3075744688, ]; - static OFFSETS: [u8; 1465] = [ + static OFFSETS: [u8; 1467] = [ 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42, 5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, @@ -167,7 +167,7 @@ pub mod alphabetic { 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, - 0, 6, 222, 2, 0, 14, 0, 0, 0, 0, 0, 5, 0, 0, + 0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( From 6686ca08a2f1350de83ac91e36cb9132fa6d53ce Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 5 Feb 2024 10:13:48 +0000 Subject: [PATCH 11/55] std::thread update freebsd stack guard handling. up to now, it had been assumed the stack guard setting default is not touched in the field but some user might just want to disable it or increase it. checking it once at runtime should be enough. --- library/std/src/sys/pal/unix/thread.rs | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 7e4a01a5ecd3..ba8d31c23a51 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -847,11 +847,31 @@ pub mod guard { let stackptr = get_stack_start_aligned()?; let guardaddr = stackptr.addr(); // Technically the number of guard pages is tunable and controlled - // by the security.bsd.stack_guard_page sysctl, but there are - // few reasons to change it from the default. The default value has - // been 1 ever since FreeBSD 11.1 and 10.4. - const GUARD_PAGES: usize = 1; - let guard = guardaddr..guardaddr + GUARD_PAGES * page_size; + // by the security.bsd.stack_guard_page sysctl. + // By default it is 1, checking once is enough since it is + // a boot time config value. + static LOCK: crate::sync::OnceLock = crate::sync::OnceLock::new(); + let guard = guardaddr + ..guardaddr + + *LOCK.get_or_init(|| { + use crate::sys::weak::dlsym; + dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); + let mut guard: usize = 0; + let mut size = crate::mem::size_of_val(&guard); + let oid = crate::ffi::CStr::from_bytes_with_nul( + b"security.bsd.stack_guard_page\0", + ) + .unwrap(); + match sysctlbyname.get() { + Some(fcn) => { + if fcn(oid.as_ptr(), &mut guard as *mut _ as *mut _, &mut size as *mut _ as *mut _, crate::ptr::null_mut(), 0) == 0 { + return guard; + } + return 1; + }, + _ => { return 1; } + } + }) * page_size; Some(guard) } else if cfg!(target_os = "openbsd") { // OpenBSD stack already includes a guard page, and stack is From 213748749e32d3ec7e136f0aa73f205700e274c1 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 12 Feb 2024 19:44:35 +0000 Subject: [PATCH 12/55] Add APIs for fetching foreign items including foreign modules, their ABIs, and their items --- Cargo.lock | 1 + compiler/rustc_smir/Cargo.toml | 1 + compiler/rustc_smir/src/rustc_internal/mod.rs | 4 + compiler/rustc_smir/src/rustc_smir/context.rs | 62 ++++++++++++- .../rustc_smir/src/rustc_smir/convert/ty.rs | 80 ++++++++++------ compiler/stable_mir/src/compiler_interface.rs | 13 ++- compiler/stable_mir/src/lib.rs | 7 +- compiler/stable_mir/src/ty.rs | 36 ++++++- tests/ui-fulldeps/stable-mir/check_foreign.rs | 93 +++++++++++++++++++ 9 files changed, 259 insertions(+), 38 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/check_foreign.rs diff --git a/Cargo.lock b/Cargo.lock index d552bb655b40..46661b9c3115 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4559,6 +4559,7 @@ dependencies = [ "rustc_data_structures", "rustc_hir", "rustc_middle", + "rustc_session", "rustc_span", "rustc_target", "scoped-tls", diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index c9e23efcb10c..1e0a60bc371a 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -9,6 +9,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } +rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } scoped-tls = "1.0" diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 43987fcf10fc..6bb8c5452b98 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -85,6 +85,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::AdtDef(self.create_def_id(did)) } + pub fn foreign_module_def(&mut self, did: DefId) -> stable_mir::ty::ForeignModuleDef { + stable_mir::ty::ForeignModuleDef(self.create_def_id(did)) + } + pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef { stable_mir::ty::ForeignDef(self.create_def_id(did)) } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 94a1fb33f99c..24dd7ad6d7eb 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -22,10 +22,10 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::Body; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, - LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, + ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef, }; -use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; +use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; use std::iter; @@ -67,6 +67,39 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.is_mir_available(def_id) } + fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + tcx.foreign_modules(crate_num.internal(&mut *tables, tcx)) + .keys() + .map(|mod_def_id| tables.foreign_module_def(*mod_def_id)) + .collect() + } + + fn foreign_module( + &self, + mod_def: stable_mir::ty::ForeignModuleDef, + ) -> stable_mir::ty::ForeignModule { + let mut tables = self.0.borrow_mut(); + let def_id = tables[mod_def.def_id()]; + let mod_def = tables.tcx.foreign_modules(def_id.krate).get(&def_id).unwrap(); + mod_def.stable(&mut *tables) + } + + fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec { + let mut tables = self.0.borrow_mut(); + let def_id = tables[mod_def.def_id()]; + tables + .tcx + .foreign_modules(def_id.krate) + .get(&def_id) + .unwrap() + .foreign_items + .iter() + .map(|item_def| tables.foreign_def(*item_def)) + .collect() + } + fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() @@ -225,6 +258,29 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.is_foreign_item(tables[item]) } + fn foreign_item_kind(&self, def: ForeignDef) -> Option { + let (def_id, hir_kind) = { + let tables = self.0.borrow(); + let def_id = tables[def.def_id()]; + let hir_kind = tables + .tcx + .hir() + .expect_foreign_item(rustc_hir::OwnerId { def_id: def_id.as_local()? }) + .kind; + (def_id, hir_kind) + }; + let kind = match hir_kind { + rustc_hir::ForeignItemKind::Fn(..) => { + ForeignItemKind::Fn(self.0.borrow_mut().fn_def(def_id)) + } + rustc_hir::ForeignItemKind::Static(..) => { + ForeignItemKind::Static(self.0.borrow_mut().static_def(def_id)) + } + rustc_hir::ForeignItemKind::Type => ForeignItemKind::Type(self.def_ty(def.def_id())), + }; + Some(kind) + } + fn adt_kind(&self, def: AdtDef) -> AdtKind { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 959a17d24b7c..29081418200e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -202,41 +202,13 @@ where impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { type T = stable_mir::ty::FnSig; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - use rustc_target::spec::abi; - use stable_mir::ty::{Abi, FnSig}; + use stable_mir::ty::FnSig; FnSig { inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(), c_variadic: self.c_variadic, unsafety: self.unsafety.stable(tables), - abi: match self.abi { - abi::Abi::Rust => Abi::Rust, - abi::Abi::C { unwind } => Abi::C { unwind }, - abi::Abi::Cdecl { unwind } => Abi::Cdecl { unwind }, - abi::Abi::Stdcall { unwind } => Abi::Stdcall { unwind }, - abi::Abi::Fastcall { unwind } => Abi::Fastcall { unwind }, - abi::Abi::Vectorcall { unwind } => Abi::Vectorcall { unwind }, - abi::Abi::Thiscall { unwind } => Abi::Thiscall { unwind }, - abi::Abi::Aapcs { unwind } => Abi::Aapcs { unwind }, - abi::Abi::Win64 { unwind } => Abi::Win64 { unwind }, - abi::Abi::SysV64 { unwind } => Abi::SysV64 { unwind }, - abi::Abi::PtxKernel => Abi::PtxKernel, - abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt, - abi::Abi::X86Interrupt => Abi::X86Interrupt, - abi::Abi::EfiApi => Abi::EfiApi, - abi::Abi::AvrInterrupt => Abi::AvrInterrupt, - abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, - abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, - abi::Abi::Wasm => Abi::Wasm, - abi::Abi::System { unwind } => Abi::System { unwind }, - abi::Abi::RustIntrinsic => Abi::RustIntrinsic, - abi::Abi::RustCall => Abi::RustCall, - abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic, - abi::Abi::Unadjusted => Abi::Unadjusted, - abi::Abi::RustCold => Abi::RustCold, - abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM, - abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS, - }, + abi: self.abi.stable(tables), } } } @@ -832,3 +804,51 @@ impl<'tcx> Stable<'tcx> for ty::Movability { } } } + +impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { + type T = stable_mir::ty::Abi; + + fn stable(&self, _: &mut Tables<'_>) -> Self::T { + use rustc_target::spec::abi; + use stable_mir::ty::Abi; + match *self { + abi::Abi::Rust => Abi::Rust, + abi::Abi::C { unwind } => Abi::C { unwind }, + abi::Abi::Cdecl { unwind } => Abi::Cdecl { unwind }, + abi::Abi::Stdcall { unwind } => Abi::Stdcall { unwind }, + abi::Abi::Fastcall { unwind } => Abi::Fastcall { unwind }, + abi::Abi::Vectorcall { unwind } => Abi::Vectorcall { unwind }, + abi::Abi::Thiscall { unwind } => Abi::Thiscall { unwind }, + abi::Abi::Aapcs { unwind } => Abi::Aapcs { unwind }, + abi::Abi::Win64 { unwind } => Abi::Win64 { unwind }, + abi::Abi::SysV64 { unwind } => Abi::SysV64 { unwind }, + abi::Abi::PtxKernel => Abi::PtxKernel, + abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt, + abi::Abi::X86Interrupt => Abi::X86Interrupt, + abi::Abi::EfiApi => Abi::EfiApi, + abi::Abi::AvrInterrupt => Abi::AvrInterrupt, + abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, + abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, + abi::Abi::Wasm => Abi::Wasm, + abi::Abi::System { unwind } => Abi::System { unwind }, + abi::Abi::RustIntrinsic => Abi::RustIntrinsic, + abi::Abi::RustCall => Abi::RustCall, + abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic, + abi::Abi::Unadjusted => Abi::Unadjusted, + abi::Abi::RustCold => Abi::RustCold, + abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM, + abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule { + type T = stable_mir::ty::ForeignModule; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + stable_mir::ty::ForeignModule { + def_id: tables.foreign_module_def(self.def_id), + abi: self.abi.stable(tables), + } + } +} diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index fb83dae57142..f55e0f9481fe 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -11,9 +11,10 @@ use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::Body; use crate::target::MachineInfo; use crate::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, - GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, - TraitDef, Ty, TyKind, VariantDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, + ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, + ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, TyKind, + VariantDef, }; use crate::{ mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind, @@ -31,6 +32,9 @@ pub trait Context { fn mir_body(&self, item: DefId) -> mir::Body; /// Check whether the body of a function is available. fn has_body(&self, item: DefId) -> bool; + fn foreign_modules(&self, crate_num: CrateNum) -> Vec; + fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; + fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; fn all_trait_decls(&self) -> TraitDecls; fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls; fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; @@ -66,6 +70,9 @@ pub trait Context { /// Returns whether this is a foreign item. fn is_foreign_item(&self, item: DefId) -> bool; + /// Returns the kind of a given foreign item. + fn foreign_item_kind(&self, def: ForeignDef) -> Option; + /// Returns the kind of a given algebraic data type fn adt_kind(&self, def: AdtDef) -> AdtKind; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 4f57f532a40c..d849c834ae00 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -30,7 +30,7 @@ pub use crate::error::*; use crate::mir::pretty::function_name; use crate::mir::Body; use crate::mir::Mutability; -use crate::ty::{ImplDef, IndexedVal, Span, TraitDef, Ty}; +use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; pub mod abi; #[macro_use] @@ -86,6 +86,11 @@ pub struct Crate { } impl Crate { + /// The list of foreign modules in this crate. + pub fn foreign_modules(&self) -> Vec { + with(|cx| cx.foreign_modules(self.id)) + } + /// The list of traits declared in this crate. pub fn trait_decls(&self) -> TraitDecls { with(|cx| cx.trait_decls(self.id)) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bdda92953470..f043ce9d898d 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -4,9 +4,9 @@ use super::{ with, DefId, Error, Symbol, }; use crate::abi::Layout; -use crate::crate_def::CrateDef; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::target::MachineInfo; +use crate::{crate_def::CrateDef, mir::mono::StaticDef}; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; @@ -539,11 +539,45 @@ pub enum Movability { Movable, } +crate_def! { + pub ForeignModuleDef; +} + +impl ForeignModuleDef { + pub fn module(&self) -> ForeignModule { + with(|cx| cx.foreign_module(*self)) + } +} + +pub struct ForeignModule { + pub def_id: ForeignModuleDef, + pub abi: Abi, +} + +impl ForeignModule { + pub fn items(&self) -> Vec { + with(|cx| cx.foreign_items(self.def_id)) + } +} + crate_def! { /// Hold information about a ForeignItem in a crate. pub ForeignDef; } +impl ForeignDef { + pub fn kind(&self) -> Option { + with(|cx| cx.foreign_item_kind(*self)) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum ForeignItemKind { + Fn(FnDef), + Static(StaticDef), + Type(Ty), +} + crate_def! { /// Hold information about a function definition in a crate. pub FnDef; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs new file mode 100644 index 000000000000..22770a56e329 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -0,0 +1,93 @@ +// run-pass +//! Test retrieval and kinds of foreign items. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate rustc_span; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::{ + ty::{Abi, ForeignItemKind}, + *, +}; +use std::assert_matches::assert_matches; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_foreign() -> ControlFlow<()> { + let mods = + local_crate().foreign_modules().into_iter().map(|def| def.module()).collect::>(); + assert_eq!(mods.len(), 2); + + let rust_mod = mods.iter().find(|m| matches!(m.abi, Abi::Rust)).unwrap(); + assert_eq!(rust_mod.items().len(), 1); + + let c_mod = mods.iter().find(|m| matches!(m.abi, Abi::C { .. })).unwrap(); + let c_items = c_mod.items(); + assert_eq!(c_items.len(), 3); + for item in c_items { + let kind = item.kind().unwrap(); + match item.name().as_str() { + "foo" => assert_matches!(kind, ForeignItemKind::Fn(..)), + "bar" => assert_matches!(kind, ForeignItemKind::Static(..)), + "Baz" => assert_matches!(kind, ForeignItemKind::Type(..)), + name => unreachable!("Unexpected item {name}"), + }; + } + ControlFlow::Continue(()) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "foreign_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, || test_foreign()).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + #![feature(extern_types)] + #![allow(unused)] + extern "Rust" {{ + fn rust_foo(x: i32) -> i32; + }} + extern "C" {{ + fn foo(x: i32) -> i32; + static bar: i32; + type Baz; + }} + "# + )?; + Ok(()) +} From dee2d0f33351491c322e5ce15c7e90a61f425b67 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 11 Feb 2024 00:01:43 +0530 Subject: [PATCH 13/55] Implement Instant for UEFI - Uses Timestamp Protocol if present. Else use rdtsc for x86 and x86-64 Signed-off-by: Ayush Singh --- library/std/src/lib.rs | 4 + library/std/src/sys/pal/uefi/time.rs | 116 +++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 571e475c3367..ad694f6d04b2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -263,6 +263,10 @@ #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))] #![cfg_attr(target_os = "xous", feature(slice_ptr_len))] #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] +#![cfg_attr( + all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"), + feature(stdarch_x86_has_cpuid) +)] // // Language features: // tidy-alphabetical-start diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 68f428c38fbb..76562cf9f51c 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -14,6 +14,15 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { + // If we have a timestamp protocol, use it. + if let Some(x) = instant_internal::timestamp_protocol() { + return x; + } + + if let Some(x) = instant_internal::platform_specific() { + return x; + } + panic!("time not implemented on this platform") } @@ -103,3 +112,110 @@ pub(crate) mod system_time_internal { Duration::new(utc_epoch, t.nanosecond) } } + +pub(crate) mod instant_internal { + use super::super::helpers; + use super::*; + use crate::mem::MaybeUninit; + use crate::ptr::NonNull; + use crate::sync::atomic::{AtomicPtr, Ordering}; + use crate::sys_common::mul_div_u64; + use r_efi::protocols::timestamp; + + const NS_PER_SEC: u64 = 1_000_000_000; + + pub fn timestamp_protocol() -> Option { + fn try_handle(handle: NonNull) -> Option { + let protocol: NonNull = + helpers::open_protocol(handle, timestamp::PROTOCOL_GUID).ok()?; + let mut properties: MaybeUninit = MaybeUninit::uninit(); + + let r = unsafe { ((*protocol.as_ptr()).get_properties)(properties.as_mut_ptr()) }; + if r.is_error() { + return None; + } + + let freq = unsafe { properties.assume_init().frequency }; + let ts = unsafe { ((*protocol.as_ptr()).get_timestamp)() }; + Some(mul_div_u64(ts, NS_PER_SEC, freq)) + } + + static LAST_VALID_HANDLE: AtomicPtr = + AtomicPtr::new(crate::ptr::null_mut()); + + if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) { + if let Some(ns) = try_handle(handle) { + return Some(Instant(Duration::from_nanos(ns))); + } + } + + if let Ok(handles) = helpers::locate_handles(timestamp::PROTOCOL_GUID) { + for handle in handles { + if let Some(ns) = try_handle(handle) { + LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release); + return Some(Instant(Duration::from_nanos(ns))); + } + } + } + + None + } + + pub fn platform_specific() -> Option { + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] { + timestamp_rdtsc().map(Instant) + } else { + None + } + } + } + + #[cfg(target_arch = "x86_64")] + fn timestamp_rdtsc() -> Option { + if !crate::arch::x86_64::has_cpuid() { + return None; + } + + static FREQUENCY: crate::sync::OnceLock = crate::sync::OnceLock::new(); + + // Get Frequency in Mhz + // Inspired by [`edk2/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c`](https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c) + let freq = FREQUENCY + .get_or_try_init(|| { + let cpuid = unsafe { crate::arch::x86_64::__cpuid(0x15) }; + if cpuid.eax == 0 || cpuid.ebx == 0 || cpuid.ecx == 0 { + return Err(()); + } + Ok(mul_div_u64(cpuid.ecx as u64, cpuid.ebx as u64, cpuid.eax as u64)) + }) + .ok()?; + + let ts = unsafe { crate::arch::x86_64::_rdtsc() }; + let ns = mul_div_u64(ts, 1000, *freq); + Some(Duration::from_nanos(ns)) + } + + #[cfg(target_arch = "x86")] + fn timestamp_rdtsc() -> Option { + if !crate::arch::x86::has_cpuid() { + return None; + } + + static FREQUENCY: crate::sync::OnceLock = crate::sync::OnceLock::new(); + + let freq = FREQUENCY + .get_or_try_init(|| { + let cpuid = unsafe { crate::arch::x86::__cpuid(0x15) }; + if cpuid.eax == 0 || cpuid.ebx == 0 || cpuid.ecx == 0 { + return Err(()); + } + Ok(mul_div_u64(cpuid.ecx as u64, cpuid.ebx as u64, cpuid.eax as u64)) + }) + .ok()?; + + let ts = unsafe { crate::arch::x86::_rdtsc() }; + let ns = mul_div_u64(ts, 1000, *freq); + Some(Duration::from_nanos(ns)) + } +} From a261f8edd8de496c1bbb8b1e220148776ccf35cb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 15 Nov 2023 10:08:36 +0000 Subject: [PATCH 14/55] Move windows_sys.lst to bindings.txt --- .../std/src/sys/pal/windows/c/{windows_sys.lst => bindings.txt} | 1 - 1 file changed, 1 deletion(-) rename library/std/src/sys/pal/windows/c/{windows_sys.lst => bindings.txt} (99%) diff --git a/library/std/src/sys/pal/windows/c/windows_sys.lst b/library/std/src/sys/pal/windows/c/bindings.txt similarity index 99% rename from library/std/src/sys/pal/windows/c/windows_sys.lst rename to library/std/src/sys/pal/windows/c/bindings.txt index f91e1054a040..1e4d696a0018 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.lst +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2593,4 +2593,3 @@ Windows.Win32.System.Threading.WakeConditionVariable Windows.Win32.System.WindowsProgramming.PROGRESS_CONTINUE Windows.Win32.UI.Shell.GetUserProfileDirectoryW // tidy-alphabetical-end - From adcbeb7fdb4157d108fd939697d0991840c7a58f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 8 Dec 2023 15:01:38 +0000 Subject: [PATCH 15/55] Add windows_sys readme --- library/std/src/sys/pal/windows/c/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 library/std/src/sys/pal/windows/c/README.md diff --git a/library/std/src/sys/pal/windows/c/README.md b/library/std/src/sys/pal/windows/c/README.md new file mode 100644 index 000000000000..d458e55efbcd --- /dev/null +++ b/library/std/src/sys/pal/windows/c/README.md @@ -0,0 +1,9 @@ +The `windows_sys.rs` file is autogenerated from `bindings.txt` and must not +be edited manually. + +To add bindings, edit `bindings.txt` then regenerate using the following command: + + ./x run generate-windows-sys && ./x fmt library/std + +If you need to override generated functions or types then add them to +`library/std/src/sys/pal/windows/c.rs`. From 846315ddc95fbe02841c88c540e85f60cb670230 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 8 Dec 2023 15:22:34 +0000 Subject: [PATCH 16/55] Automatically sort windows_sys bindings --- .../std/src/sys/pal/windows/c/bindings.txt | 2 - .../std/src/sys/pal/windows/c/windows_sys.rs | 7 +-- src/tools/generate-windows-sys/src/main.rs | 51 ++++++++++++------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 1e4d696a0018..726f1c3df829 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -1,7 +1,6 @@ --out windows_sys.rs --config flatten std --filter -// tidy-alphabetical-start !Windows.Win32.Foundation.INVALID_HANDLE_VALUE Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED Windows.Wdk.Storage.FileSystem.FILE_CONTAINS_EXTENDED_CREATE_INFORMATION @@ -2592,4 +2591,3 @@ Windows.Win32.System.Threading.WakeAllConditionVariable Windows.Win32.System.Threading.WakeConditionVariable Windows.Win32.System.WindowsProgramming.PROGRESS_CONTINUE Windows.Win32.UI.Shell.GetUserProfileDirectoryW -// tidy-alphabetical-end diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index b38b70c8983e..c386b66a722d 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,9 +1,3 @@ -// This file is autogenerated. -// -// To add bindings, edit windows_sys.lst then use `./x run generate-windows-sys` to -// regenerate the bindings. -// -// ignore-tidy-filelength // Bindings generated by `windows-bindgen` 0.52.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] @@ -4351,3 +4345,4 @@ impl ::core::clone::Clone for XSAVE_FORMAT { *self } } +// ignore-tidy-filelength diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs index dc95d969aede..c8913910bd6e 100644 --- a/src/tools/generate-windows-sys/src/main.rs +++ b/src/tools/generate-windows-sys/src/main.rs @@ -1,34 +1,49 @@ use std::env; use std::error::Error; use std::fs; -use std::io::{self, Read, Seek, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; -/// This is printed to the file before the rest of the contents. -const PRELUDE: &str = r#"// This file is autogenerated. -// -// To add bindings, edit windows_sys.lst then use `./x run generate-windows-sys` to -// regenerate the bindings. -// -// ignore-tidy-filelength -"#; - fn main() -> Result<(), Box> { let mut path: PathBuf = env::args_os().nth(1).expect("a path to the rust repository is required").into(); path.push("library/std/src/sys/pal/windows/c"); env::set_current_dir(&path)?; - let info = windows_bindgen::bindgen(["--etc", "windows_sys.lst"])?; + sort_bindings("bindings.txt")?; + + let info = windows_bindgen::bindgen(["--etc", "bindings.txt"])?; println!("{info}"); - // add some gunk to the output file. - let mut f = fs::File::options().read(true).write(true).open("windows_sys.rs")?; - let mut bindings = String::new(); - f.read_to_string(&mut bindings)?; - f.seek(io::SeekFrom::Start(0))?; - f.write_all(PRELUDE.as_bytes())?; - f.write_all(bindings.as_bytes())?; + let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?; + writeln!(&mut f, "// ignore-tidy-filelength")?; Ok(()) } + +fn sort_bindings(file_name: &str) -> Result<(), Box> { + let mut f = fs::File::options().read(true).write(true).open(file_name)?; + let mut bindings = String::new(); + f.read_to_string(&mut bindings)?; + f.set_len(0)?; + f.seek(SeekFrom::Start(0))?; + + let mut lines = bindings.split_inclusive('\n'); + for line in &mut lines { + f.write(line.as_bytes())?; + if line.contains("--filter") { + break; + } + } + let mut bindings = Vec::new(); + for line in &mut lines { + if !line.trim().is_empty() { + bindings.push(line); + } + } + bindings.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); + for line in bindings { + f.write(line.as_bytes())?; + } + Ok(()) +} From 3f27e4b3ea35c87c1e8a6b9b8a3c7e122f6299de Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 11 Feb 2024 19:50:50 +0800 Subject: [PATCH 17/55] clean up potential_query_instability with FxIndexMap and UnordMap --- .../rustc_borrowck/src/universal_regions.rs | 7 ++--- compiler/rustc_codegen_llvm/src/back/lto.rs | 6 ++--- .../src/coverageinfo/mapgen.rs | 1 - .../src/assert_module_sources.rs | 10 +++---- .../rustc_codegen_ssa/src/back/archive.rs | 4 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 26 ++++++++----------- compiler/rustc_codegen_ssa/src/back/write.rs | 4 +-- compiler/rustc_codegen_ssa/src/base.rs | 15 +++++------ compiler/rustc_codegen_ssa/src/lib.rs | 14 +++++----- .../rustc_const_eval/src/interpret/memory.rs | 10 +++---- compiler/rustc_data_structures/src/unord.rs | 5 ++++ compiler/rustc_errors/src/diagnostic.rs | 9 +++---- .../rustc_hir_analysis/src/astconv/bounds.rs | 4 +-- .../rustc_hir_analysis/src/astconv/errors.rs | 4 +-- .../rustc_hir_analysis/src/astconv/mod.rs | 4 +-- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/check/compare_impl_item.rs | 14 +++++----- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +-- .../src/coherence/inherent_impls_overlap.rs | 14 +++++----- compiler/rustc_hir_analysis/src/collect.rs | 6 ++--- .../src/outlives/explicit.rs | 6 ++--- .../src/outlives/implicit_infer.rs | 10 +++---- compiler/rustc_hir_typeck/src/expr.rs | 12 ++++----- compiler/rustc_interface/src/passes.rs | 6 +---- compiler/rustc_lint/src/context.rs | 22 +++++++--------- compiler/rustc_lint/src/non_ascii_idents.rs | 1 - compiler/rustc_middle/src/mir/mono.rs | 9 +++---- .../rustc_monomorphize/src/partitioning.rs | 4 +-- compiler/rustc_session/src/parse.rs | 12 ++++----- tests/ui/parser/emoji-identifiers.stderr | 16 ++++++------ 30 files changed, 122 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index a7bdfa4eae76..90e8f1b93b29 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -15,7 +15,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -180,7 +180,7 @@ struct UniversalRegionIndices<'tcx> { /// basically equivalent to an `GenericArgs`, except that it also /// contains an entry for `ReStatic` -- it might be nice to just /// use an args, and then handle `ReStatic` another way. - indices: FxHashMap, RegionVid>, + indices: FxIndexMap, RegionVid>, /// The vid assigned to `'static`. Used only for diagnostics. pub fr_static: RegionVid, @@ -325,9 +325,6 @@ impl<'tcx> UniversalRegions<'tcx> { } /// Gets an iterator over all the early-bound regions that have names. - /// Iteration order may be unstable, so this should only be used when - /// iteration order doesn't affect anything - #[allow(rustc::potential_query_instability)] pub fn named_universal_regions<'s>( &'s self, ) -> impl Iterator, ty::RegionVid)> + 's { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 42bd8687042a..06a681c24e69 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -21,6 +21,7 @@ use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::config::{self, CrateType, Lto}; +use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::fs::File; use std::io; @@ -787,7 +788,7 @@ pub unsafe fn optimize_thin_module( #[derive(Debug, Default)] pub struct ThinLTOKeysMap { // key = llvm name of importing module, value = LLVM cache key - keys: FxHashMap, + keys: BTreeMap, } impl ThinLTOKeysMap { @@ -797,7 +798,6 @@ impl ThinLTOKeysMap { let mut writer = io::BufWriter::new(file); // The entries are loaded back into a hash map in `load_from_file()`, so // the order in which we write them to file here does not matter. - #[allow(rustc::potential_query_instability)] for (module, key) in &self.keys { writeln!(writer, "{module} {key}")?; } @@ -806,7 +806,7 @@ impl ThinLTOKeysMap { fn load_from_file(path: &Path) -> io::Result { use std::io::BufRead; - let mut keys = FxHashMap::default(); + let mut keys = BTreeMap::default(); let file = File::open(path)?; for line in io::BufReader::new(file).lines() { let line = line?; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index b1ceb1d4dd56..6116a6fd222b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -403,7 +403,6 @@ fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet { let mut result = items.clone(); for cgu in cgus { - #[allow(rustc::potential_query_instability)] for item in cgu.items().keys() { if let mir::mono::MonoItem::Fn(ref instance) = item { let did = instance.def_id(); diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 3e5a43c6e73a..344e7dbdf034 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -25,7 +25,7 @@ use crate::errors; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::LOCAL_CRATE; @@ -218,8 +218,8 @@ pub enum ComparisonKind { } struct TrackerData { - actual_reuse: FxHashMap, - expected_reuse: FxHashMap, + actual_reuse: UnordMap, + expected_reuse: UnordMap, } pub struct CguReuseTracker { @@ -267,9 +267,7 @@ impl CguReuseTracker { fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { - #[allow(rustc::potential_query_instability)] - let mut keys = data.expected_reuse.keys().collect::>(); - keys.sort_unstable(); + let keys = data.expected_reuse.keys().into_sorted_stable_ord(); for cgu_name in keys { let &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind) = data.expected_reuse.get(cgu_name).unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 8d7ad24b4469..0dadd047c9a9 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_session::cstore::DllImport; use rustc_session::Session; @@ -41,7 +41,7 @@ pub trait ArchiveBuilderBuilder { &'a self, rlib: &'a Path, outdir: &Path, - bundled_lib_file_names: &FxHashSet, + bundled_lib_file_names: &FxIndexSet, ) -> Result<(), ExtractBundledLibsError<'_>> { let archive_map = unsafe { Mmap::map( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b29f71bfb955..435b517e602b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,7 +1,6 @@ use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; @@ -534,9 +533,9 @@ fn link_staticlib<'a>( let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter(); let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); - let relevant_libs: FxHashSet<_> = relevant.filter_map(|lib| lib.filename).collect(); + let relevant_libs: FxIndexSet<_> = relevant.filter_map(|lib| lib.filename).collect(); - let bundled_libs: FxHashSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); + let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); ab.add_archive( path, Box::new(move |fname: &str| { @@ -564,11 +563,7 @@ fn link_staticlib<'a>( .extract_bundled_libs(path, tempdir.as_ref(), &relevant_libs) .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); - // We sort the libraries below - #[allow(rustc::potential_query_instability)] - let mut relevant_libs: Vec = relevant_libs.into_iter().collect(); - relevant_libs.sort_unstable(); - for filename in relevant_libs { + for filename in relevant_libs.iter() { let joined = tempdir.as_ref().join(filename.as_str()); let path = joined.as_path(); ab.add_archive(path, Box::new(|_| false)).unwrap(); @@ -682,13 +677,14 @@ fn link_dwarf_object<'a>( } // Input rlibs contain .o/.dwo files from dependencies. - #[allow(rustc::potential_query_instability)] let input_rlibs = cg_results .crate_info .used_crate_source - .values() - .filter_map(|csource| csource.rlib.as_ref()) - .map(|(path, _)| path); + .items() + .filter_map(|(_, csource)| csource.rlib.as_ref()) + .map(|(path, _)| path) + .into_sorted_stable_ord(); + for input_rlib in input_rlibs { debug!(?input_rlib); package.add_input_object(input_rlib)?; @@ -2456,7 +2452,7 @@ fn add_native_libs_from_crate( codegen_results: &CodegenResults, tmpdir: &Path, search_paths: &SearchPaths, - bundled_libs: &FxHashSet, + bundled_libs: &FxIndexSet, cnum: CrateNum, link_static: bool, link_dynamic: bool, @@ -2777,7 +2773,7 @@ fn add_static_crate<'a>( codegen_results: &CodegenResults, tmpdir: &Path, cnum: CrateNum, - bundled_lib_file_names: &FxHashSet, + bundled_lib_file_names: &FxIndexSet, ) { let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a63642d76b97..24fdd0135092 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1001,7 +1001,7 @@ pub struct CguMessage; struct Diagnostic { msgs: Vec<(DiagnosticMessage, Style)>, - args: FxHashMap, + args: FxIndexMap, code: Option, lvl: Level, } @@ -1813,7 +1813,7 @@ impl Translate for SharedEmitter { impl Emitter for SharedEmitter { fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) { - let args: FxHashMap = + let args: FxIndexMap = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msgs: diag.messages.clone(), diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 098ea1b793cc..760b3f30ee51 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -16,9 +16,10 @@ use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCode use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_map; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -851,6 +852,8 @@ impl CrateInfo { // `compiler_builtins` are always placed last to ensure that they're linked correctly. used_crates.extend(compiler_builtins); + let crates = tcx.crates(()); + let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, crate_types, @@ -862,19 +865,15 @@ impl CrateInfo { is_no_builtins: Default::default(), native_libraries: Default::default(), used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), - crate_name: Default::default(), + crate_name: UnordMap::with_capacity(n_crates), used_crates, - used_crate_source: Default::default(), + used_crate_source: UnordMap::with_capacity(n_crates), dependency_formats: tcx.dependency_formats(()).clone(), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; - let crates = tcx.crates(()); - let n_crates = crates.len(); info.native_libraries.reserve(n_crates); - info.crate_name.reserve(n_crates); - info.used_crate_source.reserve(n_crates); for &cnum in crates.iter() { info.native_libraries @@ -901,7 +900,7 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxHashSet = info + let missing_weak_lang_items: FxIndexSet = info .used_crates .iter() .flat_map(|&cnum| tcx.missing_lang_items(cnum)) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1afc597a7ef0..92f0be541c0b 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -24,8 +24,10 @@ extern crate tracing; extern crate rustc_middle; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -152,16 +154,16 @@ impl From<&cstore::NativeLib> for NativeLib { pub struct CrateInfo { pub target_cpu: String, pub crate_types: Vec, - pub exported_symbols: FxHashMap>, - pub linked_symbols: FxHashMap>, + pub exported_symbols: UnordMap>, + pub linked_symbols: FxIndexMap>, pub local_crate_name: Symbol, pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>, - pub crate_name: FxHashMap, + pub native_libraries: FxIndexMap>, + pub crate_name: UnordMap, pub used_libraries: Vec, - pub used_crate_source: FxHashMap>, + pub used_crate_source: UnordMap>, pub used_crates: Vec, pub dependency_formats: Lrc, pub windows_subsystem: Option, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 4acf4ed893c5..a59429bfaacb 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -13,7 +13,7 @@ use std::fmt; use std::ptr; use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; @@ -104,13 +104,13 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub(super) alloc_map: M::MemoryMap, /// Map for "extra" function pointers. - extra_fn_ptr_map: FxHashMap, + extra_fn_ptr_map: FxIndexMap, /// To be able to compare pointers with null, and to check alignment for accesses /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations /// that do not exist any more. // FIXME: this should not be public, but interning currently needs access to it - pub(super) dead_alloc_map: FxHashMap, + pub(super) dead_alloc_map: FxIndexMap, } /// A reference to some allocation that was already bounds-checked for the given region @@ -135,8 +135,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn new() -> Self { Memory { alloc_map: M::MemoryMap::default(), - extra_fn_ptr_map: FxHashMap::default(), - dead_alloc_map: FxHashMap::default(), + extra_fn_ptr_map: FxIndexMap::default(), + dead_alloc_map: FxIndexMap::default(), } } diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 907c866b3edd..a99e2062039b 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -524,6 +524,11 @@ impl UnordMap { UnordItems(self.inner.into_iter()) } + #[inline] + pub fn keys(&self) -> UnordItems<&K, impl Iterator> { + UnordItems(self.inner.keys()) + } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). /// /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 2deb18484ec2..6570ae3bc385 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -3,7 +3,7 @@ use crate::{ CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; @@ -105,7 +105,7 @@ pub struct Diagnostic { pub span: MultiSpan, pub children: Vec, pub suggestions: Result, SuggestionsDisabled>, - args: FxHashMap, + args: FxIndexMap, /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of @@ -899,9 +899,6 @@ impl Diagnostic { self } - // Exact iteration order of diagnostic arguments shouldn't make a difference to output because - // they're only used in interpolation. - #[allow(rustc::potential_query_instability)] pub fn args(&self) -> impl Iterator> { self.args.iter() } @@ -915,7 +912,7 @@ impl Diagnostic { self } - pub fn replace_args(&mut self, args: FxHashMap) { + pub fn replace_args(&mut self, args: FxIndexMap) { self.args = args; } diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 1ae267d1a405..3f9c783793e0 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -241,7 +241,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { binding: &ConvertedBinding<'_, 'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - dup_bindings: &mut FxHashMap, + dup_bindings: &mut FxIndexMap, path_span: Span, only_self_bounds: OnlySelfBounds, ) -> Result<(), ErrorGuaranteed> { diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 3c64b102bae8..ea8d364bba6c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -5,7 +5,7 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -806,7 +806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if suggestions.len() != 1 || already_has_generics_args_suggestion { // We don't need this label if there's an inline suggestion, show otherwise. for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); + let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); for item in assoc_items { types_count += 1; *names.entry(item.name).or_insert(0) += 1; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a643614d33db..2028c1e45b0d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -16,7 +16,7 @@ use crate::errors::AmbiguousLifetimeBound; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, @@ -750,7 +750,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?poly_trait_ref, ?assoc_bindings); bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); - let mut dup_bindings = FxHashMap::default(); + let mut dup_bindings = FxIndexMap::default(); for binding in &assoc_bindings { // Don't register additional associated type bounds for negative bounds, // since we should have emitten an error for them earlier, and they will diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f55cba2707c5..787dc3b4d327 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1363,7 +1363,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD // `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized` // since it would overwrite the span of the user-written bound. This could be fixed by // folding the spans with `Span::to` which requires a bit of effort I think. - .collect::>() + .collect::>() }); let mut params_used = BitSet::new_empty(generics.params.len()); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6edd68f1baeb..e257907e40f5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,7 +1,7 @@ use super::potentially_plural_count; use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture}; use hir::def_id::{DefId, DefIdMap, LocalDefId}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -392,7 +392,7 @@ fn compare_method_predicate_entailment<'tcx>( struct RemapLateBound<'a, 'tcx> { tcx: TyCtxt<'tcx>, - mapping: &'a FxHashMap, + mapping: &'a FxIndexMap, } impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { @@ -553,7 +553,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // prove below that the hidden types are well formed. let universe = infcx.create_next_universe(); let mut idx = 0; - let mapping: FxHashMap<_, _> = collector + let mapping: FxIndexMap<_, _> = collector .types .iter() .map(|(_, &(ty, _))| { @@ -690,7 +690,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // contains `def_id`'s early-bound regions. let id_args = GenericArgs::identity_for_item(tcx, def_id); debug!(?id_args, ?args); - let map: FxHashMap<_, _> = std::iter::zip(args, id_args) + let map: FxIndexMap<_, _> = std::iter::zip(args, id_args) .skip(tcx.generics_of(trait_m.def_id).count()) .filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?))) .collect(); @@ -766,7 +766,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( struct ImplTraitInTraitCollector<'a, 'tcx> { ocx: &'a ObligationCtxt<'a, 'tcx>, - types: FxHashMap, ty::GenericArgsRef<'tcx>)>, + types: FxIndexMap, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, @@ -779,7 +779,7 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> Self { - ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id } + ImplTraitInTraitCollector { ocx, types: FxIndexMap::default(), span, param_env, body_id } } } @@ -838,7 +838,7 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { struct RemapHiddenTyRegions<'tcx> { tcx: TyCtxt<'tcx>, - map: FxHashMap, ty::Region<'tcx>>, + map: FxIndexMap, ty::Region<'tcx>>, num_trait_args: usize, num_impl_args: usize, def_id: DefId, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b74431983113..992b118a003c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -76,7 +76,7 @@ pub use check::check_abi; use std::num::NonZeroU32; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::ErrorGuaranteed; use rustc_errors::{pluralize, struct_span_code_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -307,7 +307,7 @@ fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator, Span)>, ) -> (String, String) { - let mut types: FxHashMap, Vec> = FxHashMap::default(); + let mut types: FxIndexMap, Vec> = FxIndexMap::default(); let mut projections = vec![]; for (predicate, _) in predicates { debug!("predicate {:?}", predicate); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 951440d6a2d0..9e1e884d9769 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,4 +1,5 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::IndexEntry; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -9,7 +10,6 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{ErrorGuaranteed, Symbol}; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; -use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let mut inherent_overlap_checker = InherentOverlapChecker { tcx }; @@ -63,7 +63,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> { let impl_items = self.tcx.associated_items(impl_); - let mut seen_items = FxHashMap::default(); + let mut seen_items = FxIndexMap::default(); let mut res = Ok(()); for impl_item in impl_items.in_definition_order() { let span = self.tcx.def_span(impl_item.def_id); @@ -71,7 +71,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let norm_ident = ident.normalize_to_macros_2_0(); match seen_items.entry(norm_ident) { - Entry::Occupied(entry) => { + IndexEntry::Occupied(entry) => { let former = entry.get(); res = Err(struct_span_code_err!( self.tcx.dcx(), @@ -84,7 +84,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .with_span_label(*former, format!("other definition for `{ident}`")) .emit()); } - Entry::Vacant(entry) => { + IndexEntry::Vacant(entry) => { entry.insert(span); } } @@ -216,7 +216,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { } let mut connected_regions: IndexVec = Default::default(); // Reverse map from the Symbol to the connected region id. - let mut connected_region_ids = FxHashMap::default(); + let mut connected_region_ids = FxIndexMap::default(); for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { if impl_items.len() == 0 { @@ -228,7 +228,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .in_definition_order() .filter_map(|item| { let entry = connected_region_ids.entry(item.name); - if let Entry::Occupied(e) = &entry { + if let IndexEntry::Occupied(e) = &entry { Some(*e.get()) } else { idents_to_add.push(item.name); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d92e1a141516..5346dcccdc71 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -15,7 +15,7 @@ //! crate as a kind of pass. This should eventually be factored away. use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -835,12 +835,12 @@ impl From for FieldDeclSpan { struct FieldUniquenessCheckContext<'tcx> { tcx: TyCtxt<'tcx>, - seen_fields: FxHashMap, + seen_fields: FxIndexMap, } impl<'tcx> FieldUniquenessCheckContext<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx, seen_fields: FxHashMap::default() } + Self { tcx, seen_fields: FxIndexMap::default() } } /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before. diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index a7fca41f86ac..1de7a0f7bc73 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, OutlivesPredicate, TyCtxt}; @@ -6,12 +6,12 @@ use super::utils::*; #[derive(Debug)] pub struct ExplicitPredicatesMap<'tcx> { - map: FxHashMap>>, + map: FxIndexMap>>, } impl<'tcx> ExplicitPredicatesMap<'tcx> { pub fn new() -> ExplicitPredicatesMap<'tcx> { - ExplicitPredicatesMap { map: FxHashMap::default() } + ExplicitPredicatesMap { map: FxIndexMap::default() } } pub(crate) fn explicit_predicates_of( diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0cb38094ceca..2429becfd195 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -15,12 +15,12 @@ use super::utils::*; /// now be filled with inferred predicates. pub(super) fn infer_predicates( tcx: TyCtxt<'_>, -) -> FxHashMap>> { +) -> FxIndexMap>> { debug!("infer_predicates"); let mut explicit_map = ExplicitPredicatesMap::new(); - let mut global_inferred_outlives = FxHashMap::default(); + let mut global_inferred_outlives = FxIndexMap::default(); // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. @@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, - global_inferred_outlives: &FxHashMap>>, + global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { @@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>, - global_inferred_outlives: &FxHashMap>>, + global_inferred_outlives: &FxIndexMap>>, required_predicates: &mut RequiredPredicates<'tcx>, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 907c1cc313e5..e895e8c2907c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -24,6 +24,7 @@ use crate::{ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey, @@ -1709,7 +1710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .fields .iter_enumerated() .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field))) - .collect::>(); + .collect::>(); let mut seen_fields = FxHashMap::default(); @@ -1954,18 +1955,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, - remaining_fields: FxHashMap, + remaining_fields: UnordMap, variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], args: GenericArgsRef<'tcx>, ) { let len = remaining_fields.len(); - #[allow(rustc::potential_query_instability)] - let mut displayable_field_names: Vec<&str> = - remaining_fields.keys().map(|ident| ident.as_str()).collect(); - // sorting &str primitives here, sort_unstable is ok - displayable_field_names.sort_unstable(); + let displayable_field_names: Vec<&str> = + remaining_fields.items().map(|(ident, _)| ident.as_str()).into_sorted_stable_ord(); let mut truncated_fields_error = String::new(); let remaining_fields_names = match &displayable_field_names[..] { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 50b2bf7da153..60d13f02ad7b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -306,11 +306,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| { - // We will soon sort, so the initial order does not matter. - #[allow(rustc::potential_query_instability)] - let mut identifiers: Vec<_> = identifiers.drain().collect(); - identifiers.sort_by_key(|&(key, _)| key); - for (ident, mut spans) in identifiers.into_iter() { + for (ident, mut spans) in identifiers.drain(..) { spans.sort(); if ident == sym::ferris { let first_span = spans[0]; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 30f05444d210..5e27a0ed8188 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -18,8 +18,9 @@ use self::TargetLint::*; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; @@ -69,10 +70,10 @@ pub struct LintStore { pub late_module_passes: Vec>, /// Lints indexed by name. - by_name: FxHashMap, + by_name: UnordMap, /// Map of registered lint groups to what lints they expand to. - lint_groups: FxHashMap<&'static str, LintGroup>, + lint_groups: FxIndexMap<&'static str, LintGroup>, } impl LintStoreMarker for LintStore {} @@ -152,8 +153,6 @@ impl LintStore { pub fn get_lint_groups<'t>( &'t self, ) -> impl Iterator, bool)> + 't { - // This function is not used in a way which observes the order of lints. - #[allow(rustc::potential_query_instability)] self.lint_groups .iter() .filter(|(_, LintGroup { depr, .. })| { @@ -326,9 +325,11 @@ impl LintStore { /// True if this symbol represents a lint group name. pub fn is_lint_group(&self, lint_name: Symbol) -> bool { - #[allow(rustc::potential_query_instability)] - let lint_groups = self.lint_groups.keys().collect::>(); - debug!("is_lint_group(lint_name={:?}, lint_groups={:?})", lint_name, lint_groups); + debug!( + "is_lint_group(lint_name={:?}, lint_groups={:?})", + lint_name, + self.lint_groups.keys().collect::>() + ); let lint_name_str = lint_name.as_str(); self.lint_groups.contains_key(lint_name_str) || { let warnings_name_str = crate::WARNINGS.name_lower(); @@ -372,12 +373,9 @@ impl LintStore { None => { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? - #[allow(rustc::potential_query_instability)] - let lints = self.by_name.keys().collect::>(); - debug!("lints={:?}", lints); + debug!("lints={:?}", self.by_name); let tool_prefix = format!("{tool_name}::"); - #[allow(rustc::potential_query_instability)] return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name, tool_name.as_str()) } else { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index f78b32ce5e77..e112cd6915c3 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -179,7 +179,6 @@ impl EarlyLintPass for NonAsciiIdents { #[allow(rustc::potential_query_instability)] let mut symbols: Vec<_> = symbols.iter().collect(); symbols.sort_by_key(|k| k.1); - for (symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); if symbol_str.is_ascii() { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6937df7bb189..eef1b2f14b76 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -4,6 +4,7 @@ use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; @@ -241,7 +242,7 @@ pub struct CodegenUnit<'tcx> { /// contain something unique to this crate (e.g., a module path) /// as well as the crate name and disambiguator. name: Symbol, - items: FxHashMap, MonoItemData>, + items: FxIndexMap, MonoItemData>, size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, @@ -316,13 +317,11 @@ impl<'tcx> CodegenUnit<'tcx> { self.primary = true; } - /// The order of these items is non-determinstic. - pub fn items(&self) -> &FxHashMap, MonoItemData> { + pub fn items(&self) -> &FxIndexMap, MonoItemData> { &self.items } - /// The order of these items is non-determinstic. - pub fn items_mut(&mut self) -> &mut FxHashMap, MonoItemData> { + pub fn items_mut(&mut self) -> &mut FxIndexMap, MonoItemData> { &mut self.items } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 5cfebcaa5a5f..8bebc30e4356 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -368,7 +368,7 @@ fn merge_codegen_units<'tcx>( // Move the items from `cgu_src` to `cgu_dst`. Some of them may be // duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. - cgu_dst.items_mut().extend(cgu_src.items_mut().drain()); + cgu_dst.items_mut().extend(cgu_src.items_mut().drain(..)); cgu_dst.compute_size_estimate(); // Record that `cgu_dst` now contains all the stuff that was in @@ -407,7 +407,7 @@ fn merge_codegen_units<'tcx>( // Move the items from `smallest` to `second_smallest`. Some of them // may be duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. - second_smallest.items_mut().extend(smallest.items_mut().drain()); + second_smallest.items_mut().extend(smallest.items_mut().drain(..)); second_smallest.compute_size_estimate(); // Don't update `cgu_contents`, that's only for incremental builds. diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 8adb0cbcc9d7..288e0a5ca6f3 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -11,7 +11,7 @@ use crate::lint::{ }; use crate::Session; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ @@ -205,19 +205,19 @@ pub struct ParseSess { /// Places where identifiers that contain invalid Unicode codepoints but that look like they /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to /// provide a single error per unique incorrect identifier. - pub bad_unicode_identifiers: Lock>>, + pub bad_unicode_identifiers: Lock>>, source_map: Lrc, pub buffered_lints: Lock>, /// Contains the spans of block expressions that could have been incomplete based on the /// operation token that followed it, but that the parser cannot identify without further /// analysis. - pub ambiguous_block_expr_parse: Lock>, + pub ambiguous_block_expr_parse: Lock>, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// Environment variables accessed during the build and their values when they exist. - pub env_depinfo: Lock)>>, + pub env_depinfo: Lock)>>, /// File paths accessed during the build. - pub file_depinfo: Lock>, + pub file_depinfo: Lock>, /// Whether cfg(version) should treat the current release as incomplete pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical @@ -247,7 +247,7 @@ impl ParseSess { bad_unicode_identifiers: Lock::new(Default::default()), source_map, buffered_lints: Lock::new(vec![]), - ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + ambiguous_block_expr_parse: Lock::new(Default::default()), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), env_depinfo: Default::default(), diff --git a/tests/ui/parser/emoji-identifiers.stderr b/tests/ui/parser/emoji-identifiers.stderr index 8250dd1ea2e9..1fc561d32c63 100644 --- a/tests/ui/parser/emoji-identifiers.stderr +++ b/tests/ui/parser/emoji-identifiers.stderr @@ -9,14 +9,6 @@ help: Unicode character '➖' (Heavy Minus Sign) looks like '-' (Minus/Hyphen), LL | let _ = i_like_to_😄_a_lot() - 4; | ~ -error: Ferris cannot be used as an identifier - --> $DIR/emoji-identifiers.rs:17:9 - | -LL | let 🦀 = 1; - | ^^ help: try using their name instead: `ferris` -LL | dbg!(🦀); - | ^^ - error: identifiers cannot contain emoji: `ABig👩👩👧👧Family` --> $DIR/emoji-identifiers.rs:1:8 | @@ -64,6 +56,14 @@ error: identifiers cannot contain emoji: `i_like_to_😄_a_lot` LL | let _ = i_like_to_😄_a_lot() ➖ 4; | ^^^^^^^^^^^^^^^^^^ +error: Ferris cannot be used as an identifier + --> $DIR/emoji-identifiers.rs:17:9 + | +LL | let 🦀 = 1; + | ^^ help: try using their name instead: `ferris` +LL | dbg!(🦀); + | ^^ + error[E0599]: no function or associated item named `full_of✨` found for struct `👀` in the current scope --> $DIR/emoji-identifiers.rs:9:8 | From 369fff6c0640fe89be9b915adaa83e66a022e00d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 14 Feb 2024 16:26:20 +0100 Subject: [PATCH 18/55] Implicitly enable evex512 if avx512 is enabled LLVM 18 requires the evex512 feature to allow use of zmm registers. LLVM automatically sets it when using a generic CPU, but not when `-C target-cpu` is specified. This will result either in backend legalization crashes, or code unexpectedly using ymm instead of zmm registers. For now, make sure that `avx512*` features imply `evex512`. Long term we'll probably have to deal with the AVX10 mess somehow. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 4 ++++ tests/ui/asm/x86_64/evex512-implicit-feature.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/ui/asm/x86_64/evex512-implicit-feature.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e48479c8da27..54e8ed85e325 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -266,6 +266,10 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { ("riscv32" | "riscv64", "fast-unaligned-access") if get_version().0 <= 17 => { LLVMFeature::new("unaligned-scalar-mem") } + // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled. + ("x86", s) if get_version().0 >= 18 && s.starts_with("avx512") => { + LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")) + } (_, s) => LLVMFeature::new(s), } } diff --git a/tests/ui/asm/x86_64/evex512-implicit-feature.rs b/tests/ui/asm/x86_64/evex512-implicit-feature.rs new file mode 100644 index 000000000000..a15060857ecc --- /dev/null +++ b/tests/ui/asm/x86_64/evex512-implicit-feature.rs @@ -0,0 +1,15 @@ +// build-pass +// only-x86_64 +// compile-flags: --crate-type=lib -C target-cpu=skylake + +#![feature(avx512_target_feature)] +#![feature(stdarch_x86_avx512)] + +use std::arch::x86_64::*; + +#[target_feature(enable = "avx512f")] +#[no_mangle] +pub unsafe fn test(res: *mut f64, p: *const f64) { + let arg = _mm512_load_pd(p); + _mm512_store_pd(res, _mm512_fmaddsub_pd(arg, arg, arg)); +} From 55f9aed9c706e62f10138f27cf46255ea4667078 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 14 Feb 2024 14:45:38 +0000 Subject: [PATCH 19/55] Move all the heavy lifting from `TyCtxtAt::create_def` into `TyCtxt::create_def` --- compiler/rustc_middle/src/ty/context.rs | 30 ++++++++++++++----------- compiler/rustc_resolve/src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5c04a34a3ba9..18958ac6d41a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1046,6 +1046,22 @@ impl<'tcx> TyCtxtAt<'tcx> { name: Symbol, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { + let feed = self.tcx.create_def(parent, name, def_kind); + + feed.def_span(self.span); + feed + } +} + +impl<'tcx> TyCtxt<'tcx> { + /// `tcx`-dependent operations performed for every created definition. + pub fn create_def( + self, + parent: LocalDefId, + name: Symbol, + def_kind: DefKind, + ) -> TyCtxtFeed<'tcx, LocalDefId> { + let data = def_kind.def_path_data(name); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to // decode the on-disk cache. @@ -1060,18 +1076,6 @@ impl<'tcx> TyCtxtAt<'tcx> { // This is fine because: // - those queries are `eval_always` so we won't miss their result changing; // - this write will have happened before these queries are called. - let def_id = self.tcx.create_def(parent, name, def_kind); - - let feed = self.tcx.feed_local_def_id(def_id); - feed.def_span(self.span); - feed - } -} - -impl<'tcx> TyCtxt<'tcx> { - /// `tcx`-dependent operations performed for every created definition. - pub fn create_def(self, parent: LocalDefId, name: Symbol, def_kind: DefKind) -> LocalDefId { - let data = def_kind.def_path_data(name); let def_id = self.untracked.definitions.write().create_def(parent, data); // This function modifies `self.definitions` using a side-effect. @@ -1091,7 +1095,7 @@ impl<'tcx> TyCtxt<'tcx> { feed.visibility(ty::Visibility::Restricted(parent_mod)); } - def_id + feed } pub fn iter_local_def_id(self) -> impl Iterator + 'tcx { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6b07bfdec671..bf811c7a4bb8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1245,7 +1245,7 @@ impl<'tcx> Resolver<'_, 'tcx> { ); // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()` - let def_id = self.tcx.create_def(parent, name, def_kind); + let def_id = self.tcx.create_def(parent, name, def_kind).def_id(); // Create the definition. if expn_id != ExpnId::root() { From fa1e35c833ad47cd5e1c49329eca46003d20d64d Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 15 Feb 2024 02:35:37 +0900 Subject: [PATCH 20/55] Remove unnecessary else block from `thread_local!` expanded code --- library/std/src/sys/pal/common/thread_local/fast_local.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/common/thread_local/fast_local.rs b/library/std/src/sys/pal/common/thread_local/fast_local.rs index 0fdca27852ca..04c0dd6f7509 100644 --- a/library/std/src/sys/pal/common/thread_local/fast_local.rs +++ b/library/std/src/sys/pal/common/thread_local/fast_local.rs @@ -94,7 +94,8 @@ pub macro thread_local_inner { if let $crate::option::Option::Some(init) = init { if let $crate::option::Option::Some(value) = init.take() { return value; - } else if $crate::cfg!(debug_assertions) { + } + if $crate::cfg!(debug_assertions) { $crate::unreachable!("missing default value"); } } From 2e691a5c12f4d96da6938f26cbf3de7d404edc87 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Wed, 14 Feb 2024 17:38:36 +0000 Subject: [PATCH 21/55] Rewrite foreign item kind query using `DefKind` --- compiler/rustc_smir/src/rustc_smir/context.rs | 34 +++++++------------ compiler/stable_mir/src/compiler_interface.rs | 2 +- compiler/stable_mir/src/ty.rs | 2 +- tests/ui-fulldeps/stable-mir/check_foreign.rs | 2 +- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 24dd7ad6d7eb..0d1424bbc0bd 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -258,27 +258,19 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.is_foreign_item(tables[item]) } - fn foreign_item_kind(&self, def: ForeignDef) -> Option { - let (def_id, hir_kind) = { - let tables = self.0.borrow(); - let def_id = tables[def.def_id()]; - let hir_kind = tables - .tcx - .hir() - .expect_foreign_item(rustc_hir::OwnerId { def_id: def_id.as_local()? }) - .kind; - (def_id, hir_kind) - }; - let kind = match hir_kind { - rustc_hir::ForeignItemKind::Fn(..) => { - ForeignItemKind::Fn(self.0.borrow_mut().fn_def(def_id)) - } - rustc_hir::ForeignItemKind::Static(..) => { - ForeignItemKind::Static(self.0.borrow_mut().static_def(def_id)) - } - rustc_hir::ForeignItemKind::Type => ForeignItemKind::Type(self.def_ty(def.def_id())), - }; - Some(kind) + fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + let mut tables = self.0.borrow_mut(); + let def_id = tables[def.def_id()]; + let tcx = tables.tcx; + use rustc_hir::def::DefKind; + match tcx.def_kind(def_id) { + DefKind::Fn => ForeignItemKind::Fn(tables.fn_def(def_id)), + DefKind::Static(..) => ForeignItemKind::Static(tables.static_def(def_id)), + DefKind::ForeignTy => ForeignItemKind::Type( + tables.intern_ty(rustc_middle::ty::Ty::new_foreign(tcx, def_id)), + ), + def_kind => unreachable!("Unexpected kind for a foreign item: {:?}", def_kind), + } } fn adt_kind(&self, def: AdtDef) -> AdtKind { diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index f55e0f9481fe..59c79ddf8da3 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -71,7 +71,7 @@ pub trait Context { fn is_foreign_item(&self, item: DefId) -> bool; /// Returns the kind of a given foreign item. - fn foreign_item_kind(&self, def: ForeignDef) -> Option; + fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind; /// Returns the kind of a given algebraic data type fn adt_kind(&self, def: AdtDef) -> AdtKind; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index f043ce9d898d..658e8aa28b54 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -566,7 +566,7 @@ crate_def! { } impl ForeignDef { - pub fn kind(&self) -> Option { + pub fn kind(&self) -> ForeignItemKind { with(|cx| cx.foreign_item_kind(*self)) } } diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 22770a56e329..e6c59354d5e2 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -43,7 +43,7 @@ fn test_foreign() -> ControlFlow<()> { let c_items = c_mod.items(); assert_eq!(c_items.len(), 3); for item in c_items { - let kind = item.kind().unwrap(); + let kind = item.kind(); match item.name().as_str() { "foo" => assert_matches!(kind, ForeignItemKind::Fn(..)), "bar" => assert_matches!(kind, ForeignItemKind::Static(..)), From 01c974ff98a293c9792779bbe4428f1e9b55a05b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Feb 2024 18:02:55 +0000 Subject: [PATCH 22/55] Do not report overflow errors on ConstArgHasType goals --- .../src/traits/fulfill.rs | 27 ++++++++++-------- tests/ui/codegen/overflow-during-mono.rs | 28 +++++++++++++++++++ tests/ui/codegen/overflow-during-mono.stderr | 11 ++++++++ 3 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 tests/ui/codegen/overflow-during-mono.rs create mode 100644 tests/ui/codegen/overflow-during-mono.stderr diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5ef7a202a125..7ad942746341 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -423,6 +423,21 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + // Compute `ConstArgHasType` above the overflow check below. + // This is because this is not ever a useful obligation to report + // as the cause of an overflow. + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + ct.ty(), + ty, + ) { + Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Err(_) => ProcessResult::Error(FulfillmentErrorCode::SelectionError( + SelectionError::Unimplemented, + )), + } + } // General case overflow check. Allow `process_trait_obligation` // and `process_projection_obligation` to handle checking for @@ -650,18 +665,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( - DefineOpaqueTypes::No, - ct.ty(), - ty, - ) { - Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), - Err(_) => ProcessResult::Error(FulfillmentErrorCode::SelectionError( - SelectionError::Unimplemented, - )), - } - } }, } } diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs new file mode 100644 index 000000000000..e45db18e4074 --- /dev/null +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -0,0 +1,28 @@ +// build-fail +//~^ ERROR overflow evaluating the requirement + +#![recursion_limit = "32"] + +fn quicksort, I: IntoIterator, T: Ord>( + i: I, +) -> Vec { + let mut i = i.into_iter(); + + match i.next() { + Some(x) => { + let less = i.clone().filter(|y| y < &x); + let greater = i.filter(|y| &x <= y); + + let mut v = quicksort(less); + let u = quicksort(greater); + v.push(x); + v.extend(u); + v + } + None => vec![], + } +} + +fn main() { + println!("{:?}", quicksort([5i32, 1, 6, 3, 6, 1, 9, 0, -1, 6, 8])); +} diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr new file mode 100644 index 000000000000..f7a3e2df3dba --- /dev/null +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: 31 redundant requirements hidden + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From ddec8c5edc488e3eec27ed59a4d8e5dbaad4130f Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 14 Feb 2024 19:12:19 +0100 Subject: [PATCH 23/55] Ignore unsized types when trying to determine the size of a type --- compiler/rustc_lint/src/reference_casting.rs | 7 +++++++ tests/ui/lint/reference_casting.rs | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 519ab8bd50fe..f386db9d8dbc 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -207,6 +207,13 @@ fn is_cast_to_bigger_memory_layout<'tcx>( } let from_layout = cx.layout_of(*inner_start_ty).ok()?; + + // if the type isn't sized, we bail out, instead of potentially giving + // the user a meaningless warning. + if from_layout.is_unsized() { + return None; + } + let alloc_layout = cx.layout_of(alloc_ty).ok()?; let to_layout = cx.layout_of(*inner_end_ty).ok()?; diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index 63541943d65c..e5d84e464fdc 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -239,6 +239,11 @@ unsafe fn bigger_layout() { //~^ ERROR casting references to a bigger memory layout } + { + let x: Box = Box::new(0i32); + let _z = unsafe { &*(&*x as *const dyn Send as *const i32) }; + } + unsafe fn from_ref(this: &i32) -> &i64 { &*(this as *const i32 as *const i64) } From 9cccf208997e0e8a9909b9d174be7b8b3e4f6e83 Mon Sep 17 00:00:00 2001 From: Peter Hall Date: Wed, 14 Feb 2024 12:13:25 +0000 Subject: [PATCH 24/55] Clarified docs on non-atomic oprations on owned/mut refs to atomics --- library/core/src/sync/atomic.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1dec2bf40cc9..e9a0d9e1d287 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -27,8 +27,9 @@ //! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`. //! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating //! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference -//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not* -//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.) +//! ends. A Rust atomic type that is exclusively owned or behind a mutable reference does *not* +//! correspond to an “atomic object” in C++, since the underlying primitive can be mutably accessed, +//! for example with `get_mut`, to perform non-atomic operations. //! //! [cpp]: https://en.cppreference.com/w/cpp/atomic //! From 8d4d572e4d8e41f9963dad997214a54df05baabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Feb 2024 19:18:28 +0000 Subject: [PATCH 25/55] Fix msg for verbose suggestions with confusable capitalization When encountering a verbose/multipart suggestion that has changes that are only caused by different capitalization of ASCII letters that have little differenciation, expand the message to highlight that fact (like we already do for inline suggestions). The logic to do this was already present, but implemented incorrectly. --- compiler/rustc_errors/src/emitter.rs | 19 ++++++++++--------- compiler/rustc_errors/src/lib.rs | 3 ++- .../tests/ui/match_str_case_mismatch.stderr | 2 +- tests/ui/error-codes/E0423.stderr | 2 +- tests/ui/parser/kw-in-trait-bounds.stderr | 8 ++++---- .../recover-fn-trait-from-fn-kw.stderr | 4 ++-- .../typod-const-in-const-param-def.stderr | 8 ++++---- .../assoc-ct-for-assoc-method.stderr | 2 +- .../suggestions/bool_typo_err_suggest.stderr | 2 +- 9 files changed, 26 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index b9e92dbb31c6..edcc23db6de3 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1742,9 +1742,17 @@ impl HumanEmitter { buffer.append(0, level.to_str(), Style::Level(*level)); buffer.append(0, ": ", Style::HeaderMsg); + let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; + if suggestions + .iter() + .take(MAX_SUGGESTIONS) + .any(|(_, _, _, only_capitalization)| *only_capitalization) + { + msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + } self.msgs_to_buffer( &mut buffer, - &[(suggestion.msg.to_owned(), Style::NoStyle)], + &msg, args, max_line_num_len, "suggestion", @@ -1753,12 +1761,8 @@ impl HumanEmitter { let mut row_num = 2; draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); - let mut notice_capitalization = false; - for (complete, parts, highlights, only_capitalization) in - suggestions.iter().take(MAX_SUGGESTIONS) - { + for (complete, parts, highlights, _) in suggestions.iter().take(MAX_SUGGESTIONS) { debug!(?complete, ?parts, ?highlights); - notice_capitalization |= only_capitalization; let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); let is_multiline = complete.lines().count() > 1; @@ -2057,9 +2061,6 @@ impl HumanEmitter { let others = suggestions.len() - MAX_SUGGESTIONS; let msg = format!("and {} other candidate{}", others, pluralize!(others)); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); - } else if notice_capitalization { - let msg = "notice the capitalization difference"; - buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index da9ef6627bea..2a0eddf6a0f3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -319,7 +319,9 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; + let mut only_capitalization = false; for part in &substitution.parts { + only_capitalization |= is_case_difference(sm, &part.snippet, part.span); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -392,7 +394,6 @@ impl CodeSuggestion { } } highlights.push(std::mem::take(&mut line_highlight)); - let only_capitalization = is_case_difference(sm, &buf, bounding_span); // if the replacement already ends with a newline, don't print the next line if !buf.ends_with('\n') { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None); diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index f799a4698b94..b178fb7512cd 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -17,7 +17,7 @@ error: this `match` arm has a differing case than its expression LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ | -help: consider changing the case of this arm to respect `to_ascii_lowercase` +help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization difference) | LL | "~!@#$%^&*()-_=+foo" => {}, | ~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/ui/error-codes/E0423.stderr b/tests/ui/error-codes/E0423.stderr index ac70d905d353..dd7a5b034c58 100644 --- a/tests/ui/error-codes/E0423.stderr +++ b/tests/ui/error-codes/E0423.stderr @@ -53,7 +53,7 @@ help: use struct literal syntax instead | LL | let f = Foo { a: val }; | ~~~~~~~~~~~~~~ -help: a function with a similar name exists +help: a function with a similar name exists (notice the capitalization difference) | LL | let f = foo(); | ~~~ diff --git a/tests/ui/parser/kw-in-trait-bounds.stderr b/tests/ui/parser/kw-in-trait-bounds.stderr index 2d3aad4d6baf..3c54e0319503 100644 --- a/tests/ui/parser/kw-in-trait-bounds.stderr +++ b/tests/ui/parser/kw-in-trait-bounds.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl fn(), _: &dyn fn()) | ~~ @@ -15,7 +15,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl Fn(), _: &dyn fn()) | ~~ @@ -26,7 +26,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl fn(), _: &dyn Fn()) | ~~ @@ -37,7 +37,7 @@ error: expected identifier, found keyword `fn` LL | G: fn(), | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | G: Fn(), | ~~ diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr index 17138a6f0792..aee31d08fe0e 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn foo(_: impl fn() -> i32) {} | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn foo(_: impl Fn() -> i32) {} | ~~ @@ -15,7 +15,7 @@ error: expected identifier, found keyword `fn` LL | fn foo2(_: T) {} | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn foo2(_: T) {} | ~~ diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr index 75d73c6ea878..80c0f1deae6f 100644 --- a/tests/ui/parser/typod-const-in-const-param-def.stderr +++ b/tests/ui/parser/typod-const-in-const-param-def.stderr @@ -4,7 +4,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn foo() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn foo() {} | ~~~~~ @@ -15,7 +15,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn baz() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn baz() {} | ~~~~~ @@ -26,7 +26,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn qux() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn qux() {} | ~~~~~ @@ -37,7 +37,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn quux() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn quux() {} | ~~~~~ diff --git a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr index 211cb1584ad7..8f00a72f1e81 100644 --- a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr +++ b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr @@ -8,7 +8,7 @@ LL | let x: i32 = MyS::foo; | = note: expected type `i32` found fn item `fn() -> MyS {MyS::foo}` -help: try referring to the associated const `FOO` instead +help: try referring to the associated const `FOO` instead (notice the capitalization difference) | LL | let x: i32 = MyS::FOO; | ~~~ diff --git a/tests/ui/suggestions/bool_typo_err_suggest.stderr b/tests/ui/suggestions/bool_typo_err_suggest.stderr index 52bde07ca077..8d59ed63e543 100644 --- a/tests/ui/suggestions/bool_typo_err_suggest.stderr +++ b/tests/ui/suggestions/bool_typo_err_suggest.stderr @@ -15,7 +15,7 @@ error[E0425]: cannot find value `False` in this scope LL | let y = False; | ^^^^^ not found in this scope | -help: you may want to use a bool value instead +help: you may want to use a bool value instead (notice the capitalization difference) | LL | let y = false; | ~~~~~ From c1bb352c8bd3457f16053f3d6a3d32b63b55cbbe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 14 Feb 2024 21:04:51 +0000 Subject: [PATCH 26/55] Continue compilation even if inherent impl checks fail --- compiler/rustc_hir_analysis/src/lib.rs | 5 +- .../ui/const-generics/wrong-normalization.rs | 1 + .../const-generics/wrong-normalization.stderr | 16 +- tests/ui/impl-trait/where-allowed.rs | 6 + tests/ui/impl-trait/where-allowed.stderr | 145 +++++++++++++----- tests/ui/issues/issue-4265.rs | 1 + tests/ui/issues/issue-4265.stderr | 26 +++- tests/ui/kinds-of-primitive-impl.rs | 2 +- tests/ui/kinds-of-primitive-impl.stderr | 18 ++- .../impl-item-type-no-body-semantic-fail.rs | 2 + ...mpl-item-type-no-body-semantic-fail.stderr | 40 ++++- tests/ui/traits/issue-33140.rs | 2 + tests/ui/traits/issue-33140.stderr | 40 ++++- 13 files changed, 244 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1cd77050217a..33092825e891 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -178,8 +178,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { let _ = tcx.ensure().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - res.and(tcx.ensure().crate_inherent_impls(())) - .and(tcx.ensure().crate_inherent_impls_overlap_check(())) + let _ = tcx.ensure().crate_inherent_impls(()); + let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); + res })?; if tcx.features().rustc_attrs { diff --git a/tests/ui/const-generics/wrong-normalization.rs b/tests/ui/const-generics/wrong-normalization.rs index f1ce317b3f78..8b2323e3d479 100644 --- a/tests/ui/const-generics/wrong-normalization.rs +++ b/tests/ui/const-generics/wrong-normalization.rs @@ -15,5 +15,6 @@ pub struct I8; impl as Identity>::Identity { //~^ ERROR no nominal type found for inherent implementation +//~| ERROR no associated item named `MIN` found for type `i8` pub fn foo(&self) {} } diff --git a/tests/ui/const-generics/wrong-normalization.stderr b/tests/ui/const-generics/wrong-normalization.stderr index 2f8dfc895b27..379a5593dd64 100644 --- a/tests/ui/const-generics/wrong-normalization.stderr +++ b/tests/ui/const-generics/wrong-normalization.stderr @@ -6,6 +6,18 @@ LL | impl as Identity>::Identity { | = note: either implement a trait on it or create a newtype to wrap it instead -error: aborting due to 1 previous error +error[E0599]: no associated item named `MIN` found for type `i8` in the current scope + --> $DIR/wrong-normalization.rs:16:15 + | +LL | impl as Identity>::Identity { + | ^^^ associated item not found in `i8` + | +help: you are looking for the module in `std`, not the primitive type + | +LL | impl as Identity>::Identity { + | +++++ -For more information about this error, try `rustc --explain E0118`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0118, E0599. +For more information about an error, try `rustc --explain E0118`. diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index 5ce63db684f3..505e2d6c171f 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -44,6 +44,7 @@ fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } // Allowed fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } +//~^ ERROR: type annotations needed // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } @@ -58,9 +59,11 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds //~| ERROR nested `impl Trait` is not allowed +//~| ERROR: type annotations needed // Allowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } +//~^ ERROR: type annotations needed // Disallowed fn in_Fn_parameter_in_generics (_: F) { panic!() } @@ -77,6 +80,7 @@ fn in_impl_Trait_in_parameters(_: impl Iterator) { panic!( // Allowed fn in_impl_Trait_in_return() -> impl IntoIterator { vec![vec![0; 10], vec![12; 7], vec![8; 3]] + //~^ ERROR: no function or associated item named `into_vec` found for slice `[_]` } // Disallowed @@ -118,11 +122,13 @@ trait DummyTrait { impl DummyTrait for () { type Out = impl Debug; //~^ ERROR `impl Trait` in associated types is unstable + //~| ERROR unconstrained opaque type fn in_trait_impl_parameter(_: impl Debug) { } // Allowed fn in_trait_impl_return() -> impl Debug { () } + //~^ ERROR `in_trait_impl_return` has an incompatible type for trait // Allowed } diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 3e1d4e22272d..c22312cce197 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:49:51 + --> $DIR/where-allowed.rs:50:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | --------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:58:57 + --> $DIR/where-allowed.rs:59:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | --------^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in associated types is unstable - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:123:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | type Out = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:154:23 + --> $DIR/where-allowed.rs:160:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | type InTypeAlias = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:157:39 + --> $DIR/where-allowed.rs:163:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!( = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:49:51 + --> $DIR/where-allowed.rs:50:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:54:53 + --> $DIR/where-allowed.rs:55:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:58:57 + --> $DIR/where-allowed.rs:59:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:66:38 + --> $DIR/where-allowed.rs:69:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:70:40 + --> $DIR/where-allowed.rs:73:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:83:32 + --> $DIR/where-allowed.rs:87:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | struct InBraceStructField { x: impl Debug } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:87:41 + --> $DIR/where-allowed.rs:91:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ @@ -159,7 +159,7 @@ LL | struct InAdtInBraceStructField { x: Vec } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:91:27 + --> $DIR/where-allowed.rs:95:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | struct InTupleStructField(impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:96:25 + --> $DIR/where-allowed.rs:100:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | InBraceVariant { x: impl Debug }, = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:98:20 + --> $DIR/where-allowed.rs:102:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ @@ -183,7 +183,7 @@ LL | InTupleVariant(impl Debug), = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` parameters - --> $DIR/where-allowed.rs:138:33 + --> $DIR/where-allowed.rs:144:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | fn in_foreign_parameters(_: impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` return types - --> $DIR/where-allowed.rs:141:31 + --> $DIR/where-allowed.rs:147:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | fn in_foreign_return() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types - --> $DIR/where-allowed.rs:157:39 + --> $DIR/where-allowed.rs:163:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in traits - --> $DIR/where-allowed.rs:162:16 + --> $DIR/where-allowed.rs:168:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ @@ -215,7 +215,7 @@ LL | impl PartialEq for () { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:167:24 + --> $DIR/where-allowed.rs:173:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | impl PartialEq<()> for impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:172:6 + --> $DIR/where-allowed.rs:178:6 | LL | impl impl Debug { | ^^^^^^^^^^ @@ -231,7 +231,7 @@ LL | impl impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:178:24 + --> $DIR/where-allowed.rs:184:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ @@ -239,7 +239,7 @@ LL | impl InInherentImplAdt { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:184:11 + --> $DIR/where-allowed.rs:190:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ @@ -247,7 +247,7 @@ LL | where impl Debug: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:191:15 + --> $DIR/where-allowed.rs:197:15 | LL | where Vec: Debug | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | where Vec: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:198:24 + --> $DIR/where-allowed.rs:204:24 | LL | where T: PartialEq | ^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | where T: PartialEq = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:205:17 + --> $DIR/where-allowed.rs:211:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | where T: Fn(impl Debug) = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:212:22 + --> $DIR/where-allowed.rs:218:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | where T: Fn() -> impl Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:218:40 + --> $DIR/where-allowed.rs:224:40 | LL | struct InStructGenericParamDefault(T); | ^^^^^^^^^^ @@ -287,7 +287,7 @@ LL | struct InStructGenericParamDefault(T); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:222:36 + --> $DIR/where-allowed.rs:228:36 | LL | enum InEnumGenericParamDefault { Variant(T) } | ^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | enum InEnumGenericParamDefault { Variant(T) } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:226:38 + --> $DIR/where-allowed.rs:232:38 | LL | trait InTraitGenericParamDefault {} | ^^^^^^^^^^ @@ -303,7 +303,7 @@ LL | trait InTraitGenericParamDefault {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:230:41 + --> $DIR/where-allowed.rs:236:41 | LL | type InTypeAliasGenericParamDefault = T; | ^^^^^^^^^^ @@ -311,7 +311,7 @@ LL | type InTypeAliasGenericParamDefault = T; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:234:11 + --> $DIR/where-allowed.rs:240:11 | LL | impl T {} | ^^^^^^^^^^ @@ -319,7 +319,7 @@ LL | impl T {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:241:40 + --> $DIR/where-allowed.rs:247:40 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^ @@ -327,7 +327,7 @@ LL | fn in_method_generic_param_default(_: T) {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/where-allowed.rs:247:29 + --> $DIR/where-allowed.rs:253:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -335,7 +335,7 @@ LL | let _in_local_variable: impl Fn() = || {}; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in closure return types - --> $DIR/where-allowed.rs:249:46 + --> $DIR/where-allowed.rs:255:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ @@ -343,7 +343,7 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:234:7 + --> $DIR/where-allowed.rs:240:7 | LL | impl T {} | ^^^^^^^^^^^^^^ @@ -353,7 +353,7 @@ LL | impl T {} = note: `#[deny(invalid_type_param_default)]` on by default error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:241:36 + --> $DIR/where-allowed.rs:247:36 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^^^^^ @@ -362,14 +362,77 @@ LL | fn in_method_generic_param_default(_: T) {} = note: for more information, see issue #36887 error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:234:1 + --> $DIR/where-allowed.rs:240:1 | LL | impl T {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error: aborting due to 45 previous errors +error[E0283]: type annotations needed + --> $DIR/where-allowed.rs:46:57 + | +LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^ cannot infer type + | + = note: cannot satisfy `_: Debug` -Some errors have detailed explanations: E0118, E0562, E0658, E0666. -For more information about an error, try `rustc --explain E0118`. +error[E0282]: type annotations needed + --> $DIR/where-allowed.rs:59:49 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^^^^^^^^^^ cannot infer type + +error[E0283]: type annotations needed + --> $DIR/where-allowed.rs:65:46 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: + - impl Fn for &F + where A: Tuple, F: Fn, F: ?Sized; + - impl Fn for Box + where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + +error[E0599]: no function or associated item named `into_vec` found for slice `[_]` in the current scope + --> $DIR/where-allowed.rs:82:5 + | +LL | vec![vec![0; 10], vec![12; 7], vec![8; 3]] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `[_]` + | + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0053]: method `in_trait_impl_return` has an incompatible type for trait + --> $DIR/where-allowed.rs:130:34 + | +LL | type Out = impl Debug; + | ---------- the expected opaque type +... +LL | fn in_trait_impl_return() -> impl Debug { () } + | ^^^^^^^^^^ + | | + | expected opaque type, found a different opaque type + | help: change the output type to match the trait: `<() as DummyTrait>::Out` + | +note: type in trait + --> $DIR/where-allowed.rs:120:34 + | +LL | fn in_trait_impl_return() -> Self::Out; + | ^^^^^^^^^ + = note: expected signature `fn() -> <() as DummyTrait>::Out` + found signature `fn() -> impl Debug` + = note: distinct uses of `impl Trait` result in different opaque types + +error: unconstrained opaque type + --> $DIR/where-allowed.rs:123:16 + | +LL | type Out = impl Debug; + | ^^^^^^^^^^ + | + = note: `Out` must be used in combination with a concrete type within the same impl + +error: aborting due to 51 previous errors + +Some errors have detailed explanations: E0053, E0118, E0282, E0283, E0562, E0599, E0658, E0666. +For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/issues/issue-4265.rs b/tests/ui/issues/issue-4265.rs index 2596079d3790..99b13283bc97 100644 --- a/tests/ui/issues/issue-4265.rs +++ b/tests/ui/issues/issue-4265.rs @@ -5,6 +5,7 @@ struct Foo { impl Foo { fn bar() { Foo { baz: 0 }.bar(); + //~^ ERROR: no method named `bar` found } fn bar() { //~ ERROR duplicate definitions diff --git a/tests/ui/issues/issue-4265.stderr b/tests/ui/issues/issue-4265.stderr index 48b1c762e19a..23d00aaa44b5 100644 --- a/tests/ui/issues/issue-4265.stderr +++ b/tests/ui/issues/issue-4265.stderr @@ -1,5 +1,5 @@ error[E0592]: duplicate definitions with name `bar` - --> $DIR/issue-4265.rs:10:5 + --> $DIR/issue-4265.rs:11:5 | LL | fn bar() { | -------- other definition for `bar` @@ -7,6 +7,26 @@ LL | fn bar() { LL | fn bar() { | ^^^^^^^^ duplicate definitions for `bar` -error: aborting due to 1 previous error +error[E0599]: no method named `bar` found for struct `Foo` in the current scope + --> $DIR/issue-4265.rs:7:24 + | +LL | struct Foo { + | ---------- method `bar` not found for this struct +... +LL | Foo { baz: 0 }.bar(); + | ---------------^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `Foo::bar()` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in an impl for the type `Foo` + --> $DIR/issue-4265.rs:6:5 + | +LL | fn bar() { + | ^^^^^^^^ -For more information about this error, try `rustc --explain E0592`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0592, E0599. +For more information about an error, try `rustc --explain E0592`. diff --git a/tests/ui/kinds-of-primitive-impl.rs b/tests/ui/kinds-of-primitive-impl.rs index 6a067a9a3609..f1c2ee8e5506 100644 --- a/tests/ui/kinds-of-primitive-impl.rs +++ b/tests/ui/kinds-of-primitive-impl.rs @@ -6,7 +6,7 @@ impl u8 { impl str { //~^ error: cannot define inherent `impl` for primitive types fn foo() {} - fn bar(self) {} + fn bar(self) {} //~ ERROR: size for values of type `str` cannot be known } impl char { diff --git a/tests/ui/kinds-of-primitive-impl.stderr b/tests/ui/kinds-of-primitive-impl.stderr index 21aac58f1f20..1c8c417e88c1 100644 --- a/tests/ui/kinds-of-primitive-impl.stderr +++ b/tests/ui/kinds-of-primitive-impl.stderr @@ -31,6 +31,20 @@ LL | impl &MyType { = help: consider using an extension trait instead = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation -error: aborting due to 4 previous errors +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/kinds-of-primitive-impl.rs:9:12 + | +LL | fn bar(self) {} + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn bar(&self) {} + | + -For more information about this error, try `rustc --explain E0390`. +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0390. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs b/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs index 5582e82d11d0..bbd207be06db 100644 --- a/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -14,8 +14,10 @@ impl X { //~^ ERROR associated type in `impl` without body //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR inherent associated types are unstable + //~| ERROR `X: Eq` is not satisfied type W where Self: Eq; //~^ ERROR associated type in `impl` without body //~| ERROR inherent associated types are unstable //~| ERROR duplicate definitions + //~| ERROR `X: Eq` is not satisfied } diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr index d23e6027473d..1c71cdacd89b 100644 --- a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -35,7 +35,7 @@ LL | type W: Ord where Self: Eq; | ^^^ error: associated type in `impl` without body - --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:18:5 | LL | type W where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | type W: Ord where Self: Eq; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: inherent associated types are unstable - --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:18:5 | LL | type W where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | type W where Self: Eq; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0592]: duplicate definitions with name `W` - --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:18:5 | LL | type W: Ord where Self: Eq; | ------ other definition for `W` @@ -91,7 +91,35 @@ LL | type W: Ord where Self: Eq; LL | type W where Self: Eq; | ^^^^^^ duplicate definitions for `W` -error: aborting due to 11 previous errors +error[E0277]: the trait bound `X: Eq` is not satisfied + --> $DIR/impl-item-type-no-body-semantic-fail.rs:13:23 + | +LL | type W: Ord where Self: Eq; + | ^^^^^^^^ the trait `Eq` is not implemented for `X` + | + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable +help: consider annotating `X` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct X; + | -Some errors have detailed explanations: E0592, E0658. -For more information about an error, try `rustc --explain E0592`. +error[E0277]: the trait bound `X: Eq` is not satisfied + --> $DIR/impl-item-type-no-body-semantic-fail.rs:18:18 + | +LL | type W where Self: Eq; + | ^^^^^^^^ the trait `Eq` is not implemented for `X` + | + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable +help: consider annotating `X` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct X; + | + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0277, E0592, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/issue-33140.rs b/tests/ui/traits/issue-33140.rs index 9bdac4b8375c..01b16f76be56 100644 --- a/tests/ui/traits/issue-33140.rs +++ b/tests/ui/traits/issue-33140.rs @@ -43,5 +43,7 @@ fn main() { assert_eq!(::uvw(), false); assert_eq!(::uvw(), true); assert_eq!(>::abc(), false); + //~^ ERROR: multiple applicable items in scope assert_eq!(>::abc(), true); + //~^ ERROR: multiple applicable items in scope } diff --git a/tests/ui/traits/issue-33140.stderr b/tests/ui/traits/issue-33140.stderr index d31281f7256e..7d7ee96f209b 100644 --- a/tests/ui/traits/issue-33140.stderr +++ b/tests/ui/traits/issue-33140.stderr @@ -25,7 +25,41 @@ LL | fn abc() -> bool { LL | fn abc() -> bool { | ---------------- other definition for `abc` -error: aborting due to 3 previous errors +error[E0034]: multiple applicable items in scope + --> $DIR/issue-33140.rs:45:40 + | +LL | assert_eq!(>::abc(), false); + | ^^^ multiple `abc` found + | +note: candidate #1 is defined in an impl for the type `Foo<(dyn Send + Sync + 'static)>` + --> $DIR/issue-33140.rs:29:5 + | +LL | fn abc() -> bool { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<(dyn Send + Sync + 'static)>` + --> $DIR/issue-33140.rs:35:5 + | +LL | fn abc() -> bool { + | ^^^^^^^^^^^^^^^^ -Some errors have detailed explanations: E0119, E0592. -For more information about an error, try `rustc --explain E0119`. +error[E0034]: multiple applicable items in scope + --> $DIR/issue-33140.rs:47:40 + | +LL | assert_eq!(>::abc(), true); + | ^^^ multiple `abc` found + | +note: candidate #1 is defined in an impl for the type `Foo<(dyn Send + Sync + 'static)>` + --> $DIR/issue-33140.rs:29:5 + | +LL | fn abc() -> bool { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<(dyn Send + Sync + 'static)>` + --> $DIR/issue-33140.rs:35:5 + | +LL | fn abc() -> bool { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0034, E0119, E0592. +For more information about an error, try `rustc --explain E0034`. From 64a9c9cfea7f454bcc48852f0e1b99074d615ddc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 15 Feb 2024 08:31:46 +1100 Subject: [PATCH 27/55] Reinstate some delayed bugs. These were changed to `has_errors` assertions in #121071 because that seemed reasonable, but evidently not. Fixes #121103. Fixes #121108. --- compiler/rustc_ast_lowering/src/expr.rs | 4 +++- compiler/rustc_mir_transform/src/lib.rs | 3 ++- tests/ui/lowering/issue-121108.rs | 9 +++++++++ tests/ui/lowering/issue-121108.stderr | 25 +++++++++++++++++++++++++ tests/ui/mir/issue-121103.rs | 3 +++ tests/ui/mir/issue-121103.stderr | 15 +++++++++++++++ 6 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/ui/lowering/issue-121108.rs create mode 100644 tests/ui/lowering/issue-121108.stderr create mode 100644 tests/ui/mir/issue-121103.rs create mode 100644 tests/ui/mir/issue-121103.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 73d1d891bb98..942aae3d5360 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -323,7 +323,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => hir::ExprKind::Err(self.dcx().has_errors().unwrap()), + ExprKind::Err => { + hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) + } ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Paren(_) | ExprKind::ForLoop { .. } => { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index c11fd5fcc90c..b4fa7f3bea6a 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -265,7 +265,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { let body = &tcx.mir_const(def).borrow(); if body.return_ty().references_error() { - assert!(tcx.dcx().has_errors().is_some(), "mir_const_qualif: MIR had errors"); + // It's possible to reach here without an error being emitted (#121103). + tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors"); return Default::default(); } diff --git a/tests/ui/lowering/issue-121108.rs b/tests/ui/lowering/issue-121108.rs new file mode 100644 index 000000000000..6b2dd24e4a84 --- /dev/null +++ b/tests/ui/lowering/issue-121108.rs @@ -0,0 +1,9 @@ +#![derive(Clone, Copy)] //~ ERROR `derive` attribute cannot be used at crate level + +use std::ptr::addr_of; + +const UNINHABITED_VARIANT: () = unsafe { + let v = *addr_of!(data).cast(); //~ ERROR cannot determine resolution for the macro `addr_of` +}; + +fn main() {} diff --git a/tests/ui/lowering/issue-121108.stderr b/tests/ui/lowering/issue-121108.stderr new file mode 100644 index 000000000000..c2c5746d6f14 --- /dev/null +++ b/tests/ui/lowering/issue-121108.stderr @@ -0,0 +1,25 @@ +error: `derive` attribute cannot be used at crate level + --> $DIR/issue-121108.rs:1:1 + | +LL | #![derive(Clone, Copy)] + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | use std::ptr::addr_of; + | ------- the inner attribute doesn't annotate this `use` import + | +help: perhaps you meant to use an outer attribute + | +LL - #![derive(Clone, Copy)] +LL + #[derive(Clone, Copy)] + | + +error: cannot determine resolution for the macro `addr_of` + --> $DIR/issue-121108.rs:6:14 + | +LL | let v = *addr_of!(data).cast(); + | ^^^^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error: aborting due to 2 previous errors + diff --git a/tests/ui/mir/issue-121103.rs b/tests/ui/mir/issue-121103.rs new file mode 100644 index 000000000000..e06361a6964c --- /dev/null +++ b/tests/ui/mir/issue-121103.rs @@ -0,0 +1,3 @@ +fn main(_: as lib2::TypeFn>::Output) {} +//~^ ERROR failed to resolve: use of undeclared crate or module `lib2` +//~| ERROR failed to resolve: use of undeclared crate or module `lib2` diff --git a/tests/ui/mir/issue-121103.stderr b/tests/ui/mir/issue-121103.stderr new file mode 100644 index 000000000000..913eee9e0c50 --- /dev/null +++ b/tests/ui/mir/issue-121103.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `lib2` + --> $DIR/issue-121103.rs:1:38 + | +LL | fn main(_: as lib2::TypeFn>::Output) {} + | ^^^^ use of undeclared crate or module `lib2` + +error[E0433]: failed to resolve: use of undeclared crate or module `lib2` + --> $DIR/issue-121103.rs:1:13 + | +LL | fn main(_: as lib2::TypeFn>::Output) {} + | ^^^^ use of undeclared crate or module `lib2` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. From 5233bc91da2f48f5bc79c688b5cfad846a8127da Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 14:50:49 +1100 Subject: [PATCH 28/55] Add an `ErrorGuaranteed` to `ast::TyKind::Err`. This makes it more like `hir::TyKind::Err`, and avoids a `span_delayed_bug` call in `LoweringContext::lower_ty_direct`. It also requires adding `ast::TyKind::Dummy`, now that `ast::TyKind::Err` can't be used for that purpose in the absence of an error emission. There are a couple of cases that aren't as neat as I would have liked, marked with `FIXME` comments. --- compiler/rustc_ast/src/ast.rs | 6 +++-- compiler/rustc_ast/src/mut_visit.rs | 9 +++++-- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 3 ++- .../rustc_ast_passes/src/ast_validation.rs | 3 ++- compiler/rustc_ast_pretty/src/pprust/state.rs | 7 ++++- compiler/rustc_expand/src/base.rs | 9 ++++--- .../rustc_parse/src/parser/diagnostics.rs | 20 +++++++------- compiler/rustc_parse/src/parser/item.rs | 26 +++++++++++++++---- compiler/rustc_parse/src/parser/path.rs | 7 ++--- compiler/rustc_parse/src/parser/ty.rs | 10 ++++--- compiler/rustc_passes/src/hir_stats.rs | 5 ++-- .../clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/rustfmt/src/types.rs | 2 +- 14 files changed, 75 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 098e2606a3be..08fc8e3c6cca 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2136,10 +2136,12 @@ pub enum TyKind { ImplicitSelf, /// A macro in the type position. MacCall(P), - /// Placeholder for a kind that has failed to be defined. - Err, /// Placeholder for a `va_list`. CVarArgs, + /// Sometimes we need a dummy value when no error has occurred. + Dummy, + /// Placeholder for a kind that has failed to be defined. + Err(ErrorGuaranteed), } impl TyKind { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d482ada170ee..c42c41999732 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -481,7 +481,12 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { let Ty { id, kind, span, tokens } = ty.deref_mut(); vis.visit_id(id); match kind { - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} + TyKind::Infer + | TyKind::ImplicitSelf + | TyKind::Err(_) + | TyKind::Dummy + | TyKind::Never + | TyKind::CVarArgs => {} TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { @@ -1649,7 +1654,7 @@ impl DummyAstNode for Ty { fn dummy() -> Self { Ty { id: DUMMY_NODE_ID, - kind: TyKind::Err, + kind: TyKind::Dummy, span: Default::default(), tokens: Default::default(), } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 4aaaa0ba4245..83f6746bdeb2 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -447,7 +447,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } TyKind::Typeof(expression) => visitor.visit_anon_const(expression), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} TyKind::MacCall(mac) => visitor.visit_mac_call(mac), TyKind::Never | TyKind::CVarArgs => {} TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b5fc0142408..c1b7af94b02a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1285,7 +1285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()), + TyKind::Err(guar) => hir::TyKind::Err(*guar), // Lower the anonymous structs or unions in a nested lowering context. // // ``` @@ -1503,6 +1503,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ebc5c17a4c4f..fa0f53261961 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -881,7 +881,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - if let TyKind::Err = self_ty.kind { + // njn: use Dummy here + if let TyKind::Err(_) = self_ty.kind { this.dcx().emit_err(errors::ObsoleteAuto { span: item.span }); } if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cda746894e86..480506272d2b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1048,11 +1048,16 @@ impl<'a> State<'a> { ast::TyKind::Infer => { self.word("_"); } - ast::TyKind::Err => { + ast::TyKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); self.pclose(); } + ast::TyKind::Dummy => { + self.popen(); + self.word("/*DUMMY*/"); + self.pclose(); + } ast::TyKind::ImplicitSelf => { self.word("Self"); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cfeb31fc4c81..20cfc72f6d36 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -567,10 +567,13 @@ impl DummyResult { } /// A plain dummy type. - pub fn raw_ty(sp: Span, is_error: bool) -> P { + pub fn raw_ty(sp: Span) -> P { + // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some + // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not + // support, so we use an empty tuple instead. P(ast::Ty { id: ast::DUMMY_NODE_ID, - kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(ThinVec::new()) }, + kind: ast::TyKind::Tup(ThinVec::new()), span: sp, tokens: None, }) @@ -611,7 +614,7 @@ impl MacResult for DummyResult { } fn make_ty(self: Box) -> Option> { - Some(DummyResult::raw_ty(self.span, self.is_error)) + Some(DummyResult::raw_ty(self.span)) } fn make_arms(self: Box) -> Option> { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 445d5b2ce790..69518287f38e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -46,14 +46,14 @@ use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; /// Creates a placeholder argument. -pub(super) fn dummy_arg(ident: Ident) -> Param { +pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingAnnotation::NONE, ident, None), span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; + let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -1540,14 +1540,14 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P) -> P { if self.token == token::Question { self.bump(); - self.dcx().emit_err(QuestionMarkInType { + let guar = self.dcx().emit_err(QuestionMarkInType { span: self.prev_token.span, sugg: QuestionMarkInTypeSugg { left: ty.span.shrink_to_lo(), right: self.prev_token.span, }, }); - self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err) + self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar)) } else { ty } @@ -2304,8 +2304,8 @@ impl<'a> Parser<'a> { pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> { let span = param.pat.span; - param.ty.kind = TyKind::Err; - self.dcx().emit_err(SelfParamNotFirst { span }); + let guar = self.dcx().emit_err(SelfParamNotFirst { span }); + param.ty.kind = TyKind::Err(guar); Ok(param) } @@ -2437,7 +2437,7 @@ impl<'a> Parser<'a> { pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { - let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) = (&input.pat.kind, &input.ty.kind) { Some(*ident) @@ -2644,8 +2644,10 @@ impl<'a> Parser<'a> { "::", Applicability::MaybeIncorrect, ); - err.emit(); - return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err))); + let guar = err.emit(); + return Ok(GenericArg::Type( + self.mk_ty(start.to(expr.span), TyKind::Err(guar)), + )); } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { // Avoid the following output by checking that we consumed a full const arg: diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 8050b34956ce..a0605b8a44c3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -591,7 +591,23 @@ impl<'a> Parser<'a> { let ty_second = if self.token == token::DotDot { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens - Some(self.mk_ty(self.prev_token.span, TyKind::Err)) + + // FIXME(nnethercote): AST validation later detects this + // `TyKind::Err` and emits an errors. So why the unchecked + // ErrorGuaranteed? + // - A `span_delayed_bug` doesn't work here, because rustfmt can + // hit this path but then not hit the follow-up path in the AST + // validator that issues the error, which results in ICEs. + // - `TyKind::Dummy` doesn't work, because it ends up reaching HIR + // lowering, which results in ICEs. Changing `TyKind::Dummy` to + // `TyKind::Err` during AST validation might fix that, but that's + // not possible because AST validation doesn't allow mutability. + // + // #121072 will hopefully remove all this special handling of the + // obsolete `impl Trait for ..` and then this can go away. + #[allow(deprecated)] + let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed(); + Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar))) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { @@ -2628,13 +2644,13 @@ impl<'a> Parser<'a> { p.recover_diff_marker(); let snapshot = p.create_snapshot_for_diagnostic(); let param = p.parse_param_general(req_name, first_param).or_else(|e| { - e.emit(); + let guar = e.emit(); let lo = p.prev_token.span; p.restore_snapshot(snapshot); // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) + Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar)) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; @@ -2671,8 +2687,8 @@ impl<'a> Parser<'a> { return if let Some(ident) = this.parameter_without_type(&mut err, pat, is_name_required, first_param) { - err.emit(); - Ok((dummy_arg(ident), TrailingToken::None)) + let guar = err.emit(); + Ok((dummy_arg(ident, guar), TrailingToken::None)) } else { Err(err) }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index e7cad74b4dd1..681039999a65 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -678,8 +678,9 @@ impl<'a> Parser<'a> { c.into() } Some(GenericArg::Lifetime(lt)) => { - self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); - self.mk_ty(span, ast::TyKind::Err).into() + let guar = + self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); + self.mk_ty(span, ast::TyKind::Err(guar)).into() } None => { let after_eq = eq.shrink_to_hi(); @@ -779,7 +780,7 @@ impl<'a> Parser<'a> { // type to determine if error recovery has occurred and if the input is not a // syntactically valid type after all. if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind - && let ast::TyKind::Err = inner_ty.kind + && let ast::TyKind::Err(_) = inner_ty.kind && let Some(snapshot) = snapshot && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 157fb9e505af..f79f2a813b22 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -346,8 +346,10 @@ impl<'a> Parser<'a> { AllowCVariadic::No => { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); - TyKind::Err + let guar = self + .dcx() + .emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); + TyKind::Err(guar) } } } else { @@ -493,8 +495,8 @@ impl<'a> Parser<'a> { { // Recover from `[LIT; EXPR]` and `[LIT]` self.bump(); - err.emit(); - self.mk_ty(self.prev_token.span, TyKind::Err) + let guar = err.emit(); + self.mk_ty(self.prev_token.span, TyKind::Err(guar)) } Err(err) => return Err(err), }; diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d02e86dd4569..96429bb77888 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -616,8 +616,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Infer, ImplicitSelf, MacCall, - Err, - CVarArgs + CVarArgs, + Dummy, + Err ] ); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index adc35bd82ae3..0467a8a65709 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -690,7 +690,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { match (&l.kind, &r.kind) { (Paren(l), _) => eq_ty(l, r), (_, Paren(r)) => eq_ty(l, r), - (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true, + (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err(_), Err(_)) | (CVarArgs, CVarArgs) => true, (Slice(l), Slice(r)) => eq_ty(l, r), (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 4cd8e6a703e5..7f220a456a8e 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -859,7 +859,7 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::CVarArgs => Some("...".to_owned()), - ast::TyKind::Err => Some(context.snippet(self.span).to_owned()), + ast::TyKind::Dummy | ast::TyKind::Err(_) => Some(context.snippet(self.span).to_owned()), ast::TyKind::Typeof(ref anon_const) => rewrite_call( context, "typeof", From 5f4e4baddb104ee3e63d1db24a4c2a73e1a703cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 15 Feb 2024 00:00:00 +0000 Subject: [PATCH 29/55] Skip coroutines in jump threading to avoid query cycles --- compiler/rustc_mir_transform/src/jump_threading.rs | 6 ++++++ tests/ui/mir/mir_query_cycle.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/mir/mir_query_cycle.rs diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 78ba166ba433..ad8f21ffbdaa 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -68,6 +68,12 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { let def_id = body.source.def_id(); debug!(?def_id); + // Optimizing coroutines creates query cycles. + if tcx.is_coroutine(def_id) { + trace!("Skipped for coroutine {:?}", def_id); + return; + } + let param_env = tcx.param_env_reveal_all_normalized(def_id); let map = Map::new(tcx, body, Some(MAX_PLACES)); let loop_headers = loop_headers(body); diff --git a/tests/ui/mir/mir_query_cycle.rs b/tests/ui/mir/mir_query_cycle.rs new file mode 100644 index 000000000000..22d1ccb6c6e0 --- /dev/null +++ b/tests/ui/mir/mir_query_cycle.rs @@ -0,0 +1,14 @@ +// Regression test for #121094. +// build-pass +// compile-flags: -O --crate-type=lib +// edition: 2021 +use std::{future::Future, pin::Pin}; + +pub async fn foo(count: u32) { + if count == 0 { + return + } else { + let fut: Pin>> = Box::pin(foo(count - 1)); + fut.await; + } +} From a8d869e1d151d70137af8e7a03155cb6ac93139c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 13 Feb 2024 11:52:27 +0100 Subject: [PATCH 30/55] rustdoc: cross-crate re-exports: correctly render late-bound params in source order even if early-bound params are present --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/inline.rs | 50 +++++++++---- src/librustdoc/clean/mod.rs | 71 +++++++++---------- src/librustdoc/clean/types.rs | 7 +- src/librustdoc/json/conversions.rs | 25 +++---- .../early-late-bound-lifetime-params.rs | 17 +++++ .../early-late-bound-lifetime-params.rs | 17 +++++ 7 files changed, 119 insertions(+), 70 deletions(-) create mode 100644 tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs create mode 100644 tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 9de547ba6dce..8cc4201c3fc2 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -334,7 +334,7 @@ where match br { // We only care about named late bound regions, as we need to add them // to the 'for<>' section - ty::BrNamed(_, name) => Some(GenericParamDef::lifetime(name)), + ty::BrNamed(def_id, name) => Some(GenericParamDef::lifetime(def_id, name)), _ => None, } }) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 23a059c6e030..e2f2c9a5e566 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -18,8 +18,8 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ - self, clean_bound_vars, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, - clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, + self, clean_bound_vars, clean_generics, clean_impl_item, clean_middle_assoc_item, + clean_middle_field, clean_middle_ty, clean_poly_fn_sig, clean_trait_ref_with_bindings, clean_ty, clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, }; @@ -72,7 +72,9 @@ pub(crate) fn try_inline( } Res::Def(DefKind::Fn, did) => { record_extern_fqn(cx, did, ItemType::Function); - cx.with_param_env(did, |cx| clean::FunctionItem(build_external_function(cx, did))) + cx.with_param_env(did, |cx| { + clean::enter_impl_trait(cx, |cx| clean::FunctionItem(build_function(cx, did))) + }) } Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, ItemType::Struct); @@ -274,18 +276,38 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds } } -fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box { - let sig = cx.tcx.fn_sig(did).instantiate_identity(); - let predicates = cx.tcx.explicit_predicates_of(did); +pub(crate) fn build_function<'tcx>( + cx: &mut DocContext<'tcx>, + def_id: DefId, +) -> Box { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + // The generics need to be cleaned before the signature. + let mut generics = + clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + let bound_vars = clean_bound_vars(sig.bound_vars()); + + // At the time of writing early & late-bound params are stored separately in rustc, + // namely in `generics.params` and `bound_vars` respectively. + // + // To reestablish the original source code order of the generic parameters, we + // need to manually sort them by their definition span after concatenation. + // + // See also: + // * https://rustc-dev-guide.rust-lang.org/bound-vars-and-params.html + // * https://rustc-dev-guide.rust-lang.org/what-does-early-late-bound-mean.html + let has_early_bound_params = !generics.params.is_empty(); + let has_late_bound_params = !bound_vars.is_empty(); + generics.params.extend(bound_vars); + if has_early_bound_params && has_late_bound_params { + // If this ever becomes a performances bottleneck either due to the sorting + // or due to the query calls, consider inserting the late-bound lifetime params + // right after the last early-bound lifetime param followed by only sorting + // the slice of lifetime params. + generics.params.sort_by_key(|param| cx.tcx.def_ident_span(param.def_id).unwrap()); + } + + let decl = clean_poly_fn_sig(cx, Some(def_id), sig); - let (generics, decl) = clean::enter_impl_trait(cx, |cx| { - // NOTE: generics need to be cleaned before the decl! - let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); - // FIXME: This does not place parameters in source order (late-bound ones come last) - generics.params.extend(clean_bound_vars(sig.bound_vars())); - let decl = clean_fn_decl_from_did_and_sig(cx, Some(did), sig); - (generics, decl) - }); Box::new(clean::Function { decl, generics }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4527d1e55e8..c4a9243816e5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -525,7 +525,6 @@ fn clean_generic_param_def<'tcx>( ( def.name, GenericParamDefKind::Type { - did: def.def_id, bounds: ThinVec::new(), // These are filled in from the where-clauses. default: default.map(Box::new), synthetic, @@ -557,7 +556,7 @@ fn clean_generic_param_def<'tcx>( ), }; - GenericParamDef { name, kind } + GenericParamDef { name, def_id: def.def_id, kind } } fn clean_generic_param<'tcx>( @@ -596,7 +595,6 @@ fn clean_generic_param<'tcx>( ( param.name.ident().name, GenericParamDefKind::Type { - did: param.def_id.to_def_id(), bounds, default: default.map(|t| clean_ty(t, cx)).map(Box::new), synthetic, @@ -614,7 +612,7 @@ fn clean_generic_param<'tcx>( ), }; - GenericParamDef { name, kind } + GenericParamDef { name, def_id: param.def_id.to_def_id(), kind } } /// Synthetic type-parameters are inserted after normal ones. @@ -646,8 +644,8 @@ pub(crate) fn clean_generics<'tcx>( let param = clean_generic_param(cx, Some(gens), param); match param.kind { GenericParamDefKind::Lifetime { .. } => unreachable!(), - GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.insert(did.into(), bounds.to_vec()); + GenericParamDefKind::Type { ref bounds, .. } => { + cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -1064,8 +1062,11 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib match literal.kind { ast::LitKind::Int(a, _) => { let gen = func.generics.params.remove(0); - if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } = - gen + if let GenericParamDef { + name, + kind: GenericParamDefKind::Const { ty, .. }, + .. + } = gen { func.decl .inputs @@ -1169,7 +1170,7 @@ fn clean_fn_decl_with_args<'tcx>( FnDecl { inputs: args, output, c_variadic: decl.c_variadic } } -fn clean_fn_decl_from_did_and_sig<'tcx>( +fn clean_poly_fn_sig<'tcx>( cx: &mut DocContext<'tcx>, did: Option, sig: ty::PolyFnSig<'tcx>, @@ -1359,16 +1360,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } } ty::AssocKind::Fn => { - let sig = tcx.fn_sig(assoc_item.def_id).instantiate_identity(); - let mut generics = clean_ty_generics( - cx, - tcx.generics_of(assoc_item.def_id), - tcx.explicit_predicates_of(assoc_item.def_id), - ); - // FIXME: This does not place parameters in source order (late-bound ones come last) - generics.params.extend(clean_bound_vars(sig.bound_vars())); - - let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig); + let mut item = inline::build_function(cx, assoc_item.def_id); if assoc_item.fn_has_self_parameter { let self_ty = match assoc_item.container { @@ -1377,12 +1369,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } ty::TraitContainer => tcx.types.self_param, }; - let self_arg_ty = sig.input(0).skip_binder(); + let self_arg_ty = + tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); if self_arg_ty == self_ty { - decl.inputs.values[0].type_ = Generic(kw::SelfUpper); + item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper); } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { if ty == self_ty { - match decl.inputs.values[0].type_ { + match item.decl.inputs.values[0].type_ { BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper), _ => unreachable!(), } @@ -1399,9 +1392,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( ty::ImplContainer => Some(assoc_item.defaultness(tcx)), ty::TraitContainer => None, }; - MethodItem(Box::new(Function { generics, decl }), defaultness) + MethodItem(item, defaultness) } else { - TyMethodItem(Box::new(Function { generics, decl })) + TyMethodItem(item) } } ty::AssocKind::Type => { @@ -2109,7 +2102,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::FnDef(..) | ty::FnPtr(_) => { // FIXME: should we merge the outer and inner binders somehow? let sig = bound_ty.skip_binder().fn_sig(cx.tcx); - let decl = clean_fn_decl_from_did_and_sig(cx, None, sig); + let decl = clean_poly_fn_sig(cx, None, sig); let generic_params = clean_bound_vars(sig.bound_vars()); BareFunction(Box::new(BareFunctionDecl { @@ -2192,10 +2185,10 @@ pub(crate) fn clean_middle_ty<'tcx>( .iter() .flat_map(|pred| pred.bound_vars()) .filter_map(|var| match var { - ty::BoundVariableKind::Region(ty::BrNamed(_, name)) + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) if name != kw::UnderscoreLifetime => { - Some(GenericParamDef::lifetime(name)) + Some(GenericParamDef::lifetime(def_id, name)) } _ => None, }) @@ -3167,20 +3160,22 @@ fn clean_bound_vars<'tcx>( bound_vars .into_iter() .filter_map(|var| match var { - ty::BoundVariableKind::Region(ty::BrNamed(_, name)) + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) if name != kw::UnderscoreLifetime => { - Some(GenericParamDef::lifetime(name)) + Some(GenericParamDef::lifetime(def_id, name)) + } + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) => { + Some(GenericParamDef { + name, + def_id, + kind: GenericParamDefKind::Type { + bounds: ThinVec::new(), + default: None, + synthetic: false, + }, + }) } - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(did, name)) => Some(GenericParamDef { - name, - kind: GenericParamDefKind::Type { - did, - bounds: ThinVec::new(), - default: None, - synthetic: false, - }, - }), // FIXME(non_lifetime_binders): Support higher-ranked const parameters. ty::BoundVariableKind::Const => None, _ => None, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 96b4d1a45f6e..9b7ec6e109a7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1326,7 +1326,7 @@ impl WherePredicate { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericParamDefKind { Lifetime { outlives: ThinVec }, - Type { did: DefId, bounds: ThinVec, default: Option>, synthetic: bool }, + Type { bounds: ThinVec, default: Option>, synthetic: bool }, // Option> makes this type smaller than `Option` would. Const { ty: Box, default: Option>, is_host_effect: bool }, } @@ -1340,12 +1340,13 @@ impl GenericParamDefKind { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct GenericParamDef { pub(crate) name: Symbol, + pub(crate) def_id: DefId, pub(crate) kind: GenericParamDefKind, } impl GenericParamDef { - pub(crate) fn lifetime(name: Symbol) -> Self { - Self { name, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } } + pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self { + Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } } } pub(crate) fn is_synthetic_param(&self) -> bool { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 32d7a80863d6..cb50a27326fe 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -456,7 +456,7 @@ impl FromWithTcx for GenericParamDefKind { Lifetime { outlives } => GenericParamDefKind::Lifetime { outlives: outlives.into_iter().map(convert_lifetime).collect(), }, - Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { + Type { bounds, default, synthetic } => GenericParamDefKind::Type { bounds: bounds.into_tcx(tcx), default: default.map(|x| (*x).into_tcx(tcx)), synthetic, @@ -486,19 +486,16 @@ impl FromWithTcx for WherePredicate { outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(), } } - clean::GenericParamDefKind::Type { - did: _, - bounds, - default, - synthetic, - } => GenericParamDefKind::Type { - bounds: bounds - .into_iter() - .map(|bound| bound.into_tcx(tcx)) - .collect(), - default: default.map(|ty| (*ty).into_tcx(tcx)), - synthetic, - }, + clean::GenericParamDefKind::Type { bounds, default, synthetic } => { + GenericParamDefKind::Type { + bounds: bounds + .into_iter() + .map(|bound| bound.into_tcx(tcx)) + .collect(), + default: default.map(|ty| (*ty).into_tcx(tcx)), + synthetic, + } + } clean::GenericParamDefKind::Const { ty, default, diff --git a/tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs b/tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs new file mode 100644 index 000000000000..70f7a84a8dcc --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs @@ -0,0 +1,17 @@ +// Here, `'a` and `'c` are late-bound and `'b`, `'d`, `T` and `N` are early-bound. + +pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy) +where + 'b:, + 'd:, +{} + +pub struct Ty; + +impl Ty { + pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy) + where + 'b:, + 'd:, + {} +} diff --git a/tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs b/tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs new file mode 100644 index 000000000000..09cc8a79072b --- /dev/null +++ b/tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs @@ -0,0 +1,17 @@ +// Check that we correctly render late-bound lifetime params in source order +// even if early-bound generic params are present. +// +// For context, at the time of writing early- and late-bound params are stored +// separately in rustc and therefore rustdoc needs to manually merge them. + +#![crate_name = "usr"] +// aux-crate:dep=early-late-bound-lifetime-params.rs +// edition:2021 + +// @has usr/fn.f.html +// @has - '//pre[@class="rust item-decl"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)" +pub use dep::f; + +// @has usr/struct.Ty.html +// @has - '//*[@id="method.f"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)" +pub use dep::Ty; From e6a21f549ebf1437a59e9a0bb3c8e41172d1dcf7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 01:07:20 +0000 Subject: [PATCH 31/55] Enforce coroutine-closure layouts are identical --- .../src/transform/validate.rs | 20 +++++++++++++++++++ compiler/rustc_middle/src/mir/query.rs | 6 ++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b5c70538c52d..1ff72516324c 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -98,6 +98,26 @@ impl<'tcx> MirPass<'tcx> for Validator { } } } + + // Enforce that coroutine-closure layouts are identical. + if let Some(layout) = body.coroutine_layout() + && let Some(by_move_body) = body.coroutine_by_move_body() + && let Some(by_move_layout) = by_move_body.coroutine_layout() + { + if layout != by_move_layout { + // If this turns out not to be true, please let compiler-errors know. + // It is possible to support, but requires some changes to the layout + // computation code. + cfg_checker.fail( + Location::START, + format!( + "Coroutine layout differs from by-move coroutine layout:\n\ + layout: {layout:#?}\n\ + by_move_layout: {by_move_layout:#?}", + ), + ); + } + } } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 90b6df1dd1f5..8bd872c1b19e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -86,7 +86,8 @@ rustc_index::newtype_index! { pub struct CoroutineSavedLocal {} } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CoroutineSavedTy<'tcx> { pub ty: Ty<'tcx>, /// Source info corresponding to the local in the original MIR body. @@ -96,7 +97,8 @@ pub struct CoroutineSavedTy<'tcx> { } /// The layout of coroutine state. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, PartialEq, Eq)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CoroutineLayout<'tcx> { /// The type of every local stored inside the coroutine. pub field_tys: IndexVec>, From 8b35f8e41ea501396c9fb77ed785f8beab90e999 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 19:09:25 +1100 Subject: [PATCH 32/55] Remove `LitError::LexerError`. `cook_lexer_literal` can emit an error about an invalid int literal but then return a non-`Err` token. And then `integer_lit` has to account for this to avoid printing a redundant error message. This commit changes `cook_lexer_literal` to return `Err` in that case. Then `integer_lit` doesn't need the special case, and `LitError::LexerError` can be removed. --- compiler/rustc_ast/src/util/literal.rs | 11 +++------- compiler/rustc_parse/src/lexer/mod.rs | 30 +++++++++++++------------- compiler/rustc_session/src/errors.rs | 3 --- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index aaeb1bb9bff8..fbe72252ec91 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -31,7 +31,6 @@ pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol { #[derive(Debug)] pub enum LitError { - LexerError, InvalidSuffix, InvalidIntSuffix, InvalidFloatSuffix, @@ -324,11 +323,7 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result= base)); - if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) } - }) + u128::from_str_radix(s, base) + .map(|i| LitKind::Int(i.into(), ty)) + .map_err(|_| LitError::IntTooLarge(base)) } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 315524526760..aa4456a1c218 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -16,7 +16,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::{edition::Edition, BytePos, Pos, Span}; mod diagnostics; @@ -478,26 +478,26 @@ impl<'sess, 'src> StringReader<'sess, 'src> { } } rustc_lexer::LiteralKind::Int { base, empty_int } => { + let mut kind = token::Integer; if empty_int { let span = self.mk_sp(start, end); self.dcx().emit_err(errors::NoDigitsLiteral { span }); - (token::Integer, sym::integer(0)) - } else { - if matches!(base, Base::Binary | Base::Octal) { - let base = base as u32; - let s = self.str_from_to(start + BytePos(2), end); - for (idx, c) in s.char_indices() { - let span = self.mk_sp( - start + BytePos::from_usize(2 + idx), - start + BytePos::from_usize(2 + idx + c.len_utf8()), - ); - if c != '_' && c.to_digit(base).is_none() { - self.dcx().emit_err(errors::InvalidDigitLiteral { span, base }); - } + kind = token::Err; + } else if matches!(base, Base::Binary | Base::Octal) { + let base = base as u32; + let s = self.str_from_to(start + BytePos(2), end); + for (idx, c) in s.char_indices() { + let span = self.mk_sp( + start + BytePos::from_usize(2 + idx), + start + BytePos::from_usize(2 + idx + c.len_utf8()), + ); + if c != '_' && c.to_digit(base).is_none() { + self.dcx().emit_err(errors::InvalidDigitLiteral { span, base }); + kind = token::Err; } } - (token::Integer, self.symbol_from_to(start, end)) } + (kind, self.symbol_from_to(start, end)) } rustc_lexer::LiteralKind::Float { base, empty_exponent } => { if empty_exponent { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index c36cec6f3532..e4bc6acf46c8 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -375,9 +375,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: let token::Lit { kind, symbol, suffix, .. } = lit; let dcx = &sess.dcx; match err { - // `LexerError` is an error, but it was already reported - // by lexer, so here we don't report it the second time. - LitError::LexerError => {} LitError::InvalidSuffix => { if let Some(suffix) = suffix { dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix }); From a513bb20c39e18bd837934c80355ff468f233a4a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 19:30:12 +1100 Subject: [PATCH 33/55] Make `report_lit_error` return `ErrorGuaranteed`. This will be helpful for subsequent commits. --- compiler/rustc_session/src/errors.rs | 43 +++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index e4bc6acf46c8..f06e2136c2c5 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,8 @@ use std::num::NonZeroU32; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, + codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, + Level, MultiSpan, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -344,7 +345,12 @@ pub(crate) struct BinaryFloatLiteralNotSupported { pub span: Span, } -pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) { +pub fn report_lit_error( + sess: &ParseSess, + err: LitError, + lit: token::Lit, + span: Span, +) -> ErrorGuaranteed { // Checks if `s` looks like i32 or u1234 etc. fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) @@ -372,24 +378,23 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } - let token::Lit { kind, symbol, suffix, .. } = lit; + let token::Lit { kind, symbol, suffix } = lit; let dcx = &sess.dcx; match err { LitError::InvalidSuffix => { - if let Some(suffix) = suffix { - dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix }); - } + let suffix = suffix.unwrap(); + dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix }) } LitError::InvalidIntSuffix => { let suf = suffix.expect("suffix error with no suffix"); let suf = suf.as_str(); if looks_like_width_suffix(&['i', 'u'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); + dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) { - dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); + dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }) } else { - dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); + dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) } } LitError::InvalidFloatSuffix => { @@ -397,19 +402,17 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: let suf = suf.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); + dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) } else { - dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); + dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }) } } - LitError::NonDecimalFloat(base) => { - match base { - 16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }), - 8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }), - 2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }), - _ => unreachable!(), - }; - } + LitError::NonDecimalFloat(base) => match base { + 16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }), + 8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }), + 2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }), + _ => unreachable!(), + }, LitError::IntTooLarge(base) => { let max = u128::MAX; let limit = match base { @@ -418,7 +421,7 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: 16 => format!("{max:#x}"), _ => format!("{max}"), }; - dcx.emit_err(IntLiteralTooLarge { span, limit }); + dcx.emit_err(IntLiteralTooLarge { span, limit }) } } } From 332c57723a03e97497d6fba6636e31c2e41fefe9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 20:29:31 +1100 Subject: [PATCH 34/55] Make `emit_unescape_error` return `Option`. And use the result in `cook_common` to decide whether to return an error token. --- compiler/rustc_parse/src/lexer/mod.rs | 16 ++--- .../src/lexer/unescape_error_reporting.rs | 58 +++++++++---------- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index aa4456a1c218..7502a5567949 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -691,7 +691,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { fn cook_common( &self, - kind: token::LitKind, + mut kind: token::LitKind, mode: Mode, start: BytePos, end: BytePos, @@ -699,7 +699,6 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, unescape: fn(&str, Mode, &mut dyn FnMut(Range, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { - let mut has_fatal_err = false; let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); @@ -711,10 +710,8 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let lo = content_start + BytePos(start); let hi = lo + BytePos(end - start); let span = self.mk_sp(lo, hi); - if err.is_fatal() { - has_fatal_err = true; - } - emit_unescape_error( + let is_fatal = err.is_fatal(); + if let Some(_guar) = emit_unescape_error( self.dcx(), lit_content, span_with_quotes, @@ -722,13 +719,16 @@ impl<'sess, 'src> StringReader<'sess, 'src> { mode, range, err, - ); + ) { + assert!(is_fatal); + kind = token::Err; + } } }); // We normally exclude the quotes for the symbol, but for errors we // include it because it results in clearer error messages. - if !has_fatal_err { + if kind != token::Err { (kind, Symbol::intern(lit_content)) } else { (token::Err, self.symbol_from_to(start, end)) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 3238f8e23bb0..3ebad6a9fd73 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, DiagCtxt}; +use rustc_errors::{Applicability, DiagCtxt, ErrorGuaranteed}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; @@ -21,7 +21,7 @@ pub(crate) fn emit_unescape_error( // range of the error inside `lit` range: Range, error: EscapeError, -) { +) -> Option { debug!( "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", lit, full_lit_span, mode, range, error @@ -31,12 +31,12 @@ pub(crate) fn emit_unescape_error( let span = err_span.with_lo(err_span.hi() - BytePos(c.len_utf8() as u32)); (c, span) }; - match error { + Some(match error { EscapeError::LoneSurrogateUnicodeEscape => { - dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true }); + dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true }) } EscapeError::OutOfRangeUnicodeEscape => { - dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }); + dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }) } EscapeError::MoreThanOneChar => { use unicode_normalization::{char::is_combining_mark, UnicodeNormalization}; @@ -106,7 +106,7 @@ pub(crate) fn emit_unescape_error( span: full_lit_span, note, suggestion: sugg, - }); + }) } EscapeError::EscapeOnlyChar => { let (c, char_span) = last_char(); @@ -116,15 +116,15 @@ pub(crate) fn emit_unescape_error( escaped_sugg: c.escape_default().to_string(), escaped_msg: escaped_char(c), byte: mode == Mode::Byte, - }); + }) } EscapeError::BareCarriageReturn => { let double_quotes = mode.in_double_quotes(); - dcx.emit_err(UnescapeError::BareCr { span: err_span, double_quotes }); + dcx.emit_err(UnescapeError::BareCr { span: err_span, double_quotes }) } EscapeError::BareCarriageReturnInRawString => { assert!(mode.in_double_quotes()); - dcx.emit_err(UnescapeError::BareCrRawString(err_span)); + dcx.emit_err(UnescapeError::BareCrRawString(err_span)) } EscapeError::InvalidEscape => { let (c, span) = last_char(); @@ -161,16 +161,14 @@ pub(crate) fn emit_unescape_error( ", ); } - diag.emit(); - } - EscapeError::TooShortHexEscape => { - dcx.emit_err(UnescapeError::TooShortHexEscape(err_span)); + diag.emit() } + EscapeError::TooShortHexEscape => dcx.emit_err(UnescapeError::TooShortHexEscape(err_span)), EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { let (c, span) = last_char(); let is_hex = error == EscapeError::InvalidCharInHexEscape; let ch = escaped_char(c); - dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch }); + dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch }) } EscapeError::NonAsciiCharInByte => { let (c, span) = last_char(); @@ -213,23 +211,23 @@ pub(crate) fn emit_unescape_error( Applicability::MaybeIncorrect, ); } - err.emit(); + err.emit() } EscapeError::OutOfRangeHexEscape => { - dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)); + dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)) } EscapeError::LeadingUnderscoreUnicodeEscape => { let (c, span) = last_char(); dcx.emit_err(UnescapeError::LeadingUnderscoreUnicodeEscape { span, ch: escaped_char(c), - }); + }) } EscapeError::OverlongUnicodeEscape => { - dcx.emit_err(UnescapeError::OverlongUnicodeEscape(err_span)); + dcx.emit_err(UnescapeError::OverlongUnicodeEscape(err_span)) } EscapeError::UnclosedUnicodeEscape => { - dcx.emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi())); + dcx.emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi())) } EscapeError::NoBraceInUnicodeEscape => { let mut suggestion = "\\u{".to_owned(); @@ -248,23 +246,17 @@ pub(crate) fn emit_unescape_error( } else { (Some(err_span), NoBraceUnicodeSub::Help) }; - dcx.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub }); + dcx.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub }) } EscapeError::UnicodeEscapeInByte => { - dcx.emit_err(UnescapeError::UnicodeEscapeInByte(err_span)); + dcx.emit_err(UnescapeError::UnicodeEscapeInByte(err_span)) } EscapeError::EmptyUnicodeEscape => { - dcx.emit_err(UnescapeError::EmptyUnicodeEscape(err_span)); - } - EscapeError::ZeroChars => { - dcx.emit_err(UnescapeError::ZeroChars(err_span)); - } - EscapeError::LoneSlash => { - dcx.emit_err(UnescapeError::LoneSlash(err_span)); - } - EscapeError::NulInCStr => { - dcx.emit_err(UnescapeError::NulInCStr { span: err_span }); + dcx.emit_err(UnescapeError::EmptyUnicodeEscape(err_span)) } + EscapeError::ZeroChars => dcx.emit_err(UnescapeError::ZeroChars(err_span)), + EscapeError::LoneSlash => dcx.emit_err(UnescapeError::LoneSlash(err_span)), + EscapeError::NulInCStr => dcx.emit_err(UnescapeError::NulInCStr { span: err_span }), EscapeError::UnskippedWhitespaceWarning => { let (c, char_span) = last_char(); dcx.emit_warn(UnescapeError::UnskippedWhitespace { @@ -272,11 +264,13 @@ pub(crate) fn emit_unescape_error( ch: escaped_char(c), char_span, }); + return None; } EscapeError::MultipleSkippedLinesWarning => { dcx.emit_warn(UnescapeError::MultipleSkippedLinesWarning(err_span)); + return None; } - } + }) } /// Pushes a character to a message string for error reporting From 25ed6e43b0ea03ca48692741624f3e70d717ea43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 20:12:05 +1100 Subject: [PATCH 35/55] Add `ErrorGuaranteed` to `ast::LitKind::Err`, `token::LitKind::Err`. This mostly works well, and eliminates a couple of delayed bugs. One annoying thing is that we should really also add an `ErrorGuaranteed` to `proc_macro::bridge::LitKind::Err`. But that's difficult because `proc_macro` doesn't have access to `ErrorGuaranteed`, so we have to fake it. --- compiler/rustc_ast/src/ast.rs | 4 ++-- compiler/rustc_ast/src/token.rs | 12 +++++----- compiler/rustc_ast/src/util/literal.rs | 6 ++--- compiler/rustc_ast_lowering/src/expr.rs | 9 ++++++-- compiler/rustc_ast_lowering/src/lib.rs | 3 ++- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_builtin_macros/src/concat.rs | 2 +- .../rustc_builtin_macros/src/concat_bytes.rs | 2 +- compiler/rustc_expand/src/base.rs | 2 +- .../rustc_expand/src/proc_macro_server.rs | 22 +++++++++++++++---- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- .../src/build/expr/as_constant.rs | 6 +---- compiler/rustc_mir_build/src/thir/constant.rs | 6 +---- compiler/rustc_mir_build/src/thir/cx/expr.rs | 12 +++++----- compiler/rustc_parse/src/lexer/mod.rs | 22 ++++++++++--------- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/validate_attr.rs | 4 ++-- library/proc_macro/src/bridge/mod.rs | 8 +++++-- library/proc_macro/src/lib.rs | 2 +- .../src/matches/match_same_arms.rs | 3 ++- .../src/redundant_type_annotations.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 2 +- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../src/server/rust_analyzer_span.rs | 4 ++-- .../proc-macro-srv/src/server/token_id.rs | 4 ++-- 26 files changed, 85 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 098e2606a3be..b74938621b30 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1846,7 +1846,7 @@ pub enum LitKind { /// A boolean literal (`true`, `false`). Bool(bool), /// Placeholder for a literal that wasn't well-formed in some way. - Err, + Err(ErrorGuaranteed), } impl LitKind { @@ -1893,7 +1893,7 @@ impl LitKind { | LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) - | LitKind::Err => false, + | LitKind::Err(_) => false, } } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d62462b1ae33..50fe37dcdb6f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -13,7 +13,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym}; #[allow(hidden_glob_reexports)] use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{edition::Edition, Span, DUMMY_SP}; +use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; @@ -75,7 +75,7 @@ pub enum LitKind { ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols CStr, CStrRaw(u8), - Err, + Err(ErrorGuaranteed), } /// A literal token. @@ -144,7 +144,7 @@ impl fmt::Display for Lit { CStrRaw(n) => { write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))? } - Integer | Float | Bool | Err => write!(f, "{symbol}")?, + Integer | Float | Bool | Err(_) => write!(f, "{symbol}")?, } if let Some(suffix) = suffix { @@ -159,7 +159,7 @@ impl LitKind { /// An English article for the literal token kind. pub fn article(self) -> &'static str { match self { - Integer | Err => "an", + Integer | Err(_) => "an", _ => "a", } } @@ -174,12 +174,12 @@ impl LitKind { Str | StrRaw(..) => "string", ByteStr | ByteStrRaw(..) => "byte string", CStr | CStrRaw(..) => "C string", - Err => "error", + Err(_) => "error", } } pub(crate) fn may_have_suffix(self) -> bool { - matches!(self, Integer | Float | Err) + matches!(self, Integer | Float | Err(_)) } } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index fbe72252ec91..e4bb23675cb9 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -144,7 +144,7 @@ impl LitKind { buf.push(0); LitKind::CStr(buf.into(), StrStyle::Raw(n)) } - token::Err => LitKind::Err, + token::Err(guar) => LitKind::Err(guar), }) } } @@ -201,7 +201,7 @@ impl fmt::Display for LitKind { } } LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?, - LitKind::Err => { + LitKind::Err(_) => { // This only shows up in places like `-Zunpretty=hir` output, so we // don't bother to produce something useful. write!(f, "")?; @@ -237,7 +237,7 @@ impl MetaItemLit { LitKind::Char(_) => token::Char, LitKind::Int(..) => token::Integer, LitKind::Float(..) => token::Float, - LitKind::Err => token::Err, + LitKind::Err(guar) => token::Err(guar), }; token::Lit::new(kind, self.symbol, self.suffix) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 73d1d891bb98..2112040621ee 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -124,8 +124,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let lit_kind = match LitKind::from_token_lit(*token_lit) { Ok(lit_kind) => lit_kind, Err(err) => { - report_lit_error(&self.tcx.sess.parse_sess, err, *token_lit, e.span); - LitKind::Err + let guar = report_lit_error( + &self.tcx.sess.parse_sess, + err, + *token_lit, + e.span, + ); + LitKind::Err(guar) } }; let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b5fc0142408..eab1383b635c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -966,10 +966,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { lit } else { + let guar = self.dcx().has_errors().unwrap(); MetaItemLit { symbol: kw::Empty, suffix: None, - kind: LitKind::Err, + kind: LitKind::Err(guar), span: DUMMY_SP, } }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cda746894e86..2765b235f991 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -254,7 +254,7 @@ fn literal_to_string(lit: token::Lit) -> String { token::CStrRaw(n) => { format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize)) } - token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(), + token::Integer | token::Float | token::Bool | token::Err(_) => symbol.to_string(), }; if let Some(suffix) = suffix { diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index dade29593af1..795161e65d81 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -40,7 +40,7 @@ pub fn expand_concat( cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); has_errors = true; } - Ok(ast::LitKind::Err) => { + Ok(ast::LitKind::Err(_)) => { has_errors = true; } Err(err) => { diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a01bbeac8249..3ef8cb7bffef 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -44,7 +44,7 @@ fn invalid_type_err( Ok(ast::LitKind::Bool(_)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); } - Ok(ast::LitKind::Err) => {} + Ok(ast::LitKind::Err(_)) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cfeb31fc4c81..09ab26421d65 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1266,7 +1266,7 @@ pub fn expr_to_spanned_string<'a>( ); Some((err, true)) } - Ok(ast::LitKind::Err) => None, + Ok(ast::LitKind::Err(_)) => None, Err(err) => { report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span); None diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 3a78bd945057..8f31b5801da7 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -10,7 +10,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{MultiSpan, PResult}; +use rustc_errors::{ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; @@ -63,7 +63,12 @@ impl FromInternal for LitKind { token::ByteStrRaw(n) => LitKind::ByteStrRaw(n), token::CStr => LitKind::CStr, token::CStrRaw(n) => LitKind::CStrRaw(n), - token::Err => LitKind::Err, + token::Err(_guar) => { + // This is the only place a `pm::bridge::LitKind::ErrWithGuar` + // is constructed. Note that an `ErrorGuaranteed` is available, + // as required. See the comment in `to_internal`. + LitKind::ErrWithGuar + } token::Bool => unreachable!(), } } @@ -82,7 +87,16 @@ impl ToInternal for LitKind { LitKind::ByteStrRaw(n) => token::ByteStrRaw(n), LitKind::CStr => token::CStr, LitKind::CStrRaw(n) => token::CStrRaw(n), - LitKind::Err => token::Err, + LitKind::ErrWithGuar => { + // This is annoying but valid. `LitKind::ErrWithGuar` would + // have an `ErrorGuaranteed` except that type isn't available + // in that crate. So we have to fake one. And we don't want to + // use a delayed bug because there might be lots of these, + // which would be expensive. + #[allow(deprecated)] + let guar = ErrorGuaranteed::unchecked_error_guaranteed(); + token::Err(guar) + } } } } @@ -477,7 +491,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { | token::LitKind::ByteStrRaw(_) | token::LitKind::CStr | token::LitKind::CStrRaw(_) - | token::LitKind::Err => return Err(()), + | token::LitKind::Err(_) => return Err(()), token::LitKind::Integer | token::LitKind::Float => {} } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 65b8505c0909..3bce8a1dd450 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) .skip_binder(), ), - ast::LitKind::Err => Ty::new_misc_error(tcx), + ast::LitKind::Err(guar) => Ty::new_error(tcx, guar), } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 6636f75d9981..7c3d2671d592 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -164,11 +164,7 @@ fn lit_to_mir_constant<'tcx>( })?, (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err, _) => { - return Err(LitToConstError::Reported( - tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), - )); - } + (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 71aebd13003b..d444de8b28ee 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -71,11 +71,7 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err, _) => { - return Err(LitToConstError::Reported( - tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), - )); - } + (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 99952e1c1787..62762168cf42 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -897,12 +897,14 @@ impl<'tcx> Cx<'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local()); let generics = self.tcx.generics_of(hir_id.owner); let Some(&index) = generics.param_def_id_to_index.get(&def_id) else { - self.tcx.dcx().has_errors().unwrap(); + let guar = self.tcx.dcx().has_errors().unwrap(); // We already errored about a late bound const - return ExprKind::Literal { - lit: &Spanned { span: DUMMY_SP, node: LitKind::Err }, - neg: false, - }; + + let lit = self + .tcx + .hir_arena + .alloc(Spanned { span: DUMMY_SP, node: LitKind::Err(guar) }); + return ExprKind::Literal { lit, neg: false }; }; let name = self.tcx.hir().name(hir_id); let param = ty::ParamConst::new(index, name); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 7502a5567949..c768ea93b5fe 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -481,8 +481,8 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let mut kind = token::Integer; if empty_int { let span = self.mk_sp(start, end); - self.dcx().emit_err(errors::NoDigitsLiteral { span }); - kind = token::Err; + let guar = self.dcx().emit_err(errors::NoDigitsLiteral { span }); + kind = token::Err(guar); } else if matches!(base, Base::Binary | Base::Octal) { let base = base as u32; let s = self.str_from_to(start + BytePos(2), end); @@ -492,8 +492,9 @@ impl<'sess, 'src> StringReader<'sess, 'src> { start + BytePos::from_usize(2 + idx + c.len_utf8()), ); if c != '_' && c.to_digit(base).is_none() { - self.dcx().emit_err(errors::InvalidDigitLiteral { span, base }); - kind = token::Err; + let guar = + self.dcx().emit_err(errors::InvalidDigitLiteral { span, base }); + kind = token::Err(guar); } } } @@ -711,7 +712,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let hi = lo + BytePos(end - start); let span = self.mk_sp(lo, hi); let is_fatal = err.is_fatal(); - if let Some(_guar) = emit_unescape_error( + if let Some(guar) = emit_unescape_error( self.dcx(), lit_content, span_with_quotes, @@ -721,18 +722,19 @@ impl<'sess, 'src> StringReader<'sess, 'src> { err, ) { assert!(is_fatal); - kind = token::Err; + kind = token::Err(guar); } } }); // We normally exclude the quotes for the symbol, but for errors we // include it because it results in clearer error messages. - if kind != token::Err { - (kind, Symbol::intern(lit_content)) + let sym = if !matches!(kind, token::Err(_)) { + Symbol::intern(lit_content) } else { - (token::Err, self.symbol_from_to(start, end)) - } + self.symbol_from_to(start, end) + }; + (kind, sym) } fn cook_unicode( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1a57474bac28..2424b6c130d2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2140,12 +2140,12 @@ impl<'a> Parser<'a> { Err(err) => { let span = token.uninterpolated_span(); self.bump(); - report_lit_error(self.sess, err, lit, span); + let guar = report_lit_error(self.sess, err, lit, span); // Pack possible quotes and prefixes from the original literal into // the error literal's symbol so they can be pretty-printed faithfully. let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err, symbol, lit.suffix); + let lit = token::Lit::new(token::Err(guar), symbol, lit.suffix); Some( MetaItemLit::from_token_lit(lit, span) .unwrap_or_else(|_| unreachable!()), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 623407eb3800..dea2b9e6ca70 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1459,7 +1459,7 @@ impl<'a> Parser<'a> { match self.parse_str_lit() { Ok(str_lit) => Some(str_lit), Err(Some(lit)) => match lit.kind { - ast::LitKind::Err => None, + ast::LitKind::Err(_) => None, _ => { self.dcx().emit_err(NonStringAbiLiteral { span: lit.span }); None diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2fafbd6d97b5..b0982029657b 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -70,11 +70,11 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta } } Err(err) => { - report_lit_error(sess, err, token_lit, expr.span); + let guar = report_lit_error(sess, err, token_lit, expr.span); let lit = ast::MetaItemLit { symbol: token_lit.symbol, suffix: token_lit.suffix, - kind: ast::LitKind::Err, + kind: ast::LitKind::Err(guar), span: expr.span, }; MetaItemKind::NameValue(lit) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 55e24b6491c7..9b337f23867f 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -337,7 +337,11 @@ pub enum LitKind { ByteStrRaw(u8), CStr, CStrRaw(u8), - Err, + // This should have an `ErrorGuaranteed`, except that type isn't available + // in this crate. (Imagine it is there.) Hence the `WithGuar` suffix. Must + // only be constructed in `LitKind::from_internal`, where an + // `ErrorGuaranteed` is available. + ErrWithGuar, } rpc_encode_decode!( @@ -352,7 +356,7 @@ rpc_encode_decode!( ByteStrRaw(n), CStr, CStrRaw(n), - Err, + ErrWithGuar, } ); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 90b76cbc26eb..7c4929417132 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1451,7 +1451,7 @@ impl Literal { f(&["cr", hashes, "\"", symbol, "\"", hashes, suffix]) } - bridge::LitKind::Integer | bridge::LitKind::Float | bridge::LitKind::Err => { + bridge::LitKind::Integer | bridge::LitKind::Float | bridge::LitKind::ErrWithGuar => { f(&[symbol, suffix]) } }) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 6595658b7692..b8f7d9668201 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -295,7 +295,8 @@ impl<'a> NormalizedPat<'a> { LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val.get()), LitKind::Bool(val) => Self::LitBool(val), - LitKind::Float(..) | LitKind::Err => Self::Wild, + LitKind::Float(..) => Self::Wild, + LitKind::Err(guar) => Self::Err(guar), }, _ => Self::Wild, }, diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs index c8352c052659..079e6500e3cf 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -200,7 +200,7 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } }, - LitKind::Err => (), + LitKind::Err(_) => (), LitKind::ByteStr(..) => { // We only lint if the type annotation is an array type (e.g. &[u8; 4]). // If instead it is a slice (e.g. &[u8]) it may not be redundant, so we diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 29c67341a467..a0a6382046d0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -279,7 +279,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match lit.value.node { LitKind::Bool(val) => kind!("Bool({val:?})"), LitKind::Char(c) => kind!("Char({c:?})"), - LitKind::Err => kind!("Err"), + LitKind::Err(_) => kind!("Err"), LitKind::Byte(b) => kind!("Byte({b})"), LitKind::Int(i, suffix) => { let int_ty = match suffix { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 61b38391d9e0..79c691992a85 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -286,7 +286,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constan _ => bug!(), }, LitKind::Bool(b) => Constant::Bool(b), - LitKind::Err => Constant::Err, + LitKind::Err(_) => Constant::Err, } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs index c7c7bea99410..8a9d52a37a2f 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs @@ -72,7 +72,7 @@ impl server::FreeFunctions for RaSpanServer { ) -> Result, ()> { // FIXME: keep track of LitKind and Suffix Ok(bridge::Literal { - kind: bridge::LitKind::Err, + kind: bridge::LitKind::Integer, // dummy symbol: Symbol::intern(self.interner, s), suffix: None, span: self.call_site, @@ -202,7 +202,7 @@ impl server::TokenStream for RaSpanServer { tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { // FIXME: handle literal kinds - kind: bridge::LitKind::Err, + kind: bridge::LitKind::Integer, // dummy symbol: Symbol::intern(self.interner, &lit.text), // FIXME: handle suffixes suffix: None, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs index edbdc67b482f..15a9e0deae44 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs @@ -64,7 +64,7 @@ impl server::FreeFunctions for TokenIdServer { ) -> Result, ()> { // FIXME: keep track of LitKind and Suffix Ok(bridge::Literal { - kind: bridge::LitKind::Err, + kind: bridge::LitKind::Integer, // dummy symbol: Symbol::intern(self.interner, s), suffix: None, span: self.call_site, @@ -187,7 +187,7 @@ impl server::TokenStream for TokenIdServer { tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { // FIXME: handle literal kinds - kind: bridge::LitKind::Err, + kind: bridge::LitKind::Integer, // dummy symbol: Symbol::intern(self.interner, &lit.text), // FIXME: handle suffixes suffix: None, From ac47f6c666a6ba90c565a40ba16e56d95e36cd44 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 15 Feb 2024 15:46:38 +1100 Subject: [PATCH 36/55] Add suffixes to `LitError`. To avoid some unwrapping. --- compiler/rustc_ast/src/util/literal.rs | 24 +++++++++++++----------- compiler/rustc_session/src/errors.rs | 18 +++++++----------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index e4bb23675cb9..5ed2762b7262 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -31,19 +31,21 @@ pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol { #[derive(Debug)] pub enum LitError { - InvalidSuffix, - InvalidIntSuffix, - InvalidFloatSuffix, - NonDecimalFloat(u32), - IntTooLarge(u32), + InvalidSuffix(Symbol), + InvalidIntSuffix(Symbol), + InvalidFloatSuffix(Symbol), + NonDecimalFloat(u32), // u32 is the base + IntTooLarge(u32), // u32 is the base } impl LitKind { /// Converts literal token into a semantic literal. pub fn from_token_lit(lit: token::Lit) -> Result { let token::Lit { kind, symbol, suffix } = lit; - if suffix.is_some() && !kind.may_have_suffix() { - return Err(LitError::InvalidSuffix); + if let Some(suffix) = suffix + && !kind.may_have_suffix() + { + return Err(LitError::InvalidSuffix(suffix)); } // For byte/char/string literals, chars and escapes have already been @@ -271,12 +273,12 @@ fn filtered_float_lit( return Err(LitError::NonDecimalFloat(base)); } Ok(match suffix { - Some(suf) => LitKind::Float( + Some(suffix) => LitKind::Float( symbol, - ast::LitFloatType::Suffixed(match suf { + ast::LitFloatType::Suffixed(match suffix { sym::f32 => ast::FloatTy::F32, sym::f64 => ast::FloatTy::F64, - _ => return Err(LitError::InvalidFloatSuffix), + _ => return Err(LitError::InvalidFloatSuffix(suffix)), }), ), None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed), @@ -317,7 +319,7 @@ fn integer_lit(symbol: Symbol, suffix: Option) -> Result return filtered_float_lit(symbol, suffix, base), - _ => return Err(LitError::InvalidIntSuffix), + _ => return Err(LitError::InvalidIntSuffix(suf)), }, _ => ast::LitIntType::Unsuffixed, }; diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index f06e2136c2c5..82846e3b4e82 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -378,28 +378,24 @@ pub fn report_lit_error( valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } - let token::Lit { kind, symbol, suffix } = lit; let dcx = &sess.dcx; match err { - LitError::InvalidSuffix => { - let suffix = suffix.unwrap(); - dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix }) + LitError::InvalidSuffix(suffix) => { + dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) } - LitError::InvalidIntSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); + LitError::InvalidIntSuffix(suffix) => { + let suf = suffix.as_str(); if looks_like_width_suffix(&['i', 'u'], suf) { // If it looks like a width, try to be helpful. dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) - } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) { + } else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) { dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }) } else { dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) } } - LitError::InvalidFloatSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); + LitError::InvalidFloatSuffix(suffix) => { + let suf = suffix.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) From ca109af2acceee83b21fefe22713e3f34c04130b Mon Sep 17 00:00:00 2001 From: Amanjeev Sethi Date: Fri, 2 Sep 2022 19:12:03 -0400 Subject: [PATCH 37/55] Add regression test --- tests/ui/statics/recursive_interior_mut.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/ui/statics/recursive_interior_mut.rs diff --git a/tests/ui/statics/recursive_interior_mut.rs b/tests/ui/statics/recursive_interior_mut.rs new file mode 100644 index 000000000000..7e3083909d52 --- /dev/null +++ b/tests/ui/statics/recursive_interior_mut.rs @@ -0,0 +1,20 @@ +// check-pass + +use std::cell::Cell; +use std::ptr::NonNull; + +struct ChunkFooter { + prev: Cell>, +} + +struct EmptyChunkFooter(ChunkFooter); + +unsafe impl Sync for EmptyChunkFooter {} + +static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter { + prev: Cell::new(unsafe { + NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter) + }), +}); + +fn main() {} From fc9d1a8133616c4cd6db7c2bcf9f4981e8860be5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 3 Jan 2024 12:05:48 +0000 Subject: [PATCH 38/55] Split a bool argument into two named functions --- .../rustc_const_eval/src/interpret/cast.rs | 4 ++-- .../src/interpret/eval_context.rs | 2 +- .../src/interpret/intrinsics.rs | 14 ++++------- .../rustc_const_eval/src/interpret/place.rs | 23 ++++++++++++++++++- .../rustc_const_eval/src/interpret/step.rs | 8 +++---- .../src/interpret/terminator.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 5 ++-- src/tools/miri/src/shims/intrinsics/mod.rs | 4 ++-- src/tools/miri/src/shims/x86/mod.rs | 3 --- src/tools/miri/src/shims/x86/sse.rs | 1 - src/tools/miri/src/shims/x86/sse2.rs | 2 -- src/tools/miri/src/shims/x86/sse41.rs | 1 - 12 files changed, 39 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 6d470ff162e0..a88e130cd4b7 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -153,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); } - self.copy_op(src, dest, /*allow_transmute*/ true)?; + self.copy_op_allow_transmute(src, dest)?; } } Ok(()) @@ -441,7 +441,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if src_field.layout.is_1zst() && cast_ty_field.is_1zst() { // Skip 1-ZST fields. } else if src_field.layout.ty == cast_ty_field.ty { - self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?; + self.copy_op(&src_field, &dst_field)?; } else { if found_cast_field { span_bug!(self.cur_span(), "unsize_into: more than one field to cast"); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 8af69220e03a..d45e8a19717b 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -899,7 +899,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .local_to_op(self.frame(), mir::RETURN_PLACE, None) .expect("return place should always be live"); let dest = self.frame().return_place.clone(); - let err = self.copy_op(&op, &dest, /*allow_transmute*/ true); + let err = self.copy_op_allow_transmute(&op, &dest); trace!("return value: {:?}", self.dump_place(&dest)); // We delay actually short-circuiting on this error until *after* the stack frame is // popped, since we want this error to be attributed to the caller, whose type defines diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7991f90b8154..f020616f6d8c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -120,7 +120,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = self.tcx.span_as_caller_location(span); let val = self.const_val_to_op(val, self.tcx.caller_location_ty(), Some(dest.layout))?; - self.copy_op(&val, dest, /* allow_transmute */ false)?; + self.copy_op(&val, dest)?; } sym::min_align_of_val | sym::size_of_val => { @@ -157,7 +157,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { tcx.const_eval_global_id(self.param_env, gid, Some(tcx.span)) })?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest, /*allow_transmute*/ false)?; + self.copy_op(&val, dest)?; } sym::ctpop @@ -391,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.project_index(&input, i)?.into() }; - self.copy_op(&value, &place, /*allow_transmute*/ false)?; + self.copy_op(&value, &place)?; } } sym::simd_extract => { @@ -401,15 +401,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { index < input_len, "index `{index}` must be in bounds of vector with length {input_len}" ); - self.copy_op( - &self.project_index(&input, index)?, - dest, - /*allow_transmute*/ false, - )?; + self.copy_op(&self.project_index(&input, index)?, dest)?; } sym::likely | sym::unlikely | sym::black_box => { // These just return their argument - self.copy_op(&args[0], dest, /*allow_transmute*/ false)?; + self.copy_op(&args[0], dest)?; } sym::raw_eq => { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 03d1dc9fd3d6..807d3804d1cf 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -758,11 +758,32 @@ where Ok(()) } + /// Copies the data from an operand to a place. + /// The layouts of the `src` and `dest` may disagree. + #[inline(always)] + pub fn copy_op_allow_transmute( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner(src, dest, /* allow_transmute */ true) + } + + /// Copies the data from an operand to a place. + #[inline(always)] + pub fn copy_op( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner(src, dest, /* allow_transmute */ false) + } + /// Copies the data from an operand to a place. /// `allow_transmute` indicates whether the layouts may disagree. #[inline(always)] #[instrument(skip(self), level = "debug")] - pub fn copy_op( + fn copy_op_inner( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 23f3d7eb67da..d4c96f4573d9 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -151,12 +151,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Use(ref operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; - self.copy_op(&op, &dest, /*allow_transmute*/ false)?; + self.copy_op(&op, &dest)?; } CopyForDeref(place) => { let op = self.eval_place_to_op(place, Some(dest.layout))?; - self.copy_op(&op, &dest, /* allow_transmute*/ false)?; + self.copy_op(&op, &dest)?; } BinaryOp(bin_op, box (ref left, ref right)) => { @@ -316,7 +316,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let field_index = active_field_index.unwrap_or(field_index); let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; let op = self.eval_operand(operand, Some(field_dest.layout))?; - self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; + self.copy_op(&op, &field_dest)?; } self.write_discriminant(variant_index, dest) } @@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { // Write the src to the first element. let first = self.project_index(&dest, 0)?; - self.copy_op(&src, &first, /*allow_transmute*/ false)?; + self.copy_op(&src, &first)?; // This is performance-sensitive code for big static/const arrays! So we // avoid writing each operand individually and instead just make many copies diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 4037220e5ed4..b2207c3d3106 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -481,7 +481,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This // is true for all `copy_op`, but there are a lot of special cases for argument passing // specifically.) - self.copy_op(&caller_arg_copy, &callee_arg, /*allow_transmute*/ true)?; + self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?; // If this was an in-place pass, protect the place it comes from for the duration of the call. if let FnArg::InPlace(place) = caller_arg { M::protect_in_place_function_argument(self, place)?; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 370f0db72cb7..a080e2423d47 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -399,7 +399,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; for (field_index, op) in fields.into_iter().enumerate() { let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest, /*allow_transmute*/ false).ok()?; + self.ecx.copy_op(op, &field_dest).ok()?; } self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; self.ecx @@ -1181,8 +1181,7 @@ fn op_to_prop_const<'tcx>( } // Everything failed: create a new allocation to hold the data. - let alloc_id = - ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest, false)).ok()?; + let alloc_id = ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).ok()?; let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; // Check that we do not leak a pointer. diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index e34fb118f723..df2761bfaf42 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -108,12 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "volatile_load" => { let [place] = check_arg_count(args)?; let place = this.deref_pointer(place)?; - this.copy_op(&place, dest, /*allow_transmute*/ false)?; + this.copy_op(&place, dest)?; } "volatile_store" => { let [place, dest] = check_arg_count(args)?; let place = this.deref_pointer(place)?; - this.copy_op(dest, &place, /*allow_transmute*/ false)?; + this.copy_op(dest, &place)?; } "write_bytes" | "volatile_set_memory" => { diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 1aaf820f460e..b24ea8aec84b 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -299,7 +299,6 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( this.copy_op( &this.project_index(&left, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } @@ -424,7 +423,6 @@ fn unary_op_ss<'tcx>( this.copy_op( &this.project_index(&op, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } @@ -484,7 +482,6 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( this.copy_op( &this.project_index(&left, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 1e9afc1e9e08..9fb947cb2a3d 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -211,7 +211,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.copy_op( &this.project_index(&left, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } } diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 49bf7547ab0d..e5c8267320a4 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -443,7 +443,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.copy_op( &this.project_index(&op, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } } @@ -584,7 +583,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.copy_op( &this.project_index(&left, i)?, &this.project_index(&dest, i)?, - /*allow_transmute*/ false, )?; } } diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 67bb63f0a3d9..2abd10fa7a77 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -60,7 +60,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.copy_op( &this.project_index(&left, i)?, &dest, - /*allow_transmute*/ false, )?; } } From 95004e5ae285c1f514b908250db319c2c086141c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 9 Oct 2023 08:02:46 +0000 Subject: [PATCH 39/55] Add new query just for static initializers --- compiler/rustc_const_eval/src/lib.rs | 7 ++++++ .../rustc_middle/src/mir/interpret/error.rs | 1 + .../rustc_middle/src/mir/interpret/mod.rs | 11 +++++---- .../rustc_middle/src/mir/interpret/queries.rs | 24 +++---------------- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 14 +++++++++-- .../recursive-zst-static.default.stderr | 11 ++++++--- tests/ui/consts/recursive-zst-static.rs | 2 +- .../recursive-zst-static.unleash.stderr | 11 ++++++--- .../write-to-static-mut-in-static.stderr | 11 ++++++--- .../recursion/recursive-static-definition.rs | 2 +- .../recursive-static-definition.stderr | 11 ++++++--- tests/ui/treat-err-as-bug/err.stderr | 2 +- 13 files changed, 65 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 839cfd8d85ac..4a00b9a59993 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -40,6 +40,13 @@ pub fn provide(providers: &mut Providers) { const_eval::provide(providers); providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; + providers.eval_static_initializer_raw = |tcx, def_id| { + assert!(tcx.is_static(def_id)); + let instance = ty::Instance::mono(tcx, def_id); + let gid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; + let param_env = ty::ParamEnv::reveal_all(); + Ok(tcx.eval_to_allocation_raw(param_env.and(gid))?.alloc_id) + }; providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index a1cdc794749c..6e06527100c0 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -83,6 +83,7 @@ impl Into for ReportedErrorInfo { TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; +pub type EvalStaticInitializerRawResult = Result; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. /// This is needed in `thir::pattern::lower_inline_const`. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 0da3524e0556..ec2af393639c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,11 +142,12 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, - EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, - ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, }; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e8aca5f2e7d8..6256de390af0 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -194,22 +194,8 @@ impl<'tcx> TyCtxtAt<'tcx> { ) -> Result, ErrorHandled> { trace!("eval_static_initializer: Need to compute {:?}", def_id); assert!(self.is_static(def_id)); - let instance = ty::Instance::mono(*self, def_id); - let gid = GlobalId { instance, promoted: None }; - self.eval_to_allocation(gid, ty::ParamEnv::reveal_all()) - } - - /// Evaluate anything constant-like, returning the allocation of the final memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - fn eval_to_allocation( - self, - gid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Result, ErrorHandled> { - trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; - Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) + let alloc_id = self.eval_static_initializer_raw(def_id)?; + Ok(self.global_alloc(alloc_id).unwrap_memory()) } } @@ -237,10 +223,6 @@ impl<'tcx> TyCtxtEnsure<'tcx> { pub fn eval_static_initializer(self, def_id: DefId) { trace!("eval_static_initializer: Need to compute {:?}", def_id); assert!(self.tcx.is_static(def_id)); - let instance = ty::Instance::mono(self.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - trace!("eval_to_allocation: Need to compute {:?}", gid); - self.eval_to_allocation_raw(param_env.and(gid)) + self.eval_static_initializer_raw(def_id); } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5666a59e38e8..cc2c921ef497 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -277,6 +277,7 @@ trivial! { rustc_middle::mir::interpret::CtfeProvenance, rustc_middle::mir::interpret::ErrorHandled, rustc_middle::mir::interpret::LitToConstError, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::thir::ExprId, rustc_middle::traits::CodegenObligationError, rustc_middle::traits::EvaluationResult, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 60d195e4d3ef..23d486eed52a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -20,7 +20,8 @@ use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; use crate::mir::interpret::{ - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, + EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, + EvalToValTreeResult, }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; @@ -1061,7 +1062,7 @@ rustc_queries! { /// Evaluates a constant and returns the computed allocation. /// - /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead. query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| @@ -1071,6 +1072,15 @@ rustc_queries! { cache_on_disk_if { true } } + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. + query eval_static_initializer_raw(key: DefId) -> EvalStaticInitializerRawResult { + desc { |tcx| + "evaluating initializer of static `{}`", + tcx.def_path_str(key) + } + cache_on_disk_if { key.is_local() } + } + /// Evaluates const items or anonymous constants /// (such as enum variant explicit discriminants or array lengths) /// into a representation suitable for the type system and const generics. diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index 5b4a0418b1e9..b2d5d50da62f 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -1,10 +1,15 @@ -error[E0391]: cycle detected when const-evaluating + checking `FOO` +error[E0391]: cycle detected when evaluating initializer of static `FOO` + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - | - = note: ...which immediately requires const-evaluating + checking `FOO` again + = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs index 4e61634b349e..14de00bad8aa 100644 --- a/tests/ui/consts/recursive-zst-static.rs +++ b/tests/ui/consts/recursive-zst-static.rs @@ -7,7 +7,7 @@ // can depend on this fact and will thus do unsound things when it is violated. // See https://github.com/rust-lang/rust/issues/71078 for more details. -static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO` +static FOO: () = FOO; //~ cycle detected when evaluating initializer of static `FOO` fn main() { FOO diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index 5b4a0418b1e9..b2d5d50da62f 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -1,10 +1,15 @@ -error[E0391]: cycle detected when const-evaluating + checking `FOO` +error[E0391]: cycle detected when evaluating initializer of static `FOO` + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - | - = note: ...which immediately requires const-evaluating + checking `FOO` again + = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index caee433a6813..dd0b05d9d441 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -4,13 +4,18 @@ error[E0080]: could not evaluate static initializer LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer -error[E0391]: cycle detected when const-evaluating + checking `C` +error[E0391]: cycle detected when evaluating initializer of static `C` + --> $DIR/write-to-static-mut-in-static.rs:5:1 + | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:34 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^ - | - = note: ...which immediately requires const-evaluating + checking `C` again + = note: ...which again requires evaluating initializer of static `C`, completing the cycle note: cycle used when linting top-level module --> $DIR/write-to-static-mut-in-static.rs:1:1 | diff --git a/tests/ui/recursion/recursive-static-definition.rs b/tests/ui/recursion/recursive-static-definition.rs index f59ef7316d89..74a094a9b01d 100644 --- a/tests/ui/recursion/recursive-static-definition.rs +++ b/tests/ui/recursion/recursive-static-definition.rs @@ -1,4 +1,4 @@ pub static FOO: u32 = FOO; -//~^ ERROR cycle detected when const-evaluating + checking `FOO` +//~^ ERROR cycle detected when evaluating initializer of static `FOO` fn main() {} diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 4fc3ee68ebc2..83459017634f 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -1,10 +1,15 @@ -error[E0391]: cycle detected when const-evaluating + checking `FOO` +error[E0391]: cycle detected when evaluating initializer of static `FOO` + --> $DIR/recursive-static-definition.rs:1:1 + | +LL | pub static FOO: u32 = FOO; + | ^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; | ^^^ - | - = note: ...which immediately requires const-evaluating + checking `FOO` again + = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle note: cycle used when linting top-level module --> $DIR/recursive-static-definition.rs:1:1 | diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index f1b61c3607b7..d4ad63a4c92f 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -8,5 +8,5 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `C` -#1 [lint_mod] linting top-level module +#1 [eval_static_initializer_raw] evaluating initializer of static `C` end of query stack From be6ccf13e32e8b4b8d92d14eb555d75377d05e24 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 9 Oct 2023 12:20:26 +0000 Subject: [PATCH 40/55] Store static initializers in metadata instead of the MIR of statics. --- compiler/rustc_const_eval/src/lib.rs | 4 ++-- .../src/rmeta/decoder/cstore_impl.rs | 9 +++++++++ compiler/rustc_metadata/src/rmeta/encoder.rs | 14 +++++++++----- compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 4a00b9a59993..42c86942a432 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -41,8 +41,8 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.eval_static_initializer_raw = |tcx, def_id| { - assert!(tcx.is_static(def_id)); - let instance = ty::Instance::mono(tcx, def_id); + assert!(tcx.is_static(def_id.to_def_id())); + let instance = ty::Instance::mono(tcx, def_id.to_def_id()); let gid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; let param_env = ty::ParamEnv::reveal_all(); Ok(tcx.eval_to_allocation_raw(param_env.and(gid))?.alloc_id) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index d79d4b226a54..e27a21490d36 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -250,6 +250,15 @@ provide! { tcx, def_id, other, cdata, fn_arg_names => { table } coroutine_kind => { table_direct } coroutine_for_closure => { table } + eval_static_initializer_raw => { + Ok(cdata + .root + .tables + .eval_static_initializer_raw + .get(cdata, def_id.index) + .map(|lazy| lazy.decode((cdata, tcx))) + .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer_raw"))) + } trait_def => { table } deduced_param_attrs => { table } is_type_alias_impl_trait => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4a24c038f7ae..eee8127b0553 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1045,11 +1045,9 @@ fn should_encode_mir( (true, mir_opt_base) } // Constants - DefKind::AnonConst - | DefKind::InlineConst - | DefKind::AssocConst - | DefKind::Static(..) - | DefKind::Const => (true, false), + DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst | DefKind::Const => { + (true, false) + } // Coroutines require optimized MIR to compute layout. DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => (false, true), // Full-fledged functions + closures @@ -1454,6 +1452,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .coroutine_for_closure .set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into()); } + if let DefKind::Static(_) = def_kind { + if !self.tcx.is_foreign_item(def_id) { + let data = self.tcx.eval_static_initializer_raw(def_id).unwrap(); + record!(self.tables.eval_static_initializer_raw[def_id] <- data); + } + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 4d0a6cb60ee7..14e48ea0a401 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -443,6 +443,7 @@ define_tables! { fn_arg_names: Table>, coroutine_kind: Table, coroutine_for_closure: Table, + eval_static_initializer_raw: Table>, trait_def: Table>, trait_item_def_id: Table, expn_that_defined: Table>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 23d486eed52a..d09835464990 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1079,6 +1079,7 @@ rustc_queries! { tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } + separate_provide_extern } /// Evaluates const items or anonymous constants diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 045856dd9cd6..2f6121d0e62b 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -63,6 +63,7 @@ trivially_parameterized_over_tcx! { crate::middle::lib_features::FeatureStability, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, + crate::mir::interpret::AllocId, ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, From e2386270df9d619bb6d3d62664e89c632baeb6cb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 Oct 2023 08:52:21 +0000 Subject: [PATCH 41/55] Return ConstAllocation from eval_static_initializer query directly --- .../src/const_eval/eval_queries.rs | 26 +++++++++++++++ compiler/rustc_const_eval/src/lib.rs | 8 +---- .../src/rmeta/decoder/cstore_impl.rs | 6 ++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +-- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- .../rustc_middle/src/mir/interpret/error.rs | 4 +-- .../rustc_middle/src/mir/interpret/queries.rs | 33 +------------------ compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 2 ++ compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- .../recursive-zst-static.default.stderr | 9 ++--- .../recursive-zst-static.unleash.stderr | 9 ++--- .../write-to-static-mut-in-static.stderr | 9 ++--- .../recursive-static-definition.stderr | 9 ++--- tests/ui/treat-err-as-bug/err.rs | 2 +- tests/ui/treat-err-as-bug/err.stderr | 4 +-- 18 files changed, 53 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c55d899e4d5a..05baf102d885 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -8,6 +8,7 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::abi::{self, Abi}; @@ -249,11 +250,36 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } +#[instrument(skip(tcx), level = "debug")] +pub fn eval_static_initializer_provider<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> { + assert!(tcx.is_static(def_id.to_def_id())); + + let instance = ty::Instance::mono(tcx, def_id.to_def_id()); + let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; + let ecx = InterpCx::new( + tcx, + tcx.def_span(def_id), + ty::ParamEnv::reveal_all(), + // Statics (and promoteds inside statics) may access other statics, because unlike consts + // they do not have to behave "as if" they were evaluated at runtime. + CompileTimeInterpreter::new(CanAccessMutGlobal::Yes, CheckAlignment::Error), + ); + let alloc_id = eval_in_interpreter(ecx, cid, true)?.alloc_id; + let alloc = tcx.global_alloc(alloc_id).unwrap_memory(); + Ok(alloc) +} + #[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // This shouldn't be used for statics, since statics are conceptually places, + // not values -- so what we do here could break pointer identity. + assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())); // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of // opaque types. This is needed for trivial things like `size_of`, but also for using associated // types that are not specified in the opaque type. diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 42c86942a432..e33f374c3595 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -40,13 +40,7 @@ pub fn provide(providers: &mut Providers) { const_eval::provide(providers); providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; - providers.eval_static_initializer_raw = |tcx, def_id| { - assert!(tcx.is_static(def_id.to_def_id())); - let instance = ty::Instance::mono(tcx, def_id.to_def_id()); - let gid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - Ok(tcx.eval_to_allocation_raw(param_env.and(gid))?.alloc_id) - }; + providers.eval_static_initializer = const_eval::eval_static_initializer_provider; providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index e27a21490d36..178bfc3a380c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -250,14 +250,14 @@ provide! { tcx, def_id, other, cdata, fn_arg_names => { table } coroutine_kind => { table_direct } coroutine_for_closure => { table } - eval_static_initializer_raw => { + eval_static_initializer => { Ok(cdata .root .tables - .eval_static_initializer_raw + .eval_static_initializer .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) - .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer_raw"))) + .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer"))) } trait_def => { table } deduced_param_attrs => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eee8127b0553..6f908f7752ad 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1454,8 +1454,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Static(_) = def_kind { if !self.tcx.is_foreign_item(def_id) { - let data = self.tcx.eval_static_initializer_raw(def_id).unwrap(); - record!(self.tables.eval_static_initializer_raw[def_id] <- data); + let data = self.tcx.eval_static_initializer(def_id).unwrap(); + record!(self.tables.eval_static_initializer[def_id] <- data); } } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 14e48ea0a401..eac78a3cd7c2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -443,7 +443,7 @@ define_tables! { fn_arg_names: Table>, coroutine_kind: Table, coroutine_for_closure: Table, - eval_static_initializer_raw: Table>, + eval_static_initializer: Table>>, trait_def: Table>, trait_item_def_id: Table, expn_that_defined: Table>, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 6e06527100c0..9d4ec7d25bb6 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, AllocRange, Pointer, Scalar}; +use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; @@ -83,7 +83,7 @@ impl Into for ReportedErrorInfo { TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; -pub type EvalStaticInitializerRawResult = Result; +pub type EvalStaticInitializerRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. /// This is needed in `thir::pattern::lower_inline_const`. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 6256de390af0..643b61c1de3d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,7 +1,7 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; -use crate::query::{TyCtxtAt, TyCtxtEnsure}; +use crate::query::TyCtxtEnsure; use crate::ty::visit::TypeVisitableExt; use crate::ty::GenericArgs; use crate::ty::{self, TyCtxt}; @@ -173,30 +173,6 @@ impl<'tcx> TyCtxt<'tcx> { self.eval_to_valtree(inputs) } } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - #[inline(always)] - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result, ErrorHandled> { - self.at(DUMMY_SP).eval_static_initializer(def_id) - } -} - -impl<'tcx> TyCtxtAt<'tcx> { - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result, ErrorHandled> { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.is_static(def_id)); - let alloc_id = self.eval_static_initializer_raw(def_id)?; - Ok(self.global_alloc(alloc_id).unwrap_memory()) - } } impl<'tcx> TyCtxtEnsure<'tcx> { @@ -218,11 +194,4 @@ impl<'tcx> TyCtxtEnsure<'tcx> { let inputs = self.tcx.erase_regions(param_env.and(cid)); self.eval_to_const_value_raw(inputs) } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - pub fn eval_static_initializer(self, def_id: DefId) { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.tcx.is_static(def_id)); - self.eval_static_initializer_raw(def_id); - } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e22d52286283..3017f912ef02 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2,7 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar}; +use crate::mir::interpret::{AllocRange, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a011f6114de9..5638b575b319 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -4,6 +4,8 @@ use std::fs; use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; +use crate::mir::interpret::ConstAllocation; + use super::graphviz::write_mir_fn_graphviz; use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cc2c921ef497..7ac7fa0ac33a 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -277,7 +277,6 @@ trivial! { rustc_middle::mir::interpret::CtfeProvenance, rustc_middle::mir::interpret::ErrorHandled, rustc_middle::mir::interpret::LitToConstError, - rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::thir::ExprId, rustc_middle::traits::CodegenObligationError, rustc_middle::traits::EvaluationResult, @@ -338,6 +337,7 @@ tcx_lifetime! { rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::traits::query::type_op::AscribeUserType, rustc_middle::traits::query::type_op::Eq, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d09835464990..a7f4e75e2143 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1073,7 +1073,7 @@ rustc_queries! { } /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - query eval_static_initializer_raw(key: DefId) -> EvalStaticInitializerRawResult { + query eval_static_initializer(key: DefId) -> EvalStaticInitializerRawResult<'tcx> { desc { |tcx| "evaluating initializer of static `{}`", tcx.def_path_str(key) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 2f6121d0e62b..22f0574d6148 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -63,7 +63,6 @@ trivially_parameterized_over_tcx! { crate::middle::lib_features::FeatureStability, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, - crate::mir::interpret::AllocId, ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, @@ -127,6 +126,7 @@ parameterized_over_tcx! { crate::middle::exported_symbols::ExportedSymbol, crate::mir::Body, crate::mir::CoroutineLayout, + crate::mir::interpret::ConstAllocation, ty::Ty, ty::FnSig, ty::GenericPredicates, diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index b2d5d50da62f..9e31209204bc 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when evaluating initializer of static `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle + | + = note: ...which immediately requires evaluating initializer of static `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index b2d5d50da62f..9e31209204bc 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when evaluating initializer of static `FOO` - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ - = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle + | + = note: ...which immediately requires evaluating initializer of static `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index dd0b05d9d441..23dd1346ad93 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -5,17 +5,12 @@ LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer error[E0391]: cycle detected when evaluating initializer of static `C` - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:34 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^ - = note: ...which again requires evaluating initializer of static `C`, completing the cycle + | + = note: ...which immediately requires evaluating initializer of static `C` again note: cycle used when linting top-level module --> $DIR/write-to-static-mut-in-static.rs:1:1 | diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index 83459017634f..f071e501e38b 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when evaluating initializer of static `FOO` - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; | ^^^ - = note: ...which again requires evaluating initializer of static `FOO`, completing the cycle + | + = note: ...which immediately requires evaluating initializer of static `FOO` again note: cycle used when linting top-level module --> $DIR/recursive-static-definition.rs:1:1 | diff --git a/tests/ui/treat-err-as-bug/err.rs b/tests/ui/treat-err-as-bug/err.rs index 4090a706f99b..74992497dab2 100644 --- a/tests/ui/treat-err-as-bug/err.rs +++ b/tests/ui/treat-err-as-bug/err.rs @@ -1,7 +1,7 @@ // compile-flags: -Ztreat-err-as-bug // failure-status: 101 // error-pattern: aborting due to `-Z treat-err-as-bug=1` -// error-pattern: [eval_to_allocation_raw] const-evaluating + checking `C` +// error-pattern: [eval_static_initializer] evaluating initializer of static `C` // normalize-stderr-test "note: .*\n\n" -> "" // normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> "" // rustc-env:RUST_BACKTRACE=0 diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index d4ad63a4c92f..ca04ee9e0cfd 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -7,6 +7,6 @@ LL | pub static C: u32 = 0 - 1; error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [eval_to_allocation_raw] const-evaluating + checking `C` -#1 [eval_static_initializer_raw] evaluating initializer of static `C` +#0 [eval_static_initializer] evaluating initializer of static `C` +#1 [lint_mod] linting top-level module end of query stack From 73b38c661d9bc0466547af16d20089e5383f754b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 Oct 2023 11:27:43 +0000 Subject: [PATCH 42/55] Do not allocate a second "background" alloc id for the main allocation of a static. Instead we re-use the static's alloc id within the interpreter for its initializer to refer to the `Allocation` that only exists within the interpreter. --- compiler/rustc_const_eval/messages.ftl | 2 + .../rustc_const_eval/src/const_eval/error.rs | 4 +- .../src/const_eval/eval_queries.rs | 62 ++++++++++--------- .../src/const_eval/machine.rs | 15 +++++ .../src/interpret/eval_context.rs | 14 ++++- .../rustc_const_eval/src/interpret/intern.rs | 32 ++++++++-- .../rustc_const_eval/src/interpret/machine.rs | 15 +++++ .../rustc_const_eval/src/interpret/memory.rs | 24 +++++-- .../rustc_const_eval/src/interpret/mod.rs | 1 + .../rustc_const_eval/src/interpret/place.rs | 28 ++++++++- .../rustc_const_eval/src/interpret/util.rs | 28 ++++++++- .../src/interpret/validity.rs | 19 +++--- .../recursive-zst-static.default.stderr | 26 ++++++-- tests/ui/consts/recursive-zst-static.rs | 6 +- .../recursive-zst-static.unleash.stderr | 26 ++++++-- .../consts/write-to-static-mut-in-static.rs | 2 +- .../write-to-static-mut-in-static.stderr | 25 ++------ .../recursion/recursive-static-definition.rs | 10 ++- .../recursive-static-definition.stderr | 25 +++----- 19 files changed, 262 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 85ebbb00c5f2..4a6d4fe930cf 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -313,6 +313,8 @@ const_eval_realloc_or_alloc_with_offset = *[other] {""} } {$ptr} which does not point to the beginning of an object +const_eval_recursive_static = encountered static that tried to initialize itself with itself + const_eval_remainder_by_zero = calculating the remainder with a divisor of zero const_eval_remainder_overflow = diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 80d02589900f..935329f11890 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -19,6 +19,7 @@ use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopTy pub enum ConstEvalErrKind { ConstAccessesMutGlobal, ModifiedGlobal, + RecursiveStatic, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, } @@ -31,13 +32,14 @@ impl MachineStopType for ConstEvalErrKind { ConstAccessesMutGlobal => const_eval_const_accesses_mut_global, ModifiedGlobal => const_eval_modified_global, Panic { .. } => const_eval_panic, + RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), } } fn add_args(self: Box, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) { use ConstEvalErrKind::*; match *self { - ConstAccessesMutGlobal | ModifiedGlobal => {} + RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {} AssertFailure(kind) => kind.add_args(adder), Panic { msg, line, col, file } => { adder("msg".into(), msg.into_diagnostic_arg()); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 05baf102d885..7099cdd5a754 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,7 +2,6 @@ use either::{Left, Right}; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; -use rustc_middle::mir::pretty::write_allocation_bytes; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; @@ -18,8 +17,9 @@ use crate::errors; use crate::errors::ConstEvalError; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx, - InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, + create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc, CtfeValidationMode, + GlobalId, Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, + OpTy, RefTracking, StackPopCleanup, }; // Returns a pointer to where the result lives @@ -47,7 +47,21 @@ fn eval_body_using_ecx<'mir, 'tcx>( ); let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; assert!(layout.is_sized()); - let ret = ecx.allocate(layout, MemoryKind::Stack)?; + + let intern_kind = if cid.promoted.is_some() { + InternKind::Promoted + } else { + match tcx.static_mutability(cid.instance.def_id()) { + Some(m) => InternKind::Static(m), + None => InternKind::Constant, + } + }; + + let ret = if let InternKind::Static(_) = intern_kind { + create_static_alloc(ecx, cid.instance.def_id(), layout)? + } else { + ecx.allocate(layout, MemoryKind::Stack)? + }; trace!( "eval_body_using_ecx: pushing stack frame for global: {}{}", @@ -67,14 +81,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( while ecx.step()? {} // Intern the result - let intern_kind = if cid.promoted.is_some() { - InternKind::Promoted - } else { - match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None => InternKind::Constant, - } - }; intern_const_alloc_recursive(ecx, intern_kind, &ret)?; Ok(ret) @@ -259,7 +265,7 @@ pub fn eval_static_initializer_provider<'tcx>( let instance = ty::Instance::mono(tcx, def_id.to_def_id()); let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; - let ecx = InterpCx::new( + let mut ecx = InterpCx::new( tcx, tcx.def_span(def_id), ty::ParamEnv::reveal_all(), @@ -267,8 +273,9 @@ pub fn eval_static_initializer_provider<'tcx>( // they do not have to behave "as if" they were evaluated at runtime. CompileTimeInterpreter::new(CanAccessMutGlobal::Yes, CheckAlignment::Error), ); - let alloc_id = eval_in_interpreter(ecx, cid, true)?.alloc_id; - let alloc = tcx.global_alloc(alloc_id).unwrap_memory(); + let alloc_id = eval_in_interpreter(&mut ecx, cid, true)?.alloc_id; + let alloc = take_static_root_alloc(&mut ecx, alloc_id); + let alloc = tcx.mk_const_alloc(alloc); Ok(alloc) } @@ -299,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( let def = cid.instance.def.def_id(); let is_static = tcx.is_static(def); - let ecx = InterpCx::new( + let mut ecx = InterpCx::new( tcx, tcx.def_span(def), key.param_env, @@ -309,11 +316,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // so we have to reject reading mutable global memory. CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); - eval_in_interpreter(ecx, cid, is_static) + eval_in_interpreter(&mut ecx, cid, is_static) } pub fn eval_in_interpreter<'mir, 'tcx>( - mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, cid: GlobalId<'tcx>, is_static: bool, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { @@ -321,7 +328,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>( debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some()); let res = ecx.load_mir(cid.instance.def, cid.promoted); - match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) { + match res.and_then(|body| eval_body_using_ecx(ecx, cid, body)) { Err(error) => { let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); @@ -356,8 +363,11 @@ pub fn eval_in_interpreter<'mir, 'tcx>( } Ok(mplace) => { // Since evaluation had no errors, validate the resulting constant. - // This is a separate `try` block to provide more targeted error reporting. + + // Temporarily allow access to the static_root_alloc_id for the purpose of validation. + let static_root_alloc_id = ecx.machine.static_root_alloc_id.take(); let validation = const_validate_mplace(&ecx, &mplace, cid); + ecx.machine.static_root_alloc_id = static_root_alloc_id; let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); @@ -409,15 +419,9 @@ pub fn const_report_error<'mir, 'tcx>( let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {}); - let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); - let mut bytes = String::new(); - if alloc.size() != abi::Size::ZERO { - bytes = "\n".into(); - // FIXME(translation) there might be pieces that are translatable. - write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap(); - } - let raw_bytes = - errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes }; + let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); + let (size, align, _) = ecx.get_alloc_info(alloc_id); + let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; crate::const_eval::report( *ecx.tcx, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 5019bec388ce..2c60ede79758 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -58,6 +58,9 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// Whether to check alignment during evaluation. pub(super) check_alignment: CheckAlignment, + + /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization. + pub(crate) static_root_alloc_id: Option, } #[derive(Copy, Clone)] @@ -91,6 +94,7 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { stack: Vec::new(), can_access_mut_global, check_alignment, + static_root_alloc_id: None, } } } @@ -746,6 +750,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Everything else is fine. Ok(()) } + + fn before_alloc_read( + ecx: &InterpCx<'mir, 'tcx, Self>, + alloc_id: AllocId, + ) -> InterpResult<'tcx> { + if Some(alloc_id) == ecx.machine.static_root_alloc_id { + Err(ConstEvalErrKind::RecursiveStatic.into()) + } else { + Ok(()) + } + } } // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index d45e8a19717b..517994d47416 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -899,7 +899,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .local_to_op(self.frame(), mir::RETURN_PLACE, None) .expect("return place should always be live"); let dest = self.frame().return_place.clone(); - let err = self.copy_op_allow_transmute(&op, &dest); + let err = if self.stack().len() == 1 { + // The initializer of constants and statics will get validated separately + // after the constant has been fully evaluated. While we could fall back to the default + // code path, that will cause -Zenforce-validity to cycle on static initializers. + // Reading from a static's memory is not allowed during its evaluation, and will always + // trigger a cycle error. Validation must read from the memory of the current item. + // For Miri this means we do not validate the root frame return value, + // but Miri anyway calls `read_target_isize` on that so separate validation + // is not needed. + self.copy_op_no_dest_validation(&op, &dest) + } else { + self.copy_op_allow_transmute(&op, &dest) + }; trace!("return value: {:?}", self.dump_place(&dest)); // We delay actually short-circuiting on this error until *after* the stack frame is // popped, since we want this error to be attributed to the caller, whose type defines diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7feac6156bce..959ec2ca8655 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -85,6 +85,8 @@ pub enum InternKind { /// /// This *cannot raise an interpreter error*. Doing so is left to validation, which /// tracks where in the value we are and thus can show much better error messages. +/// +/// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller. #[instrument(level = "debug", skip(ecx))] pub fn intern_const_alloc_recursive< 'mir, @@ -97,12 +99,12 @@ pub fn intern_const_alloc_recursive< ) -> Result<(), ErrorGuaranteed> { // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. - let (base_mutability, inner_mutability) = match intern_kind { + let (base_mutability, inner_mutability, is_static) = match intern_kind { InternKind::Constant | InternKind::Promoted => { // Completely immutable. Interning anything mutably here can only lead to unsoundness, // since all consts are conceptually independent values but share the same underlying // memory. - (Mutability::Not, Mutability::Not) + (Mutability::Not, Mutability::Not, false) } InternKind::Static(Mutability::Not) => { ( @@ -115,22 +117,31 @@ pub fn intern_const_alloc_recursive< // Inner allocations are never mutable. They can only arise via the "tail // expression" / "outer scope" rule, and we treat them consistently with `const`. Mutability::Not, + true, ) } InternKind::Static(Mutability::Mut) => { // Just make everything mutable. We accept code like // `static mut X = &mut [42]`, so even inner allocations need to be mutable. - (Mutability::Mut, Mutability::Mut) + (Mutability::Mut, Mutability::Mut, true) } }; // Intern the base allocation, and initialize todo list for recursive interning. let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); + trace!(?base_alloc_id, ?base_mutability); // First we intern the base allocation, as it requires a different mutability. // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. - let mut todo: Vec<_> = - intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect(); + let mut todo: Vec<_> = if is_static { + // Do not steal the root allocation, we need it later for `take_static_root_alloc` + // But still change its mutability to match the requested one. + let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); + alloc.1.mutability = base_mutability; + alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() + } else { + intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect() + }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. let mut just_interned: FxHashSet<_> = std::iter::once(base_alloc_id).collect(); @@ -148,7 +159,17 @@ pub fn intern_const_alloc_recursive< // before validation, and interning doesn't know the type of anything, this means we can't show // better errors. Maybe we should consider doing validation before interning in the future. while let Some(prov) = todo.pop() { + trace!(?prov); let alloc_id = prov.alloc_id(); + + if base_alloc_id == alloc_id && is_static { + // This is a pointer to the static itself. It's ok for a static to refer to itself, + // even mutably. Whether that mutable pointer is legal at all is checked in validation. + // See tests/ui/statics/recursive_interior_mut.rs for how such a situation can occur. + // We also already collected all the nested allocations, so there's no need to do that again. + continue; + } + // Crucially, we check this *before* checking whether the `alloc_id` // has already been interned. The point of this check is to ensure that when // there are multiple pointers to the same allocation, they are *all* immutable. @@ -176,6 +197,7 @@ pub fn intern_const_alloc_recursive< // `&None::>` lead to promotion that can produce mutable pointers. We rely // on the promotion analysis not screwing up to ensure that it is sound to intern // promoteds as immutable. + trace!("found bad mutable pointer"); found_bad_mutable_pointer = true; } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index b981a1ee2ca1..0106ec425bc5 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -388,6 +388,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Takes read-only access to the allocation so we can keep all the memory read /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you /// need to mutate. + /// + /// This is not invoked for ZST accesses, as no read actually happens. #[inline(always)] fn before_memory_read( _tcx: TyCtxtAt<'tcx>, @@ -399,7 +401,20 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { Ok(()) } + /// Hook for performing extra checks on any memory read access, + /// that involves an allocation, even ZST reads. + /// + /// Used to prevent statics from self-initializing by reading from their own memory + /// as it is being initialized. + fn before_alloc_read( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _alloc_id: AllocId, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Hook for performing extra checks on a memory write access. + /// This is not invoked for ZST accesses, as no write actually happens. #[inline(always)] fn before_memory_write( _tcx: TyCtxtAt<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 4acf4ed893c5..2e642ac15b42 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -624,19 +624,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size, CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { + // We want to call the hook on *all* accesses that involve an AllocId, + // including zero-sized accesses. That means we have to do it here + // rather than below in the `Some` branch. + M::before_alloc_read(self, alloc_id)?; let alloc = self.get_alloc_raw(alloc_id)?; Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; + if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); M::before_memory_read(self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { - // Even in this branch we have to be sure that we actually access the allocation, in - // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of - // magically pulling *any* ZST value from the ether. However, the `get_raw` above is - // always called when `ptr` has an `AllocId`. Ok(None) } } @@ -855,6 +856,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { DumpAllocs { ecx: self, allocs } } + /// Print the allocation's bytes, without any nested allocations. + pub fn print_alloc_bytes_for_diagnostics(&self, id: AllocId) -> String { + // Using the "raw" access to avoid the `before_alloc_read` hook, we specifically + // want to be able to read all memory for diagnostics, even if that is cyclic. + let alloc = self.get_alloc_raw(id).unwrap(); + let mut bytes = String::new(); + if alloc.size() != Size::ZERO { + bytes = "\n".into(); + // FIXME(translation) there might be pieces that are translatable. + rustc_middle::mir::pretty::write_allocation_bytes(*self.tcx, alloc, &mut bytes, " ") + .unwrap(); + } + bytes + } + /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true. pub fn find_leaked_allocations( diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index c1b6ce4eb4e3..a15e52d07e60 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -39,4 +39,5 @@ use self::{ }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; +pub(crate) use self::util::{create_static_alloc, take_static_root_alloc}; use eval_context::{from_known_layout, mir_assign_valid_types}; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 807d3804d1cf..6e987784ff9e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -758,6 +758,22 @@ where Ok(()) } + /// Copies the data from an operand to a place. + /// The layouts of the `src` and `dest` may disagree. + /// Does not perform validation of the destination. + /// The only known use case for this function is checking the return + /// value of a static during stack frame popping. + #[inline(always)] + pub(super) fn copy_op_no_dest_validation( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner( + src, dest, /* allow_transmute */ true, /* validate_dest */ false, + ) + } + /// Copies the data from an operand to a place. /// The layouts of the `src` and `dest` may disagree. #[inline(always)] @@ -766,17 +782,22 @@ where src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - self.copy_op_inner(src, dest, /* allow_transmute */ true) + self.copy_op_inner( + src, dest, /* allow_transmute */ true, /* validate_dest */ true, + ) } /// Copies the data from an operand to a place. + /// `src` and `dest` must have the same layout and the copied value will be validated. #[inline(always)] pub fn copy_op( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - self.copy_op_inner(src, dest, /* allow_transmute */ false) + self.copy_op_inner( + src, dest, /* allow_transmute */ false, /* validate_dest */ true, + ) } /// Copies the data from an operand to a place. @@ -788,6 +809,7 @@ where src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, + validate_dest: bool, ) -> InterpResult<'tcx> { // Generally for transmutation, data must be valid both at the old and new type. // But if the types are the same, the 2nd validation below suffices. @@ -798,7 +820,7 @@ where // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; - if M::enforce_validity(self, dest.layout()) { + if validate_dest && M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! self.validate_operand(&dest.to_op(self)?)?; } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 3a9ee9047340..2a13671a8297 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,9 +1,15 @@ -use rustc_middle::mir::interpret::InterpResult; +use crate::const_eval::CompileTimeEvalContext; +use crate::interpret::{MemPlaceMeta, MemoryKind}; +use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_span::def_id::DefId; use std::ops::ControlFlow; +use super::MPlaceTy; + /// Checks whether a type contains generic parameters which must be instantiated. /// /// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization @@ -73,3 +79,23 @@ where Ok(()) } } + +pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + alloc_id: AllocId, +) -> Allocation { + ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1 +} + +pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + static_def_id: DefId, + layout: TyAndLayout<'tcx>, +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?; + let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id); + assert_eq!(ecx.machine.static_root_alloc_id, None); + ecx.machine.static_root_alloc_id = Some(alloc_id); + assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); + Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) +} diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index eb9f3fee1650..08a2e38bfa1b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -27,9 +27,9 @@ use rustc_target::abi::{ use std::hash::Hash; use super::{ - format_interp_error, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, - InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, - ValueVisitor, + format_interp_error, machine::AllocMap, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, + Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, + Scalar, ValueVisitor, }; // for the validation errors @@ -712,11 +712,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { if let Some(mplace) = op.as_mplace_or_imm().left() { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - if self.ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner().mutability - == Mutability::Mut - { - return true; - } + let mutability = match self.ecx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Static(_) => { + self.ecx.memory.alloc_map.get(alloc_id).unwrap().1.mutability + } + GlobalAlloc::Memory(alloc) => alloc.inner().mutability, + _ => span_bug!(self.ecx.tcx.span, "not a memory allocation"), + }; + return mutability == Mutability::Mut; } } false diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index 9e31209204bc..7679c50c74bc 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -1,21 +1,35 @@ -error[E0391]: cycle detected when evaluating initializer of static `FOO` +error[E0080]: could not evaluate static initializer --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ + | ^^^ encountered static that tried to initialize itself with itself + +error[E0391]: cycle detected when evaluating initializer of static `A` + --> $DIR/recursive-zst-static.rs:13:16 | - = note: ...which immediately requires evaluating initializer of static `FOO` again +LL | static A: () = B; + | ^ + | +note: ...which requires evaluating initializer of static `B`... + --> $DIR/recursive-zst-static.rs:14:16 + | +LL | static B: () = A; + | ^ + = note: ...which again requires evaluating initializer of static `A`, completing the cycle note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | LL | / static FOO: () = FOO; LL | | -LL | | fn main() { +LL | | +LL | | static A: () = B; +... | LL | | FOO LL | | } | |_^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0080, E0391. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs index 14de00bad8aa..9311490020d2 100644 --- a/tests/ui/consts/recursive-zst-static.rs +++ b/tests/ui/consts/recursive-zst-static.rs @@ -7,7 +7,11 @@ // can depend on this fact and will thus do unsound things when it is violated. // See https://github.com/rust-lang/rust/issues/71078 for more details. -static FOO: () = FOO; //~ cycle detected when evaluating initializer of static `FOO` +static FOO: () = FOO; +//~^ ERROR could not evaluate static initializer + +static A: () = B; //~ cycle detected when evaluating initializer of static `A` +static B: () = A; fn main() { FOO diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index 9e31209204bc..7679c50c74bc 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -1,21 +1,35 @@ -error[E0391]: cycle detected when evaluating initializer of static `FOO` +error[E0080]: could not evaluate static initializer --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; - | ^^^ + | ^^^ encountered static that tried to initialize itself with itself + +error[E0391]: cycle detected when evaluating initializer of static `A` + --> $DIR/recursive-zst-static.rs:13:16 | - = note: ...which immediately requires evaluating initializer of static `FOO` again +LL | static A: () = B; + | ^ + | +note: ...which requires evaluating initializer of static `B`... + --> $DIR/recursive-zst-static.rs:14:16 + | +LL | static B: () = A; + | ^ + = note: ...which again requires evaluating initializer of static `A`, completing the cycle note: cycle used when linting top-level module --> $DIR/recursive-zst-static.rs:10:1 | LL | / static FOO: () = FOO; LL | | -LL | | fn main() { +LL | | +LL | | static A: () = B; +... | LL | | FOO LL | | } | |_^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0080, E0391. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/write-to-static-mut-in-static.rs b/tests/ui/consts/write-to-static-mut-in-static.rs index 43c63fed8cef..a2985d05a793 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.rs +++ b/tests/ui/consts/write-to-static-mut-in-static.rs @@ -3,8 +3,8 @@ pub static mut B: () = unsafe { A = 1; }; //~^ ERROR could not evaluate static initializer pub static mut C: u32 = unsafe { C = 1; 0 }; -//~^ ERROR cycle detected pub static D: u32 = D; +//~^ ERROR could not evaluate static initializer fn main() {} diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr index 23dd1346ad93..9616f8eeeb76 100644 --- a/tests/ui/consts/write-to-static-mut-in-static.stderr +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -4,27 +4,12 @@ error[E0080]: could not evaluate static initializer LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer -error[E0391]: cycle detected when evaluating initializer of static `C` - --> $DIR/write-to-static-mut-in-static.rs:5:34 +error[E0080]: could not evaluate static initializer + --> $DIR/write-to-static-mut-in-static.rs:7:21 | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^ - | - = note: ...which immediately requires evaluating initializer of static `C` again -note: cycle used when linting top-level module - --> $DIR/write-to-static-mut-in-static.rs:1:1 - | -LL | / pub static mut A: u32 = 0; -LL | | pub static mut B: () = unsafe { A = 1; }; -LL | | -LL | | -... | -LL | | -LL | | fn main() {} - | |____________^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +LL | pub static D: u32 = D; + | ^ encountered static that tried to initialize itself with itself error: aborting due to 2 previous errors -Some errors have detailed explanations: E0080, E0391. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/recursion/recursive-static-definition.rs b/tests/ui/recursion/recursive-static-definition.rs index 74a094a9b01d..5317c47076e5 100644 --- a/tests/ui/recursion/recursive-static-definition.rs +++ b/tests/ui/recursion/recursive-static-definition.rs @@ -1,4 +1,12 @@ pub static FOO: u32 = FOO; -//~^ ERROR cycle detected when evaluating initializer of static `FOO` +//~^ ERROR could not evaluate static initializer + +#[derive(Copy, Clone)] +pub union Foo { + x: u32, +} + +pub static BAR: Foo = BAR; +//~^ ERROR could not evaluate static initializer fn main() {} diff --git a/tests/ui/recursion/recursive-static-definition.stderr b/tests/ui/recursion/recursive-static-definition.stderr index f071e501e38b..86a22c990e9f 100644 --- a/tests/ui/recursion/recursive-static-definition.stderr +++ b/tests/ui/recursion/recursive-static-definition.stderr @@ -1,20 +1,15 @@ -error[E0391]: cycle detected when evaluating initializer of static `FOO` +error[E0080]: could not evaluate static initializer --> $DIR/recursive-static-definition.rs:1:23 | LL | pub static FOO: u32 = FOO; - | ^^^ - | - = note: ...which immediately requires evaluating initializer of static `FOO` again -note: cycle used when linting top-level module - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | / pub static FOO: u32 = FOO; -LL | | -LL | | -LL | | fn main() {} - | |____________^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + | ^^^ encountered static that tried to initialize itself with itself -error: aborting due to 1 previous error +error[E0080]: could not evaluate static initializer + --> $DIR/recursive-static-definition.rs:9:23 + | +LL | pub static BAR: Foo = BAR; + | ^^^ encountered static that tried to initialize itself with itself -For more information about this error, try `rustc --explain E0391`. +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. From bd546fb20a2d299a0a2e9c2062df9227e82bdb65 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 15 Feb 2024 01:06:27 +0800 Subject: [PATCH 43/55] add extra indent spaces for rust-playground link --- src/librustdoc/doctest.rs | 18 ++++++++++++-- src/librustdoc/doctest/tests.rs | 44 ++++++++++++++++++++++++++++++++- src/librustdoc/html/markdown.rs | 7 ++++-- tests/rustdoc/playground-arg.rs | 2 +- tests/rustdoc/playground.rs | 2 +- 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f2e083de0ec7..f9d4d1af1140 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -40,6 +40,9 @@ use crate::lint::init_lints; pub(crate) struct GlobalTestOptions { /// Whether to disable the default `extern crate my_crate;` when creating doctests. pub(crate) no_crate_inject: bool, + /// Whether inserting extra indent spaces in code block, + /// default is `false`, only `true` for generating code link of Rust playground + pub(crate) insert_indent_space: bool, /// Additional crate-level attributes to add to doctests. pub(crate) attrs: Vec, } @@ -221,7 +224,8 @@ pub(crate) fn run_tests( fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions { use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() }; + let mut opts = + GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false }; let test_attrs: Vec<_> = attrs .iter() @@ -725,7 +729,17 @@ pub(crate) fn make_test( // /// ``` <- end of the inner main line_offset += 1; - prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); + // add extra 4 spaces for each line to offset the code block + let content = if opts.insert_indent_space { + everything_else + .lines() + .map(|line| format!(" {}", line)) + .collect::>() + .join("\n") + } else { + everything_else.to_string() + }; + prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned()); } debug!("final doctest:\n{prog}"); diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a30fe28f94f9..9629acb31eb6 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -53,7 +53,8 @@ assert_eq!(2+2, 4); fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] }; + let opts = + GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -302,3 +303,44 @@ assert_eq!(2+2, 4); make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } + +#[test] +fn make_test_insert_extra_space() { + // will insert indent spaces in the code block if `insert_indent_space` is true + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +assert_eq!(2+2, 4); +eprintln!(\"hello anan\"); +"; + let expected = "#![allow(unused)] +fn main() { + use std::*; + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_insert_extra_space_fn_main() { + // if input already has a fn main, it should insert a space before it + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}"; + let expected = "#![allow(unused)] +use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 1)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ee5891c12fc5..21f682d15b97 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -45,6 +45,7 @@ use std::str::{self, CharIndices}; use crate::clean::RenderedLink; use crate::doctest; +use crate::doctest::GlobalTestOptions; use crate::html::escape::Escape; use crate::html::format::Buffer; use crate::html::highlight; @@ -302,8 +303,10 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .intersperse("\n".into()) .collect::(); let krate = krate.as_ref().map(|s| s.as_str()); - let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition, None); + + let mut opts: GlobalTestOptions = Default::default(); + opts.insert_indent_space = true; + let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let test_escaped = small_url_encode(test); diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs index 2542ed657c1a..1d7085064e5a 100644 --- a/tests/rustdoc/playground-arg.rs +++ b/tests/rustdoc/playground-arg.rs @@ -10,4 +10,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run" diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs index 5c7fa33efc5e..a2fc9eb7387a 100644 --- a/tests/rustdoc/playground.rs +++ b/tests/rustdoc/playground.rs @@ -22,6 +22,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run" From cc7b4e02beecdb75b3b5ee348840b50d06ad67c1 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 25 Jan 2024 15:28:23 +0000 Subject: [PATCH 44/55] Update aarch64 target feature docs to match LLVM --- compiler/rustc_target/src/target_features.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 04943fa3879f..2b7ac68c21df 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -86,7 +86,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-start - // FEAT_AES + // FEAT_AES & FEAT_PMULL ("aes", Stable), // FEAT_BF16 ("bf16", Stable), @@ -124,7 +124,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("lor", Stable), // FEAT_LSE ("lse", Stable), - // FEAT_MTE + // FEAT_MTE & FEAT_MTE2 ("mte", Stable), // FEAT_AdvSimd & FEAT_FP ("neon", Stable), @@ -138,7 +138,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("pmuv3", Stable), // FEAT_RAND ("rand", Stable), - // FEAT_RAS + // FEAT_RAS & FEAT_RASv1p1 ("ras", Stable), // FEAT_RCPC ("rcpc", Stable), @@ -156,7 +156,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("sm4", Stable), // FEAT_SPE ("spe", Stable), - // FEAT_SSBS + // FEAT_SSBS & FEAT_SSBS2 ("ssbs", Stable), // FEAT_SVE ("sve", Stable), From 5d65b1954ef4dc6ea3a1260e1bce31524fc286f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 15 Feb 2024 00:00:00 +0000 Subject: [PATCH 45/55] Avoid debug logging entire MIR body If there is a need to examine the MIR body there is -Zmir-dump. --- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b4fa7f3bea6a..fb174192b849 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -653,7 +653,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { debug!("about to call mir_drops_elaborated..."); let body = tcx.mir_drops_elaborated_and_const_checked(did).steal(); let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); - debug!("body: {:#?}", body); if body.tainted_by_errors.is_some() { return body; diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 095119e2e3ff..fb52bfa468a0 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -15,7 +15,8 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { } fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("remove_noop_landing_pads({:?})", body); + let def_id = body.source.def_id(); + debug!(?def_id); self.remove_nop_landing_pads(body) } } @@ -81,8 +82,6 @@ impl RemoveNoopLandingPads { } fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { - debug!("body: {:#?}", body); - // Skip the pass if there are no blocks with a resume terminator. let has_resume = body .basic_blocks From ec8e8981930d1b2dfc950fb23ee6fa9e792f6172 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 27 Dec 2023 03:17:37 +0000 Subject: [PATCH 46/55] Consider principal trait ref's auto-trait super-traits in dyn upcasting --- .../src/solve/trait_goals.rs | 23 +++-- .../src/traits/select/candidate_assembly.rs | 95 ++++++++++--------- .../src/traits/select/mod.rs | 13 ++- .../add-supertrait-auto-traits.rs | 14 +++ 4 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index eacdd9fde51a..73bf66f66890 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,7 +1,10 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. +use crate::traits::supertrait_def_ids; + use super::assembly::{self, structural_traits, Candidate}; use super::{EvalCtxt, GoalSource, SolverMode}; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; @@ -663,13 +666,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; - // All of a's auto traits need to be in b's auto traits. - let auto_traits_compatible = - b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b)); - if !auto_traits_compatible { - return vec![]; - } - let mut responses = vec![]; // If the principal def ids match (or are both none), then we're not doing // trait upcasting. We're just removing auto traits (or shortening the lifetime). @@ -757,6 +753,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> QueryResult<'tcx> { let param_env = goal.param_env; + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet = a_data + .auto_traits() + .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { + supertrait_def_ids(self.tcx(), principal_def_id) + .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + })) + .collect(); + // More than one projection in a_ty's bounds may match the projection // in b_ty's bound. Use this to first determine *which* apply without // having any inference side-effects. We process obligations because @@ -806,7 +813,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { - if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + if !a_auto_traits.contains(&def_id) { return Err(NoSolution); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 149dc4c75a7e..39f4ceda9f17 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -10,7 +10,7 @@ use std::ops::ControlFlow; use hir::def_id::DefId; use hir::LangItem; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; @@ -968,52 +968,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // We always perform upcasting coercions when we can because of reason // #2 (region bounds). - let auto_traits_compatible = b_data - .auto_traits() - // All of a's auto traits need to be in b's auto traits. - .all(|b| a_data.auto_traits().any(|a| a == b)); - if auto_traits_compatible { - let principal_def_id_a = a_data.principal_def_id(); - let principal_def_id_b = b_data.principal_def_id(); - if principal_def_id_a == principal_def_id_b { - // no cyclic + let principal_def_id_a = a_data.principal_def_id(); + let principal_def_id_b = b_data.principal_def_id(); + if principal_def_id_a == principal_def_id_b { + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet = a_data + .auto_traits() + .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| { + util::supertrait_def_ids(self.tcx(), principal_def_id) + .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + })) + .collect(); + let auto_traits_compatible = b_data + .auto_traits() + // All of a's auto traits need to be in b's auto traits. + .all(|b| a_auto_traits.contains(&b)); + if auto_traits_compatible { candidates.vec.push(BuiltinUnsizeCandidate); - } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { - // not casual unsizing, now check whether this is trait upcasting coercion. - let principal_a = a_data.principal().unwrap(); - let target_trait_did = principal_def_id_b.unwrap(); - let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); - if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( - source, - obligation.param_env, - &obligation.cause, - ) { - if deref_trait_ref.def_id() == target_trait_did { - return; - } + } + } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { + // not casual unsizing, now check whether this is trait upcasting coercion. + let principal_a = a_data.principal().unwrap(); + let target_trait_did = principal_def_id_b.unwrap(); + let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( + source, + obligation.param_env, + &obligation.cause, + ) { + if deref_trait_ref.def_id() == target_trait_did { + return; } + } - for (idx, upcast_trait_ref) in - util::supertraits(self.tcx(), source_trait_ref).enumerate() - { - self.infcx.probe(|_| { - if upcast_trait_ref.def_id() == target_trait_did - && let Ok(nested) = self.match_upcast_principal( - obligation, - upcast_trait_ref, - a_data, - b_data, - a_region, - b_region, - ) - { - if nested.is_none() { - candidates.ambiguous = true; - } - candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + for (idx, upcast_trait_ref) in + util::supertraits(self.tcx(), source_trait_ref).enumerate() + { + self.infcx.probe(|_| { + if upcast_trait_ref.def_id() == target_trait_did + && let Ok(nested) = self.match_upcast_principal( + obligation, + upcast_trait_ref, + a_data, + b_data, + a_region, + b_region, + ) + { + if nested.is_none() { + candidates.ambiguous = true; } - }) - } + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + } + }) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ab0c53e6a9b0..5bcf46a96ed9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2526,6 +2526,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let tcx = self.tcx(); let mut nested = vec![]; + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet = a_data + .auto_traits() + .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { + util::supertrait_def_ids(tcx, principal_def_id) + .filter(|def_id| tcx.trait_is_auto(*def_id)) + })) + .collect(); + let upcast_principal = normalize_with_depth_to( self, obligation.param_env, @@ -2588,7 +2599,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { - if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + if !a_auto_traits.contains(&def_id) { return Err(SelectionError::Unimplemented); } } diff --git a/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs b/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs new file mode 100644 index 000000000000..7e242ed91260 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/add-supertrait-auto-traits.rs @@ -0,0 +1,14 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Znext-solver + +#![feature(trait_upcasting)] + +trait Target {} +trait Source: Send + Target {} + +fn upcast(x: &dyn Source) -> &(dyn Target + Send) { x } + +fn same(x: &dyn Source) -> &(dyn Source + Send) { x } + +fn main() {} From c763f833d14d31fbe63e0b26370a23a51b4f11c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 14:34:42 +0000 Subject: [PATCH 47/55] Only point out non-diverging arms for match suggestions --- compiler/rustc_hir_typeck/src/_match.rs | 14 +++++------ .../src/infer/error_reporting/mod.rs | 13 ++++++---- .../src/infer/error_reporting/suggest.rs | 11 +++++--- compiler/rustc_middle/src/traits/mod.rs | 2 +- .../ui/match/dont-highlight-diverging-arms.rs | 17 +++++++++++++ .../dont-highlight-diverging-arms.stderr | 25 +++++++++++++++++++ .../match/match-arm-resolving-to-never.stderr | 5 +++- 7 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 tests/ui/match/dont-highlight-diverging-arms.rs create mode 100644 tests/ui/match/dont-highlight-diverging-arms.stderr diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 0311aa94cd48..214066814221 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { CoerceMany::with_coercion_sites(coerce_first, arms) }; - let mut other_arms = vec![]; // Used only for diagnostics. + let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics. let mut prior_arm = None; for arm in arms { if let Some(e) = &arm.guard { @@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scrut_span: scrut.span, scrut_hir_id: scrut.hir_id, source: match_src, - prior_arms: other_arms.clone(), + prior_non_diverging_arms: prior_non_diverging_arms.clone(), opt_suggest_box_span, })), ), @@ -142,16 +142,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, ); - other_arms.push(arm_span); - if other_arms.len() > 5 { - other_arms.remove(0); - } - if !arm_ty.is_never() { // When a match arm has type `!`, then it doesn't influence the expected type for // the following arm. If all of the prior arms are `!`, then the influence comes // from elsewhere and we shouldn't point to any previous arm. prior_arm = Some((arm_block_id, arm_ty, arm_span)); + + prior_non_diverging_arms.push(arm_span); + if prior_non_diverging_arms.len() > 5 { + prior_non_diverging_arms.remove(0); + } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b953b25d6c4c..aa92f91f24f8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -777,7 +777,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prior_arm_span, prior_arm_ty, source, - ref prior_arms, + ref prior_non_diverging_arms, opt_suggest_box_span, scrut_span, scrut_hir_id, @@ -817,12 +817,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }); let source_map = self.tcx.sess.source_map(); let mut any_multiline_arm = source_map.is_multiline(arm_span); - if prior_arms.len() <= 4 { - for sp in prior_arms { + if prior_non_diverging_arms.len() <= 4 { + for sp in prior_non_diverging_arms { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label(*sp, format!("this is found to be of type `{t}`")); } - } else if let Some(sp) = prior_arms.last() { + } else if let Some(sp) = prior_non_diverging_arms.last() { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label( *sp, @@ -865,7 +865,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_boxing_for_return_impl_trait( err, ret_sp, - prior_arms.iter().chain(std::iter::once(&arm_span)).copied(), + prior_non_diverging_arms + .iter() + .chain(std::iter::once(&arm_span)) + .copied(), ); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 248e1c0fcc87..c6f6c32fe60c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - prior_arms, + prior_non_diverging_arms, .. }) => { - if let [.., arm_span] = &prior_arms[..] { + if let [.., arm_span] = &prior_non_diverging_arms[..] { Some(ConsiderAddingAwait::BothFuturesSugg { first: arm_span.shrink_to_hi(), second: exp_span.shrink_to_hi(), @@ -234,11 +234,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - ref prior_arms, + ref prior_non_diverging_arms, .. }) => Some({ ConsiderAddingAwait::FutureSuggMultiple { - spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(), + spans: prior_non_diverging_arms + .iter() + .map(|arm| arm.shrink_to_hi()) + .collect(), } }), _ => None, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8e5f026b4c27..683610ba3b6a 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -571,7 +571,7 @@ pub struct MatchExpressionArmCause<'tcx> { pub scrut_span: Span, pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, - pub prior_arms: Vec, + pub prior_non_diverging_arms: Vec, pub opt_suggest_box_span: Option, } diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs new file mode 100644 index 000000000000..dc3b4ca9caad --- /dev/null +++ b/tests/ui/match/dont-highlight-diverging-arms.rs @@ -0,0 +1,17 @@ +fn main() { + let m = 42u32; + + let value = 'out: { + match m { + 1 => break 'out Some(1u16), + 2 => Some(2u16), + 3 => break 'out Some(3u16), + 4 => break 'out Some(4u16), + 5 => break 'out Some(5u16), + _ => {} + //~^ ERROR `match` arms have incompatible types + } + + None + }; +} \ No newline at end of file diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr new file mode 100644 index 000000000000..886c1af13fa3 --- /dev/null +++ b/tests/ui/match/dont-highlight-diverging-arms.stderr @@ -0,0 +1,25 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/dont-highlight-diverging-arms.rs:11:18 + | +LL | / match m { +LL | | 1 => break 'out Some(1u16), +LL | | 2 => Some(2u16), + | | ---------- this is found to be of type `Option` +LL | | 3 => break 'out Some(3u16), +... | +LL | | _ => {} + | | ^^ expected `Option`, found `()` +LL | | +LL | | } + | |_________- `match` arms have incompatible types + | + = note: expected enum `Option` + found unit type `()` +help: consider using a semicolon here, but this will discard any values in the match arms + | +LL | }; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/match-arm-resolving-to-never.stderr b/tests/ui/match/match-arm-resolving-to-never.stderr index 6cbdf03d4c27..fd0c8708b8ca 100644 --- a/tests/ui/match/match-arm-resolving-to-never.stderr +++ b/tests/ui/match/match-arm-resolving-to-never.stderr @@ -3,11 +3,14 @@ error[E0308]: `match` arms have incompatible types | LL | / match E::F { LL | | E::A => 1, + | | - this is found to be of type `{integer}` LL | | E::B => 2, + | | - this is found to be of type `{integer}` LL | | E::C => 3, + | | - this is found to be of type `{integer}` LL | | E::D => 4, + | | - this is found to be of type `{integer}` LL | | E::E => unimplemented!(""), - | | ------------------ this and all prior arms are found to be of type `{integer}` LL | | E::F => "", | | ^^ expected integer, found `&str` LL | | }; From acb201af54e15b1beebb5b8a6691f6c851afe177 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Feb 2024 23:52:57 +0000 Subject: [PATCH 48/55] make better async fn kind errors --- compiler/rustc_trait_selection/messages.ftl | 12 +- compiler/rustc_trait_selection/src/errors.rs | 10 ++ .../error_reporting/type_err_ctxt_ext.rs | 123 ++++++++++++++---- tests/ui/async-await/async-closures/not-fn.rs | 15 +++ .../async-await/async-closures/not-fn.stderr | 16 +++ .../async-closures/wrong-fn-kind.rs | 3 +- .../async-closures/wrong-fn-kind.stderr | 12 +- 7 files changed, 154 insertions(+), 37 deletions(-) create mode 100644 tests/ui/async-await/async-closures/not-fn.rs create mode 100644 tests/ui/async-await/async-closures/not-fn.stderr diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 41db8059cbee..0dcba0e05f76 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -8,14 +8,16 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur *[other] arguments } -trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here +trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment -trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment +trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here -trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}` - .label = this closure implements `{$found}`, not `{$expected}` +trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment -trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here +trait_selection_closure_kind_mismatch = expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}` + .label = this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}` + +trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 20cd573f46e9..407fff03e158 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -135,6 +135,8 @@ pub struct ClosureKindMismatch { #[label(trait_selection_closure_kind_requirement)] pub cause_span: Span, + pub trait_prefix: &'static str, + #[subdiagnostic] pub fn_once_label: Option, @@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel { pub span: Span, pub place: String, } + +#[derive(Diagnostic)] +#[diag(trait_selection_async_closure_not_fn)] +pub(crate) struct AsyncClosureNotFn { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 73effb335606..68b1a0d4e61c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2,7 +2,9 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; -use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; +use crate::errors::{ + AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, +}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxtExt as _; @@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn emit_specialized_closure_kind_error( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + mut trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option { - let self_ty = trait_ref.self_ty().skip_binder(); - if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() - && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(self_ty) + // If `AsyncFnKindHelper` is not implemented, that means that the closure kind + // doesn't extend the goal kind. This is worth reporting, but we can only do so + // if we actually know which closure this goal comes from, so look at the cause + // to see if we can extract that information. + if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() + && let Some(expected_kind) = + trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) - && let sig = closure_args.as_closure().sig() - && self.can_sub( - obligation.param_env, - trait_ref, - sig.map_bound(|sig| { - ty::TraitRef::new( - self.tcx, - trait_ref.def_id(), - [trait_ref.self_ty().skip_binder(), sig.inputs()[0]], - ) - }), - ) { - let mut err = - self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind); - self.note_obligation_cause(&mut err, &obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - Some(err.emit()) - } else { - None + if let Some((_, Some(parent))) = obligation.cause.code().parent() { + // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. + trait_ref = parent.to_poly_trait_ref(); + } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + && let Some(typeck_results) = &self.typeck_results + && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = + *typeck_results.node_type(arg_hir_id).kind() + { + // Otherwise, extract the closure kind from the obligation. + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "async ", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } } + + let self_ty = trait_ref.self_ty().skip_binder(); + + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) { + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; + + let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1)); + + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_sub(obligation.param_env, expected_args, found_args) + }) + }) { + return None; + } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig) = by_ref_captures.kind() + && !sig.skip_binder().output().is_unit() + { + let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + } + None } fn fn_arg_obligation( @@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx>; fn report_cyclic_signature_error( @@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx> { let closure_span = self.tcx.def_span(closure_def_id); @@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: kind, found: found_kind, cause_span: obligation.cause.span, + trait_prefix, fn_once_label: None, fn_mut_label: None, }; diff --git a/tests/ui/async-await/async-closures/not-fn.rs b/tests/ui/async-await/async-closures/not-fn.rs new file mode 100644 index 000000000000..4505e6243e96 --- /dev/null +++ b/tests/ui/async-await/async-closures/not-fn.rs @@ -0,0 +1,15 @@ +// edition:2021 + +// FIXME(async_closures): This needs a better error message! + +#![feature(async_closure)] + +fn main() { + fn needs_fn(_: impl FnMut() -> T) {} + + let mut x = 1; + needs_fn(async || { + //~^ ERROR async closure does not implement `FnMut` because it captures state from its environment + x += 1; + }); +} diff --git a/tests/ui/async-await/async-closures/not-fn.stderr b/tests/ui/async-await/async-closures/not-fn.stderr new file mode 100644 index 000000000000..9c40613599a8 --- /dev/null +++ b/tests/ui/async-await/async-closures/not-fn.stderr @@ -0,0 +1,16 @@ +error: async closure does not implement `FnMut` because it captures state from its environment + --> $DIR/not-fn.rs:11:14 + | +LL | needs_fn(async || { + | -------- ^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_fn` + --> $DIR/not-fn.rs:8:28 + | +LL | fn needs_fn(_: impl FnMut() -> T) {} + | ^^^^^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index f86cee3e0709..1e372deb984e 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -9,8 +9,7 @@ fn main() { let mut x = 1; needs_async_fn(async || { - //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper - // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. + //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` x += 1; }); } diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 4ef8484cc34c..34a6b3a485a6 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,15 +1,17 @@ -error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not satisfied +error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` --> $DIR/wrong-fn-kind.rs:11:20 | LL | needs_async_fn(async || { - | _____--------------_^ + | -------------- -^^^^^^^ + | | | + | _____|______________this closure implements `async FnMut`, not `async Fn` | | | | | required by a bound introduced by this call LL | | -LL | | // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. LL | | x += 1; + | | - closure is `async FnMut` because it mutates the variable `x` here LL | | }); - | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not implemented for `i16` + | |_____- the requirement to implement `async Fn` derives from here | note: required by a bound in `needs_async_fn` --> $DIR/wrong-fn-kind.rs:8:31 @@ -19,4 +21,4 @@ LL | fn needs_async_fn(_: impl async Fn()) {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0525`. From 6018e21d8ad072d28dbd2e991dfd8295e2de321f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 14:38:52 +0000 Subject: [PATCH 49/55] Remove a suggestion that is redundant --- compiler/rustc_hir_typeck/src/_match.rs | 1 - .../rustc_infer/src/infer/error_reporting/mod.rs | 13 ------------- compiler/rustc_middle/src/traits/mod.rs | 1 - tests/ui/match/dont-highlight-diverging-arms.rs | 2 +- .../ui/match/dont-highlight-diverging-arms.stderr | 4 ---- tests/ui/suggestions/issue-81839.stderr | 15 ++++----------- tests/ui/wf/wf-unsafe-trait-obj-match.stderr | 4 ---- 7 files changed, 5 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 214066814221..b0caf45b40af 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -118,7 +118,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, - scrut_hir_id: scrut.hir_id, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), opt_suggest_box_span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index aa92f91f24f8..104bf4a5be87 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -780,7 +780,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ref prior_non_diverging_arms, opt_suggest_box_span, scrut_span, - scrut_hir_id, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -848,18 +847,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { err.subdiagnostic(subdiag); } - if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id) - && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id) - && let hir::StmtKind::Expr(_) = stmt.kind - { - err.span_suggestion_verbose( - stmt.span.shrink_to_hi(), - "consider using a semicolon here, but this will discard any values \ - in the match arms", - ";", - Applicability::MaybeIncorrect, - ); - } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 683610ba3b6a..119e0a49acf1 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -569,7 +569,6 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, pub scrut_span: Span, - pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, pub prior_non_diverging_arms: Vec, pub opt_suggest_box_span: Option, diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs index dc3b4ca9caad..0fb614fa18a6 100644 --- a/tests/ui/match/dont-highlight-diverging-arms.rs +++ b/tests/ui/match/dont-highlight-diverging-arms.rs @@ -14,4 +14,4 @@ fn main() { None }; -} \ No newline at end of file +} diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr index 886c1af13fa3..f0aaecbb7adb 100644 --- a/tests/ui/match/dont-highlight-diverging-arms.stderr +++ b/tests/ui/match/dont-highlight-diverging-arms.stderr @@ -15,10 +15,6 @@ LL | | } | = note: expected enum `Option` found unit type `()` -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr index de1ea98554be..34ff16c653af 100644 --- a/tests/ui/suggestions/issue-81839.stderr +++ b/tests/ui/suggestions/issue-81839.stderr @@ -4,22 +4,15 @@ error[E0308]: `match` arms have incompatible types LL | / match num { LL | | 1 => { LL | | cx.answer_str("hi"); - | | -------------------- this is found to be of type `()` + | | -------------------- + | | | | + | | | help: consider removing this semicolon + | | this is found to be of type `()` LL | | } LL | | _ => cx.answer_str("hi"), | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found future LL | | } | |_____- `match` arms have incompatible types - | -help: consider removing this semicolon - | -LL - cx.answer_str("hi"); -LL + cx.answer_str("hi") - | -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index 3b53f55ffdc1..e30cb8ff921a 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -11,10 +11,6 @@ LL | | } | = note: expected reference `&S` found reference `&R` -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 From fdc56b68860a3e0fc9a9733d746a0f932f9e53cc Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 15 Feb 2024 18:38:36 +0100 Subject: [PATCH 50/55] doc: add note before panicking examples for strict_overflow_ops --- library/core/src/num/int_macros.rs | 36 +++++++++++++++++++++++++++++ library/core/src/num/uint_macros.rs | 16 +++++++++++++ 2 files changed, 52 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d052dcc3e6ee..434bcace616f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -472,6 +472,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] @@ -552,6 +554,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] @@ -606,6 +610,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] @@ -686,6 +692,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] @@ -740,6 +748,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] /// ``` /// + /// The following panics because of overflow: + /// /// ``` should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] @@ -831,11 +841,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] @@ -901,11 +915,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] @@ -970,11 +988,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] @@ -1039,11 +1061,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] @@ -1121,6 +1147,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] @@ -1175,6 +1203,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] @@ -1256,6 +1286,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] @@ -1340,6 +1372,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] @@ -1414,6 +1448,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index a217c2e259d2..5036a3b0c71c 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -480,6 +480,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] @@ -561,6 +563,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] /// ``` /// + /// The following panic because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")] @@ -620,6 +624,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] @@ -700,6 +706,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ``` should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] @@ -1172,6 +1180,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] @@ -1226,6 +1236,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] @@ -1307,6 +1319,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] @@ -1406,6 +1420,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] From 675d092e3e69e1ca6f0abcad4b18d746e6ed558a Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 15 Feb 2024 18:41:30 +0100 Subject: [PATCH 51/55] doc: panicking division by zero examples for unsigned strict div ops --- library/core/src/num/uint_macros.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 5036a3b0c71c..f2f29e4ad819 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -793,6 +793,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -848,6 +855,12 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] /// ``` + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -903,6 +916,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -959,6 +979,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ From 954d56591cbbc057d53c233f86895658febe407d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 13:20:33 +0000 Subject: [PATCH 52/55] Fix closure kind docs --- compiler/rustc_middle/src/ty/sty.rs | 41 ++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 66086ac87f16..a58171252675 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2363,28 +2363,42 @@ impl<'tcx> Ty<'tcx> { } /// When we create a closure, we record its kind (i.e., what trait - /// it implements) into its `ClosureArgs` using a type + /// it implements, constrained by how it uses its borrows) into its + /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type /// parameter. This is kind of a phantom type, except that the /// most convenient thing for us to are the integral types. This /// function converts such a special type into the closure - /// kind. To go the other way, use `closure_kind.to_ty(tcx)`. + /// kind. To go the other way, use [`Ty::from_closure_kind`]. /// /// Note that during type checking, we use an inference variable /// to represent the closure kind, because it has not yet been /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`) - /// is complete, that type variable will be unified. - /// - /// To be noted that you can use [`ClosureArgs::kind()`] or [`CoroutineClosureArgs::kind()`] - /// to get the same information, which you can get by calling [`GenericArgs::as_closure()`] - /// or [`GenericArgs::as_coroutine_closure()`], depending on the type of the closure. - /// - /// Otherwise, this method can be used as follows: + /// is complete, that type variable will be unified with one of + /// the integral types. /// /// ```rust,ignore (snippet of compiler code) - /// let TyKind::Closure(def_id, [closure_fn_kind_ty, ..]) = closure_ty.kind() - /// && let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind() /// { - /// // your code + /// println!("{closure_kind:?}"); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } + /// ``` + /// + /// After upvar analysis, you should instead use [`ClosureArgs::kind()`] + /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` + /// has been constrained instead of manually calling this method. + /// + /// ```rust,ignore (snippet of compiler code) + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_closure().kind()); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_coroutine_closure().kind()); /// } /// ``` pub fn to_opt_closure_kind(self) -> Option { @@ -2406,7 +2420,8 @@ impl<'tcx> Ty<'tcx> { } } - /// Inverse of [`Ty::to_opt_closure_kind`]. + /// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method + /// for explanation of the relationship between `Ty` and [`ty::ClosureKind`]. pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { match kind { ty::ClosureKind::Fn => tcx.types.i8, From 089eb6b11faee46ca2bd3cfdefacc0bd4b4b4c1d Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Fri, 16 Feb 2024 04:54:51 +0000 Subject: [PATCH 53/55] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2748518e634d..2115e482c64a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -502ce8287bc3c86dca07acc38c5ff9431a6097be +0f806a9812b62c36bdab08d33c14cf2d3ecf4355 From db4ba498d9ffd584f9fd5483acd0c996c3379d8e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 16 Feb 2024 09:29:39 +0000 Subject: [PATCH 54/55] Fix an ICE in the recursion lint --- compiler/rustc_mir_build/src/lints.rs | 4 +- .../ui/traits/normalize-conflicting-impls.rs | 49 +++++++++++++++++++ .../traits/normalize-conflicting-impls.stderr | 21 ++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/normalize-conflicting-impls.rs create mode 100644 tests/ui/traits/normalize-conflicting-impls.stderr diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 508936be29d7..3f2b7c482a67 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -137,7 +137,9 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { let func_ty = func.ty(body, tcx); if let ty::FnDef(callee, args) = *func_ty.kind() { - let normalized_args = tcx.normalize_erasing_regions(param_env, args); + let Ok(normalized_args) = tcx.try_normalize_erasing_regions(param_env, args) else { + return false; + }; let (callee, call_args) = if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, callee, normalized_args) { diff --git a/tests/ui/traits/normalize-conflicting-impls.rs b/tests/ui/traits/normalize-conflicting-impls.rs new file mode 100644 index 000000000000..454b2fd01535 --- /dev/null +++ b/tests/ui/traits/normalize-conflicting-impls.rs @@ -0,0 +1,49 @@ +fn problematic_function(material_surface_element: ()) +where + DefaultAllocator: FiniteElementAllocator<(), Space>, +{ + let _: Point2 = material_surface_element.map_reference_coords().into(); +} + +impl Allocator for DefaultAllocator +where + R::Value: DimName, //~ ERROR: `Value` not found for `R` +{ + type Buffer = (); +} +impl Allocator for DefaultAllocator {} +//~^ ERROR: conflicting implementations +impl DimName for () {} +impl DimName for u32 {} +impl From> for Point { + fn from(_: VectorN) -> Self { + todo!() + } +} + +impl FiniteElement for () {} + +type VectorN = Matrix<>::Buffer>; + +type Point2 = Point; + +struct DefaultAllocator; +struct Matrix(S); +struct Point(N, D); + +trait Allocator { + type Buffer; +} +trait DimName {} +trait FiniteElementAllocator: + Allocator + Allocator +{ +} + +trait FiniteElement { + fn map_reference_coords(&self) -> VectorN { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/traits/normalize-conflicting-impls.stderr b/tests/ui/traits/normalize-conflicting-impls.stderr new file mode 100644 index 000000000000..9a66fe00c3fe --- /dev/null +++ b/tests/ui/traits/normalize-conflicting-impls.stderr @@ -0,0 +1,21 @@ +error[E0220]: associated type `Value` not found for `R` + --> $DIR/normalize-conflicting-impls.rs:10:8 + | +LL | R::Value: DimName, + | ^^^^^ associated type `Value` not found + +error[E0119]: conflicting implementations of trait `Allocator<_, ()>` for type `DefaultAllocator` + --> $DIR/normalize-conflicting-impls.rs:14:1 + | +LL | / impl Allocator for DefaultAllocator +LL | | where +LL | | R::Value: DimName, + | |______________________- first implementation here +... +LL | impl Allocator for DefaultAllocator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `DefaultAllocator` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0220. +For more information about an error, try `rustc --explain E0119`. From 840ca093e6e44588b7af0564756cd2384c9a6da9 Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Fri, 16 Feb 2024 05:03:16 +0000 Subject: [PATCH 55/55] fmt --- src/tools/miri/src/shims/x86/mod.rs | 15 +++------------ src/tools/miri/src/shims/x86/sse.rs | 5 +---- src/tools/miri/src/shims/x86/sse2.rs | 10 ++-------- src/tools/miri/src/shims/x86/sse41.rs | 5 +---- 4 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index b24ea8aec84b..115be1d6f223 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -296,10 +296,7 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( this.write_scalar(res0, &this.project_index(&dest, 0)?)?; for i in 1..dest_len { - this.copy_op( - &this.project_index(&left, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } Ok(()) @@ -420,10 +417,7 @@ fn unary_op_ss<'tcx>( this.write_scalar(res0, &this.project_index(&dest, 0)?)?; for i in 1..dest_len { - this.copy_op( - &this.project_index(&op, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&op, i)?, &this.project_index(&dest, i)?)?; } Ok(()) @@ -479,10 +473,7 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( )?; for i in 1..dest_len { - this.copy_op( - &this.project_index(&left, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } Ok(()) diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 9fb947cb2a3d..da0db92738fa 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -208,10 +208,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.write_immediate(*res0, &dest0)?; for i in 1..dest_len { - this.copy_op( - &this.project_index(&left, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } } _ => return Ok(EmulateForeignItemResult::NotSupported), diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index e5c8267320a4..b34b93e37390 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -440,10 +440,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.write_scalar(res0, &this.project_index(&dest, 0)?)?; for i in 1..dest_len { - this.copy_op( - &this.project_index(&op, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&op, i)?, &this.project_index(&dest, i)?)?; } } // Used to implement _mm_sqrt_pd functions. @@ -580,10 +577,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // Copy remianing from `left` for i in 1..dest_len { - this.copy_op( - &this.project_index(&left, i)?, - &this.project_index(&dest, i)?, - )?; + this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } } // Used to implement the `_mm_pause` function. diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 2abd10fa7a77..32b1fe43c583 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -57,10 +57,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.write_immediate(*src_value, &dest)?; } else { // copy from `left` - this.copy_op( - &this.project_index(&left, i)?, - &dest, - )?; + this.copy_op(&this.project_index(&left, i)?, &dest)?; } } }